
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
3
\me              	   @   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Zd dlZd dl	m
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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rd dl&m'Z' ej(e)Z*dZ+dZ,dZ-dZ.dZ/dZ0dZ1e#j2ddddZ3edZ4ede4f ede4f dddZ5e5dd Z6e5dd  Z7dd!e8e#j9d"d#d$Z:d%d& Z;e5e%d' fd(d)Z<e5d*d+ Z=e
d,d- Z>d.d/ Z?e5dd0d1d2e8e@eeA eBeBejCd3d4d5ZDe8e8e8eAd6d7d8ZEG d9d: d:ZFG d;d< d<eGZHG d=d> d>ZIG d?d@ d@ZJG dAdB dBZKG dCdD dDZLe5dTe8eee8  ee8 dEdFdGZMe5e8dHdIdJdKZNdLdM ZOG dNdO dOeGZPG dPdQ dQeGZQG dRdS dSZRdS )U    N)contextmanager)datetime)ENOENT)sleeptime)TYPE_CHECKINGCallableListOptionalTypeVarUnion)ElementTree)escape)distrossubp
temp_utils
url_helperutilversion)events)CFG_BUILTIN)errorsz168.63.129.16zboot-telemetryzsystem-infoZ
diagnosticZ
compressedi  z'/run/cloud-init/log_pushed_to_kvp_indexzazure-dsz initialize reporter for azure dsT)namedescriptionZreporting_enabledT.)funcreturnc                s    fdd}|S )Nc           
      s*   t j j jtd  | |S Q R X d S )N)r   r   parent)r   ReportEventStack__name__azure_ds_reporter)argskwargs)r    /usr/lib/python3.6/azure.pyimpl5   s
    
z)azure_ds_telemetry_reporter.<locals>.implr#   )r   r%   r#   )r   r$   azure_ds_telemetry_reporter4   s    r&   c           2   C   s8  t j stdtjd ytt ttj  } W n, t	k
r` } ztd|W Y dd}~X nX yXt
j
ddddgd	d
\}}d}|rd|kr|jdd }|std| t|d  }W nb t
jk
r } ztd| |W Y dd}~X n2 t	k
r } ztd| |W Y dd}~X nX y`t
j
dddddgd	d
\}}d}|r^d|kr^|jdd }|sltd| t|d  }W nd t
jk
r } ztd| |W Y dd}~X n2 t	k
r } ztd| |W Y dd}~X nX tjtddtj| j d tj|j d tj|j d f tj}tj| |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 timestampNZ	systemctlZshowz-pZUserspaceTimestampMonotonicT)capture=   z8Failed to parse UserspaceTimestampMonotonic from systemdi@B z-Failed to get UserspaceTimestampMonotonic: %sz<Failed to parse UserspaceTimestampMonotonic from systemd: %szcloud-init-localZInactiveExitTimestampMonotonicz;Failed to parse InactiveExitTimestampMonotonic from systemdz0Failed to get InactiveExitTimestampMonotonic: %sz?Failed to parse InactiveExitTimestampMonotonic from systemd: %szboot-telemetryz5kernel_start=%s user_start=%s cloudinit_activation=%sZ)r   Zuses_systemdRuntimeErrorLOGdebugfloatr   r   Zuptime
ValueErrorr   splitZProcessExecutionErrorr   ReportingEventBOOT_EVENT_TYPEr   ZutcfromtimestampZ	isoformatDEFAULT_EVENT_ORIGINreport_event)Zkernel_starteout_ZtsmZ
user_startZcloudinit_activationevtr#   r#   r$   get_boot_telemetry@   sx    


r9   c              C   sb   t j } tjtddtj | d | d | d d | d d | d d | d	 f tj}tj| |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releaseZvariantZdistr   r)      python)	r   Zsystem_infor   r1   SYSTEMINFO_EVENT_TYPEr   Zversion_stringr3   r4   )infor8   r#   r#   r$   get_system_info   s    




