o Hcf{@sddlZddlZddlZddlmZddlmZmZmZm Z m Z ddl m Z m Z mZmZmZmZmZmZmZddlmZddlmZddlmZddlmZdd lmZmZdd l m!Z!dd l"m#Z#d Z$d Z%d Z&dZ'dZ(dZ)dZ*dZ+dZ,dZ-dZ.dddddZ/e 0Z1e2e3e4Z5edddgZ6Gddde!j7Z8de9fdd Z: !dJd"ed#ee;efd$ee;efd%ed/ej?d'ej@fd0d1ZAd2d3ZBd"ed'eefd4d5ZCd"ed6e;d'ee;effd7d8ZDd"ed'eZG dLd?ee;efd@e;dAe;de e;d'eeFee;efff dBdCZH  dMd+ee;efdDe e;de e;d'dfdEdFZId"edGee;efd'ee6fdHdIZJdS)NN) 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 c @sHeZdZdZejejgdd d%ddZde e e ffdd Z d e de e e ffd d Z ejejgddd ejfddZ d%de de dee de e e ffddZddZde de e e ffddZde e e ffddZde fddZ d%de de dee de e e ffdd Z d%de de dee de fd!d"Zd#d$ZdS)&UAContractClient contract_url)rrr) retry_sleepsNc Cs|st|j}|}|dd|i|}||d<||d}t|}|j t ||d}|j dkr:t |j dkrCt||j dkrRt jt |j |jd |j} tj| d d | d gD] } tj| d d qe| 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_idcfgr-updateformat_get_activity_info isoformat_support_old_machine_info request_urlAPI_V1_ADD_CONTRACT_MACHINEr2r AttachInvalidTokenError_raise_attach_forbidden_messageContractAPIErrorr3 json_dictr secrets add_secretget) selfcontract_token attachment_dt machine_idr- activity_infor,backcompat_dataresponse response_jsonr7rP3/usr/lib/python3/dist-packages/uaclient/contract.pyadd_contract_machineDs8       z%UAContractClient.add_contract_machinereturncCsT|}|jt|d|d|d|ddd}|jdkr'tjt|j|jd|jS) z=Requests list of entitlements available to this machine type. architecturerkernelvirtrTrrUrV) query_paramsr/r0)r<r?API_V1_AVAILABLE_RESOURCESr2r rCr3rD)rHrLrNrPrPrQavailable_resourcesos  z$UAContractClient.available_resourcesrIcCsN|}|dd|i|jt|d}|jdkr$tjt|j|jd|j S)Nr&r'r-r/r0) r-r:r;r?API_V1_GET_CONTRACT_USING_TOKENr2r rCr3rD)rHrIr-rNrPrPrQget_contract_using_tokens z)UAContractClient.get_contract_using_tokeninstancecCs~|jtj|jd|jd}|jdkr0|jdd}|r&t |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)r,r/messager5) error_msgr0 contractToken)r?,API_V1_GET_CONTRACT_TOKEN_FOR_CLOUD_INSTANCEr;r_ identity_docr2rDrGLOGdebugr InvalidProImagerCr3r rErF)rHr^rNmsgrOrPrPrQ%get_contract_token_for_cloud_instances*     z6UAContractClient.get_contract_token_for_cloud_instance machine_tokenresourcerKc Cs|st|j}|}|dd|itj||d}|j||d}|jdkr3t j t|j|j d|j drA|jd|j d<|j }| dgD] }tj| d d qJ|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. r&r')rkmachiner[r/r0expiresr6r7r5)rr8r9r-r:r;"API_V1_GET_RESOURCE_MACHINE_ACCESSr?r2r rCr3rGrDr rErF) rHrjrkrKr-r1rNrOr7rPrPrQget_resource_machine_accesss(   z,UAContractClient.get_resource_machine_accesscCs|jjj}|jjd}t|j}|}tj ||d}| }| dd |i|j |||d}|j dkrBtj||j |jd|jrW|jj}|j|d<|jj|d Sd S) zReport current activity token and enabled services. This will report to the contracts backend all the current enabled services in the system. r4contractrlr&r')r-r,r/r0r+N)r9machine_token_file contract_idrjrGrr8r<API_V1_UPDATE_ACTIVITY_TOKENr;r-r:r?r2r rCr3rDwrite)rHrsrjrK request_datar1r-rNrPrPrQupdate_activity_tokens&     z&UAContractClient.update_activity_token magic_tokencCs|}|dd|i|jt|d}|jdkrt|jdkr't|jdkr6tj t|j|j d|j }gd}|D] }t j ||d q?|S) zRequest magic attach token info. When the magic token is registered, it will contain new fields that will allow us to know that the attach process can proceed r&r'r[r.r/r0r7userCoderbr5)r-r:r;r?"API_V1_GET_MAGIC_ATTACH_TOKEN_INFOr2r MagicAttachTokenErrorMagicAttachUnavailablerCr3rDr rErFrG)rHrxr-rNrO secret_fieldsfieldrPrPrQget_magic_attach_token_infos(   z,UAContractClient.get_magic_attach_token_infocCsx|}|jt|dd}|jdkrt|jdkr$tjt|j|jd|j}gd}|D] }t j | |dq-|S)z)Create a magic attach token for the user.POSTr-methodryr/r0rzr5) r-r?API_V1_NEW_MAGIC_ATTACHr2r r~rCr3rDr rErFrG)rHr-rNrOrrrPrPrQnew_magic_attach_tokens&  z'UAContractClient.new_magic_attach_tokencCs|}|dd|i|jt|dd}|jdkrt|jdkr(t|jdkr1t |jdkr@tj t|j|j d d S) z)Revoke a magic attach token for the user.r&r'DELETErir.ryr/r0N) r-r:r;r?API_V1_REVOKE_MAGIC_ATTACHr2r MagicAttachTokenAlreadyActivatedr}r~rCr3)rHrxr-rNrPrPrQrevoke_magic_attach_token1s(    z*UAContractClient.revoke_magic_attach_tokenrsc Cs|st|j}|}|dd|itj||d}|}|j|d||d|d|d|dd d }|j d krFt j ||j |j d |j d rT|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. r&r'rpGETrTrrUrVrW)rr-rXr/r0rm)rr8r9r-r:r;API_V1_GET_CONTRACT_MACHINEr<r?r2r rCr3rGrD)rHrjrsrKr-r1rLrNrPrPrQget_contract_machineHs4    z%UAContractClient.get_contract_machinec Cs|st|j}|}|dd|i||d}t|}tj||d}|j ||d|d}|j dkr@t j ||j |j d|jd rN|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 r&r'r)rpr)r-rr,r/r0rm)rr8r9r-r:r;r<r>API_V1_UPDATE_CONTRACT_MACHINEr?r2r rCr3rGrD) rHrjrsrKr-r,rMr1rNrPrPrQupdate_contract_machiness*    z(UAContractClient.update_contract_machinecCstjtjtjtttt d}t |j j rQt|j j}t}|j jjp5t|j |j jjdd|Ddd|D|rL|jndd}ni}i||S)z9Return a dict of activity info data for contract requests) distributionrUrrTdesktoprV clientVersioncSsg|]}|jqSrP)r".0servicerPrPrQ sz7UAContractClient._get_activity_info..cSsi|] }|jr|j|jqSrP)variant_enabledr" variant_namerrPrPrQ s z7UAContractClient._get_activity_info..N) activityID activityToken resourcesresourceVariantsr()rget_release_inforget_kernel_info uname_releaser get_dpkg_arch is_desktop get_virt_typer get_versionrr9 is_attachedrenabled_servicesrreadrr activity_idr8activity_token attached_atr=)rH machine_inforattachment_datarLrPrPrQr<s8     z#UAContractClient._get_activity_infoN)__name__ __module__ __qualname__cfg_url_base_attrrretrysockettimeoutrRrstrrrZr]rAutoAttachCloudInstancerirrorwrrrrrr<rPrPrPrQr#As\ * $  &&  / (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. r+r*rTrrUrLinux)rrUrtyperelease)r*r+rTos)rGrrr)rrLrPrPrQr>s r>Tr9past_entitlementsnew_entitlements allow_enablerrSc Csjddlm}d}g}g}||D]|} z|| } Wn ty!Yqwg}zt||| i| ||d\} } WnMtjy[} zt| d}| | t d| | WYd} ~ qd} ~ wt y} zt| | | | | td| | WYd} ~ qd} ~ ww| r| rt | qt |t|dkrtjd d t||Dd |rtjd 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)r9 orig_access new_accessrrTz+Failed to process contract delta for %s: %rNz5Unexpected error processing contract delta for %s: %rcSs*g|]\}}|tjjt|tdfqS))ralog_path)r UNEXPECTED_ERRORr;rr)rr" exceptionrPrPrQr%sz.process_entitlements_delta..)failed_servicescSsg|]}|tjfqSrP)r !E_ATTACH_FAILURE_DEFAULT_SERVICES)rr"rPrPrQr2s)uaclient.entitlementsrKeyErrorprocess_entitlement_deltarGr UbuntuProErrorrerappenderror Exceptioneventservice_processedservices_failedlenAttachFailureUnknownErrorzipAttachFailureDefaultServices)r9rrrrr delta_errorunexpected_errorsrr"new_entitlementdeltasservice_enablederPrPrQprocess_entitlements_deltasr              rFrrc Csddlm}|r t|t||}d}|rn|did}|s*|did}|s3tj||d|didid d } z |||| d } Wntjy_} zt d || d } ~ ww| ||d} | 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)orignew entitlements obligations use_selectorr5r9r"r z3Skipping entitlement deltas for "%s". No such classN)r9 assume_yesr) rrapply_contract_overridesrget_dict_deltasrGr InvalidContractDeltasServiceTypeEntitlementNotFoundErrorrerfprocess_contract_deltas) r9rrrrrrretr"r ent_clsexcrrPrPrQr9s>    rrNcCs|jd}|rJ|d}|d}|dkr(|dt}tj|||ddd|dkr@|dt}tj|||ddd |d krJtj|d t) Ninfo contractIdreasonzno-longer-effectivetimez%m-%d-%Y)rsdatecontract_expiry_dateznot-effective-yet)rsrcontract_effective_dateznever-effective)rs) rDrGstrftimerr AttachForbiddenExpiredAttachForbiddenNotYetAttachForbiddenNeverAttachExpiredToken)rNrrsrrrPrPrQrBus*    rBcCs|jj}|j}|d}|ddd}t|}|j||d}|j|tj| di dt|}t |t |||jjddd S) aRequest contract refresh from ua-contracts service. :param cfg: Instance of UAConfig for this machine. :raise UbuntuProError: on failure to update contract or error processing contract deltas :raise ConnectivityError: On failure during a connection r4machineTokenInfo contractInfoid)rjrsr*FrN) rrrrjr#rrurr8 cache_clearrGrr)r9orig_entitlements orig_tokenrjrscontract_clientresprKrPrPrQrefreshs(       rcCst|}|}|dgS)zDQuery available resources from the contract server for this machine.r)r#rZrG)r9clientrrPrPrQget_available_resourcess rr7cCst|}||S)z/Query contract information for a specific token)r#r])r9r7rrPrPrQget_contract_informations rc Cs|j}|jj}|dd}|dididd}|sdSt|}|||}|dididd}|r;|n|jj}|jj|krGdS|j|} t| D]\} } t || i| } | rfdSqSdS) Nr4r5rrrF effectiveToT) rjrrrrGr#rcontract_expiry_datetimeget_entitlements_from_tokensorteditemsrr) r9rrrjrsrr resp_expiry new_expirycurr_entitlementsr"rrrPrPrQis_contract_changeds@      roverride_selectorselector_valuescCs<d}|D]\}}||f|vrdS|t|7}q|S)Nr)r OVERRIDE_SELECTOR_WEIGHTS)rroverride_weightselectorvaluerPrPrQ_get_override_weights rr series_namer_c Cszi}||d}|r ||d<|di|i}|r||td<t|dg}|D]}t|d|} | r:||| <q*|S)N)rrr rr overridesr)poprcopydeepcopyrGr) rrr_r rrrgeneral_overridesoverrideweightrPrPrQ_select_overridess"   rrcCsddlm}tt|td|vgstd||dur!tj n|}|\}}| di}t ||||}t | D]%\} } | D]\} } |d | } t| trY| | qC| |d| <qCq;dS)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)uaclient.clouds.identityr all isinstancedict RuntimeErrorr;rrrrGrr r r:)rrr r rr__orig_entitlementr_weightoverrides_to_applykeyrcurrentrPrPrQrs*     rrc Csddlm}g}|D]L\}}|didd}z ||||d}Wn tjy-Yq w||}|didi} |d} || | rX|\} } | rX|t ||d q |S) Nrrrrr5rr resourceToken)r"r ) rrr rGr r_should_enable_by_default can_enablerr!) r9rrenable_by_default_servicesent_name ent_valuer rentrr,r.r&rPrPrQget_enabled_by_default_servicesAs2     r3)T)FTr)NN)Krloggingr collectionsrtypingrrrrruaclientrr r r r r rrr-uaclient.api.u.pro.status.enabled_services.v1r(uaclient.api.u.pro.status.is_attached.v1ruaclient.configruaclient.defaultsruaclient.files.state_filesrr uaclient.httpr uaclient.logrr@rrrYrnrcrtr\r|rrrget_event_loggerr getLoggerreplace_top_level_logger_namerrer!UAServiceClientr#r$r>rboolrr HTTPResponse NamedMessagerBrrrrintrrrr3rPrPrPrQs ,         ^    < "&       1