o
    f\                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlmZ d dl	m	Z	 d dl
mZm
Z
 d dlmZmZmZmZmZ d dlmZ d dlmZ d dlmZmZmZmZmZmZ d d	lmZ d d
lm Z  e!e"Z#dZ$dZ%dZ&dZ'dZ(ej)ddddZ*edZ+dede+f dede+f fddZ,e,dd Z-e,dd Z.ddde/dej0fd d!Z1d"d# Z2e,d$d% Z3ed&d' Z4e,dd(d)d*d+e/d,e5d-ee6 d.e7d/e7dej8fd0d1Z9d2e/d3e/d4e/de6fd5d6Z:G d7d8 d8Z;G d9d: d:e<Z=G d;d< d<Z>G d=d> d>Z?G d?d@ d@Z@G dAdB dBZAe,		dSdCe/dDejBdEeee/  dFee/ fdGdHZCe,dCe/dIdJfdKdLZDdMdN ZEG dOdP dPe<ZFG dQdR dRZGdS )T    N)contextmanager)datetime)sleeptime)CallableListOptionalTypeVarUnion)ElementTree)escape)distrossubp
temp_utils
url_helperutilversion)events)errorsz168.63.129.16boot-telemetryzsystem-info
diagnostic
compressedzazure-dsz initialize reporter for azure dsT)namedescriptionreporting_enabledTfunc.returnc                    s    fdd}|S )Nc                     sF   t j j jtd  | i |W  d    S 1 sw   Y  d S )Nr   r   parent)r   ReportEventStack__name__azure_ds_reporter)argskwargsr    A/usr/lib/python3/dist-packages/cloudinit/sources/helpers/azure.pyimpl*   s   $z)azure_ds_telemetry_reporter.<locals>.implr&   )r   r(   r&   r%   r'   azure_ds_telemetry_reporter)   s   r)   c               
   C   s  t  stdtd ztt tt  } W n t	y+ } ztd|d}~ww z*t
j
g ddd\}}d}|rGd|v rG|dd	 }|sMtd
| t|d  }W n& t
jyj } ztd| |d}~w t	y| } ztd| |d}~ww z*t
j
g ddd\}}d}|rd|v r|dd	 }|std| t|d  }W n& t
jy } ztd| |d}~w t	y } ztd| |d}~ww ttddt|  d t| d t| d f tj}t| |S )z[Report timestamps related to kernel initialization and systemd
    activation of cloud-initz1distro not using systemd, skipping boot telemetryzCollecting boot telemetryz*Failed to determine kernel start timestampN)	systemctlshow-pUserspaceTimestampMonotonicT)capture=   z8Failed to parse UserspaceTimestampMonotonic from systemdi@B z-Failed to get UserspaceTimestampMonotonic: %sz<Failed to parse UserspaceTimestampMonotonic from systemd: %s)r*   r+   zcloud-init-localr,   InactiveExitTimestampMonotonicz;Failed to parse InactiveExitTimestampMonotonic from systemdz0Failed to get InactiveExitTimestampMonotonic: %sz?Failed to parse InactiveExitTimestampMonotonic from systemd: %sr   z5kernel_start=%s user_start=%s cloudinit_activation=%sZ)r   uses_systemdRuntimeErrorLOGdebugfloatr   r   uptime
ValueErrorr   splitProcessExecutionErrorr   ReportingEventBOOT_EVENT_TYPEr   utcfromtimestamp	isoformatDEFAULT_EVENT_ORIGINreport_event)kernel_starteout_tsm
user_startcloudinit_activationevtr&   r&   r'   get_boot_telemetry5   s   





rJ   c                  C   sb   t  } ttddt | d | d | d d | d d | d d | d	 f tj}t| |S )
z%Collect and report system informationzsystem informationztcloudinit_version=%s, kernel_version=%s, variant=%s, distro_name=%s, distro_version=%s, flavor=%s, python_version=%sreleasevariantdistr   r0      python)	r   system_infor   r<   SYSTEMINFO_EVENT_TYPEr   version_stringr@   rA   )inforI   r&   r&   r'   get_system_info   s$   



