3
 a|?                 @   s  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 yd dlmZm	Z	m
Z
mZ W n ek
rt   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eeddddZd(ddeeddddZeedddZd)dd d!d"Zd#d$d%d&ZdS )*    N)clouds)
exceptions)status)serviceclient)util)AnyDictListOptionalz/v1/context/machines/tokenz3/v1/contracts/{contract}/context/machines/{machine}z/v1/resourcesz3/v1/resources/{resource}/context/machines/{machine}z/v1/clouds/{cloud_type}/tokenz	%B %d, %Yc                   s:   e Zd Z fddZdd Zd
ddZ fdd	Z  ZS )ContractAPIErrorc                s^   t  j||j|j|j d|kr,|d | _n|g| _x$| jD ]}|jd|jd|d< q<W 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<   x6| j D ],}||jdkrdS |jddj|rdS qW dS )Nr   Tmessage F)r   r   
startswith)r   
error_coder   r   r   r   __contains__%   s    zContractAPIError.__contains__Nc             C   s(   x"| j D ]}|d |kr|d S qW |S )Nr   detail)r   )r   r   defaultr   r   r   r   __get__-   s    zContractAPIError.__get__c                s   t  j }g }xj| jD ]`}|jds@|j|jd|jdd qx4|d j D ]$}t|trh|j| qN|j| qNW qW |d | j	 d dj
| S )Nextrar   r   r   z: []z, )r   __str__r   r   appendvalues
isinstancelistextendr   join)r   prefixdetailserrr"   )r   r   r   r$   3   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dd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 )!UAContractClientcontract_urlNc             C   sL   | j  }|jddj|i | j|}| jt||d\}}| j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.
        Authorizationz	Bearer {})datar   zmachine-token)r   updateformat_get_platform_datarequest_urlAPI_V1_CONTEXT_MACHINE_TOKENcfgwrite_cache)r   contract_token
machine_idr   r5   machine_token_headersr   r   r   request_contract_machine_attachG   s    
z0UAContractClient.request_contract_machine_attachzDict[str, Any])returnc             C   s6   t j }|d |d |d d}| jt|d\}}|S )z=Requests list of entitlements available to this machine type.archserieskernel)architecturerD   rE   )query_params)r   get_platform_infor9   API_V1_RESOURCES)r   platformrG   Zresource_responser   r   r   r   request_resources[   s    z"UAContractClient.request_resources)instancec            C   s0   | j tj|jd|jd\}}| j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)r5   zcontract-token)r9   API_V1_AUTO_ATTACH_CLOUD_TOKENr7   rM   Zidentity_docr;   r<   )r   rL   responser@   r   r   r   "request_auto_attach_contract_tokenh   s    	z3UAContractClient.request_auto_attach_contract_tokenzOptional[str])r?   resourcer>   rB   c             C   s|   |st j| jj}| j }|jddj|i tj||d}| j||d\}}|j	drd|d |d< | jj
dj|| |S )a  Requests machine access context for a given resource

        @param machine_token: The authentication token needed to talk to
            this contract service endpoint.
        @param resource: Entitlement name.
        @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 entitlement accessInfo.
        r4   z	Bearer {})rQ   machine)r   expireszmachine-access-{})r   get_machine_idr;   data_dirr   r6   r7   #API_V1_TMPL_RESOURCE_MACHINE_ACCESSr9   r   r<   )r   r?   rQ   r>   r   r   Zresource_accessr   r   r   request_resource_machine_accessz   s    

z0UAContractClient.request_resource_machine_accessr   )r?   contract_idr>   rB   c             C   s   | j |||ddS )z6Update existing machine-token for an attached machine.F)r?   rX   r>   detach)_request_machine_token_update)r   r?   rX   r>   r   r   r   request_machine_token_update   s
    z-UAContractClient.request_machine_token_updatec             C   sP   | j ddjdd}| jjd}t|t|kr>tjd i S | j|||ddS )	zAReport the attached machine should be detached from the contract.N)r>   	machineIdr   z
machine-idz<Found new machine-id. Do not call detach on contract backendT)r?   rX   r>   rY   )r8   r   r;   
read_cachestrloggingdebugrZ   )r   r?   rX   r>   Zcurr_machine_idZpast_machine_idr   r   r   detach_machine_from_contract   s    z-UAContractClient.detach_machine_from_contractF)r?   rX   r>   rY   rB   c       
      C   s   | j  }|jddj|i | j|}tj||d d}d|i}|rNd|d< nd|d< ||d	< | j|f|\}	}|jd
r|d
 |	d
< |s| jjd|	 | jjd|jd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   z	Bearer {}r\   )contractrR   r   ZDELETEmethodPOSTr5   rS   zmachine-tokenz
machine-idr   )	r   r6   r7   r8   *API_V1_TMPL_CONTEXT_MACHINE_TOKEN_RESOURCEr9   r   r;   r<   )
r   r?   rX   r>   rY   r   r5   r   kwargsrO   r   r   r   rZ      s"    


