U
    M[^80                     @   s   d dl m Z  d dlZd dlZd dlmZ d dlmZ d dlmZ d dlmZ d dlmZ zd dl	m
Z
mZmZmZ W n ek
r   Y nX d	Zd
ZdZdZdZdZG dd dejZG dd dejZdddZdddddZddddZdS )     )datetimeN)clouds)
exceptions)status)serviceclient)util)AnyDictListOptionalzinvalid tokenz/v1/context/machines/tokenz3/v1/contracts/{contract}/context/machines/{machine}z/v1/resourcesz3/v1/resources/{resource}/context/machines/{machine}z/v1/clouds/{cloud_type}/tokenc                       s:   e Zd Z fddZdd Zd
ddZ fdd	Z  ZS )ContractAPIErrorc                    sZ   t  ||j|j|j d|kr,|d | _n|g| _| jD ]}|d|d|d< q:d S )NZ
error_listtitlecode)super__init__r   headersurl
api_errorsget)selfeZerror_responseerror	__class__ 3/usr/lib/python3/dist-packages/uaclient/contract.pyr      s    
zContractAPIError.__init__c                 C   s<   | j D ]0}||dkr dS |dd|r dS qdS )Nr   Tmessage F)r   r   
startswith)r   
error_coder   r   r   r   __contains__'   s    
zContractAPIError.__contains__Nc                 C   s(   | j D ]}|d |kr|d   S q|S )Nr   detail)r   )r   r   defaultr   r   r   r   __get__/   s    
zContractAPIError.__get__c              
      s   t   }g }| jD ]\}|ds>||d|dd q|d  D ]$}t|trd|| qJ|| qJq|d | j	 d d
| S )Nextrar!   r   r   z: []z, )r   __str__r   r   appendvalues
isinstancelistextendr   join)r   prefixZdetailserrr$   r   r   r   r&   5   s    



zContractAPIError.__str__)N)__name__
__module____qualname__r   r    r#   r&   __classcell__r   r   r   r   r      s   	
r   c                   @   s   e Zd ZdZeZdddZddddZej	d	d
dZ
deeeddddZdeeeddddZdeeeeddddZdd ZdS )UAContractClientZcontract_urlNc                 C   sL   |   }|dd|i | |}| jt||d\}}| jd| |S )a  Requests machine attach to the provided contact_id.

        @param contract_id: Unique contract id provided by contract service.
        @param contract_token: Token string providing authentication to
            ContractBearer service endpoint.
        @param machine_id: Optional unique system machine id. When absent,
            contents of /etc/machine-id will be used.

        @return: Dict of the JSON response containing the machine-token.
        Authorization	Bearer {})datar   machine-token)r   updateformat_get_platform_datarequest_urlAPI_V1_CONTEXT_MACHINE_TOKENcfgwrite_cache)r   contract_token
machine_idr   r6   machine_token_headersr   r   r   request_contract_machine_attachI   s    
  
z0UAContractClient.request_contract_machine_attachzDict[str, Any]returnc                 C   sB   t  }|d |d |d d}| td tj| \}}|S )z=Requests list of entitlements available to this machine type.archserieskernel)architecturerG   rH   ?)r   get_platform_infor;   API_V1_RESOURCESurllibparseZ	urlencode)r   platformZquery_paramsZresource_responser   r   r   r   request_resources]   s    z"UAContractClient.request_resources)instancec                C   s0   | j tj|jd|jd\}}| jd| |S )zRequests contract token for auto-attach images for Pro clouds.

        @param instance: AutoAttachCloudInstance for the cloud.

        @return: Dict of the JSON response containing the contract-token.
        )
cloud_type)r6   zcontract-token)r;   API_V1_AUTO_ATTACH_CLOUD_TOKENr9   rR   Zidentity_docr=   r>   )r   rQ   responserB   r   r   r   "request_auto_attach_contract_tokenj   s    	
z3UAContractClient.request_auto_attach_contract_tokenr	   )rA   contract_idr@   rE   c                 C   s   | j |||ddS )z6Update existing machine-token for an attached machine.FrA   rV   r@   detach_request_machine_token_updater   rA   rV   r@   r   r   r   request_machine_token_update|   s    z-UAContractClient.request_machine_token_updatec                 C   s   | j |||ddS )zAReport the attached machine should be detached from the contract.TrW   rY   r[   r   r   r   detach_machine_from_contract   s    z-UAContractClient.detach_machine_from_contractF)rA   rV   r@   rX   rE   c           
      C   s   |   }|dd|i | |}tj||d d}d|i}|rNd|d< nd|d< ||d	< | j|f|\}	}|d
r|d
 |	d
< |s| jd|	 |	S )aB  Request machine token refresh from contract server.

        @param machine_token: The machine token needed to talk to
            this contract service endpoint.
        @param contract_id: Unique contract id provided by contract service.
        @param machine_id: Optional unique system machine id. When absent,
            contents of /etc/machine-id will be used.
        @param detach: Boolean set True if detaching this machine from the
            active contract. Default is False.

        @return: Dict of the JSON response containing refreshed machine-token
        r4   r5   	machineId)Zcontractmachiner   ZDELETEmethodZPOSTr6   Zexpiresr7   )	r   r8   r9   r:   *API_V1_TMPL_CONTEXT_MACHINE_TOKEN_RESOURCEr;   r   r=   r>   )