rT   logger_funcmsgc                C   s6   t |r||  ttd| tj}tj|dhd |S )zReport a diagnostic eventzdiagnostic messagelogexcluded_handler_types)callabler   r<   DIAGNOSTIC_EVENT_TYPEr@   rA   )rW   rV   rI   r&   r&   r'   report_diagnostic_event   s   r]   c                 C   sN   t t|}d|dd}tt| t	|tj
}tj|h dd |S )zReport a compressed eventzgz+b64ascii)encodingdata>   rX   printwebhookrY   )base64encodebyteszlibcompressdecoder   r<   COMPRESSED_EVENT_TYPEjsondumpsr@   rA   )
event_nameevent_contentcompressed_data
event_datarI   r&   r&   r'   report_compressed_event   s   ro   c               
   C   sn   t d ztjdgddd\} }td|  W dS  ty6 } ztdt| t jd W Y d}~dS d}~ww )	zReport dmesg to KVP.zDumping dmesg log to KVPdmesgFT)rg   r.   z$Exception when dumping dmesg log: %srU   N)r5   r6   r   ro   	Exceptionr]   reprwarning)rD   rE   exr&   r&   r'   report_dmesg_to_kvp   s   

ru   c              	   c   s@    t  }t t j|  zd V  W t | d S t | w N)osgetcwdchdirpath
expanduser)newdirprevdirr&   r&   r'   cd   s   r~         )r`   retry_sleeptimeout_minutesurlheadersr`   r   r   c          	   
   C   s   |d t   }d}d}|sT|d7 }ztj| ||dd}W n7 tjyM } z$td| |||j|jf tjd t  | |ksBd	t	|v rC W Y d}~nd}~ww t
| |rtd
| |f tjd |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.
    <   r   Nr0   )r   r   )r   r`   timeoutzdFailed HTTP request with Azure endpoint %s during attempt %d with exception: %s (code=%r headers=%r)rU   zNetwork is unreachablez@Successful HTTP request with Azure endpoint %s after %d attempts)r   r   readurlUrlErrorr]   coder   r5   r6   strr   )	r   r   r`   r   r   r   attemptresponserC   r&   r&   r'   http_with_retries   s@   r   usernamehostnamedisableSshPwdc                 C   s$   t d}|j| ||d}|dS )Na.          <ns0:Environment xmlns:ns0="http://schemas.dmtf.org/ovf/environment/1"
         xmlns:ns1="http://schemas.microsoft.com/windowsazure"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
          <ns1:ProvisioningSection>
            <ns1:Version>1.0</ns1:Version>
            <ns1:LinuxProvisioningConfigurationSet>
              <ns1:ConfigurationSetType>LinuxProvisioningConfiguration
              </ns1:ConfigurationSetType>
              <ns1:UserName>{username}</ns1:UserName>
              <ns1:DisableSshPasswordAuthentication>{disableSshPwd}
              </ns1:DisableSshPasswordAuthentication>
              <ns1:HostName>{hostname}</ns1:HostName>
            </ns1:LinuxProvisioningConfigurationSet>
          </ns1:ProvisioningSection>
          <ns1:PlatformSettingsSection>
            <ns1:Version>1.0</ns1:Version>
            <ns1:PlatformSettings>
              <ns1:ProvisionGuestAgent>true</ns1:ProvisionGuestAgent>
            </ns1:PlatformSettings>
          </ns1:PlatformSettingsSection>
        </ns0:Environment>
        )r   r   r   utf-8)textwrapdedentformatencode)r   r   r   OVF_ENV_TEMPLATEretr&   r&   r'   build_minimal_ovf  s   