r?   )logger_func)msgr   c            C   s6   t |r||  tjtd| tj}tj|dhd |S )zReport a diagnostic eventzdiagnostic messagelog)excluded_handler_types)callabler   r1   DIAGNOSTIC_EVENT_TYPEr3   r4   )rA   r@   r8   r#   r#   r$   report_diagnostic_event   s    rF   c             C   sP   t jtj|}d|jdd}tjt| tj	|tj
}tj|dddhd |S )zReport a compressed eventzgz+b64ascii)encodingdatarB   printZwebhook)rC   )base64Zencodebyteszlibcompressdecoder   r1   COMPRESSED_EVENT_TYPEjsondumpsr3   r4   )Z
event_nameZevent_contentZcompressed_dataZ
event_datar8   r#   r#   r$   report_compressed_event   s    rR   Zdef_log_filec             C   s@  t  }tjd yt| dt}|jdtj t|j t	 |}t
dj|j | |tjd |j|tj td|j  tjtt|j  W dQ R X W n8 tk
r } zt
dt| tjd W Y dd}~X nX tjd	 y$tjd
gddd\}}td
| W n: tk
r: } zt
dt| tjd W Y dd}~X nX dS )az  Push a portion of cloud-init.log file or the whole file to KVP
    based on the file size.
    The first time this function is called after VM boot, It will push the last
    n bytes of the log file such that n < MAX_LOG_TO_KVP_LENGTH
    If called again on the same boot, it continues from where it left off.
    In addition to cloud-init.log, dmesg log will also be collected.z"Dumping cloud-init.log file to KVPrbr   zMDumping last {0} bytes of cloud-init.log file to KVP starting from index: {1})r@   zcloud-init.logNz#Exception when dumping log file: %szDumping dmesg log to KVPZdmesgFT)rN   r'   z$Exception when dumping dmesg log: %s)%get_last_log_byte_pushed_to_kvp_indexr,   r-   openseekosSEEK_ENDmaxtellMAX_LOG_TO_KVP_LENGTHrF   formatSEEK_SETrR   readr   Z
write_fileLOG_PUSHED_TO_KVP_INDEX_FILEstr	Exceptionreprwarningr   )	file_nameZstart_indexfZ
seek_indexZexr6   r7   r#   r#   r$   push_log_to_kvp   s2    	

"


rf   c              C   s   y"t td} t| j S Q R X W n tk
rd } z&|jtkrTtdt| t	j
d W Y d d }~X nn tk
r } ztdt| t	j
d W Y d d }~X n8 tk
r } ztdt| t	j
d W Y d d }~X nX dS )Nrz0Reading LOG_PUSHED_TO_KVP_INDEX_FILE failed: %s.)r@   z2Invalid value in LOG_PUSHED_TO_KVP_INDEX_FILE: %s.z2Failed to get the last log byte pushed to KVP: %s.r   )rU   r_   intr^   IOErrorerrnor   rF   rb   r,   rc   r/   ra   )re   r5   r#   r#   r$   rT      s"    



rT   c             c   s6   t j }t jt jj|  z
d V  W d t j| X d S )N)rW   getcwdchdirpath
expanduser)ZnewdirZprevdirr#   r#   r$   cd  s
    
ro   c             C   s|   | j dd}t|dkrhd}x.|jdD ] }t|dkr@d| }||7 }q(W tjdt|j ddd}n
|jd	}tj|S )
N\    :r)   0z>L   zutf-8)	replacelenr0   structpackrh   encodesocketZ	inet_ntoa)Zfallback_lease_valueZunescaped_valueZ
hex_stringZhex_pairZpacked_bytesr#   r#   r$   get_ip_from_lease_value!  s    
r|         )rI   retry_sleeptimeout_minutes)urlheadersrI   r   r   r   c      	      C   s   |d t   }d}d}x|s|d7 }ytj| ||dd}P W n` tjk
r } zBtd| |||j|jf tjd t  | |ksd	t	|kr W Y dd}~X nX t
| qW 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   Nr)   r}   )r   rI   timeoutzdFailed HTTP request with Azure endpoint %s during attempt %d with exception: %s (code=%r headers=%r))r@   zNetwork is unreachablez@Successful HTTP request with Azure endpoint %s after %d attempts)r}   r   )r   r   ZreadurlZUrlErrorrF   coder   r,   r-   r`   r   )	r   r   rI   r   r   r   Zattemptresponser5   r#   r#   r$   http_with_retries/  s.    
	
r   )usernamehostnamedisableSshPwdr   c             C   s$   t jd}|j| ||d}|j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   zutf-8)textwrapdedentr\   rz   )r   r   r   ZOVF_ENV_TEMPLATEretr#   r#   r$   build_minimal_ovff  s
    r   c               @   sH   e Zd ZdddZdd Zdejddd	Zdee	 ejdddZ