r   rA   rV   r@   rX   r   r6   r   kwargsrT   r   r   r   rZ      s$    
 

z.UAContractClient._request_machine_token_updatec                 C   s0   |st | jj}t  }|d}|||dS )z<"Return a dict of platform-relateddata for contract requestsrF   )r^   rI   os)r   Zget_machine_idr=   Zdata_dirrK   pop)r   r@   rO   rF   r   r   r   r:      s
    
z#UAContractClient._get_platform_data)N)N)N)NF)r/   r0   r1   Zcfg_url_base_attrr   Zapi_error_clsrC   rP   r   ZAutoAttachCloudInstancerU   strr\   r]   boolrZ   r:   r   r   r   r   r3   D   s<   
        &r3   Fc                 C   s   ddl m} t| t| |}|r| di d}|sN|di d}|sbtd| |z|| }W n$ tk
r   t	
d| | Y S X | }|j| ||d |S )a:  Process a entitlement access dictionary deltas if they exist.

    :param orig_access: Dict with original entitlement access details before
        contract refresh deltas
    :param orig_access: Dict with updated entitlement access details after
        contract refresh
    :param allow_enable: Boolean set True if allowed to perform the enable
        operation. When False, a message will be logged to inform the user
        about the recommended enabled service.

    :raise UserFacingError: on failure to process deltas.
    :return: Dict of processed deltas
    r   )ENTITLEMENT_CLASS_BY_NAMEentitlementtypez5Could not determine contract delta service type {} {}z3Skipping entitlement deltas for "%s". No such classallow_enable)Zuaclient.entitlementsrg   r   Zapply_series_overridesZget_dict_deltasr   RuntimeErrorr9   KeyErrorloggingdebugZprocess_contract_deltas)Zorig_accessZ
new_accessrk   rg   ZdeltasnameZent_clsrh   r   r   r   process_entitlement_delta   s:    
  
  rq   zOptional[str]r?   c                 C   s  | j }| j}|r|rtdt| }|rz|j|d}W q tjk
r } zTt|trnt	|krjt
tj|t  tt| W 5 Q R X t
tjW 5 d}~X Y qX n&|d }|d d d }	|j||	d}|d d d	}
|
rt|
d
t k rt
tjd}d}t| j D ]\}}zt||i ||d W n t
jk
r   d}t  tdj||d W 5 Q R X Y nB tk
r   d}t  tdj||d W 5 Q R X Y nX q&|rt
tjn|rt
tjdS )af  Request contract refresh from ua-contracts service.

    Compare original token to new token and react to entitlement deltas.

    :param cfg: Instance of UAConfig for this machine.
    :param contract_token: String contraining an optional contract token.
    :param allow_enable: Boolean set True if allowed to perform the enable
        operation. When False, a message will be logged to inform the user
        about the recommended enabled service.

    :raise UserFacingError: on failure to update contract or error processing
        contract deltas
    :raise UrlError: On failure to contact the server
    z<Got unexpected contract_token on an already attached machinerr   NZmachineTokenZmachineTokenInfoZcontractInfoid)rA   rV   ZeffectiveToz%Y-%m-%dT%H:%M:%SZFrj   Tz4Failed to process contract delta for {name}: {delta})rp   Zdeltaz>Unexpected error processing contract delta for {name}: {delta}) rA   Zentitlementsrl   r3   rC   r   UrlErrorr)   r   API_ERROR_INVALID_TOKENr   ZUserFacingErrorr   ZMESSAGE_ATTACH_INVALID_TOKENZdisable_log_to_consolern   Z	exceptionre   ZMESSAGE_CONNECTIVITY_ERRORr\   r   r   strptimeZutcnowZMESSAGE_CONTRACT_EXPIRED_ERRORsorteditemsrq   r9   	ExceptionZMESSAGE_UNEXPECTED_ERRORZ'MESSAGE_ATTACH_FAILURE_DEFAULT_SERVICES)r=   r?   rk   Z
orig_tokenZorig_entitlementsZcontract_clientZ	new_tokenr   rA   rV   ZexpiryZdelta_errorZunexpected_errorrp   Znew_entitlementr   r   r   request_updated_contract   s    


  


 
 rz   z
List[Dict]rD   c                 C   s   t | }| }|dg S )zCQuery available resources from the contrct server for this machine.	resources)r3   rP   r   )r=   Zclientr{   r   r   r   get_available_resources=  s    r|   )F)NF)r   rn   rM   Zuaclientr   r   r   r   r   typingr   r	   r
   r   ImportErrorru   r<   ra   rL   Z#API_V1_TMPL_RESOURCE_MACHINE_ACCESSrS   rt   r   ZUAServiceClientr3   rq   rz   r|   r   r   r   r   <module>   s8   '}
+   R