r   c                   @   sL   e Zd ZdddZdd Zddejfdd	Z	
ddee	 dejfddZ
d
S )AzureEndpointHttpClientWALinuxAgentz
2012-11-30)zx-ms-agent-namezx-ms-versionc                 C   s   d|d| _ d S )NDES_EDE3_CBC)zx-ms-cipher-namez!x-ms-guest-agent-public-x509-cert)extra_secure_headers)selfcertificater&   r&   r'   __init__B  s   z AzureEndpointHttpClient.__init__Fr   c                 C   s,   | j }|r| j  }|| j t||dS )N)r   )r   copyupdater   r   )r   r   securer   r&   r&   r'   getH  s
   
zAzureEndpointHttpClient.getNr`   c                 C   s0   | j }|d ur| j  }|| t|||dS )N)r`   r   )r   r   r   r   )r   r   r`   extra_headersr   r&   r&   r'   postO  s
   

zAzureEndpointHttpClient.post)FNN)r!   
__module____qualname__r   r   r   UrlResponser   r   bytesr   r&   r&   r&   r'   r   <  s    r   c                   @   s   e Zd ZdZdS )InvalidGoalStateXMLExceptionz9Raised when GoalState XML is invalid or has missing data.N)r!   r   r   __doc__r&   r&   r&   r'   r   Y  s    r   c                	   @   s:   e Zd Z	ddeeef dededdfddZd	d
 Z	dS )	GoalStateTunparsed_xmlazure_endpoint_clientneed_certificater   Nc              
   C   s   || _ zt|| _W n tjy" } z
td| tjd  d}~ww | d| _	| d| _
| d| _dD ]}t| |du rOd| }t|tjd t|q7d| _| d	}|dur|rtjd
dtd | j j|ddj| _| jdu rztdW d   dS 1 sw   Y  dS dS dS )ah  Parses 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: %srU   Nz./Container/ContainerIdz4./Container/RoleInstanceList/RoleInstance/InstanceIdz./Incarnation)container_idinstance_idincarnationzMissing %s in GoalState XMLzD./Container/RoleInstanceList/RoleInstance/Configuration/Certificateszget-certificates-xmlzget certificates xmlr   T)r   z/Azure endpoint returned empty certificates xml.)r   r   
fromstringroot
ParseErrorr]   r5   rs   _text_from_xpathr   r   r   getattrr   certificates_xmlr   r    r"   r   contents)r   r   r   r   rC   attrrW   r   r&   r&   r'   r   ^  sX   
"zGoalState.__init__c                 C   s   | j |}|d ur|jS d S rv   )r   findtext)r   xpathelementr&   r&   r'   r     s   zGoalState._text_from_xpath)T)
r!   r   r   r
   r   r   r   boolr   r   r&   r&   r&   r'   r   ]  s    

7r   c                   @   s   e Zd ZdddZdd Zdd Zedd	 Zejd
d	 Ze	dd Z
ee	dd Ze	dd Ze	dd Ze	dd Ze	dd ZdS )OpenSSLManagerzTransportPrivate.pemzTransportCert.pem)private_keyr   c                 C   s   t  | _d | _|   d S rv   )r   mkdtemptmpdir_certificategenerate_certificater   r&   r&   r'   r     s   
zOpenSSLManager.__init__c                 C   s   t | j d S rv   )r   del_dirr   r   r&   r&   r'   clean_up  s   zOpenSSLManager.clean_upc                 C   s   | j S rv   r   r   r&   r&   r'   r     s   zOpenSSLManager.certificatec                 C   s
   || _ d S rv   r   )r   valuer&   r&   r'   r     s   
c                 C   s   t d | jd urt d d S t| j: tddddddd	d
ddd| jd d| jd g d}t| jd D ]}d|vrE|| 7 }q9|| _W d    n1 sSw   Y  t d d S )Nz7Generating certificate for communication with fabric...zCertificate already generated.opensslreqz-x509z-nodesz-subjz/CN=LinuxTransportz-days32768z-newkeyzrsa:2048z-keyoutr   z-outr    CERTIFICATEzNew certificate generated.)	r5   r6   r   r~   r   r   certificate_namesopenrstrip)r   r   liner&   r&   r'   r     s<   


z#OpenSSLManager.generate_certificatec                 C   s"   ddd| g}t j ||d\}}|S )Nr   x509z-nooutr`   )r   )actioncertcmdresultrE   r&   r&   r'   _run_x509_action  s   zOpenSSLManager._run_x509_actionc                 C   s*   |  d|}g d}tj||d\}}|S )Nz-pubkey)z
ssh-keygenz-iz-mPKCS8z-fz
/dev/stdinr   )r   r   )r   r   pub_key
keygen_cmdssh_keyrE   r&   r&   r'   _get_ssh_key_from_cert  s   z%OpenSSLManager._get_ssh_key_from_certc                 C   s6   |  d|}|d}||d d d}d|S )a  openssl 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/   r0   :r   )r   r   r:   join)r   r   raw_fpeqoctetsr&   r&   r'   _get_fingerprint_from_cert  s   	