d
S )AzureEndpointHttpClientZWALinuxAgentz
2012-11-30)zx-ms-agent-namezx-ms-versionc             C   s   d|d| _ d S )NZDES_EDE3_CBC)zx-ms-cipher-namez!x-ms-guest-agent-public-x509-cert)extra_secure_headers)selfcertificater#   r#   r$   __init__  s    z AzureEndpointHttpClient.__init__F)r   c             C   s,   | j }|r | j j }|j| j t||dS )N)r   )r   copyupdater   r   )r   r   securer   r#   r#   r$   get  s
    
zAzureEndpointHttpClient.getN)rI   r   c             C   s0   | j }|d k	r"| j j }|j| t|||dS )N)rI   r   )r   r   r   r   )r   r   rI   extra_headersr   r#   r#   r$   post  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     s   r   c               @   s2   e Zd Zdeeef eeddddZdd Z	dS )		GoalStateTN)unparsed_xmlazure_endpoint_clientneed_certificater   c             C   s  || _ ytj|| _W n8 tjk
rN } ztd| tjd  W Y dd}~X nX | jd| _	| jd| _
| jd| _x8dD ]0}t| |dkrzd
| }t|tjd t|qzW d| _| jd}|dk	o|rtjddtd. | j j|ddj| _| jdkrtdW dQ R X 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: %s)r@   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 xml)r   r   r   T)r   z/Azure endpoint returned empty certificates xml.)r   r   r   )r   r   
fromstringroot
ParseErrorrF   r,   rc   _text_from_xpathr   r   r   getattrr   certificates_xmlr   r   r    r   contents)r   r   r   r   r5   attrrA   r   r#   r#   r$   r     s<    


zGoalState.__init__c             C   s   | j j|}|d k	r|jS d S )N)r   findtext)r   Z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   2r   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 j | _d | _| j  d S )N)r   Zmkdtemptmpdir_certificategenerate_certificate)r   r#   r#   r$   r     s    
zOpenSSLManager.__init__c             C   s   t j| j d S )N)r   Zdel_dirr   )r   r#   r#   r$   clean_up  s    zOpenSSLManager.clean_upc             C   s   | j S )N)r   )r   r#   r#   r$   r     s    zOpenSSLManager.certificatec             C   s
   || _ d S )N)r   )r   valuer#   r#   r$   r     s    c             C   s   t jd | jd k	r"t jd d S t| jn tjddddddd	d
ddd| jd d| jd g d}x*t| jd D ]}d|krt||j 7 }qtW || _W d Q R X t jd d S )Nz7Generating certificate for communication with fabric...zCertificate already generated.opensslZreqz-x509z-nodesz-subjz/CN=LinuxTransportz-daysZ32768z-newkeyzrsa:2048z-keyoutr   z-outr   rq   ZCERTIFICATEzNew certificate generated.)	r,   r-   r   ro   r   r   certificate_namesrU   rstrip)r   r   liner#   r#   r$   r      s4    


z#OpenSSLManager.generate_certificatec             C   s"   ddd| g}t j ||d\}}|S )Nr   Zx509z-noout)rI   )r   )actionZcertcmdresultr7   r#   r#   r$   _run_x509_action   s    zOpenSSLManager._run_x509_actionc             C   s2   | j d|}ddddddg}tj||d\}}|S )	Nz-pubkeyz
ssh-keygenz-iz-mZPKCS8z-fz
/dev/stdin)rI   )r   r   )r   r   Zpub_keyZ
keygen_cmdssh_keyr7   r#   r#   r$   _get_ssh_key_from_cert'  s    z%OpenSSLManager._get_ssh_key_from_certc             C   s6   | j d|}|jd}||d d jd}dj|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
'

        Azure control plane passes that fingerprint as so:
        '073E19D14D1C799224C6A0FD8DDAB6A8BF27D473'
        z-fingerprintr(   r)   rs   rq   )r   r   r0   join)r   r   Zraw_fpeqZoctetsr#   r#   r$   _get_fingerprint_from_cert.  s    	