z.UAContractClient._request_machine_token_updatec             C   s0   |st j| jj}t j }|jd}|||dS )z<"Return a dict of platform-relateddata for contract requestsrC   )r\   rF   os)r   rT   r;   rU   rH   pop)r   r>   rJ   rC   r   r   r   r8      s
    
z#UAContractClient._get_platform_data)N)N)N)N)NF)r.   r/   r0   Zcfg_url_base_attrr   Zapi_error_clsrA   rK   r   ZAutoAttachCloudInstancerP   r^   rW   r[   ra   boolrZ   r8   r   r   r   r   r2   B   s   

 
!r2   TzDict[str, Any])past_entitlementsnew_entitlementsallow_enableseries_overridesrB   c             C   s   d}d}xt |j D ]\}}yt| j|i |||d W q tjk
r|   d}tj  tj	dj
||d W dQ R X Y q tk
r   d}tj  tjdj
||d W dQ R X Y qX qW |rtjtjn|rtjtjdS )a  Iterate over all entitlements in new_entitlement and apply any delta
    found according to past_entitlements.

    :param past_entitlements: dict containing the last valid information
        regarding service entitlements.
    :param new_entitlements: dict containing the current information regarding
        service entitlements.
    :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.
    :param series_overrides: Boolean set True if series overrides should be
        applied to the new_access dict.
    F)rl   rm   Tz4Failed to process contract delta for {name}: {delta})namedeltaNz>Unexpected error processing contract delta for {name}: {delta})sorteditemsprocess_entitlement_deltar   r   UserFacingErrorr   disable_log_to_consoler_   r   r7   	Exception	exceptionr   MESSAGE_UNEXPECTED_ERROR'MESSAGE_ATTACH_FAILURE_DEFAULT_SERVICES)rj   rk   rl   rm   Zdelta_errorZunexpected_errorrn   Znew_entitlementr   r   r   process_entitlements_delta   s4    


 ry   Fr   )orig_access
new_accessrl   rm   rB   c       	      C   s   ddl m} |rtj| tj| |}|r| jdi jd}|sR|jdi jd}|sftdj| |y|| }W n  tk
r   t	j
d| |S X ||d}|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 new_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.
    :param series_overrides: Boolean set True if series overrides should be
        applied to the new_access dict.

    :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)
assume_yes)rl   )uaclient.entitlementsr|   r   apply_series_overridesget_dict_deltasr   RuntimeErrorr7   KeyErrorr_   r`   process_contract_deltas)	rz   r{   rl   rm   r|   deltasrn   ent_clsr}   r   r   r   rr     s,    


rr   )r   rB   c             C   s   t j}t| drt| jdkrd| jd kr| jd d }|d }|d }d}|dkrv|d jt}t jj||d	}n>|d
kr|d jt}t j	j||d	}n|dkrt j
j|d}t jj|d}|S )Nr   r   infoZ
contractIdreasonr   zno-longer-effectivetime)rX   dateznot-effective-yetznever-effective)rX   )r   )r   MESSAGE_ATTACH_EXPIRED_TOKENhasattrlenr   strftimeATTACH_FAIL_DATE_FORMAT MESSAGE_ATTACH_FORBIDDEN_EXPIREDr7    MESSAGE_ATTACH_FORBIDDEN_NOT_YETMESSAGE_ATTACH_FORBIDDEN_NEVERMESSAGE_ATTACH_FORBIDDEN)r   msgr   rX   r   Z
reason_msgr   r   r   r    _create_attach_forbidden_messageP  s*    
r   zOptional[str])r=   c       
      C   s  | j }| j}|r|rtdt| }|ry|j|d W n tjk
r } zt|trt	|dr|j
dkrxtjtjn|j
dkrt|}tj||tj  tjt| W dQ R X tjtjW Y dd}~X nX n&|d }|d d	 d
 }	|j||	d 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 machine)r=   r   i  i  NZmachineTokenmachineTokenInfocontractInfoid)r?   rX   )r?   entitlementsr   r2   rA   r   UrlErrorr'   r   r   r   r   rs   r   MESSAGE_ATTACH_INVALID_TOKENr   rt   r_   rv   r^   MESSAGE_CONNECTIVITY_ERRORr[   ry   )
r;   r=   rl   Z
orig_tokenZorig_entitlementsZcontract_clientr   r   r?   rX   r   r   r   request_updated_contractm  s:    






 
r   z
List[Dict])rB   c             C   s   t | }|j }|jdg S )zCQuery available resources from the contrct server for this machine.	resources)r2   rK   r   )r;   clientr   r   r   r   get_available_resources  s    r   )T)FT)NF)r_   uaclientr   r   r   r   r   typingr   r   r	   r
   ImportErrorr:   re   rI   rV   rN   r   r   r   ZUAServiceClientr2   ri   ry   rr   r^   r   r   r   r   r   r   r   <module>   s4   ' -
1 
.6