z)OpenSSLManager._get_fingerprint_from_certc                 C   s   t |d}|j}ddddd|dg}t| j tjdjdi | j	d	d

|d\}}W d   |S 1 s;w   Y  |S )zDecrypt the certificates XML document using the our private key;
        return the list of certs and private keys contained in the doc.
        z.//Datas   MIME-Version: 1.0s<   Content-Disposition: attachment; filename="Certificates.p7m"s?   Content-Type: application/x-pkcs7-mime; name="Certificates.p7m"s!   Content-Transfer-Encoding: base64    r   zuopenssl cms -decrypt -in /dev/stdin -inkey {private_key} -recip {certificate} | openssl pkcs12 -nodes -password pass:T   
)shellr`   Nr&   )r   r   r   r   r   r~   r   r   r   r   r   )r   r   tagcertificates_contentlinesrD   rE   r&   r&   r'   _decrypt_certs_from_xml  s2   

z&OpenSSLManager._decrypt_certs_from_xmlc           	      C   sv   |  |}g }i }| D ]+}|| td|rg }qtd|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[-]+$
)r   
splitlinesappendrematchr   r   r   )	r   r   rD   currentkeysr   r   r   fingerprintr&   r&   r'   parse_certificates	  s   




z!OpenSSLManager.parse_certificatesN)r!   r   r   r   r   r   propertyr   setterr)   r   staticmethodr   r   r   r   r   r&   r&   r&   r'   r     s.    





r   c                   @   s   e Zd ZedZedZdZdZdZ	dZ
deded	ed
dfddZedddZeded
dfddZ		ddedededed
ef
ddZeded
dfddZdS )GoalStateHealthReportera          <?xml version="1.0" encoding="utf-8"?>
        <Health xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:xsd="http://www.w3.org/2001/XMLSchema">
          <GoalStateIncarnation>{incarnation}</GoalStateIncarnation>
          <Container>
            <ContainerId>{container_id}</ContainerId>
            <RoleInstanceList>
              <Role>
                <InstanceId>{instance_id}</InstanceId>
                <Health>
                  <State>{health_status}</State>
                  {health_detail_subsection}
                </Health>
              </Role>
            </RoleInstanceList>
          </Container>
        </Health>
        z        <Details>
          <SubStatus>{health_substatus}</SubStatus>
          <Description>{health_description}</Description>
        </Details>
        ReadyNotReadyProvisioningFailedi   
goal_stater   endpointr   Nc                 C   s   || _ || _|| _dS )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   r   r   r   r&   r&   r'   r   D  s   
z GoalStateHealthReporter.__init__c              
   C   sv   | j | jj| jj| jj| jd}td z| j|d W n t	y3 } z
t
d| tjd  d }~ww td d S )N)r   r   r   statusz Reporting ready to Azure fabric.documentz#exception while reporting ready: %srU   zReported ready to Azure fabric.)build_reportr  r   r   r   PROVISIONING_SUCCESS_STATUSr5   r6   _post_health_reportrq   r]   errorrS   )r   r  rC   r&   r&   r'   send_ready_signalY  s$   
z)GoalStateHealthReporter.send_ready_signalr   c              
   C   sv   | j | jj| jj| jj| j| j|d}z| j|d W n ty3 } zd| }t	|t
jd  d }~ww t
d d S )N)r   r   r   r  	substatusr   r  z%exception while reporting failure: %srU   z!Reported failure to Azure fabric.)r  r  r   r   r   PROVISIONING_NOT_READY_STATUSPROVISIONING_FAILURE_SUBSTATUSr	  rq   r]   r5   r
  rs   )r   r   r  rC   rW   r&   r&   r'   send_failure_signalm  s"   z+GoalStateHealthReporter.send_failure_signalr   r   r   r  c           	      C   sb   d}|d ur| j jt|t|d | j d}| jjtt|t|t|t||d}|dS )Nr   )health_substatushealth_description)r   r   r   health_statushealth_detail_subsectionr   )%HEALTH_DETAIL_SUBSECTION_XML_TEMPLATEr   r   "HEALTH_REPORT_DESCRIPTION_TRIM_LENHEALTH_REPORT_XML_TEMPLATEr   r   )	r   r   r   r   r  r  r   health_detailhealth_reportr&   r&   r'   r    s    	

z$GoalStateHealthReporter.build_reportr  c                 C   sB   t d td d| j}| jj||ddid td d S )Nr   z&Sending health report to Azure fabric.zhttp://{}/machine?comp=healthzContent-Typeztext/xml; charset=utf-8)r`   r   z/Successfully sent health report to Azure fabric)r   r5   r6   r   r  r  r   )r   r  r   r&   r&   r'   r	    s   
z+GoalStateHealthReporter._post_health_report)r   Nr   )r!   r   r   r   r   r  r  r  r  r  r  r   r   r   r   r)   r  r  r   r  r	  r&   r&   r&   r'   r     sN    	

