3 \me @sddlZddlZddlZddlZddlZddlZddlZddlZddlZddl m Z ddl m Z ddl m Z ddlmZmZddlmZmZmZmZmZmZddlmZddlmZdd lmZmZmZmZm Z m!Z!dd l"m#Z#dd l$m%Z%erdd l&m'Z'ej(e)Z*d Z+dZ,dZ-dZ.dZ/dZ0dZ1e#j2ddddZ3edZ4ede4fede4fdddZ5e5ddZ6e5dd Z7dd!e8e#j9d"d#d$Z:d%d&Z;e5e%d'fd(d)Zd.d/Z?e5dd0d1d2e8e@eeAeBeBejCd3d4d5ZDe8e8e8eAd6d7d8ZEGd9d:d:ZFGd;d<dd>ZIGd?d@d@ZJGdAdBdBZKGdCdDdDZLe5dTe8eee8ee8dEdFdGZMe5e8dHdIdJdKZNdLdMZOGdNdOdOeGZPGdPdQdQeGZQGdRdSdSZRdS)UN)contextmanager)datetime)ENOENT)sleeptime) TYPE_CHECKINGCallableListOptionalTypeVarUnion) ElementTree)escape)distrossubp temp_utils url_helperutilversion)events) CFG_BUILTIN)errorsz 168.63.129.16zboot-telemetryz system-infoZ diagnosticZ compressediz'/run/cloud-init/log_pushed_to_kvp_indexzazure-dsz initialize reporter for azure dsT)name descriptionZreporting_enabledT.)funcreturncsfdd}|S)Nc s*tjjjtd ||SQRXdS)N)rrparent)rReportEventStack__name__azure_ds_reporter)argskwargs)r/usr/lib/python3.6/azure.pyimpl5s  z)azure_ds_telemetry_reporter..implr#)rr%r#)rr$azure_ds_telemetry_reporter4s r&c2Cs8tjstdtjdyttttj}Wn,t k r`}ztd|WYdd}~XnXyXt j ddddgd d \}}d}|rd |kr|j d d }|std |t|d}Wnbt j k r}ztd||WYdd}~Xn2t k r}ztd||WYdd}~XnXy`t j dddddgd d \}}d}|r^d |kr^|j d d }|sltd|t|d}Wndt j k r}ztd||WYdd}~Xn2t k r}ztd||WYdd}~XnXt jtddtj|jdtj|jdtj|jdft j}t j||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 timestampNZ systemctlZshowz-pZUserspaceTimestampMonotonicT)capture=z8Failed to parse UserspaceTimestampMonotonic from systemdi@Bz-Failed to get UserspaceTimestampMonotonic: %szLzutf-8) replacelenr0structpackrhencodesocketZ inet_ntoa)Zfallback_lease_valueZunescaped_valueZ hex_stringZhex_pairZ packed_bytesr#r#r$get_ip_from_lease_value!s     r|)rI retry_sleeptimeout_minutes)urlheadersrIrrrc Cs|dt}d}d}x|s|d7}ytj|||d d}PWn`tjk r}zBtd||||j|jftjdt||ksd t |krWYdd}~XnXt |qWtd ||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)r})rrItimeoutzdFailed HTTP request with Azure endpoint %s during attempt %d with exception: %s (code=%r headers=%r))r@zNetwork is unreachablez@Successful HTTP request with Azure endpoint %s after %d attempts)r}r) rrZreadurlZUrlErrorrFcoderr,r-r`r) rrrIrrrZattemptresponser5r#r#r$http_with_retries/s.    r)usernamehostname disableSshPwdrcCs$tjd}|j|||d}|jdS)Na. 1.0 LinuxProvisioningConfiguration {username} {disableSshPwd} {hostname} 1.0 true )rrrzutf-8)textwrapdedentr\rz)rrrZOVF_ENV_TEMPLATEretr#r#r$build_minimal_ovffs  rc@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__sz AzureEndpointHttpClient.__init__F)rcCs,|j}|r |jj}|j|jt||dS)N)r)rcopyupdaterr)rrsecurerr#r#r$gets   zAzureEndpointHttpClient.getN)rIrcCs0|j}|dk r"|jj}|j|t|||dS)N)rIr)rrrr)rrrI extra_headersrr#r#r$posts   zAzureEndpointHttpClient.post)F)NN) r __module__ __qualname__rrr UrlResponserr bytesrr#r#r#r$rs rc@seZdZdZdS)InvalidGoalStateXMLExceptionz9Raised when GoalState XML is invalid or has missing data.N)rrr__doc__r#r#r#r$rsrc@s2eZdZdeeefeeddddZddZ dS) GoalStateTN) unparsed_xmlazure_endpoint_clientneed_certificatercCs||_ytj||_Wn8tjk rN}ztd|tjdWYdd}~XnX|jd|_ |jd|_ |jd|_ x8dD]0}t ||dkrzd |}t|tjdt |qzWd|_|jd }|dk o|rtjd d td.|jj|ddj|_|jdkrt dWdQRXdS)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: %s)r@Nz./Container/ContainerIdz4./Container/RoleInstanceList/RoleInstance/InstanceIdz ./Incarnation container_id instance_id incarnationzMissing %s in GoalState XMLzD./Container/RoleInstanceList/RoleInstance/Configuration/Certificateszget-certificates-xmlzget certificates xml)rrrT)rz/Azure endpoint returned empty certificates xml.)rrr)rr fromstringroot ParseErrorrFr,rc_text_from_xpathrrrgetattrrcertificates_xmlrrr rcontents)rrrrr5attrrArr#r#r$rs<        zGoalState.__init__cCs|jj|}|dk r|jSdS)N)rfindtext)rZxpathelementr#r#r$rs zGoalState._text_from_xpath)T) rrrr r`rrboolrrr#r#r#r$rs2rc@seZdZdddZddZddZedd Zejd d Ze d d Z e e d dZ e ddZ e ddZe ddZe ddZdS)OpenSSLManagerzTransportPrivate.pemzTransportCert.pem) private_keyrcCstj|_d|_|jdS)N)rZmkdtemptmpdir _certificategenerate_certificate)rr#r#r$rs zOpenSSLManager.__init__cCstj|jdS)N)rZdel_dirr)rr#r#r$clean_upszOpenSSLManager.clean_upcCs|jS)N)r)rr#r#r$rszOpenSSLManager.certificatecCs ||_dS)N)r)rvaluer#r#r$rscCstjd|jdk r"tjddSt|jntjddddddd d d d d |jdd|jdgd}x*t|jdD]}d|krt||j7}qtW||_WdQRXtjddS)Nz7Generating certificate for communication with fabric...zCertificate already generated.opensslZreqz-x509z-nodesz-subjz/CN=LinuxTransportz-daysZ32768z-newkeyzrsa:2048z-keyoutrz-outrrqZ CERTIFICATEzNew certificate generated.) r,r-rrorrcertificate_namesrUrstrip)rrliner#r#r$rs4    z#OpenSSLManager.generate_certificatecCs"ddd|g}tj||d\}}|S)NrZx509z-noout)rI)r)actionZcertcmdresultr7r#r#r$_run_x509_action s zOpenSSLManager._run_x509_actioncCs2|jd|}ddddddg}tj||d\}}|S) Nz-pubkeyz ssh-keygenz-iz-mZPKCS8z-fz /dev/stdin)rI)rr)rrZpub_keyZ keygen_cmdssh_keyr7r#r#r$_get_ssh_key_from_cert's z%OpenSSLManager._get_ssh_key_from_certcCs6|jd|}|jd}||ddjd}dj|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 ' Azure control plane passes that fingerprint as so: '073E19D14D1C799224C6A0FD8DDAB6A8BF27D473' z -fingerprintr(r)rsrq)rrr0join)rrZraw_fpeqZoctetsr#r#r$_get_fingerprint_from_cert.s  z)OpenSSLManager._get_fingerprint_from_certc Csjtj|jd}|j}ddddd|jdg}t|j*tjdjf|j d d j |d \}}Wd QRX|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: base64zutf-8zuopenssl cms -decrypt -in /dev/stdin -inkey {private_key} -recip {certificate} | openssl pkcs12 -nodes -password pass:T )shellrIN) r rrrrzrorrr\rr)rrtagZcertificates_contentlinesr6r7r#r#r$_decrypt_certs_from_xml<s  z&OpenSSLManager._decrypt_certs_from_xmlc Csz|j|}g}i}xb|jD]V}|j|tjd|r {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)rrrrr#r#r$rsz GoalStateHealthReporter.__init__)rcCs|j|jj|jj|jj|jd}tjdy|j|dWn6t k rp}zt d|tj dWYdd}~XnXtj ddS)N)rrrstatusz Reporting ready to Azure fabric.)documentz#exception while reporting ready: %s)r@zReported ready to Azure fabric.) build_reportrrrrPROVISIONING_SUCCESS_STATUSr,r-_post_health_reportrarFerrorr>)rrr5r#r#r$send_ready_signals   z)GoalStateHealthReporter.send_ready_signal)rrcCs|j|jj|jj|jj|j|j|d}y|j|dWn:tk rp}zd|}t |t j dWYdd}~XnXt j ddS)N)rrrr substatusr)rz%exception while reporting failure: %s)r@z!Reported failure to Azure fabric.) rrrrrPROVISIONING_NOT_READY_STATUSPROVISIONING_FAILURE_SUBSTATUSrrarFr,rrc)rrrr5rAr#r#r$send_failure_signalsz+GoalStateHealthReporter.send_failure_signal)rrrrrc Csbd}|dk r.|jjt|t|d|jd}|jjtt|t|t|t||d}|jdS)Nrq)Zhealth_substatusZhealth_description)rrrZ health_statusZhealth_detail_subsectionzutf-8)%HEALTH_DETAIL_SUBSECTION_XML_TEMPLATEr\r"HEALTH_REPORT_DESCRIPTION_TRIM_LENHEALTH_REPORT_XML_TEMPLATEr`rz) rrrrrrrZ health_detailZ health_reportr#r#r$rs  z$GoalStateHealthReporter.build_report)rrcCsHttdtjddj|j}|jj||ddidtjddS)Nrz&Sending health report to Azure fabric.zhttp://{}/machine?comp=healthz Content-Typeztext/xml; charset=utf-8)rIrz/Successfully sent health report to Azure fabric)rfrr,r-r\rrr)rrrr#r#r$rs   z+GoalStateHealthReporter._post_health_report)NN)rrrrrrrrrrrrrr`rr&rrrrrr#r#r#r$rjs* rc@seZdZedddZddZedddd Zedee edd d Z eedd d dZ ee e dddZeedddZeeeefe e dddZee eedddZeeeedddZdS)WALinuxAgentShim)rcCs||_d|_d|_dS)N)ropenssl_managerr)rrr#r#r$r szWALinuxAgentShim.__init__cCs|jdk r|jjdS)N)rr)rr#r#r$rs zWALinuxAgentShim.clean_upN)rcCsVytjdtjd|gWn4tk rP}ztd|tjdWYdd}~XnXdS)NzEjecting the provisioning isoZejectz(Failed ejecting the provisioning iso: %s)r@)r,r-rrarFr)riso_devr5r#r#r$ eject_isos zWALinuxAgentShim.eject_isocCsd}|jdkr&|dk r&t|_|jj}|jdkr:t||_|j|dk d}d}|dk rb|j||}t||j|j}|dk r|j ||j |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. N)r) rrrrr_fetch_goal_state_from_azure_get_user_pubkeysrrrr)r pubkey_inforZhttp_client_certificaterssh_keyshealth_reporterr#r#r$"register_with_azure_and_fetch_data s$    z3WALinuxAgentShim.register_with_azure_and_fetch_data)rrcCs@|jdkrtd|_|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. NF)r)r)rrrrrr)rrrrr#r#r$®ister_with_azure_and_report_failureFs    z7WALinuxAgentShim.register_with_azure_and_report_failure)rrcCs|j}|j||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$rUs z-WALinuxAgentShim._fetch_goal_state_from_azurecCstjddj|j}y,tjddtd|jj|}WdQRXWn6t k rx}zt d|tj dWYdd}~XnXtj 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 goalstate)rrrNz9failed to register with Azure and fetch GoalState XML: %s)r@z#Successfully fetched GoalState XML.)r,r>r\rrrr rrrarFrcr-r)rrrr5r#r#r$rds      z3WALinuxAgentShim._get_raw_goal_state_xml_from_azure)rrrcCs~yt||j|}Wn6tk rH}ztd|tjdWYdd}~XnXdjd|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: %s)r@Nz, zGoalState XML container id: %szGoalState XML instance id: %szGoalState XML incarnation: %s) rrrarFr,rcrrrrr-)rrrrr5rAr#r#r$rs   z*WALinuxAgentShim._parse_raw_goal_state_xml)rrrcCsHg}|jdk rD|dk rD|jdk rDtjd|jj|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.)rrr,r-r_filter_pubkeys)rrrrkeys_by_fingerprintr#r#r$rs    z"WALinuxAgentShim._get_user_pubkeys)rrrcCsg}xv|D]n}d|kr.|dr.|j|dq d|krl|drl|d}||kr^|j||qxtjd|q tjd|q W|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)rr,rc)rrrZpubkeyrr#r#r$rs   z WALinuxAgentShim._filter_pubkeys)NN)rrrr`rrr&rr r rrrrrrrr rlistrrdictrr#r#r#r$r s. #  'r)rrrc Cs(t|d}z|j||dS|jXdS)N)r)rr)rrr)rrrshimr#r#r$get_metadata_from_fabrics   rzerrors.ReportableError)rrc Cs2t|d}|j}z|j|dWd|jXdS)N)r)r)rZas_encoded_reportrr)rrrrr#r#r$report_failure_to_fabrics  rcCs(td|tjdtd|tjddS)Nzdhclient output stream: %s)r@zdhclient error stream: %s)rFr,r-)r6errr#r#r$ dhcp_log_cb src@s eZdZdS)BrokenAzureDataSourceN)rrrr#r#r#r$rsrc@s eZdZdS)NonAzureDataSourceN)rrrr#r#r#r$rsrc @seZdZdddZdddddddddeeeeeeeeeeeee eeedd dd Z ed d d Z e edd ddZ deeedddZdeeeedddZddZddZddZdS) OvfEnvXmlz)http://schemas.dmtf.org/ovf/environment/1z)http://schemas.microsoft.com/windowsazure)ZovfwaNF)rpasswordr custom_datadisable_ssh_password_auth public_keyspreprovisioned_vmpreprovisioned_vm_type) rrrr r r r r rc Cs8||_||_||_||_||_|p$g|_||_||_dS)N)rrrr r r r r ) rrrrr r r r r r#r#r$r s  zOvfEnvXml.__init__)rcCs |j|jkS)N)__dict__)rotherr#r#r$__eq__5szOvfEnvXml.__eq__) ovf_env_xmlrcCszytj|}Wn6tjk rD}zd|}t||WYdd}~XnX|jd|js\tdt}|j||j ||S)zParser for ovf-env.xml data. :raises NonAzureDataSource: if XML is not in Azure's format. :raises BrokenAzureDataSource: if XML is unparseable or invalid. zInvalid ovf-env.xml: %sNz./wa:ProvisioningSectionz=Ignoring non-Azure ovf-env.xml: ProvisioningSection not found) r rrrr NAMESPACESrr&_parse_linux_configuration_set_section _parse_platform_settings_section)clsrrr5Z error_strinstancer#r#r$ parse_text8s  zOvfEnvXml.parse_textr)rrequired namespacecCsl|jd||ftj}t|dkrDd|}tj||r@t|dSt|dkrdtd|t|f|dS)Nz./%s:%srz#No ovf-env.xml configuration for %rr)z:Multiple configuration matches in ovf-exml.xml for %r (%d))findallrrrwr,r-r)rnoderrrmatchesrAr#r#r$_findQs   zOvfEnvXml._find)rr decode_base64 parse_boolc Cs|jd|tj}t|dkr@d|}tj||rdSx`|jdtjD]N}|j|ddd}|j|ddd}|j|dd dd }|||d }|jj|qNWdS) NZSSHF)rZ PublicKeysz./wa:PublicKeyZ FingerprintZPathZValuerq)r r)rrmr)r rrrrr!r) rr#Z ssh_sectionZpublic_keys_sectionZ public_keyrrmrrr#r#r$r"s&  zOvfEnvXml._parse_ssh_section)r)FFN)rrrrr r`rrr rrr classmethodrrr!rrr"r#r#r#r$rs*6 "r)NN)SrKrPZloggingrWrr{rxrrL contextlibrrrjrrrZtypingrrr r r r Z xml.etreer Zxml.sax.saxutilsrZ cloudinitrrrrrrZcloudinit.reportingrZcloudinit.settingsrZcloudinit.sources.azurerZ getLoggerrr,ZDEFAULT_WIRESERVER_ENDPOINTr2r=rErOr[r_rr rr&r9r?r`r1rFrRrfrTror|rrrhrrrrrarrrrrrrrrrrr#r#r#r$s            T (  0 ?"f"