z)OpenSSLManager._get_fingerprint_from_certc             C   sj   t j|jd}|j}ddddd|jdg}t| j* tjdjf | j	d	d
j
|d\}}W dQ R X |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    zutf-8zuopenssl cms -decrypt -in /dev/stdin -inkey {private_key} -recip {certificate} | openssl pkcs12 -nodes -password pass:T   
)shellrI   N)r   r   r   r   rz   ro   r   r   r\   r   r   )r   r   tagZcertificates_contentlinesr6   r7   r#   r#   r$   _decrypt_certs_from_xml<  s    z&OpenSSLManager._decrypt_certs_from_xmlc       	      C   sz   | j |}g }i }xb|j D ]V}|j| tjd|r<g }qtjd|rdj|}| j|}| j|}|||< g }qW |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   r6   Zcurrentkeysr   r   r   fingerprintr#   r#   r$   parse_certificatesU  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jdZejdZdZdZdZ	dZ
eeeddd	d
ZeddddZeeddddZdeeeeedddZeedd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>
        ZReadyZNotReadyZProvisioningFailedi   N)
goal_stater   endpointr   c             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     s    z GoalStateHealthReporter.__init__)r   c             C   s   | j | jj| jj| jj| jd}tjd y| j|d W n6 t	k
rp } zt
d| tjd  W Y d d }~X nX tjd d S )N)r   r   r   statusz Reporting ready to Azure fabric.)documentz#exception while reporting ready: %s)r@   zReported ready to Azure fabric.)build_reportr   r   r   r   PROVISIONING_SUCCESS_STATUSr,   r-   _post_health_reportra   rF   errorr>   )r   r   r5   r#   r#   r$   send_ready_signal  s    


z)GoalStateHealthReporter.send_ready_signal)r   r   c             C   s   | j | jj| jj| jj| j| j|d}y| j|d W n: tk
rp } zd| }t	|t
jd  W Y d d }~X nX t
jd d S )N)r   r   r   r   	substatusr   )r   z%exception while reporting failure: %s)r@   z!Reported failure to Azure fabric.)r   r   r   r   r   PROVISIONING_NOT_READY_STATUSPROVISIONING_FAILURE_SUBSTATUSr   ra   rF   r,   r   rc   )r   r   r   r5   rA   r#   r#   r$   send_failure_signal  s    z+GoalStateHealthReporter.send_failure_signal)r   r   r   r   r   c       	      C   sb   d}|d k	r.| j jt|t|d | j d}| jjtt|t|t|t||d}|jdS )Nrq   )Zhealth_substatusZhealth_description)r   r   r   Zhealth_statusZhealth_detail_subsectionzutf-8)%HEALTH_DETAIL_SUBSECTION_XML_TEMPLATEr\   r   "HEALTH_REPORT_DESCRIPTION_TRIM_LENHEALTH_REPORT_XML_TEMPLATEr`   rz   )	r   r   r   r   r   r   r   Zhealth_detailZhealth_reportr#   r#   r$   r     s    	
z$GoalStateHealthReporter.build_report)r   r   c             C   sH   t   td tjd dj| j}| jj||ddid tjd d S )Nr   z&Sending health report to Azure fabric.zhttp://{}/machine?comp=healthzContent-Typeztext/xml; charset=utf-8)rI   r   z/Successfully sent health report to Azure fabric)rf   r   r,   r-   r\   r   r   r   )r   r   r   r#   r#   r$   r     s    
z+GoalStateHealthReporter._post_health_report)NN)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   j  s*    
r   c               @   s   e Zd ZedddZdd Zedddd	Zedee	e  dd
dZ
eeddddZeeedddZeedddZeeeef eedddZeeeedddZeeeedddZdS )WALinuxAgentShim)r   c             C   s   || _ d | _d | _d S )N)r   openssl_managerr   )r   r   r#   r#   r$   r     s    zWALinuxAgentShim.__init__c             C   s   | j d k	r| j j  d S )N)r   r   )r   r#   r#   r$   r     s    
zWALinuxAgentShim.clean_upN)r   c             C   sV   yt jd tjd|g W n4 tk
rP } ztd| t jd W Y d d }~X nX d S )NzEjecting the provisioning isoZejectz(Failed ejecting the provisioning iso: %s)r@   )r,   r-   r   ra   rF   r   )r   iso_devr5   r#   r#   r$   	eject_iso  s    
zWALinuxAgentShim.eject_isoc             C   s   d}| j dkr&|dk	r&t | _ | j j}| jdkr:t|| _| j|dk	d}d}|dk	rb| j||}t|| j| j}|dk	r| j	| |j
  |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   _fetch_goal_state_from_azure_get_user_pubkeysr   r   r   r   )r   pubkey_infor   Zhttp_client_certificater   ssh_keyshealth_reporterr#   r#   r$   "register_with_azure_and_fetch_data   s$    