r   c                   @   s   e Zd ZdefddZdd Zedejddfd	d
Z	e	ddejde
ee  fddZededdfddZededefddZedefddZedeeef dedefddZedededefddZedededefddZdS ) WALinuxAgentShimr   c                 C   s   || _ d | _d | _d S rv   )r   openssl_managerr   )r   r   r&   r&   r'   r     s   
zWALinuxAgentShim.__init__c                 C   s   | j d ur| j   d S d S rv   )r  r   r   r&   r&   r'   r     s   
zWALinuxAgentShim.clean_updistror   Nc              
   C   sT   t d z|| W d S  ty) } ztd| t jd W Y d }~d S d }~ww )NzEjecting the provisioning isoz(Failed ejecting the provisioning iso: %srU   )r5   r6   eject_mediarq   r]   r
  )r   iso_devr  rC   r&   r&   r'   	eject_iso  s   
zWALinuxAgentShim.eject_isoc                 C   s   d}| j du r|durt | _ | j j}| jdu rt|| _| j|dud}d}|dur1| ||}t|| j| j}|durD| j	||d |
  |S )a  Gets 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   )r  )r  r   r   r   r   _fetch_goal_state_from_azure_get_user_pubkeysr   r   r  r  )r   r  pubkey_infor  http_client_certificater   ssh_keyshealth_reporterr&   r&   r'   "register_with_azure_and_fetch_data  s*   

z3WALinuxAgentShim.register_with_azure_and_fetch_datar   c                 C   s@   | j du r
td| _ | jdd}t|| j | j}|j|d dS )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   )r   r   r   r   r   r  )r   r   r   r%  r&   r&   r'   &register_with_azure_and_report_failure  s   


z7WALinuxAgentShim.register_with_azure_and_report_failurer   c                 C   s   |   }| ||S )a   Fetches 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   r   unparsed_goal_state_xmlr&   r&   r'   r     s   
z-WALinuxAgentShim._fetch_goal_state_from_azurec              
   C   s   t d d| j}z tjddtd | j|}W d   n1 s%w   Y  W n t	yA } z
