o
    K&bH                     @   sp  d dl Z d dlmZmZmZmZmZ d dlmZm	Z	m
Z
mZmZmZ d dlmZ d dlmZ d dlmZ dZdZd	Zd
ZdZdZdZe	 ZG dd dejZ	d)deeef deeef de de ddf
ddZ!		d*deeef deeef de de deee f f
ddZ"de
j#dej$fddZ%	d+d ee fd!d"Z&d#edee fd$d%Z'd#ed&edeeef fd'd(Z(dS ),    N)AnyDictListOptionalTuple)cloudsevent_logger
exceptionsmessagesserviceclientutil)UAConfig)ATTACH_FAIL_DATE_FORMAT)UserFacingStatusz/v1/context/machines/tokenz3/v1/contracts/{contract}/context/machines/{machine}z/v1/resourcesz3/v1/resources/{resource}/context/machines/{machine}z/v1/clouds/{cloud_type}/tokenz3/v1/contracts/{contract}/machine-activity/{machine}z/v1/contractc                   @   s   e Zd ZdZejZd ddZdee	e
f fddZde	dee	e
f fd	d
ZdejfddZ	d de	de	dee	 dee	e
f fddZ	d de	de	de	defddZdd Z		d!de	de	de	dedef
ddZdd Zd dee	 fddZdS )"UAContractClientZcontract_urlNc                 C   s~   |   }|dd|i | |}| jt||d\}}| jd| tj	
  |di d|d}| jd| |S )a}  Requests machine attach to the provided machine_id.

        @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 {})dataheadersmachine-tokenmachineTokenInfo	machineId
machine-id)r   updateformat_get_platform_datarequest_urlAPI_V1_CONTEXT_MACHINE_TOKENcfgwrite_cacher   get_machine_idcache_clearget)selfcontract_token
machine_idr   r   machine_token_headers r(   3/usr/lib/python3/dist-packages/uaclient/contract.pyrequest_contract_machine_attach$   s   




z0UAContractClient.request_contract_machine_attachreturnc                 C   s6   t  }|d |d |d d}| jt|d\}}|S )z=Requests list of entitlements available to this machine type.archserieskernel)architecturer-   r.   )query_params)r   get_platform_infor   API_V1_RESOURCES)r#   platformr0   Zresource_responser   r(   r(   r)   request_resources>   s   
z"UAContractClient.request_resourcesr$   c                 C   s2   |   }|dd|i | jt|d\}}|S )Nr   r   r   )r   r   r   r   API_V1_CONTRACT_INFORMATION)r#   r$   r   Zresponse_dataZ_response_headersr(   r(   r)   request_contract_informationK   s   
z-UAContractClient.request_contract_information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)r   zcontract-token)r   API_V1_AUTO_ATTACH_CLOUD_TOKENr   r9   Zidentity_docr   r   )r#   r8   responser'   r(   r(   r)   "request_auto_attach_contract_tokenU   s   	
z3UAContractClient.request_auto_attach_contract_tokenr&   resourcer%   c                 C   sz   |st | j}|  }|dd|i tj||d}| j||d\}}|dr1|d |d< | j	d|| |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.
        r   r   )r=   machiner5   expireszmachine-access-{})
r   r    r   r   r   r   #API_V1_TMPL_RESOURCE_MACHINE_ACCESSr   r"   r   )r#   r&   r=   r%   r   urlZresource_accessr(   r(   r)   request_resource_machine_accessg   s   

z0UAContractClient.request_resource_machine_accesscontract_idc                 C   s   | j |||ddS )z6Update existing machine-token for an attached machine.F)r&   rC   r%   detach)_request_machine_token_update)r#   r&   rC   r%   r(   r(   r)   request_machine_token_update   s   z-UAContractClient.request_machine_token_updatec           	      C   s   | j j}| j jd}t| j }| |}tj||d}| 	 }|
dd|i | j|||d\}}|rJ| j d}||d< | j d| dS dS )	zReport current activity token and enabled services.

        This will report to the contracts backend all the current
        enabled services in the system.
        machineTokenZcontractr>   r   r   )r   r   r   activityInfoN)r   rC   r&   r"   r   r    _get_activity_infoAPI_V1_MACHINE_ACTIVITYr   r   r   r   Z
read_cacher   )	r#   rC   r&   r%   Zrequest_datarA   r   r;   _r(   r(   r)   report_machine_activity   s   
z(UAContractClient.report_machine_activityFrD   c           
      C   s   |   }|dd|i | |}|  |d< tj||d d}d|i}|r-d|d< nd	|d< ||d
< | j|fi |\}	}|drK|d |	d< |sm| j	d|	 t
j  |	di d|d}| 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
        r   r   rI   r   rH   r   ZDELETEmethodZPOSTr   r?   r   r   r   )r   r   r   r   rJ   *API_V1_TMPL_CONTEXT_MACHINE_TOKEN_RESOURCEr   r"   r   r   r   r    r!   )
r#   r&   rC   r%   rD   r   r   rA   kwargsr;   r(   r(   r)   rE      s.   




