o x[h@sddlZddlZddlZddlZddlZddlZddlZddlmZddl m Z m Z ddl m Z m Z ddl mZmZmZmZmZddlmZddlmZddlmZmZmZmZmZmZdd lm Z dd l!m"Z"e#e$Z%d Z&d Z'd Z(dZ)dZ*e j+ddddZ,edZ-dede-fdede-ffddZ.e.ddZ/e.ddZ0ddde1de j2fd d!Z3d"d#Z4e.d$d%Z5ed&d'Z6e.dd(d)d*d+e1d,e7d-ee8d.e9d/e9dej:f d0d1Z;d2e1d3e1d4e1de8fd5d6ZZ?Gd;d<d<Z@Gd=d>d>ZAGd?d@d@ZBGdAdBdBZCe.  dSdCe1dDejDdEeee1dFee1fdGdHZEe.dCe1dIdJfdKdLZFdMdNZGGdOdPdPe>ZHGdQdRdRZIdS)TN)contextmanager)datetimetimezone)sleeptime)CallableListOptionalTypeVarUnion) ElementTree)escape)distrossubp temp_utils url_helperutilversion)events)errorsz 168.63.129.16boot-telemetryz system-info diagnostic compressedzazure-dsz initialize reporter for azure dsT)name descriptionreporting_enabledTfunc.returncsfdd}|S)NcsFtjjjtd|i|WdS1swYdS)Nrrparent)rReportEventStack__name__azure_ds_reporter)argskwargsrA/usr/lib/python3/dist-packages/cloudinit/sources/helpers/azure.pyimpl*s $z)azure_ds_telemetry_reporter..implr')rr)r'r&r(azure_ds_telemetry_reporter)s r*c Cststdtdz tttt}Wnt y+}ztd|d}~wwz*t j gddd\}}d}|rGd|vrG| dd }|sMtd |t|d }Wn&t j yj}ztd ||d}~wt y|}ztd ||d}~wwz*t j gddd\}}d}|rd|vr| dd }|std|t|d }Wn&t j y}ztd||d}~wt y}ztd||d}~wwt tddt|tjt|tjt|tjft j}t ||S)z[Report timestamps related to kernel initialization and systemd activation of cloud-initz1distro not using systemd, skipping boot telemetryzCollecting boot telemetryz*Failed to determine kernel start timestampN) systemctlshow-pUserspaceTimestampMonotonicT)capture=z8Failed to parse UserspaceTimestampMonotonic from systemdi@Bz-Failed to get UserspaceTimestampMonotonic: %szrYprintwebhookrZ) base64 encodebyteszlibcompressdecoderr<COMPRESSED_EVENT_TYPEjsondumpsrArB) event_name event_contentcompressed_data event_datarJr'r'r(report_compressed_eventsrpc Csntdztjdgddd\}}td|WdSty6}ztdt|tjdWYd}~dSd}~ww) zReport dmesg to KVP.zDumping dmesg log to KVPdmesgFT)rhr/z$Exception when dumping dmesg log: %srVN)r5r6rrp Exceptionr^reprwarning)rErFexr'r'r(report_dmesg_to_kvps  rvc cs@t}ttj|z dVWt|dSt|wN)osgetcwdchdirpath expanduser)newdirprevdirr'r'r(cds r)ra retry_sleeptimeout_minutesurlheadersrarrc Cs|dt}d}d}|sT|d7}z tj|||dd}Wn7tjyM}z$td||||j|jftjdt||ksBd t |vrCWYd}~nd}~wwt ||r td ||ftjd|S) zReadurl wrapper for querying wireserver. :param retry_sleep: Time to sleep before retrying. :param timeout_minutes: Retry up to specified number of minutes. :raises UrlError: on error fetching data. <rNr1)rr)rratimeoutzdFailed HTTP request with Azure endpoint %s during attempt %d with exception: %s (code=%r headers=%r)rVzNetwork is unreachablez@Successful HTTP request with Azure endpoint %s after %d attempts) rrreadurlUrlErrorr^coderr5r6strr) rrrarrrattemptresponserDr'r'r(http_with_retriess@  rusernamehostname disableSshPwdcCs$td}|j|||d}|dS)Na. 1.0 LinuxProvisioningConfiguration {username} {disableSshPwd} {hostname} 1.0 true )rrrutf-8)textwrapdedentformatencode)rrrOVF_ENV_TEMPLATEretr'r'r(build_minimal_ovfs rc@sLeZdZdddZddZddejfdd Z dd ee dejfd d Z d S)AzureEndpointHttpClient WALinuxAgentz 2012-11-30)zx-ms-agent-namez x-ms-versioncCsd|d|_dS)N DES_EDE3_CBC)zx-ms-cipher-namez!x-ms-guest-agent-public-x509-cert)extra_secure_headers)self certificater'r'r(__init__Ds z AzureEndpointHttpClient.__init__FrcCs,|j}|r|j}||jt||dS)N)r)rcopyupdaterr)rrsecurerr'r'r(getJs    zAzureEndpointHttpClient.getNracCs0|j}|dur|j}||t|||dS)N)rar)rrrr)rrra extra_headersrr'r'r(postQs   zAzureEndpointHttpClient.post)FNN) r" __module__ __qualname__rrr UrlResponserr bytesrr'r'r'r(r>src@seZdZdZdS)InvalidGoalStateXMLExceptionz9Raised when GoalState XML is invalid or has missing data.N)r"rr__doc__r'r'r'r(r[src @s:eZdZ d deeefdededdfddZd d Z dS) GoalStateT unparsed_xmlazure_endpoint_clientneed_certificaterNc Cs ||_zt||_Wntjy"}z td|tjdd}~ww|d|_ |d|_ |d|_ dD]}t ||durOd|}t|tjdt |q7d|_|d }|dur|rtjd d td |jj|d dj|_|jdurzt dWddS1swYdSdSdS)ahParses a GoalState XML string and returns a GoalState object. @param unparsed_xml: string representing a GoalState XML. @param azure_endpoint_client: instance of AzureEndpointHttpClient. @param need_certificate: switch to know if certificates is needed. @return: GoalState object representing the GoalState XML string. z!Failed to parse GoalState XML: %srVNz./Container/ContainerIdz4./Container/RoleInstanceList/RoleInstance/InstanceIdz ./Incarnation) container_id instance_id incarnationzMissing %s in GoalState XMLzD./Container/RoleInstanceList/RoleInstance/Configuration/Certificateszget-certificates-xmlzget certificates xmlrT)rz/Azure endpoint returned empty certificates xml.)rET fromstringroot ParseErrorr^r5rt_text_from_xpathrrrgetattrrcertificates_xmlrr!r#rcontents)rrrrrDattrrXrr'r'r(r`sX     "zGoalState.__init__cCs|j|}|dur |jSdSrw)rfindtext)rxpathelementr'r'r(rs zGoalState._text_from_xpath)T) r"rrr rrrboolrrr'r'r'r(r_s  7rc@seZdZdddZddZddZedd Zejd d Ze d d Z e e d dZ e ddZ e ddZe ddZe ddZdS)OpenSSLManagerzTransportPrivate.pemzTransportCert.pem) private_keyrcCst|_d|_|dSrw)rmkdtemptmpdir _certificategenerate_certificaterr'r'r(rs  zOpenSSLManager.__init__cCst|jdSrw)rdel_dirrrr'r'r(clean_upszOpenSSLManager.clean_upcCs|jSrwrrr'r'r(rszOpenSSLManager.certificatecCs ||_dSrwr)rvaluer'r'r(rs cCstd|jdurtddSt|j=tddddddd d d d d |jdd|jdgd}t|jd D] }d|vrH|| 7}q<||_Wdn1sVwYtddS)Nz7Generating certificate for communication with fabric...zCertificate already generated.opensslreqz-x509z-nodesz-subjz/CN=LinuxTransportz-days32768z-newkeyzrsa:3072z-keyoutrz-outr CERTIFICATEzNew certificate generated.) r5r6rrrrcertificate_namesrload_text_file splitlinesrstrip)rrliner'r'r(rsD     z#OpenSSLManager.generate_certificatecCs"ddd|g}tj||d\}}|S)Nrx509z-nooutra)r)actioncertcmdresultrFr'r'r(_run_x509_actions zOpenSSLManager._run_x509_actioncCs*|d|}gd}tj||d\}}|S)Nz-pubkey)z ssh-keygenz-iz-mPKCS8z-fz /dev/stdinr)rr)rrpub_key keygen_cmdssh_keyrFr'r'r(_get_ssh_key_from_certs z%OpenSSLManager._get_ssh_key_from_certcCs6|d|}|d}||ddd}d|S)aopenssl x509 formats fingerprints as so: 'SHA1 Fingerprint=07:3E:19:D1:4D:1C:79:92:24:C6:A0:FD:8D:DA:\ B6:A8:BF:27:D4:73\n' Azure control plane passes that fingerprint as so: '073E19D14D1C799224C6A0FD8DDAB6A8BF27D473' z -fingerprintr0r1:r)rrr:join)rrraw_fpeqoctetsr'r'r(_get_fingerprint_from_certs  z)OpenSSLManager._get_fingerprint_from_certcCst|d}|j}ddddd|dg}t|jtjdjd i|j d d |d \}}Wd |S1s;wY|S)zDecrypt the certificates XML document using the our private key; return the list of certs and private keys contained in the doc. z.//DatasMIME-Version: 1.0s<Content-Disposition: attachment; filename="Certificates.p7m"s?Content-Type: application/x-pkcs7-mime; name="Certificates.p7m"s!Content-Transfer-Encoding: base64rzuopenssl cms -decrypt -in /dev/stdin -inkey {private_key} -recip {certificate} | openssl pkcs12 -nodes -password pass:T )shellraNr') rrrrrrrrrrr)rrtagcertificates_contentlinesrErFr'r'r(_decrypt_certs_from_xmls.  z&OpenSSLManager._decrypt_certs_from_xmlc Csv||}g}i}|D]+}||td|rg}q td|r8d|}||}||}|||<g}q |S)zGiven the Certificates XML document, return a dictionary of fingerprints and associated SSH keys derived from the certs.z[-]+END .*?KEY[-]+$z[-]+END .*?CERTIFICATE[-]+$ )rrappendrematchrrr) rrrEcurrentkeysrrr fingerprintr'r'r(parse_certificates s        z!OpenSSLManager.parse_certificatesN)r"rrrrrpropertyrsetterr*r staticmethodrrrrrr'r'r'r(rs.   !    rc @seZdZedZedZdZdZdZ dZ de de d e d d fd d ZedddZede d d fddZ dde de de de d ef ddZeded d fddZd S)GoalStateHealthReportera {incarnation} {container_id} {instance_id} {health_status} {health_detail_subsection} z
{health_substatus} {health_description}
ReadyNotReadyProvisioningFailedi goal_staterendpointrNcCs||_||_||_dS)a?Creates instance that will report provisioning status to an endpoint @param goal_state: An instance of class GoalState that contains goal state info such as incarnation, container id, and instance id. These 3 values are needed when reporting the provisioning status to Azure @param azure_endpoint_client: Instance of class AzureEndpointHttpClient @param endpoint: Endpoint (string) where the provisioning status report will be sent to @return: Instance of class GoalStateHealthReporter N) _goal_state_azure_endpoint_client _endpoint)rrrrr'r'r(rFs z GoalStateHealthReporter.__init__c Csv|j|jj|jj|jj|jd}tdz|j|dWnt y3}z t d|tj dd}~wwt ddS)N)rrrstatusz Reporting ready to Azure fabric.documentz#exception while reporting ready: %srVzReported ready to Azure fabric.) build_reportrrrrPROVISIONING_SUCCESS_STATUSr5r6_post_health_reportrrr^errorrT)rrrDr'r'r(send_ready_signal[s$ z)GoalStateHealthReporter.send_ready_signalrc Csv|j|jj|jj|jj|j|j|d}z|j|dWnty3}z d|}t |t j dd}~wwt ddS)N)rrrr substatusrrz%exception while reporting failure: %srVz!Reported failure to Azure fabric.) r rrrrPROVISIONING_NOT_READY_STATUSPROVISIONING_FAILURE_SUBSTATUSr rrr^r5r rt)rrrrDrXr'r'r(send_failure_signalos"z+GoalStateHealthReporter.send_failure_signalrrrrc Csbd}|dur|jjt|t|d|jd}|jjtt|t|t|t||d}|dS)Nr)health_substatushealth_description)rrr health_statushealth_detail_subsectionr)%HEALTH_DETAIL_SUBSECTION_XML_TEMPLATErr "HEALTH_REPORT_DESCRIPTION_TRIM_LENHEALTH_REPORT_XML_TEMPLATErr) rrrrrrr health_detail health_reportr'r'r(r s     z$GoalStateHealthReporter.build_reportrcCsBtdtdd|j}|jj||ddidtddS)Nrz&Sending health report to Azure fabric.zhttp://{}/machine?comp=healthz Content-Typeztext/xml; charset=utf-8)rarz/Successfully sent health report to Azure fabric)rr5r6rrrr)rrrr'r'r(r s  z+GoalStateHealthReporter._post_health_report)rNr)r"rrrrrrr rrrrrrrr*r rrr r r'r'r'r(r sN    rc@seZdZdefddZddZedejddfd d Z e ddejde e efd d Z ed eddfddZ ededefddZedefddZedeeefdedefddZedededefddZedededefddZdS) WALinuxAgentShimrcCs||_d|_d|_dSrw)ropenssl_managerr)rrr'r'r(rs zWALinuxAgentShim.__init__cCs|jdur |jdSdSrw)rrrr'r'r(rs zWALinuxAgentShim.clean_updistrorNc CsTtdz||WdSty)}ztd|tjdWYd}~dSd}~ww)NzEjecting the provisioning isoz(Failed ejecting the provisioning iso: %srV)r5r6 eject_mediarrr^r )riso_devrrDr'r'r( eject_isos zWALinuxAgentShim.eject_isocCsd}|jdur|durt|_|jj}|jdurt||_|j|dud}d}|dur1|||}t||j|j}|durD|j ||d| |S)aGets the VM's GoalState from Azure, uses the GoalState information to report ready/send the ready signal/provisioning complete signal to Azure, and then uses pubkey_info to filter and obtain the user's pubkeys from the GoalState. @param pubkey_info: List of pubkey values and fingerprints which are used to filter and obtain the user's pubkey values from the GoalState. @return: The list of user's authorized pubkey values. Nr)r) rrrrr_fetch_goal_state_from_azure_get_user_pubkeysrrr r )rr pubkey_inforhttp_client_certificaterssh_keyshealth_reporterr'r'r("register_with_azure_and_fetch_datas*   z3WALinuxAgentShim.register_with_azure_and_fetch_datarcCs@|jdur td|_|jdd}t||j|j}|j|ddS)zGets the VM's GoalState from Azure, uses the GoalState information to report failure/send provisioning failure signal to Azure. @param: user visible error description of provisioning failure. NFr!r)rrr"rrr)rrrr'r'r'r(®ister_with_azure_and_report_failures    z7WALinuxAgentShim.register_with_azure_and_report_failurercCs|}|||S)aFetches the GoalState XML from the Azure endpoint, parses the XML, and returns a GoalState object. @param need_certificate: switch to know if certificates is needed. @return: GoalState object representing the GoalState XML )"_get_raw_goal_state_xml_from_azure_parse_raw_goal_state_xml)rrunparsed_goal_state_xmlr'r'r(r"s z-WALinuxAgentShim._fetch_goal_state_from_azurec Cstdd|j}z tjddtd|j|}Wdn1s%wYWnt yA}z t d|tj dd}~wwt d |j S) zFetches the GoalState XML from the Azure endpoint and returns the XML as a string. @return: GoalState XML string zRegistering with Azure...z!http://{}/machine/?comp=goalstatezgoalstate-retrievalzretrieve goalstaterNz9failed to register with Azure and fetch GoalState XML: %srVz#Successfully fetched GoalState XML.)r5rTrrrr!r#rrrrr^rtr6r)rrrrDr'r'r(r+s.   z3WALinuxAgentShim._get_raw_goal_state_xml_from_azurer-c Cstz t||j|}Wnty}z td|tjdd}~wwdd|jd|jd|j g}t|tj d|S)aParses a GoalState XML string and returns a GoalState object. @param unparsed_goal_state_xml: GoalState XML string @param need_certificate: switch to know if certificates is needed. @return: GoalState object representing the GoalState XML z"Error processing GoalState XML: %srVNz, zGoalState XML container id: %szGoalState XML instance id: %szGoalState XML incarnation: %s) rrrrr^r5rtrrrrr6)rr-rrrDrXr'r'r(r,2s, z*WALinuxAgentShim._parse_raw_goal_state_xmlrr$cCsHg}|jdur"|dur"|jdur"td|j|j}|||}|S)aGets and filters the VM admin user's authorized pubkeys. The admin user in this case is the username specified as "admin" when deploying VMs on Azure. See https://docs.microsoft.com/en-us/cli/azure/vm#az-vm-create. cloud-init expects a straightforward array of keys to be dropped into the admin user's authorized_keys file. Azure control plane exposes multiple public keys to the VM via wireserver. Select just the admin user's key(s) and return them, ignoring any other certs. @param goal_state: GoalState object. The GoalState object contains a certificate XML, which contains both the VM user's authorized pubkeys and other non-user pubkeys, which are used for MSI and protected extension handling. @param pubkey_info: List of VM user pubkey dicts that were previously obtained from provisioning data. Each pubkey dict in this list can either have the format pubkey['value'] or pubkey['fingerprint']. Each pubkey['fingerprint'] in the list is used to filter and obtain the actual pubkey value from the GoalState certificates XML. Each pubkey['value'] requires no further processing and is immediately added to the return list. @return: A list of the VM user's authorized pubkey values. Nz/Certificate XML found; parsing out public keys.)rrr5r6r_filter_pubkeys)rrr$r&keys_by_fingerprintr'r'r(r#Ts    z"WALinuxAgentShim._get_user_pubkeysr/cCs|g}|D]7}d|vr|dr||dqd|vr5|dr5|d}||vr.|||qtd|qtd|q|S)a8Filter and return only the user's actual pubkeys. @param keys_by_fingerprint: pubkey fingerprint -> pubkey value dict that was obtained from GoalState Certificates XML. May contain non-user pubkeys. @param pubkey_info: List of VM user pubkeys. Pubkey values are added to the return list without further processing. Pubkey fingerprints are used to filter and obtain the actual pubkey values from keys_by_fingerprint. @return: A list of the VM user's authorized pubkey values. rrzIovf-env.xml specified PublicKey fingerprint %s not found in goalstate XMLzFovf-env.xml specified PublicKey with neither value nor fingerprint: %s)rr5rt)r/r$rpubkeyrr'r'r(r.~s" z WALinuxAgentShim._filter_pubkeysr)r"rrrrrr*rDistror r rr(r*rrr"rr+r r,listr#rdictr.r'r'r'r(rsP   %   ! )rrrr$rcCs0t|d}z |j|||dW|S|w)Nr)rr$r)rr(r)rrr$rshimr'r'r(get_metadata_from_fabrics r6r zerrors.ReportableErrorcCs8t|d}|}z |j|dW|dS|w)Nr4r))ras_encoded_reportr*r)rr r5rr'r'r(report_failure_to_fabrics r8cCs(td|tjdtd|tjddS)Nzdhclient output stream: %srVzdhclient error stream: %s)r^r5r6)rEerrr'r'r( dhcp_log_cbs    r:c@s eZdZdS)NonAzureDataSourceN)r"rrr'r'r'r(r;sr;c@seZdZdddZdddddddddd deedeed eed eed eed eee d edeededdfddZ defddZ e deddfddZ d(dededefddZ   d)dedededefd d!Zd"d#Zd$d%Zd&d'ZdS)* OvfEnvXmlz)http://schemas.dmtf.org/ovf/environment/1z)http://schemas.microsoft.com/windowsazure)ovfwaNF rpasswordr custom_datadisable_ssh_password_auth public_keyspreprovisioned_vmpreprovisioned_vm_typeprovision_guest_proxy_agentrr@rrArBrCrDrErFrc Cs>||_||_||_||_||_|pg|_||_||_| |_dSrwr?) rrr@rrArBrCrDrErFr'r'r(rs   zOvfEnvXml.__init__cCs |j|jkSrw)__dict__)rotherr'r'r(__eq__s zOvfEnvXml.__eq__ ovf_env_xmlc Cspzt|}Wntjy}ztj|d|d}~ww|d|jdur)tdt}| || ||S)zParser for ovf-env.xml data. :raises NonAzureDataSource: if XML is not in Azure's format. :raises errors.ReportableErrorOvfParsingException: if XML is unparsable or invalid. ) exceptionNz./wa:ProvisioningSectionz=Ignoring non-Azure ovf-env.xml: ProvisioningSection not found) rrrr"ReportableErrorOvfParsingExceptionr NAMESPACESr;r<&_parse_linux_configuration_set_section _parse_platform_settings_section)clsrJrrDinstancer'r'r( parse_texts  zOvfEnvXml.parse_textr>rrequired namespacecCsh|d||ftj}|sd|}t||rt|dSt|dkr0td|t|f|dS)Nz./%s:%smissing configuration for %rr1*multiple configuration matches for %r (%d)r)findallr<rMr5r6r!ReportableErrorOvfInvalidMetadatalen)rnoderrSrTmatchesrXr'r'r(_finds     zOvfEnvXml._find decode_base64 parse_boolc Cs|d|tj}|sd|}t||rt||St|dkr.td|t|f|dj} | dur9|} |rI| durIt d | } |rPt | } | S)Nz./wa:rUr1rVrr)rWr<rMr5r6rrXrYrrd b64decoderr:rtranslate_bool) rrZrrSr]r^defaultr[rXrr'r'r(_parse_propertys*        zOvfEnvXml._parse_propertycCs|j|ddd}|j|ddd}|j|dddd|_|j|ddd|_|j|d dd|_|j|d dd|_|j|d ddd |_||dS) NProvisioningSectionTrS!LinuxProvisioningConfigurationSet CustomDataF)r]rSUserName UserPasswordHostName DisableSshPasswordAuthentication)r^rS)r\rbrArr@rrB_parse_ssh_section)rrprovisioning_section config_setr'r'r(rN@s<z0OvfEnvXml._parse_linux_configuration_set_sectioncCsb|j|ddd}|j|ddd}|j|ddddd|_|j|ddd|_|j|d dddd|_dS) NPlatformSettingsSectionTrdPlatformSettingsPreprovisionedVmF)r^rarSPreprovisionedVMTypeProvisionGuestProxyAgent)r\rbrDrErF)rrplatform_settings_sectionplatform_settingsr'r'r(rObs2 z*OvfEnvXml._parse_platform_settings_sectionc Csg|_|j|ddd}|durdS|j|ddd}|durdS|dtjD]'}|j|ddd}|j|ddd}|j|dd dd }|||d }|j|q&dS) NSSHFrd PublicKeysz./wa:PublicKey FingerprintPathValuer)rarS)rr{r)rCr\rWr<rMrbr) rrm ssh_sectionpublic_keys_section public_keyrr{rrr'r'r(rk~s2zOvfEnvXml._parse_ssh_section)r>)FFN)r"rrrMr rrrrr3rrI classmethodrRr\rbrNrOrkr'r'r'r(r<sx       %" r<r)Jrdrjloggingrxrrrf contextlibrrrrrtypingrrr r r xml.etreer rxml.sax.saxutilsr cloudinitrrrrrrcloudinit.reportingrcloudinit.sources.azurer getLoggerr"r5DEFAULT_WIRESERVER_ENDPOINTr=rRr]rir!r#rr*rKrUrr<r^rprvrr3rintrrrrrrrrrrrr1r6r8r:r;r<r'r'r'r(s       " U      6 "?f