t
d| t jd  d}~ww t d	 |jS )
zFetches the GoalState XML from the Azure endpoint and returns
        the XML as a string.

        @return: GoalState XML string
        zRegistering with Azure...z!http://{}/machine/?comp=goalstatezgoalstate-retrievalzretrieve goalstater   Nz9failed to register with Azure and fetch GoalState XML: %srU   z#Successfully fetched GoalState XML.)r5   rS   r   r   r   r    r"   r   r   rq   r]   rs   r6   r   )r   r   r   rC   r&   r&   r'   r)    s.   

z3WALinuxAgentShim._get_raw_goal_state_xml_from_azurer+  c              
   C   st   z	t || j|}W n ty } z
td| tjd  d}~ww dd|j d|j d|j	 g}t|tj
d |S )a  Parses 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: %srU   Nz, zGoalState XML container id: %szGoalState XML instance id: %szGoalState XML incarnation: %s)r   r   rq   r]   r5   rs   r   r   r   r   r6   )r   r+  r   r   rC   rW   r&   r&   r'   r*  0  s,   z*WALinuxAgentShim._parse_raw_goal_state_xmlr   r"  c                 C   sH   g }|j dur"|dur"| jdur"td | j|j }| ||}|S )a  Gets 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.)r   r  r5   r6   r   _filter_pubkeys)r   r   r"  r$  keys_by_fingerprintr&   r&   r'   r!  R  s   


z"WALinuxAgentShim._get_user_pubkeysr-  c                 C   s|   g }|D ]7}d|v r|d r| |d  qd|v r5|d r5|d }|| v r.| | |  qtd| qtd| q|S )a8  Filter 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.
        r   r   zIovf-env.xml specified PublicKey fingerprint %s not found in goalstate XMLzFovf-env.xml specified PublicKey with neither value nor fingerprint: %s)r   r5   rs   )r-  r"  r   pubkeyr   r&   r&   r'   r,  |  s"   z WALinuxAgentShim._filter_pubkeysr   )r!   r   r   r   r   r   r)   r   Distror  r   r   r&  r(  r   r   r   r   r)  r
   r*  listr!  r   dictr,  r&   r&   r&   r'   r    sP    

%
!)r  r   r  r"  r  c                 C   s0   t | d}z|j|||dW |  S |  w )Nr   )r  r"  r  )r  r&  r   )r   r  r"  r  shimr&   r&   r'   get_metadata_from_fabric  s   
r4  r
  zerrors.ReportableErrorc                 C   s8   t | d}| }z|j|d W |  d S |  w )Nr2  r'  )r  as_encoded_reportr(  r   )r   r
  r3  r   r&   r&   r'   report_failure_to_fabric  s
   
r6  c                 C   s(   t d|  tjd t d| tjd d S )Nzdhclient output stream: %srU   zdhclient error stream: %s)r]   r5   r6   )rD   errr&   r&   r'   dhcp_log_cb  s   


r8  c                   @   s   e Zd ZdS )NonAzureDataSourceN)r!   r   r   r&   r&   r&   r'   r9    s    r9  c                   @   s   e Zd ZdddZdddddddddd	dee dee d	ee d
ee dee deee	  dedee deddfddZ
defddZededd fddZ	d(dededefddZ			d)dedededefd d!Zd"d# Zd$d% Zd&d' ZdS )*	OvfEnvXmlz)http://schemas.dmtf.org/ovf/environment/1z)http://schemas.microsoft.com/windowsazure)ovfwaNF	r   passwordr   custom_datadisable_ssh_password_authpublic_keyspreprovisioned_vmpreprovisioned_vm_typeprovision_guest_proxy_agentr   r>  r   r?  r@  rA  rB  rC  rD  r   c       	   
      C   s>   || _ || _|| _|| _|| _|pg | _|| _|| _|	| _d S rv   r=  )
r   r   r>  r   r?  r@  rA  rB  rC  rD  r&   r&   r'   r     s   

zOvfEnvXml.__init__c                 C   s   | j |j kS rv   )__dict__)r   otherr&   r&   r'   __eq__  s   zOvfEnvXml.__eq__ovf_env_xmlc              
   C   sl   zt |}W n t jy } ztj|d|d}~ww |d| js'tdt }|	| |
