a 'Dg @srddlZddlZddlZddlZddlZddlZddlZddlmZddl 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-ede-fede-fdddZ.e.ddZ/e.ddZ0dde1e j2ddd Z3d!d"Z4e.d#d$Z5ed%d&Z6e.dd'd(d)e1e7ee8e9e9ej:d*d+d,Z;e1e1e1e8d-d.d/ZZ?Gd4d5d5Z@Gd6d7d7ZAGd8d9d9ZBGd:d;d;ZCe.dIe1ejDeee1ee1d<d=d>ZEe.e1d?d@dAdBZFdCdDZGGdEdFdFe>ZHGdGdHdHZIdS)JN)contextmanager)datetimetimezone)sleeptime)CallableListOptionalTypeVarUnion) ElementTree)escape)distrossubp temp_utils url_helperutilversion)events)errorsz 168.63.129.16boot-telemetryz system-infoZ diagnostic compressedzazure-dsz initialize reporter for azure dsT)name descriptionZreporting_enabledT.)funcreturncsfdd}|S)NcsFtjjjtd|i|WdS1s80YdS)Nrrparent)rReportEventStack__name__azure_ds_reporter)argskwargsrC/usr/lib/python3.9/site-packages/cloudinit/sources/helpers/azure.pyimpl*s z)azure_ds_telemetry_reporter..implr%)rr'r%r$r&azure_ds_telemetry_reporter)s r(c Cs8tstdtdztttt}Wn.t yb}ztd|WYd}~n d}~00zTt j gddd\}}d}|rd|vr| dd }|std |t|d }Wnft j y}ztd ||WYd}~nprintZwebhookrFrG) base64Z encodebyteszlibcompressdecoderr5COMPRESSED_EVENT_TYPEjsondumpsr7r8)Z event_nameZ event_contentZcompressed_dataZ event_datar<r%r%r&report_compressed_eventsrVc Csntdz$tjdgddd\}}td|Wn:tyh}z"tdt|tjdWYd}~n d}~00dS) zReport dmesg to KVP.zDumping dmesg log to KVPZdmesgFT)rRr,z$Exception when dumping dmesg log: %srCN)r0r1rrV ExceptionrJreprwarning)r:r;exr%r%r&report_dmesg_to_kvps  r[c cs@t}ttj|zdVWt|n t|0dSN)osgetcwdchdirpath expanduser)ZnewdirZprevdirr%r%r&cds rb)rM retry_sleeptimeout_minutes)urlheadersrMrerfrc Cs|dt}d}d}|s|d7}ztj|||dd}WqWnbtjy}zHtd||||j|jftjdt||ksd t |vrWYd}~n d}~00t |qtd ||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. <rNr.)rcri)rhrMtimeoutzdFailed HTTP request with Azure endpoint %s during attempt %d with exception: %s (code=%r headers=%r)rCzNetwork is unreachablez@Successful HTTP request with Azure endpoint %s after %d attempts) rrZreadurlZUrlErrorrJcoderhr0r1strr) rgrhrMrerfrjZattemptresponser9r%r%r&http_with_retriess<   rn)usernamehostname disableSshPwdrcCs$td}|j|||d}|dS)Na. 1.0 LinuxProvisioningConfiguration {username} {disableSshPwd} {hostname} 1.0 true )rorprqutf-8)textwrapdedentformatencode)rorprqZOVF_ENV_TEMPLATEretr%r%r&build_minimal_ovfsrxc@sHeZdZdddZddZdejddd Zdee ejd d d Z d S)AzureEndpointHttpClientZ WALinuxAgentz 2012-11-30)zx-ms-agent-namez x-ms-versioncCsd|d|_dS)NZ DES_EDE3_CBC)zx-ms-cipher-namez!x-ms-guest-agent-public-x509-cert)extra_secure_headers)self certificater%r%r&__init__Dsz AzureEndpointHttpClient.__init__FrcCs,|j}|r |j}||jt||dS)N)rh)rhcopyupdaterzrn)r{rgsecurerhr%r%r&getJs   zAzureEndpointHttpClient.getN)rMrcCs0|j}|dur"|j}||t|||dS)N)rMrh)rhrrrn)r{rgrM extra_headersrhr%r%r&postQs   zAzureEndpointHttpClient.post)F)NN) r __module__ __qualname__rhr}r UrlResponserr bytesrr%r%r%r&ry>sryc@seZdZdZdS)InvalidGoalStateXMLExceptionz9Raised when GoalState XML is invalid or has missing data.N)r rr__doc__r%r%r%r&r[src@s2eZdZdeeefeeddddZddZ dS) GoalStateTN) unparsed_xmlazure_endpoint_clientneed_certificaterc Cs*||_zt||_Wn:tjyP}z td|tjdWYd}~n d}~00|d|_ |d|_ |d|_ dD]0}t ||durzd|}t|tjdt |qzd|_|d }|dur&|r&tjd d td 8|jj|d dj|_|jdurt dWdn1s0YdS)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: %srCNz./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 ParseErrorrJr0rY_text_from_xpathrrrgetattrrcertificates_xmlrrr!rcontents)r{rrrr9attrrErgr%r%r&r}`sH      zGoalState.__init__cCs|j|}|dur|jSdSr\)rfindtext)r{Zxpathelementr%r%r&rs zGoalState._text_from_xpath)T) r rrr rlrryboolr}rr%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_keyr|cCst|_d|_|dSr\)rZmkdtemptmpdir _certificategenerate_certificater{r%r%r&r}s zOpenSSLManager.__init__cCst|jdSr\)rZdel_dirrrr%r%r&clean_upszOpenSSLManager.clean_upcCs|jSr\rrr%r%r&r|szOpenSSLManager.certificatecCs ||_dSr\r)r{valuer%r%r&r|scCstd|jdur"tddSt|jztddddddd d d d d |jdd|jdgd}t|jd D]}d|vrx|| 7}qx||_Wdn1s0YtddS)Nz7Generating certificate for communication with fabric...zCertificate already generated.opensslZreqz-x509z-nodesz-subjz/CN=LinuxTransportz-daysZ32768z-newkeyzrsa:2048z-keyoutrz-outr|Z CERTIFICATEzNew certificate generated.) r0r1r|rbrrcertificate_namesrZload_text_file splitlinesrstrip)r{r|liner%r%r&rs<     $z#OpenSSLManager.generate_certificatecCs"ddd|g}tj||d\}}|S)NrZx509z-nooutrM)r)actionZcertcmdresultr;r%r%r&_run_x509_actions zOpenSSLManager._run_x509_actioncCs*|d|}gd}tj||d\}}|S)Nz-pubkey)z ssh-keygenz-iz-mZPKCS8z-fz /dev/stdinr)rr)r{r|Zpub_keyZ keygen_cmdssh_keyr;r%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 -fingerprintr-r.:r)rrr4join)r{r|Zraw_fpeqoctetsr%r%r&_get_fingerprint_from_certs  z)OpenSSLManager._get_fingerprint_from_certcCst|d}|j}ddddd|dg}t|j8tjdjfi|j d d |d \}}Wd n1st0Y|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: base64rrzuopenssl cms -decrypt -in /dev/stdin -inkey {private_key} -recip {certificate} | openssl pkcs12 -nodes -password pass:T )shellrMN) rrrrrvrbrrrurr)r{rtagZcertificates_contentlinesr:r;r%r%r&_decrypt_certs_from_xmls$ (z&OpenSSLManager._decrypt_certs_from_xmlc Csv||}g}i}|D]V}||td|r:g}qtd|rd|}||}||}|||<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) r{rr:currentkeysrr|r fingerprintr%r%r&parse_certificates s        z!OpenSSLManager.parse_certificatesN)r rrrr}rpropertyr|setterr(r staticmethodrrrrrr%r%r%r&rs,   !    rc@seZdZedZedZdZdZdZ dZ e e e ddd d Zedd d d Zee ddddZde e e e edddZeeddddZdS)GoalStateHealthReportera {incarnation} {container_id} {instance_id} {health_status} {health_detail_subsection} z
{health_substatus} {health_description}
ZReadyZNotReadyZProvisioningFailediN) goal_staterendpointrcCs||_||_||_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)r{rrrr%r%r&r}Fsz GoalStateHealthReporter.__init__r~c Cs|j|jj|jj|jj|jd}tdz|j|dWn8t yr}z t d|tj dWYd}~n d}~00t ddS)N)rrrstatusz Reporting ready to Azure fabric.documentz#exception while reporting ready: %srCzReported ready to Azure fabric.) build_reportrrrrPROVISIONING_SUCCESS_STATUSr0r1_post_health_reportrWrJerrorrA)r{rr9r%r%r&send_ready_signal[s  z)GoalStateHealthReporter.send_ready_signalrrc Cs|j|jj|jj|jj|j|j|d}z|j|dWn<tyr}z$d|}t |t j dWYd}~n d}~00t ddS)N)rrrr substatusrrz%exception while reporting failure: %srCz!Reported failure to Azure fabric.) rrrrrPROVISIONING_NOT_READY_STATUSPROVISIONING_FAILURE_SUBSTATUSrrWrJr0rrY)r{rrr9rEr%r%r&send_failure_signalosz+GoalStateHealthReporter.send_failure_signal)rrrrrc Csbd}|dur.|jjt|t|d|jd}|jjtt|t|t|t||d}|dS)Nr)Zhealth_substatusZhealth_description)rrrZ health_statusZhealth_detail_subsectionrr)%HEALTH_DETAIL_SUBSECTION_XML_TEMPLATErur "HEALTH_REPORT_DESCRIPTION_TRIM_LENHEALTH_REPORT_XML_TEMPLATErlrv) r{rrrrrrZ health_detailZ health_reportr%r%r&rs   z$GoalStateHealthReporter.build_report)rrcCsBtdtdd|j}|jj||ddidtddS)Nrz&Sending health report to Azure fabric.zhttp://{}/machine?comp=healthz Content-Typeztext/xml; charset=utf-8)rMrz/Successfully sent health report to Azure fabric)rr0r1rurrr)r{rrgr%r%r&rs  z+GoalStateHealthReporter._post_health_report)NN)r rrrsrtrrrrrrrryrlr}r(rrrrrr%r%r%r&r s<   rc@seZdZedddZddZeejdddd Z edeje e edd d Z eedd d dZ eeedddZeedddZeeeefeedddZeeeedddZeeeedddZdS)WALinuxAgentShimrcCs||_d|_d|_dSr\)ropenssl_managerr)r{rr%r%r&r}szWALinuxAgentShim.__init__cCs|jdur|jdSr\)rrrr%r%r&rs zWALinuxAgentShim.clean_upN)distrorc CsTtdz||Wn6tyN}ztd|tjdWYd}~n d}~00dS)NzEjecting the provisioning isoz(Failed ejecting the provisioning iso: %srC)r0r1Z eject_mediarWrJr)r{iso_devrr9r%r%r& eject_isos zWALinuxAgentShim.eject_isocCsd}|jdur&|dur&t|_|jj}|jdur:t||_|j|dud}d}|durb|||}t||j|j}|dur|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) rrr|rry_fetch_goal_state_from_azure_get_user_pubkeysrrrr)r{r pubkey_inforZhttp_client_certificaterssh_keyshealth_reporterr%r%r&"register_with_azure_and_fetch_datas*   z3WALinuxAgentShim.register_with_azure_and_fetch_datarcCs@|jdurtd|_|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. NFrr)rryrrrr)r{rrrr%r%r&®ister_with_azure_and_report_failures    z7WALinuxAgentShim.register_with_azure_and_report_failure)rrcCs|}|||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)r{runparsed_goal_state_xmlr%r%r&rs z-WALinuxAgentShim._fetch_goal_state_from_azurer~c Cstdd|j}z@tjddtd|j|}Wdn1sJ0YWn8t y}z t d|tj dWYd}~n d}~00t 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: %srCz#Successfully fetched GoalState XML.)r0rArurrrr!rrrWrJrYr1r)r{rgrmr9r%r%r&rs&  . z3WALinuxAgentShim._get_raw_goal_state_xml_from_azure)rrrc Cszt||j|}Wn8tyJ}z td|tjdWYd}~n d}~00dd|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: %srCNz, zGoalState XML container id: %szGoalState XML instance id: %szGoalState XML incarnation: %s) rrrWrJr0rYrrrrr1)r{rrrr9rEr%r%r&r2s( z*WALinuxAgentShim._parse_raw_goal_state_xml)rrrcCsHg}|jdurD|durD|jdurDtd|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.)rrr0r1r_filter_pubkeys)r{rrrkeys_by_fingerprintr%r%r&rTs  z"WALinuxAgentShim._get_user_pubkeys)rrrcCs|g}|D]n}d|vr,|dr,||dqd|vrj|drj|d}||vr\|||qvtd|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)rr0rY)rrrZpubkeyrr%r%r&r~s" z WALinuxAgentShim._filter_pubkeys)NN)r rrrlr}rr(rDistrorr rrrrrrrrr rlistrrdictrr%r%r%r&rs:  % !)r)rrrrcCs4t|d}z|j|||dW|S|0dS)Nr)rrr)rrr)rrrrshimr%r%r&get_metadata_from_fabrics rzerrors.ReportableError)rrcCs:t|d}|}z|j|dW|n |0dS)Nrr)rZas_encoded_reportrr)rrrrr%r%r&report_failure_to_fabrics  rcCs(td|tjdtd|tjddS)Nzdhclient output stream: %srCzdhclient error stream: %s)rJr0r1)r:errr%r%r& dhcp_log_cbs   rc@s eZdZdS)NonAzureDataSourceN)r rrr%r%r%r&rsrc @seZdZdddZdddddddddd eeeeeeeeeeeee eeeedd dd Z ed d d Z e edd ddZ deeedddZdeeeedddZddZddZddZdS) OvfEnvXmlz)http://schemas.dmtf.org/ovf/environment/1z)http://schemas.microsoft.com/windowsazure)ZovfwaNF ropasswordrp custom_datadisable_ssh_password_auth public_keyspreprovisioned_vmpreprovisioned_vm_typeprovision_guest_proxy_agent) rorrprrrrrrrc Cs>||_||_||_||_||_|p$g|_||_||_| |_dSr\r) r{rorrprrrrrrr%r%r&r}s  zOvfEnvXml.__init__r~cCs |j|jkSr\)__dict__)r{otherr%r%r&__eq__szOvfEnvXml.__eq__) ovf_env_xmlrc Cs|zt|}Wn4tjyB}ztj|d|WYd}~n d}~00|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) rrrrZ"ReportableErrorOvfParsingExceptionr NAMESPACESrr&_parse_linux_configuration_set_section _parse_platform_settings_section)clsr rr9instancer%r%r& parse_texts$  zOvfEnvXml.parse_textr)rrequired namespacecCsp|d||ftj}t|dkrFd|}t||rBt|dSt|dkrhtd|t|f|dS)Nz./%s:%srmissing configuration for %rr.*multiple configuration matches for %r (%d))findallrrlenr0r1r!ReportableErrorOvfInvalidMetadata)r{noderrrmatchesrEr%r%r&_finds      zOvfEnvXml._find)rr decode_base64 parse_boolc Cs|d|tj}t|dkrBd|}t||r>t||St|dkrdtd|t|f|dj} | durz|} |r| durt d | } |rt | } | S)Nz./wa:rrr.rr)rrrrr0r1rrrrOZ b64decoderr4rZtranslate_bool) r{rrrrrdefaultrrErr%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) NZProvisioningSectionTrZ!LinuxProvisioningConfigurationSetZ CustomDataF)rrZUserNameZ UserPasswordZHostNameZ DisableSshPasswordAuthentication)rr)rr!rrorrpr_parse_ssh_section)r{rZprovisioning_section config_setr%r%r&r?s<z0OvfEnvXml._parse_linux_configuration_set_sectioncCsb|j|ddd}|j|ddd}|j|ddddd|_|j|ddd|_|j|d dddd|_dS) NZPlatformSettingsSectionTr"ZPlatformSettingsZPreprovisionedVmF)rr rZPreprovisionedVMTypeZProvisionGuestProxyAgent)rr!rrr)r{rZplatform_settings_sectionZplatform_settingsr%r%r&ras2z*OvfEnvXml._parse_platform_settings_sectionc Csg|_|j|ddd}|dur"dS|j|ddd}|dur>dS|dtjD]N}|j|ddd}|j|ddd}|j|dd dd }|||d }|j|qLdS) NZSSHFr"Z PublicKeysz./wa:PublicKeyZ FingerprintPathZValuer)r r)rr`r)rrrrrr!r) r{r$Z ssh_sectionZpublic_keys_sectionZ public_keyrr`rrr%r%r&r#}s0zOvfEnvXml._parse_ssh_section)r)FFN)r rrrr rlrrrrr}r  classmethodrrr!rrr#r%r%r%r&rsZ    $"r)NN)JrOrTZloggingr]rrsrP contextlibrrrrrtypingrrr r r Z xml.etreer rZxml.sax.saxutilsr Z cloudinitrrrrrrZcloudinit.reportingrZcloudinit.sources.azurerZ getLoggerr r0ZDEFAULT_WIRESERVER_ENDPOINTr6r@rIrSrr!rr(r=rBrlr5rJrVr[rbrrintrrnrxryrWrrrrrrrrrrrr%r%r%r&s         U    7 "?f