z.UAContractClient._request_machine_token_updatec                 C   s6   |st | j}t  }| }|d}|||dS )z<Return a dict of platform-related data for contract requestsr,   )r   r/   os)r   r    r   r1   copypop)r#   r%   r3   Zplatform_osr,   r(   r(   r)   r      s   
z#UAContractClient._get_platform_datac                    sJ   ddl m} |st j} jjp|} fdd|D }| jj|dS )z9Return a dict of activity info data for contract requestsr   )ENTITLEMENT_CLASSESc                    s0   g | ]}| j  d  tjkr| j jqS )r   )r   Zuser_facing_statusr   ZACTIVEname).0Zentr#   r(   r)   
<listcomp>   s    
z7UAContractClient._get_activity_info.<locals>.<listcomp>)Z
activityIDZactivityToken	resources)uaclient.entitlementsrT   r   r    r   activity_idZactivity_token)r#   r%   rT   r[   Zenabled_servicesr(   rW   r)   rJ      s   
z#UAContractClient._get_activity_info)NNF)__name__
__module____qualname__Zcfg_url_base_attrr	   ContractAPIErrorZapi_error_clsr*   r   strr   r4   r7   r   ZAutoAttachCloudInstancer<   r   rB   rF   rM   boolrE   r   rJ   r(   r(   r(   r)   r      sb    






 
'
,r   Tpast_entitlementsnew_entitlementsallow_enableseries_overridesr+   c           
      C   sT  d}d}t | D ]\}}zt| |i |||d\}}	W ne tjy(   Y q
 tjyV   d}t| t	
  tdj||d W d   n1 sOw   Y  Y q
 ty   d}t| t	
  tdj||d W d   n1 s|w   Y  Y q
w |	r|rt| q
|rtjtjjtjjd|rtjtjjtjjd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)re   rf   Tz4Failed to process contract delta for {name}: {delta})rU   ZdeltaNz>Unexpected error processing contract delta for {name}: {delta}msgZmsg_code)sorteditemsprocess_entitlement_deltar"   r	   EntitlementNotFoundErrorUserFacingErroreventZservice_failedr   disable_log_to_consoleloggingerrorr   	Exception	exceptionZservice_processedr
   ZUNEXPECTED_ERRORrh   rU   ZATTACH_FAILURE_DEFAULT_SERVICES)
rc   rd   re   rf   Zdelta_errorZunexpected_errorrU   Znew_entitlementdeltasZservice_enabledr(   r(   r)   process_entitlements_delta  sb   





ru   Forig_access
new_accessc              
   C   s   ddl m} |rt| t| |}d}|rg| di d}|s+|di d}|s>tjj| |d}t	j
|j|jdz||}	W n t	jyY }
 ztd| |
d	}
~
ww |	|d
}|j| ||d}||f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: A tuple containing a dict of processed deltas and a
             boolean indicating if the service was fully processed
    r   )entitlement_factoryFentitlementtype)Zorignewrg   z3Skipping entitlement deltas for "%s". No such classN)Z
assume_yes)re   )rZ   rx   r   Zapply_series_overridesZget_dict_deltasr"   r
   Z$INVALID_CONTRACT_DELTAS_SERVICE_TYPEr   r	   rm   rh   rU   rl   rp   debugZprocess_contract_deltas)rv   rw   re   rf   rx   rt   retrU   rh   Zent_clsexcry   r(   r(   r)   rk   E  s8   

rk   ec                 C   s   t j}t| drht| jdkrhd| jd v rh| jd d }|d }|d }d }|dkr;|d t}t jj||d}n|d	krO|d t}t j	j||d}n|d
krZt j
j|d}|rht jj|jd}|j|_|S )N
api_errorsr   infoZ
contractIdreasonzno-longer-effectivetime)rC   dateznot-effective-yetznever-effective)rC   )r   )r
   ZATTACH_EXPIRED_TOKENhasattrlenr   strftimer   ZATTACH_FORBIDDEN_EXPIREDr   ZATTACH_FORBIDDEN_NOT_YETZATTACH_FORBIDDEN_NEVERZATTACH_FORBIDDENrh   rU   )r   rh   r   rC   r   Z
reason_msgr   r(   r(   r)    _create_attach_forbidden_messagez  s:   r   r$   c           
      C   s8  | j }| j}|r|rtj}tj|j|jdt| }|rz|j	|d W nn tj
y } zNt|tjrUt|drS|jdkrAt |jdkrSt|}tj|j|jd|t  tt| W d   n1 skw   Y  tjtjjtjjdd}~ww |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
    rg   )r$   codei  i  NrG   r   ZcontractInfoid)r&   rC   )r&   Zentitlementsr
   Z-UNEXPECTED_CONTRACT_TOKEN_ON_ATTACHED_MACHINEr	   rm   rh   rU   r   r*   ZUrlError
isinstancer`   r   r   ZAttachInvalidTokenErrorr   r   ro   rp   rs   ra   ZCONNECTIVITY_ERRORrF   ru   )
r   r$   re   Z
orig_tokenZorig_entitlementsrh   Zcontract_clientr   r&   rC   r(   r(   r)   request_updated_contract  sN   




r   r   c                 C   s   t | }| }|dg S )zDQuery available resources from the contract server for this machine.rY   )r   r4   r"   )r   clientrY   r(   r(   r)   get_available_resources  s   r   tokenc                 C   s   t | }||S )z/Query contract information for a specific token)r   r7   )r   r   r   r(   r(   r)   get_contract_information  s   
r   )T)FTr\   ))rp   typingr   r   r   r   r   Zuaclientr   r   r	   r
   r   r   Zuaclient.configr   Zuaclient.defaultsr   Zuaclient.statusr   r   rO   r2   r@   r:   rK   r6   Zget_event_loggerrn   ZUAServiceClientr   ra   rb   ru   rk   r`   ZNamedMessager   r   r   r   r(   r(   r(   r)   <module>   sl      k


C



5
%
9"