| |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)r   r   r   r   "ReportableErrorOvfParsingExceptionr   
NAMESPACESr9  r:  &_parse_linux_configuration_set_section _parse_platform_settings_section)clsrH  r   rC   instancer&   r&   r'   
parse_text  s   

zOvfEnvXml.parse_textr<  r   required	namespacec                 C   sp   | d||f tj}t|dkr#d| }t| |r!t|d S t|dkr4td|t|f |d S )Nz./%s:%sr   missing configuration for %rr0   *multiple configuration matches for %r (%d))findallr:  rK  lenr5   r6   r   !ReportableErrorOvfInvalidMetadata)r   noder   rQ  rR  matchesrW   r&   r&   r'   _find  s    


zOvfEnvXml._finddecode_base64
parse_boolc           
      C   s   | d| tj}t|dkr!d| }t| |rt||S t|dkr2td|t|f |d j}	|	d u r=|}	|rM|	d urMt	
d|	 }	|rTt|	}	|	S )Nz./wa:r   rS  r0   rT  r   )rU  r:  rK  rV  r5   r6   r   rW  r   rc   	b64decoder   r:   r   translate_bool)
r   rX  r   rQ  r[  r\  defaultrY  rW   r   r&   r&   r'   _parse_property  s*   	




zOvfEnvXml._parse_propertyc                 C   s   | j |ddd}| j |ddd}| j|dddd| _| j|ddd| _| j|d	dd| _| j|d
dd| _| j|dddd| _| | d S )NProvisioningSectionTrQ  !LinuxProvisioningConfigurationSet
CustomDataF)r[  rQ  UserNameUserPasswordHostName DisableSshPasswordAuthentication)r\  rQ  )rZ  r`  r?  r   r>  r   r@  _parse_ssh_section)r   r   provisioning_section
config_setr&   r&   r'   rL  =  s<   z0OvfEnvXml._parse_linux_configuration_set_sectionc                 C   sb   | j |ddd}| j |ddd}| j|ddddd| _| j|ddd| _| j|d	dddd| _d S )
NPlatformSettingsSectionTrb  PlatformSettingsPreprovisionedVmF)r\  r_  rQ  PreprovisionedVMTypeProvisionGuestProxyAgent)rZ  r`  rB  rC  rD  )r   r   platform_settings_sectionplatform_settingsr&   r&   r'   rM  _  s2   z*OvfEnvXml._parse_platform_settings_sectionc           	      C   s   g | _ | j|ddd}|d u rd S | j|ddd}|d u rd S |dtjD ]'}| j|ddd}| j|ddd}| j|dd	dd
}|||d}| j | q&d S )NSSHFrb  
PublicKeysz./wa:PublicKeyFingerprintPathValuer   )r_  rQ  )r   rz   r   )rA  rZ  rU  r:  rK  r`  r   )	r   rk  ssh_sectionpublic_keys_section
public_keyr   rz   r   r   r&   r&   r'   ri  {  s2   zOvfEnvXml._parse_ssh_section)r<  )FFN)r!   r   r   rK  r   r   r   r   r   r1  r   rG  classmethodrP  rZ  r`  rL  rM  ri  r&   r&   r&   r'   r:    sx    
	



$"r:  r   )Hrc   ri   loggingrw   r   r   re   
contextlibr   r   r   r   typingr   r   r   r	   r
   	xml.etreer   xml.sax.saxutilsr   	cloudinitr   r   r   r   r   r   cloudinit.reportingr   cloudinit.sources.azurer   	getLoggerr!   r5   DEFAULT_WIRESERVER_ENDPOINTr=   rQ   r\   rh   r    r"   r   r)   rJ   rT   r   r<   r]   ro   ru   r~   r1  r   intr   r   r   r   rq   r   r   r   r   r  r/  r4  r6  r8  r9  r:  r&   r&   r&   r'   <module>   s    
"
S



	6
"?   f
		