z3WALinuxAgentShim.register_with_azure_and_fetch_data)r   r   c             C   s@   | j dk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.
        NF)r   )r   )r   r   r   r   r   r   )r   r   r   r   r#   r#   r$   &register_with_azure_and_report_failureF  s    

z7WALinuxAgentShim.register_with_azure_and_report_failure)r   r   c             C   s   | j  }| j||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   U  s    
z-WALinuxAgentShim._fetch_goal_state_from_azurec             C   s   t jd dj| j}y,tjddtd | jj|}W dQ R X W n6 t	k
rx } zt
d| t jd  W Y dd}~X nX t j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 goalstate)r   r   r   Nz9failed to register with Azure and fetch GoalState XML: %s)r@   z#Successfully fetched GoalState XML.)r,   r>   r\   r   r   r   r    r   r   ra   rF   rc   r-   r   )r   r   r   r5   r#   r#   r$   r   d  s     



z3WALinuxAgentShim._get_raw_goal_state_xml_from_azure)r   r   r   c             C   s~   yt || j|}W n6 tk
rH } ztd| tjd  W Y dd}~X nX dj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: %s)r@   Nz, zGoalState XML container id: %szGoalState XML instance id: %szGoalState XML incarnation: %s)r   r   ra   rF   r,   rc   r   r   r   r   r-   )r   r   r   r   r5   rA   r#   r#   r$   r     s     

z*WALinuxAgentShim._parse_raw_goal_state_xml)r   r   r   c             C   sH   g }|j dk	rD|dk	rD| jdk	rDtjd | jj|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   r,   r-   r   _filter_pubkeys)r   r   r   r   keys_by_fingerprintr#   r#   r$   r     s    


z"WALinuxAgentShim._get_user_pubkeys)r   r   r   c             C   s   g }xv|D ]n}d|kr.|d r.|j |d  q
d|krl|d rl|d }|| kr^|j | |  qxtjd| q
tjd| q
W |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   r,   rc   )r   r   r   Zpubkeyr   r#   r#   r$   r     s    

z WALinuxAgentShim._filter_pubkeys)NN)r   r   r   r`   r   r   r&   r   r
   r	   r   r   r   r   r   r   r   r   r   listr   r   dictr   r#   r#   r#   r$   r     s.   
#
'r   )r   r   r   c          
   C   s(   t | d}z|j||dS |j  X d S )N)r   )r   r   )r   r   r   )r   r   r   shimr#   r#   r$   get_metadata_from_fabric  s
    

r   zerrors.ReportableError)r   r   c          
   C   s2   t | d}|j }z|j|d W d |j  X d S )N)r   )r   )r   Zas_encoded_reportr   r   )r   r   r   r   r#   r#   r$   report_failure_to_fabric  s
    
r  c             C   s(   t d|  tjd t d| tjd d S )Nzdhclient output stream: %s)r@   zdhclient error stream: %s)rF   r,   r-   )r6   errr#   r#   r$   dhcp_log_cb	  s    r  c               @   s   e Zd ZdS )BrokenAzureDataSourceN)r   r   r   r#   r#   r#   r$   r    s   r  c               @   s   e Zd ZdS )NonAzureDataSourceN)r   r   r   r#   r#   r#   r$   r    s   r  c               @   s   e Zd ZdddZdddddddddee ee ee ee ee eee	  eee dd	dd	Z
ed
ddZeed dddZdeeedddZdeeeed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)ZovfwaNF)r   passwordr   custom_datadisable_ssh_password_authpublic_keyspreprovisioned_vmpreprovisioned_vm_type)	r   r  r   r	  r
  r  r  r  r   c      	      C   s8   || _ || _|| _|| _|| _|p$g | _|| _|| _d S )N)r   r  r   r	  r
  r  r  r  )	r   r   r  r   r	  r
  r  r  r  r#   r#   r$   r      s    
zOvfEnvXml.__init__)r   c             C   s   | j |j kS )N)__dict__)r   otherr#   r#   r$   __eq__5  s    zOvfEnvXml.__eq__)ovf_env_xmlr   c             C   sz   yt j|}W n6 t jk
rD } zd| }t||W Y dd}~X nX |jd| js\tdt }|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.
        zInvalid ovf-env.xml: %sNz./wa:ProvisioningSectionz=Ignoring non-Azure ovf-env.xml: ProvisioningSection not found)
r   r   r   r  r   
NAMESPACESr  r  &_parse_linux_configuration_set_section _parse_platform_settings_section)clsr  r   r5   Z	error_strinstancer#   r#   r$   
parse_text8  s    

zOvfEnvXml.parse_textr  )r   required	namespacec             C   sl   |j d||f tj}t|dkrDd| }tj| |r@t|d S t|dkrdtd|t|f |d S )Nz./%s:%sr   z#No ovf-env.xml configuration for %rr)   z:Multiple configuration matches in ovf-exml.xml for %r (%d))findallr  r  rw   r,   r-   r  )r   noder   r  r  matchesrA   r#   r#   r$   _findQ  s    
zOvfEnvXml._find)r   r  decode_base64
parse_boolc       
      C   s   |j d| tj}t|dkr@d| }tj| |r<t||S t|dkr`td|t|f |d j}	|	d krv|}	|r|	d k	rtj	dj
