U (fw @sddlZddlZddlZddlmZddlmZmZmZm Z m Z ddl m m ZddlmZmZmZmZmZmZmZmZmZddlmZddlmZddlmZddlm Z dd l!m"Z"m#Z#dd l$m%Z%dd l&m'Z'd Z(d Z)d Z*dZ+dZ,dZ-dZ.dZ/dZ0dZ1dZ2dddddZ3e4Z5e6e7e8Z9edddgZ:Gddde%j;ZdAeee?efee?efe@e@dd"d#d$ZAdBeee?efee?efe@e@e ee@fd&d'd(ZBejCejDd)d*d+ZEed,d-d.ZFeeed/d0d1ZGee?ee?efd2d3d4ZHee?e?fee?e?feId5d6d7ZJdCee?efe?e?e e?eeIee?effd8d9d:ZKdDee?efe e?e e?dd;dd?d@ZMdS)EN) namedtuple)AnyDictListOptionalTuple) clouds event_logger exceptionshttpmessagessecret_managersystemutilversion)_enabled_services) _is_attached)UAConfig)ATTACH_FAIL_DATE_FORMAT)attachment_data_filemachine_id_file) serviceclient)get_user_or_root_log_file_pathz/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/contractz/v1/magic-attach)series_overridesseriescloudvariantEnableByDefaultServicenamer csLeZdZdZd(eeddfdd Zeje j dddgdd)d d Z e e efd d d Ze e e efdddZeje j dddgdejdddZd*e e ee e e efdddZddZe e e efdddZe e efd ddZe ddd Zd+e e ee e e efd!d"d#Zd,e e ee e d!d$d%Zd&d'ZZS)-UAContractClientZ contract_urlNcfgreturncstj|dt|_dS)Nr%)super__init__mtfget_machine_token_filemachine_token_file)selfr% __class__3/usr/lib/python3/dist-packages/uaclient/contract.pyr)EszUAContractClient.__init__rr)Z retry_sleepsc Cs|st|j}|}|dd|i|}||d<||d}t|}|j t ||d}|j dkrvt n|j dkrt||j dkrt jt |j |jd |j} tj| d d | d gD]} tj| d d q| 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 {}lastAttachment machineId activityInfo)dataheadersiurlcodebody machineTokenresourceTokenstoken)rget_machine_idr%r9updateformat_get_activity_info isoformat_support_old_machine_info request_urlAPI_V1_ADD_CONTRACT_MACHINEr>r ZAttachInvalidTokenError_raise_attach_forbidden_messageContractAPIErrorr? json_dictr secrets add_secretget) r-contract_tokenZ attachment_dt machine_idr9 activity_infor8backcompat_dataresponse response_jsonrCr0r0r1add_contract_machineLs<         z%UAContractClient.add_contract_machine)r&cCsT|}|jt|d|d|d|ddd}|jdkrNtjt|j|jd|jS) z=Requests list of entitlements available to this machine type. architecturerkernelvirtrYrrZr[) query_paramsr;r<)rGrJAPI_V1_AVAILABLE_RESOURCESr>r rMr?rN)r-rTrVr0r0r1available_resourcesws  z$UAContractClient.available_resources)rRr&cCsN|}|dd|i|jt|d}|jdkrHtjt|j|jd|j S)Nr2r3r9r;r<) r9rErFrJAPI_V1_GET_CONTRACT_USING_TOKENr>r rMr?rN)r-rRr9rVr0r0r1get_contract_using_tokens z)UAContractClient.get_contract_using_token)instancecCs~|jtj|jd|jd}|jdkr`|jdd}|rLt |t j |dt j t|j|j d|j}tj|dd|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)r8r;messagerA) error_msgr< contractToken)rJ,API_V1_GET_CONTRACT_TOKEN_FOR_CLOUD_INSTANCErFrdZ identity_docr>rNrQLOGdebugr ZInvalidProImagerMr?r rOrP)r-rcrVmsgrWr0r0r1%get_contract_token_for_cloud_instances*     z6UAContractClient.get_contract_token_for_cloud_instance) machine_tokenresourcerSr&c Cs|st|j}|}|dd|itj||d}|j||d}|jdkrft j t|j|j d|j dr|jd|j d<|j }| dgD]}tj| d d q|S) aRequests 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. r2r3)rnmachiner`r;r<expiresrBrCrA)rrDr%r9rErF"API_V1_GET_RESOURCE_MACHINE_ACCESSrJr>r rMr?rQrNr rOrP) r-rmrnrSr9r=rVrWrCr0r0r1get_resource_machine_accesss*   z,UAContractClient.get_resource_machine_accesscCs|jj}|jjd}t|j}|}tj ||d}| }| dd |i|j |||d}|j dkrtj||j |jd|jr|jj}|j|d<|j|d S) zReport current activity token and enabled services. This will report to the contracts backend all the current enabled services in the system. r@Zcontractror2r3)r9r8r;r<r7N)r, contract_idrmrQrrDr%rGAPI_V1_UPDATE_ACTIVITY_TOKENrFr9rErJr>r rMr?rNwrite)r-rtrmrSZ request_datar=r9rVr0r0r1update_activity_tokens.   z&UAContractClient.update_activity_token) magic_tokenr&cCs|}|dd|i|jt|d}|jdkrr MagicAttachTokenErrorMagicAttachUnavailablerMr?rNr rOrPrQ)r-rxr9rVrW secret_fieldsfieldr0r0r1get_magic_attach_token_infos*    z,UAContractClient.get_magic_attach_token_infocCsz|}|jt|dd}|jdkr*t|jdkrHtjt|j|jd|j}dddg}|D]}t j | |d q\|S) z)Create a magic attach token for the user.POSTr9methodryr;r<rCrzrgrA) r9rJAPI_V1_NEW_MAGIC_ATTACHr>r r}rMr?rNr rOrPrQ)r-r9rVrWr~rr0r0r1new_magic_attach_token$s&   z'UAContractClient.new_magic_attach_token)rxcCs|}|dd|i|jt|dd}|jdkr>t|jdkrPt|jdkrbt |jdkrtj t|j|j d d S) z)Revoke a magic attach token for the user.r2r3ZDELETErir:ryr;r<N) r9rErFrJAPI_V1_REVOKE_MAGIC_ATTACHr>r Z MagicAttachTokenAlreadyActivatedr|r}rMr?)r-rxr9rVr0r0r1revoke_magic_attach_token;s&    z*UAContractClient.revoke_magic_attach_token)rmrtrSr&c Cs|st|j}|}|dd|itj||d}|}|j|d||d|d|d|dd d }|j d krt j ||j |j d |j d r|jd |jd <|jS)a|Get the updated machine token from the 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. r2r3rsZGETrYrrZr[r\)rr9r]r;r<rp)rrDr%r9rErFAPI_V1_GET_CONTRACT_MACHINErGrJr>r rMr?rQrN)r-rmrtrSr9r=rTrVr0r0r1get_contract_machineRs8   z%UAContractClient.get_contract_machinec Cs|st|j}|}|dd|i||d}t|}tj||d}|j ||d|d}|j dkrt j ||j |j d|jd r|jd |jd <|jS) aRequest 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. @return: Dict of the JSON response containing refreshed machine-token r2r3r5rsr)r9rr8r;r<rp)rrDr%r9rErFrGrIAPI_V1_UPDATE_CONTRACT_MACHINErJr>r rMr?rQrN) r-rmrtrSr9r8rUr=rVr0r0r1update_contract_machine}s6   z(UAContractClient.update_contract_machinecCstjtjtjtttt d}t |j j rt|j j}t}|jjpht|j |jjdd|Ddd|D|r|jndd}ni}||S)z9Return a dict of activity info data for contract requests) distributionrZrrYZdesktopr[Z clientVersioncSsg|] }|jqSr0)r".0Zservicer0r0r1 sz7UAContractClient._get_activity_info..cSsi|]}|jr|j|jqSr0)Zvariant_enabledr"Z variant_namerr0r0r1 sz7UAContractClient._get_activity_info..N)Z activityIDZ activityToken resourcesZresourceVariantsr4)rget_release_inforZget_kernel_infoZ uname_releaserZ get_dpkg_archZ is_desktopZ get_virt_typerZ get_versionrr%Z is_attachedrenabled_servicesrreadr,Z activity_idrDZactivity_tokenZ attached_atrH)r-Z machine_inforZattachment_datarTr0r0r1rGs4     z#UAContractClient._get_activity_info)N)N)N)N)N)__name__ __module__ __qualname__Zcfg_url_base_attrrrr)rZretrysocketZtimeoutrXrstrrr_rbrZAutoAttachCloudInstancerlrrrwrrrrrrG __classcell__r0r0r.r1r#BsP *$ &( / (r#) request_bodyc CsJ|di}|d||d|d|d|ddtjdd S) a? Transforms a request_body that has the new activity_info into a body that includes both old and new forms of machineInfo/activityInfo This is necessary because there may be old ua-airgapped contract servers deployed that we need to support. This function is used for attach and refresh calls. r7r6rYrrZrZLinux)rrZrtyperelease)r6r7rYos)rQrrr)rrTr0r0r1rIs rIT)r%past_entitlementsnew_entitlements allow_enablerr&c Csvddlm}d}g}g}||D]} z || } Wntk rJYq YnXg}z"t||| i| ||d\} } Wntjk r} z*t| d}| | t d| | W5d} ~ XYq t k r } z0t| | | | | td| | W5d} ~ XYq X| r | r t | q t |t|dkrVtjd d t||Dd n|rrtjd d |Dd dS) aIterate over all entitlements in new_entitlement and apply any delta found according to past_entitlements. :param cfg: UAConfig instance :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. r)entitlements_enable_orderF)r% orig_access new_accessrrTz+Failed to process contract delta for %s: %rNz5Unexpected error processing contract delta for %s: %rcSs*g|]"\}}|tjjt|tdfqS))rfZlog_path)r ZUNEXPECTED_ERRORrFrr)rr" exceptionr0r0r1r/sz.process_entitlements_delta..)failed_servicescSsg|]}|tjfqSr0)r Z!E_ATTACH_FAILURE_DEFAULT_SERVICES)rr"r0r0r1r<s)uaclient.entitlementsrKeyErrorprocess_entitlement_deltarQr ZUbuntuProErrorrirappenderror ExceptioneventZservice_processedZservices_failedlenZAttachFailureUnknownErrorzipZAttachFailureDefaultServices)r%rrrrrZ delta_errorZunexpected_errorsrr"Znew_entitlementdeltasZservice_enableder0r0r1process_entitlements_deltasf            rF)r%rrrrr&c Csddlm}|rt|t||}d}|r|did}|sT|did}|sftj||d|didid d } z|||| d } Wn4tjk r} zt d || W5d } ~ XYnX| j |||d}||fS)a,Process a entitlement access dictionary deltas if they exist. :param cfg: UAConfig instance :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 UbuntuProError: on failure to process deltas. :return: A tuple containing a dict of processed deltas and a boolean indicating if the service was fully processed rentitlement_factoryF entitlementr)Zorignew entitlements obligations use_selectorrAr%r"r z3Skipping entitlement deltas for "%s". No such classNr) rrapply_contract_overridesrZget_dict_deltasrQr Z InvalidContractDeltasServiceTypeEntitlementNotFoundErrorrirjZprocess_contract_deltas) r%rrrrrrZretr"r rexcr0r0r1rCsP    r)rVr&cCs|jd}|r|d}|d}|dkrR|dt}tj|||dddnF|dkr|dt}tj|||ddd n|d krtj|d tdS) NinfoZ contractIdreasonzno-longer-effectivetimez%m-%d-%Y)rtdateZcontract_expiry_dateznot-effective-yet)rtrZcontract_effective_dateznever-effective)rt) rNrQstrftimerr ZAttachForbiddenExpiredZAttachForbiddenNotYetZAttachForbiddenNeverZAttachExpiredToken)rVrrtrrr0r0r1rLs*    rLr'c Cst|}|}|j}|d}|ddd}t|d}|j||d}||tj | di dt|}t |t |||dd d S) zRequest contract refresh from ua-contracts service. :raise UbuntuProError: on failure to update contract or error processing contract deltas :raise ConnectivityError: On failure during a connection r@ZmachineTokenInfoZ contractInfoidr')rmrtr6FrN) r*r+rrmr#rrvrrD cache_clearrQrr) r%r,Zorig_entitlementsZ orig_tokenrmrtZcontract_clientZresprSr0r0r1refreshs.      rr$cCst|}|}|dgS)zDQuery available resources from the contract server for this machine.r)r#r_rQ)r%clientrr0r0r1get_available_resourcessr)r%rCr&cCst|}||S)z/Query contract information for a specific token)r#rb)r%rCrr0r0r1get_contract_informationsr)override_selectorselector_valuesr&cCs<d}|D]*\}}||f|kr*dS|t|7}q |S)Nr)itemsOVERRIDE_SELECTOR_WEIGHTS)rrZoverride_weightselectorvaluer0r0r1_get_override_weights r)r series_namerdr r&c Cszi}||d}|r||d<|di|i}|r>||td<t|dg}|D] }t|d|} | rT||| <qT|S)N)rrr rr overridesr)poprcopydeepcopyrQr) rrrdr rrrZgeneral_overridesoverrideZweightr0r0r1_select_overridess"   r)rrr r&cCsddlm}tt|td|kgs0td||dkrBtj n|}|\}}| di}t ||||}t | D]J\} } | D]8\} } |d | } t| tr| | q| |d| <qqvdS)aApply series-specific overrides to an entitlement dict. This function mutates orig_access dict by applying any series-overrides to the top-level keys under 'entitlement'. The series-overrides are sparse and intended to supplement existing top-level dict values. So, sub-keys under the top-level directives, obligations and affordance sub-key values will be preserved if unspecified in series-overrides. To more clearly indicate that orig_access in memory has already had the overrides applied, the 'series' key is also removed from the orig_access dict. :param orig_access: Dict with original entitlement access details r)get_cloud_typerz?Expected entitlement access dict. Missing "entitlement" key: {}N)Zuaclient.clouds.identityrall isinstancedict RuntimeErrorrFrrrrQrsortedrrE)rrr rrrd_Zorig_entitlementrZ_weightZoverrides_to_applykeyrZcurrentr0r0r1rs.     r)r%rr&c Csddlm}g}|D]\}}|didd}z||||d}Wntjk r`YqYnX|didi}|d} ||| r|\} } | r|t ||d q|S) NrrrrrArr resourceToken)r"r ) rrrrQr rZ_should_enable_by_default can_enablerr!) r%rrZenable_by_default_servicesZent_nameZ ent_valuer Zentrrrrr0r0r1get_enabled_by_default_services's(     r)T)FT)N)NN)NrZloggingr collectionsrtypingrrrrrZuaclient.files.machine_tokenfilesrmr*Zuaclientrr r r r r rrrZ-uaclient.api.u.pro.status.enabled_services.v1rZ(uaclient.api.u.pro.status.is_attached.v1rZuaclient.configrZuaclient.defaultsrZuaclient.files.state_filesrrZ uaclient.httprZ uaclient.logrrKrrr^rqrhrurar{rrrZget_event_loggerrZ getLoggerZreplace_top_level_logger_namerrir!ZUAServiceClientr#rrIrboolrrZ HTTPResponseZ NamedMessagerLrrrintrrrrr0r0r0r1s ,          ^   @ !      2