|	j }	|rtj|	}	|	S )Nz./wa:r   z#No ovf-env.xml configuration for %rr)   z:Multiple configuration matches in ovf-exml.xml for %r (%d)rq   )r  r  r  rw   r,   r-   r  r   rK   Z	b64decoder   r0   r   Ztranslate_bool)
r   r  r   r  r  r  defaultr  rA   r   r#   r#   r$   _parse_propertyi  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| _| j| d S )NZProvisioningSectionT)r  Z!LinuxProvisioningConfigurationSetZ
CustomDataF)r  r  ZUserNameZUserPasswordZHostNameZ DisableSshPasswordAuthentication)r  r  )r  r!  r	  r   r  r   r
  _parse_ssh_section)r   r   Zprovisioning_section
config_setr#   r#   r$   r    s.    

z0OvfEnvXml._parse_linux_configuration_set_sectionc             C   sL   | j |ddd}| j |ddd}| j|ddddd| _| j|ddd| _d S )	NZPlatformSettingsSectionT)r  ZPlatformSettingsZPreprovisionedVmF)r  r   r  ZPreprovisionedVMType)r  r!  r  r  )r   r   Zplatform_settings_sectionZplatform_settingsr#   r#   r$   r    s    
z*OvfEnvXml._parse_platform_settings_sectionc       	      C   s   g | _ | j|ddd}|d kr"d S | j|ddd}|d kr>d S x`|jdtjD ]N}| j|ddd}| j|ddd}| j|dd	dd
}|||d}| j j| qNW d S )NZSSHF)r  Z
PublicKeysz./wa:PublicKeyZFingerprintZPathZValuerq   )r   r  )r   rm   r   )r  r  r  r  r  r!  r   )	r   r#  Zssh_sectionZpublic_keys_sectionZ
public_keyr   rm   r   r   r#   r#   r$   r"    s&    zOvfEnvXml._parse_ssh_section)r  )FFN)r   r   r   r  r
   r`   r   r   r	   r   r   r  classmethodr  r  r!  r  r  r"  r#   r#   r#   r$   r    s*   6
  "r  )NN)SrK   rP   ZloggingrW   r   r{   rx   r   rL   
contextlibr   r   rj   r   r   r   Ztypingr   r   r	   r
   r   r   Z	xml.etreer   Zxml.sax.saxutilsr   Z	cloudinitr   r   r   r   r   r   Zcloudinit.reportingr   Zcloudinit.settingsr   Zcloudinit.sources.azurer   Z	getLoggerr   r,   ZDEFAULT_WIRESERVER_ENDPOINTr2   r=   rE   rO   r[   r_   r   r    r   r&   r9   r?   r`   r1   rF   rR   rf   rT   ro   r|   r   r   rh   r   r   r   r   ra   r   r   r   r   r   r   r  r  r  r  r  r#   r#   r#   r$   <module>   s     
 T(
0 ?  " f "		