
-P`/_                @   s  d  d l  Z  d  d l Z d  d l Z d  d l m 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 j j Z d  d l m Z d  d l m Z d  d l m Z d  d	 l m Z d  d
 l m Z d  d l m Z d  d l m Z d  d l m Z d  d l m Z d  d l m  Z  d  d l! 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. m/ Z/ m0 Z0 m1 Z1 m2 Z2 m3 Z3 m4 Z4 e j5 e6  Z7 d Z8 d d i Z9 d d d g Z: d Z; d d d g Z< d d d g Z= d Z> d  Z? d! Z@ d" ZA d# ZB d$ ZC d% ZD d& ZE d' ZF d( ZG d) ZH d* ZI d+ ZJ d, ZK Gd- d.   d. e  ZL d/ ZM d0 d1 d2 d3 g ZN d4 d5 g ZO d6 d7   ZP d8 d9   ZQ d: d;   ZR d d< d=  ZS d> d?   ZT d@ dA   ZU dB dC   ZV dD dE   ZW e% jX   rpdF Z? dG Z@ dH ZA eW dI  ZY eY d k	 r]e7 jZ dJ  dK eY Z> n e7 jZ dL  d ZM dM e; dN eG dO dP dQ dR e? dS dP dT dU dV dW i dX dY e> i dZ e@ d[ d\ i Z[ d] dY d^ d_ d` da g db dP i i dc dd eA de df i g i Z\ dg e8 g Z] dh Z^ di Z_ dj Z` dW dk dl  Za dW dm dO  Zb e+ e jc dW dn do    Zd Gdp dq   dq e je  Zf dr ds dt  Zg e+ du dv    Zh e+ dw dx    Zi e+ e> d\ d\ dy dz   Zj e+ d{ d|    Zk e+ d d} d~   Zl e+ d d    Zm e+ d d d   Zn e+ d d    Zo d d   Zp e+ d d    Zq e+ d d    Zr e+ d d    Zs e+ d d    Zt e+ d d    Zu d d d  Zv e+ d d    Zw e+ eM d d   Zx e+ d d    Zy e+ d d    Zz e+ e{ d d d     Z| e+ e{ d d d     Z} e+ e{ d d d     Z~ e+ eL j eJ d d   Z e+ eL j eJ d d   Z e+ d d d   Z d d   Z Gd d   d e  Z Gd d   d e  Z ef Z ef e j f f g Z d d   Z d S)    N)partial)time)sleep)minidom)Enum)dmi)log)net)	EventType)device_driver)EphemeralDHCPv4)sources)netlink)subp)UrlErrorreadurlretry_on_url_exc)util)events)+DEFAULT_REPORT_FAILURE_USER_VISIBLE_MESSAGEazure_ds_reporterazure_ds_telemetry_reporterget_metadata_from_fabricget_boot_telemetryget_system_inforeport_diagnostic_eventEphemeralDHCPv4WithReportingis_byte_swappeddhcp_log_cbpush_log_to_kvpreport_failure_to_fabricAzurezinstance-idziid-AZURE-NODEserviceZwalinuxagentstartZ__builtin__shz-xcz>i=$interface; x=0; ifdown $i || x=$?; ifup $i || x=$?; exit $xzLi=$interface; x=0; ifconfig down $i || x=$?; ifconfig up $i || x=$?; exit $xz/dev/disk/cloud/azure_resourceZeth0z"/var/lib/dhcp/dhclient.eth0.leasesZext4z 7783-7084-3265-9085-8269-3286-77z/var/lib/cloud/data/poll_imdsz'/var/lib/cloud/data/wait_for_nic_attachz /var/lib/cloud/data/nic_detachedz"/var/lib/cloud/data/reported_readyz/var/lib/waagent   zhttp://169.254.169.254/metadataz
2019-06-01z
2020-09-01c               @   s=   e  Z d  Z d j e  Z d j e  Z d j e  Z d S)metadata_typez{}/instancez{}/instance/networkz{}/reprovisiondataN)__name__
__module____qualname__formatIMDS_URLcomputenetworkreprovisiondata r/   r/   C/usr/lib/python3/dist-packages/cloudinit/sources/DataSourceAzure.pyr&   V   s   r&   z/sys/firmware/acpi/tables/OEM0z"/etc/netplan/90-hotplug-azure.yamlz /usr/local/sbin/ephemeral_eth.shz+/etc/udev/rules.d/10-net-device-added.rulesz#/run/network/interfaces.ephemeral.dZ	mlx4_coreZ	mlx5_corec             C   s   x |  j    D] } t j d |  r | j   } t |  d k r | d j d  } t |  d k r | d d k r | d j |  r | d j d  } | d Sq Wd	 S)
z
    dev.storvsc.1.%pnpinfo:
        classid=32412632-86cb-44a2-9b5c-50d1417354f5
        deviceid=00000000-0001-8899-0000-000000000000
    Zpnpinfo   r%   =r   deviceid   .N)
splitlinesresearchsplitlen
startswith)
sysctl_outr3   lineZfieldscolumnscompsr/   r/   r0   "find_storvscid_from_sysctl_pnpinfo{   s    r@   c             C   sA   x: |  j    D], } t j | |  r | j   } | d Sq Wd S)z
    scbus0 on ata0 bus 0
    scbus1 on ata1 bus 0
    scbus2 on blkvsc0 bus 0
    scbus3 on blkvsc1 bus 0
    scbus4 on storvsc2 bus 0
    scbus5 on storvsc3 bus 0
    scbus-1 on xpt0 bus 0
    r   N)r6   r7   r8   r9   )camcontrol_outZdisk_drvr=   itemsr/   r/   r0   find_busdev_from_disk   s
    rC   c             C   si   xb |  j    D]T } t j | |  r | j d  } t |  d k r | d j d  } | d Sq Wd S)z
    <Msft Virtual CD/ROM 1.0>          at scbus1 target 0 lun 0 (cd0,pass0)
    <Msft Virtual Disk 1.0>            at scbus2 target 0 lun 0 (da0,pass1)
    <Msft Virtual Disk 1.0>            at scbus3 target 1 lun 0 (da1,pass2)
    (r%   r4   ,r   N)r6   r7   r8   r9   r:   )rA   Zbusdevr=   rB   Zdev_passr/   r/   r0   find_dev_from_busdev   s    rF   c             C   sN   y t  j  |   d SWn2 t  j k
 rI t j d d j |    | SYn Xd  S)Nr   zFailed to execute: %s )r   ProcessExecutionErrorLOGdebugjoin)cmdfail_retr/   r/   r0   execute_or_debug   s
    rN   c               C   s   t  d d g d d S)NZsysctlzdev.storvscrM    )rN   r/   r/   r/   r0   get_dev_storvsc_sysctl   s    rP   c               C   s   t  d d d g  S)N
camcontroldevlistz-b)rN   r/   r/   r/   r0   get_camcontrol_dev_bus   s    rS   c               C   s   t  d d g  S)NrQ   rR   )rN   r/   r/   r/   r0   get_camcontrol_dev   s    rT   c             C   s1  d } |  d k r" d } |  d }  d t  |   } d j | |  } t   } t | |  } | ss t j d  d  St   } t   } d j |  } t | |  }	 |	 r t	 | |	  }
 |
 d  k r t j d	  d  S|
 Sd
 j |  } t | |  }	 |	 r-t	 | |	  }
 |
 d  k r)t j d	  d  S|
 Sd  S)NZ00000000r4   Z00000001r%   Z000z{0}-{1}z#Fail to find storvsc id from sysctlz	blkvsc{0}zFail to find /dev/daXz
storvsc{0})
strr*   rP   r@   rI   rJ   rS   rT   rC   rF   )Zport_idZg0Zg1Zg0g1r<   Z	storvscidZcamcontrol_b_outrA   ZblkvscZscbusxZdevnameZstorvscr/   r/   r0   get_resource_disk_on_freebsd   s<    
			rV   Zhn0z/var/db/dhclient.leases.hn0zfreebsd-ufsr4   zresource disk is not Nonez/dev/zresource disk is Noneagent_commanddata_dirset_hostnameThostname_bounce	interfacepolicycommandbuiltinhostname_commandhostnamedisk_aliasesZ
ephemeral0dhclient_lease_fileapply_network_configF
disk_setupZ
table_typeZgptZlayoutd   Z	overwriteZfs_setupZ
filesystemZdevicezephemeral0.1
datasourceZnever_destroy_ntfszTemporary StorageZREDACTEDc             C   s;   t  |  t t f  s |  f }  t j |  d d d j   S)NcaptureTr   )
isinstancelisttupler   strip)r_   r/   r/   r0   get_hostname"  s    	rl   c             C   s   t  j  | |  g  d  S)N)r   )r`   r_   r/   r/   r0   rY   (  s    c             c   s   | d d } t  |  } t j | j d   sZ t j |  sZ | |  k rc | d k rc d Vd Sy t |  |  WnE t k
 r } z% t d | d t j	 d Vd SWYd d } ~ Xn Xz	 | VWd t | |  Xd S)z
    Set a temporary hostname, restoring the previous hostname on exit.

    Will have the value of the previous hostname when used as a context
    manager, or None if the hostname was not changed.
    rZ   r\   rY   ZforceNz%Failed setting temporary hostname: %slogger_func)
rl   r   is_truegetis_falserY   	Exceptionr   rI   warning)temp_hostnamecfgr_   r\   Zprevious_hostnameer/   r/   r0   temporary_hostname,  s$    	

	rv   c                   sn  e  Z d  Z d Z d Z e j Z d d   Z d d   Z	 e
 d d    Z e
 d	 d
    Z d d   Z e
 d d    Z d d   Z f    f d d  Z e
 d d    Z e
 e j d d   Z d d   Z e
 d d    Z d d   Z d d   Z d d  d!  Z e
 d" d#    Z e
 d$ d%    Z e
 d& d'    Z e
 d( d)    Z e
 d* d+    Z e
 d, d-    Z e
 d. d/    Z  e
 d0 d1    Z! e
 d2 d3    Z" e
 d e# d4 d5 d6    Z$ e% e# d7 d8 d9    Z& e# d4 d: d;    Z' d< d=   Z( d> d?   Z) e
 d@ dA    Z* e
 dB dC    Z+ e, dD dE    Z- e, dF dG    Z. e, dH dI    Z/   S)JDataSourceAzurer!   Fc             C   s   t  j j |  | | |  t j j | j d  |  _ i  |  _ d  |  _ t	 j
 t	 j | t i   t g  |  _ |  j j d  |  _ d  |  _ |  j d j t j  d  |  _ d |  _ d  S)NZazurerb   r-   F)r   
DataSource__init__ospathrK   seed_dirrt   seedr   mergemanydictget_cfg_by_pathDS_CFG_PATHBUILTIN_DS_CONFIGds_cfgro   rb   _network_configZupdate_eventsaddr
   BOOT_ephemeral_dhcp_ctxfailed_desired_api_version)selfsys_cfgdistropathsr/   r/   r0   ry   P  s    				zDataSourceAzure.__init__c             C   s#   t  j j |   } d | |  j f S)Nz%s [seed=%s])r   rx   __str__r}   )r   rootr/   r/   r0   r   `  s    zDataSourceAzure.__str__c             C   s   |  j  j d  } t j d |  |  j d d } t | |  j d |  } | d  k	 r t j |  j j d   r |  j d } y t d | d | d |  SWnL t	 k
 r } z, t
 d	 | d
 t j t j t d  WYd  d  } ~ Xn XWd  QRXd S)Nzlocal-hostnamezHostname in metadata is %srZ   r_   rY   r`   rt   prev_hostnamezFailed publishing hostname: %srm   zhandling set_hostname failedF)metadataro   rI   rJ   r   rv   r   rn   perform_hostname_bouncerq   r   rr   logexc)r   Zazure_hostnamer_   Zprevious_hnrt   ru   r/   r/   r0   "bounce_network_with_azure_hostnamed  s&    	

*z2DataSourceAzure.bounce_network_with_azure_hostnamec       
      C   s  |  j  j d  } |  j d } t j d | |  |  j   y t |  Wn/ t j k
 r{ t	 j
 t d |  j d  Yn X|  j d } g  } d  } x |  j j d g   D]o } | j d d   r | d } t j d  q t | d	 d
  } | t j j | |  g 7} t j d  q Wt j d d d d d t  Q t	 j d t j d d d t	 j d | d f  } t |  rt j d |  Wd  QRXi  }	 | pt |  |	 d <|	 S)Nzlocal-hostnamerW   z/Getting metadata via agent.  hostname=%s cmd=%szagent command '%s' failed.rX   _pubkeysvaluez+SSH authentication: using value from fabricfingerprintz.crtz1SSH authentication: using fingerprint from fabricnamezwaiting-for-ssh-public-keydescriptionz$wait for agents to retrieve SSH keysparentlogfuncmsgz waiting for SSH public key filesfuncargsi  z$Did not find files, but going on: %szpublic-keys)r   ro   r   rI   rJ   r   invoke_agentr   rH   r   r   rt   rU   rz   r{   rK   r   ReportEventStackr   log_timeZwait_for_filesr:   rr   pubkeys_from_crt_files)
r   rs   Z	agent_cmdddirZfp_files	key_valueZpkZbnameZmissingr   r/   r/   r0   get_metadata_from_agent  sB    	


	
	z'DataSourceAzure.get_metadata_from_agentc             C   s2   |  j  j d  r d } n d } d | |  j  f S)z/Return the subplatform metadata source details.z/devzconfig-diskzseed-dirz%s (%s))r}   r;   )r   Zsubplatform_typer/   r/   r0   _get_subplatform  s    	z DataSourceAzure._get_subplatformc             C   s  i  } |  j  d } |  j g } t j j t  r[ | j d d  t d t d t j	 n9 t j j t
  r | j d d  t d t
 d t j	 | j t    | r | j |  d } d	 } d	 } x]| D]U} y | d k r d } d
 } nr | d k rd } d
 } nW | j d  rZt j   rEt j | t d d } qft j | t  } n t |  } Wn t k
 rt d | d t j	 w Yn t k
 r}	 z1 d |	 }
 t |
 d t j t j |
   WYd d }	 ~	 Xn/ t j k
 rt d | d t j w Yn X| p&|  j |  } | p;|  j |  } | sJ| rt j   r~d }
 t |
 d t j t j |
   | r|  j   |  j   } |  j |  j d d } | \ } } } } | |  _  | j! d | d | d t j" | d | i g  d | i  | } t d | d t j	 Pq W| sWd }
 t |
 d t j t j |
   | | k rzt d | d t j	 t#   } | r| | d d <|  j$   | d d <| s| rt j% d  |  j& j' j( |  j  ot) |  d d  } | r|  j* d  |  j+ j,  |  j+ j-   nl y* t. t/   } |  j* d  |  Wd QRXWn? t0 k
 r} z t d! | d t j   WYd d } ~ Xn X| S)"a  Walk all instance metadata sources returning a dict on success.

        @return: A dictionary of any metadata content for this instance.
        @raise: InvalidMetaDataException when the expected metadata service is
            unavailable, broken or disabled.
        rX   r   ZIMDSzJReprovision marker file already present before crawling Azure metadata: %srm   ZNIC_ATTACH_MARKER_PRESENTzUReprovision nic attach marker file already present before crawling Azure metadata: %sNFTz/dev/mtypeudfz$Did not find Azure data source in %szBrokenAzureDataSource: %sz%s was not mountablez%Free BSD is not supported for PPS VMsretries
   rt   filesr   imdsuserdata_rawzfound datasource in %szNo Azure metadata foundzusing files cached in %sZrandom_seedzinstance-idz6Reporting ready to Azure after getting ReprovisionDatar   leasez#exception while reporting ready: %s)1r   r|   rz   r{   isfileREPROVISION_MARKER_FILEinsertr   rI   rJ   "REPROVISION_NIC_ATTACH_MARKER_FILEextendlist_possible_azure_ds_devsappendr;   r   
is_FreeBSDmount_cbload_azure_ds_dirNonAzureDataSourceBrokenAzureDataSourceerrorr   InvalidMetaDataExceptionMountFailedErrorrr   _should_reprovision$_should_reprovision_after_nic_attach_wait_for_all_nics_ready_reprovisionget_imds_data_with_api_fallbackfallback_interfacer}   updater~   _get_random_seed_iidinfor   
networkingis_upgetattr_report_readyr   r   clean_networkr   r   rq   )r   crawled_datar   Z
candidatesfoundZreprovisionZreprovision_after_nic_attachZcdevretexcr   Zperform_reprovisionZ$perform_reprovision_after_nic_attachimds_mdmdr   rt   r   r}   Zuse_cached_ephemeralr   ru   r/   r/   r0   crawl_metadata  s    
		


!
					

zDataSourceAzure.crawl_metadatac             C   s   t  |  j  S)z@Check platform environment to report if this datasource may run.)_is_platform_viabler|   )r   r/   r/   r0   r   ?  s    z#DataSourceAzure._is_platform_viablec                s&   t  t |   j |  t j |  _ d S)z.Reset any cached class attributes to defaults.N)superrw   clear_cached_attrsr   UNSET_metadata_imds)r   Zattr_defaults)	__class__r/   r0   r   C  s    z"DataSourceAzure.clear_cached_attrsc          /   C   sU  |  j    s d Sy t   Wn5 t k
 rR } z t j d |  WYd d } ~ Xn Xy t   Wn5 t k
 r } z t j d |  WYd d } ~ Xn Xt |  j j _	 y( t
 j d t j d d d |  j  } WnP t k
 r} z0 t d	 | d
 t j |  j d t  d SWYd d } ~ Xn X|  j rT|  j j d k rT|  j j d  rTt   t } t j j |  rt d | d
 t j t
 j | d t g  |  _ n$ t d | d
 t j | d |  _ | d d |  _ t
 j | d t g  |  _ | d |  _  t
 j! |  j t" i   } t
 j | |  j g  |  _ t# |  j d | d d d d S)zCrawl and process datasource metadata caching metadata as attrs.

        @return: True on success, False on error, invalid or disabled
            datasource.
        Fz Failed to get boot telemetry: %sNz$Failed to get system information: %sr   r   zCrawl of metadata servicer   z"Could not crawl Azure metadata: %srm   r   Zubunturc   zXEphemeral resource disk '%s' exists. Merging default Azure cloud ephemeral disk configs.rt   zdEphemeral resource disk '%s' does not exist. Not merging default Azure cloud ephemeral disk configs.r   r   r   rX   r   dirmodei  T)$r   r   rq   rI   rr   r   BLACKLIST_DRIVERSr   r   blacklist_driversr   r   rJ   r   r   r   _report_failurer   r   r   ro   *maybe_remove_ubuntu_network_config_scriptsRESOURCE_DISK_PATHrz   r{   existsr~   #BUILTIN_CLOUD_EPHEMERAL_DISK_CONFIGrt   r   DEFAULT_METADATAr   r   r   r   write_files)r   ru   r   devpathZuser_ds_cfgr/   r/   r0   	_get_dataH  s^    ##	

	

zDataSourceAzure._get_datac             C   s   |  j  s x t |  D] } y3 t j d t  t d | d d d | d t  SWq t k
 r } zP t j d t  | j d k r d	 j t	  } t
 | d
 t j d |  _  PWYd d } ~ Xq Xq Wt j d t	  t d | d | d | d t	  S)a=  
        Wrapper for get_metadata_from_imds so that we can have flexibility
        in which IMDS api-version we use. If a particular instance of IMDS
        does not have the api version that is desired, we want to make
        this fault tolerant and fall back to a good known minimum api
        version.
        zAttempting IMDS api-version: %sfallback_nicr   r   md_typeapi_versionz"UrlError with IMDS api-version: %si  z!Fall back to IMDS api-version: {}rm   TNzUsing IMDS api-version: %s)r   rangerI   r   IMDS_VER_WANTget_metadata_from_imdsr   coder*   IMDS_VER_MINr   )r   r   r   r   _errlog_msgr/   r/   r0   r     s:    		
	z/DataSourceAzure.get_imds_data_with_api_fallbackc             C   s   |  j  d j |  S)Nra   )r   ro   )r   r   r/   r/   r0   device_name_to_device  s    z%DataSourceAzure.device_name_to_devicec             C   s   t  j d  g  } y? t d   d d   |  j d d d D } t  j d  Wnw t k
 r d	 } t | d
 t  j y |  j d } t  j d  Wn+ t k
 r d } t | d
 t  j Yn XYn X| S)aw  
        Try to get the ssh keys from IMDS first, and if that fails
        (i.e. IMDS is unavailable) then fallback to getting the ssh
        keys from OVF.

        The benefit to getting keys from IMDS is a large performance
        advantage, so this is a strong preference. But we must keep
        OVF as a second option for environments that don't have IMDS.
        zRetrieving public SSH keysz#Not using public SSH keys from IMDSc             S   s   g  |  ] } | d   q S)ZkeyDatar/   ).0Z
public_keyr/   r/   r0   
<listcomp>  s   	z7DataSourceAzure.get_public_ssh_keys.<locals>.<listcomp>r   r,   
publicKeyszRetrieved SSH keys from IMDSz1Unable to get keys from IMDS, falling back to OVFrm   zpublic-keyszRetrieved keys from OVFzNo keys available from OVF)rI   rJ   KeyErrorr   r   )r   Zssh_keysr   r/   r/   r0   get_public_ssh_keys  s$    		z#DataSourceAzure.get_public_ssh_keysc             C   s   |  j  S)N)rt   )r   r/   r/   r0   get_config_obj  s    zDataSourceAzure.get_config_objc             C   s   t  j |  j    S)N)r   Zinstance_id_matches_system_uuidget_instance_id)r   r   r/   r/   r0   check_instance_id  s    z!DataSourceAzure.check_instance_idNc             C   s   t  j j |  j j d  d  } t j d  j   } t  j j |  r t	 j
 |  j   } | j   | k rs | St | j   |  r | S| S)Ndatazinstance-idzsystem-uuid)rz   r{   rK   r   Z	get_cpathr   read_dmi_datalowerr   r   	load_filerk   r   )r   ZpreviousZprev_iid_pathZiidr/   r/   r0   r     s    	zDataSourceAzure._iidc             C   s   |  j  d k rf t j d |  j   |  |  j   } t j d |  | rZ |  j j |  d |  _  n t j d |  j    d  S)NFz$negotiating for %s (new_instance=%s)znegotiating returned %sTznegotiating already done for %s)_negotiatedrI   rJ   r   
_negotiater   r   )r   is_new_instancefabric_datar/   r/   r0   setup  s    		zDataSourceAzure.setupc             C   s  y d } t  j d d d d d t   t j |  } Wd QRX| d k rf d } t | d t j n t d	 | d t j t } t j	 d
 |  t
 j | d j d t j   d t     Wn; t k
 r } z t | d t j   WYd d } ~ Xn Xd S)zUse the netlink socket provided to wait for nic detach event.
           NOTE: The function doesn't close the socket. The caller owns closing
           the socket and disposing it safely.
        Nr   zwait-for-nic-detachr   zwait for nic detachr   zHPreprovisioned nic not detached as expected. Proceeding without failing.rm   z%The preprovisioned nic %s is detachedz+Creating a marker file for nic detached: %sz{pid}: {time}
pidr   )r   r   r   r   Zwait_for_nic_detach_eventr   rI   rr   $REPROVISION_NIC_DETACHED_MARKER_FILEr   r   
write_filer*   rz   getpidr   AssertionErrorr   )r   nl_sockifnamer   r{   r   r/   r/   r0   _wait_for_nic_detach  s&    	
z$DataSourceAzure._wait_for_nic_detachc             C   s5  |  j  j j |  r0 t d | d t j d St j d |  d } x t j d |  t j | d  j d  } t	 j
 d	 |  t	 j
 d
 |  | d } |  j  j j |  r d | | f } t | d t j d Sd } d | | f } | d d k rt | d t j n t j |  t |  qI Wd S)at  In cases where the link state is still showing down after a nic is
           hot-attached, we can attempt to bring it up by forcing the hv_netvsc
           drivers to query the link state by unbinding and then binding the
           device. This function attempts infinitely until the link is up,
           because we cannot proceed further until we have a stable link.zThe link %s is already up.rm   NzAttempting to bring %s upr   z&Unbinding and binding the interface %szdevice/device_idz{}z'/sys/bus/vmbus/drivers/hv_netvsc/unbindz%/sys/bus/vmbus/drivers/hv_netvsc/bindr4   z#The link %s is up after %s attemptszHLink is not up after %d attempts with %d seconds sleep between attempts.r   )r   r   Ztry_set_link_upr   rI   r   r	   Zread_sys_netrk   r   r  r   )r   r  ZattemptsZ
devicenamer   Zsleep_durationr/   r/   r0   wait_for_link_up1  s6    
			

z DataSourceAzure.wait_for_link_upc             C   sX   t  } t j d |  t j | d j d t j   d t     t	 d d t j
 d  S)Nz*Creating a marker file to report ready: %sz{pid}: {time}
r  r   zRSuccessfully created reported ready marker file while in the preprovisioning pool.rm   )REPORTED_READY_MARKER_FILErI   r   r   r  r*   rz   r  r   r   rJ   )r   r{   r/   r/   r0   _create_report_ready_marker]  s    
z+DataSourceAzure._create_report_ready_markerc             C   s   t  j j t  } | r t d d t j y* t t   } |  j	 d |  Wd QRXWn? t
 k
 r } z t d | d t j   WYd d } ~ Xn X|  j   n t d t d t j d S)zlReport ready to the platform if the marker file is not present,
        and create the marker file.
        z!Reporting ready before nic detachrm   r   NzFException reporting ready during preprovisioning before nic detach: %szLAlready reported ready before nic detach. The marker file already exists: %s)rz   r{   r   r
  r   rI   r   r   r   r   rq   r   r  )r   Zhave_not_reported_readyr   ru   r/   r/   r0   _report_ready_if_neededi  s    	
z'DataSourceAzure._report_ready_if_neededc          &   C   sx  d } d } d } yM t  j d d d d | d t  $ t d	 | d
 t  } | j   Wd QRXWnE t k
 r } z% t d | | f d t j	   WYd d } ~ Xn Xz[ y |  j
 | d t j  } Wn8 t k
 r } z t j d | |  WYd d } ~ Xn XWd | d k r| j   X| d k	 rnt j d |  d } | |  _ t | d  } t d | d t j | | f S)zCheck if a given interface is the primary nic or not. If it is the
        primary nic, then we also get the expected total nic count from IMDS.
        IMDS will process the request and send a response only for primary NIC.
        Fr4   Nr   zobtain-dhcp-leaser   zlobtain dhcp lease for %s when attempting to determine primary NIC during reprovision of a pre-provisioned VMr   Zifacedhcp_log_funczsGiving up. Failed to obtain dhcp lease for %s when attempting to determine primary NIC during reprovision due to %srm      zFailed to get network metadata using nic %s. Attempt to contact IMDS failed with error %s. Assuming this is not the primary nic.z%s is the primary nicTr[   zExpected nic count: %d)r   r   r   r   r   obtain_leaserq   r   rI   r   r   r&   r-   rr   r   r   r   r:   )r   r  Z
is_primaryexpected_nic_countr   Zdhcp_ctxru   r/   r/   r0   _check_if_nic_is_primary  sJ    	
	!	z(DataSourceAzure._check_if_nic_is_primaryc             C   s9  t  j d  y g  } d } d } x d } t j d d d d t |  d	 t   t j | |  } Wd QRX| j |  t	 d
 | d t  j |  j
 |  | s t  j d |  |  j |  \ } } | d k r% t |  | k r% t  j d  Pq% WWn8 t k
 r4} z t	 | d t  j WYd d } ~ Xn Xd S)zWait until all the expected nics for the vm are hot-attached.
        The expected nic count is obtained by requesting the network metadata
        from IMDS.
        z#Waiting for nics to be hot-attachedFr4   Nr   zwait-for-nic-attachr   z4wait for nic attach after %d nics have been attachedr   zDetected nic %s attached.rm   z!Checking if %s is the primary niczFound all the nics for this VM.r  r  )rI   r   r   r   r:   r   r   Zwait_for_nic_attach_eventr   r   r	  r  r  r   )r   r  Z
nics_foundZprimary_nic_foundr  r  r   r/   r/   r0   _wait_for_hot_attached_nics  s8    	
	
		z+DataSourceAzure._wait_for_hot_attached_nicsc             C   s   d } z y t  j   } t t j j t   } |  j   t t j j t   } | sr t	 j
 d  |  j |  |  j s |  j |  n t d | d t	 j
 Wn> t  j k
 r } z t | d t	 j   WYd d } ~ Xn XWd | r | j   Xd S)a  Wait for nic(s) to be hot-attached. There may be multiple nics
           depending on the customer request.
           But only primary nic would be able to communicate with wireserver
           and IMDS. So we detect and save the primary nic to be used later.
        NzNIC has not been detached yet.zSkipping waiting for nic attach because we already have a fallback interface. Report Ready marker present before detaching nics: %srm   )r   create_bound_netlink_socketboolrz   r{   r   r
  r  r  rI   r   r  r   r  r   NetlinkCreateSocketErrorrr   close)r   r  Zreport_ready_marker_presentZhas_nic_been_detachedru   r/   r/   r0   r     s*    
	z(DataSourceAzure._wait_for_all_nics_readyc          8      sN  d j  t j j t  } d d i } d } t t j j t	   } d   _
 d   _ d } d } d }   f d d	   }   j d k	 }	 d
 }
 |	 r | r t |
 d t j t |
   xWz?y|	 st j d d d d d t  & t d t    _   j j   } Wd QRX| r| d 7} | ry t j   } WnM t j k
 r} z* t d | d t j   j j   PWYd d } ~ Xn X  j d |  } | sd }
 t |
 d t j   j j   t j |
     j   d } t j  d  t j d d d d d t  ] y t j! | | d  Wn= t" k
 re} z t d | d t j PWYd d } ~ Xn XWd QRXd }   j j   nT t j d d d d d t  2 t# | d t$ d | d | d  d d! d j% } Wd QRXPWn t& k
 r  j j   Yn XWd | r| j'   Xq W| rJt d" | d t j  t d#   j d t j  | S)$ztPoll IMDS for the new provisioning data until we get a valid
        response. Then return the returned JSON object.z{}?api-version={}MetadatatrueNr4   r   Fc                s   t  | t  r | j d k r   j   j k rx   j d 9_ t j d   j  t d |  | j | j f d t j   j d 7_ d St d |  | j | j f d t j	 d	 St d
 | d t j	 d	 S)N    r%   z:Backing off logging threshold for the same exception to %dz4poll IMDS with %s failed. Exception: %s and code: %srm   r4   TFz1poll IMDS failed with an unexpected exception: %s)r  r  )
rh   r   r   imds_poll_counterimds_logging_thresholdrI   rJ   r   causerr   )r   Z	exception)r   r/   r0   exc_cb?  s,    	
	
	

z*DataSourceAzure._poll_imds.<locals>.exc_cbzeUnexpected error. Dhcp context is not expected to be already set when we need to wait for vnet switchrm   r   zobtain-dhcp-leaser   zobtain dhcp leaser   r  z)Failed to create bound netlink socket: %sr   z9Failed reporting ready while in the preprovisioning pool.zWait for vnetswitch to happenz!wait-for-media-disconnect-connectzwait for vnet switchr[   z'Error while waiting for vnet switch: %sTzget-reprovision-data-from-imdszget reprovision data from imdstimeoutheadersexception_cbZinfiniteZlog_req_respz#attempted dhcp %d times after reusez polled imds %d times after reuse)(r*   r&   r.   r   r   r  rz   r{   r   r
  r  r  r   r   rI   r   RuntimeErrorr   r   r   r   r   r  r   r  r  rr   r   r   r   r   r  rJ   Z!wait_for_media_disconnect_connectr  r   IMDS_TIMEOUT_IN_SECONDScontentsr   r  )r   urlr!  r  Zreport_readyZdhcp_attemptsZvnet_switchedZ
return_valr  Zis_ephemeral_ctx_presentr   r   ru   Zreport_ready_succeededr/   )r   r0   
_poll_imds.  s    				#	




	


	
	


zDataSourceAzure._poll_imds)returnc          ,   C   s  d } y |  j  j j |  j  r t |  d d  r t |  j d d  r | |  j j k r t d d t j	 t
 d |  j j | d |  |  j j   d	 SWn< t k
 r } z t d
 | d t j WYd d } ~ Xn XyH t d d t j	 t t   } t
 d | | d |  Wd QRXd	 SWn< t k
 ra} z t d | d t j	 WYd d } ~ Xn Xy( t d  t
 d |  j d |  d	 SWn< t k
 r} z t d | d t j	 WYd d } ~ Xn Xd S)zTells the Azure fabric that provisioning has failed.

        @param description: A description of the error encountered.
        @return: The success status of sending the failure signal.
        zunknown-245r   Nr   z>Using cached ephemeral dhcp context to report failure to Azurerm   Z	dhcp_optsr   Tz@Failed to report failure using cached ephemeral dhcp context: %sz3Using new ephemeral dhcp to report failure to Azurez5Failed to report failure using new ephemeral dhcp: %sz/Using fallback lease to report failure to Azurefallback_lease_filez1Failed to report failure using fallback lease: %sF)r   r   r   r   r   r   r   r   rI   rJ   r    r   rq   r   r   r   rb   )r   r   Zunknown_245_keyru   r   r/   r/   r0   r     sX    



	
zDataSourceAzure._report_failure)r   r(  c             C   s`   y t  d | d  d SWn@ t k
 r[ } z  t d | d t j d SWYd d } ~ Xn Xd S)zTells the fabric provisioning has completed.

        @param lease: dhcp lease to use for sending the ready signal.
        @return: The success status of sending the ready signal.
        Nzunknown-245TzQError communicating with Azure fabric; You may experience connectivity issues: %srm   F)r   rq   r   rI   rr   )r   r   ru   r/   r/   r0   r     s    zDataSourceAzure._report_readyc             C   s   | s
 d S| \ } } } } t  } | j d d  d k sL t j j |  r t j j |  s t j d |  t j | d j	 d t j
   d t     d	 Sd S)
aI  Whether or not we should wait for nic attach and then poll
        IMDS for reprovisioning data. Also sets a marker file to poll IMDS.

        The marker file is used for the following scenario: the VM boots into
        wait for nic attach, which we expect to be proceeding infinitely until
        the nic is attached. If for whatever reason the platform moves us to a
        new host (for instance a hardware issue), we need to keep waiting.
        However, since the VM reports ready to the Fabric, we will not attach
        the ISO, thus cloud-init needs to have a way of knowing that it should
        jump back into the waiting mode in order to retrieve the ovf_env.

        @param candidate_metadata: Metadata obtained from reading ovf-env.
        @return: Whether to reprovision after waiting for nics to be attached.
        FPreprovisionedVMTypeNZSavablez1Creating a marker file to wait for nic attach: %sz{pid}: {time}
r  r   T)r   ro   rz   r{   r   rI   r   r   r  r*   r  r   )r   Zcandidate_metadata_md_userdata_rawrt   _filesr{   r/   r/   r0   r     s    	z4DataSourceAzure._should_reprovision_after_nic_attachc             C   s   | s
 d S| \ } } } } t  } | j d  d k sa | j d d  d k sa t j j |  r t j j |  s t j d |  t j | d j	 d	 t j
   d
 t     d Sd S)a  Whether or not we should poll IMDS for reprovisioning data.
        Also sets a marker file to poll IMDS.

        The marker file is used for the following scenario: the VM boots into
        this polling loop, which we expect to be proceeding infinitely until
        the VM is picked. If for whatever reason the platform moves us to a
        new host (for instance a hardware issue), we need to keep polling.
        However, since the VM reports ready to the Fabric, we will not attach
        the ISO, thus cloud-init needs to have a way of knowing that it should
        jump back into the polling loop in order to retrieve the ovf_env.FPreprovisionedVmTr*  NZRunningz'Creating a marker file to poll imds: %sz{pid}: {time}
r  r   )r   ro   rz   r{   r   rI   r   r   r  r*   r  r   )r   r   r+  r,  rt   r-  r{   r/   r/   r0   r   !  s    	z#DataSourceAzure._should_reprovisionc             C   sa   |  j    } t j d d d d d t  0 t |  \ } } } | | | d | i f SWd QRXd S)z%Initiate the reprovisioning workflow.r   zreprovisioning-read-azure-ovfr   z$read azure ovf during reprovisioningr   zovf-env.xmlN)r'  r   r   r   read_azure_ovf)r   r%  r   udrt   r/   r/   r0   r   ;  s    	
zDataSourceAzure._reprovisionc             C   sm  |  j  d t k r |  j   d } yM t d   |  j d d d } t j d | d k	 rh t |  n d  Wn4 t k
 r t j d	  |  j j	 d
 d  } Yn Xt
 t d |  j d | } n	 |  j } t j d |  j  d  y |   } Wn@ t k
 r4} z  t d | d t j d SWYd d } ~ Xn Xt j t  t j t  t j t  t j t  | S)zNegotiate with fabric and return data from it.

           On success, returns a dictionary including 'public_keys'.
           On failure, returns False.
        rW   Nz#Not using public SSH keys from IMDSr   r,   r   z*Successfully retrieved %s key(s) from IMDSr   zMUnable to retrieve SSH keys from IMDS during negotiation, falling back to OVFr   r)  pubkey_infoz,negotiating with fabric via agent command %szQError communicating with Azure fabric; You may experience connectivity issues: %srm   F)r   AGENT_START_BUILTINr   r   r   rI   rJ   r:   rt   ro   r   r   rb   r   rq   r   rr   r   del_filer
  r   r   r  )r   r1  Zpublic_keysZmetadata_funcr   ru   r/   r/   r0   r   E  sB    
					zDataSourceAzure._negotiatec             C   s?   z& t  d | d |  j j t d   Wd  t |  j d  Xd  S)Nr   preserve_ntfsFZdef_log_file)address_ephemeral_resizer   ro   DS_CFG_KEY_PRESERVE_NTFSr   r   )r   rt   r   r/   r/   r0   activate{  s    	zDataSourceAzure.activatec             C   s(   |  j  j d i   j d i   j d  S)Nr   r,   ZplatformFaultDomain)r   ro   )r   r/   r/   r0   availability_zone  s    	z!DataSourceAzure.availability_zonec             C   sV   |  j  s |  j  t j k rO |  j j d  r: |  j } n d } t |  |  _  |  j  S)a  Generate a network config like net.generate_fallback_network() with
           the following exceptions.

           1. Probe the drivers of the net-devices present and inject them in
              the network configuration under params: driver: <driver> value
           2. Generate a fallback network config that does not include any of
              the blacklisted devices.
        rc   N)r   r   r   r   ro   r   parse_network_config)r   Znc_srcr/   r/   r0   network_config  s    
zDataSourceAzure.network_configc             C   s(   |  j  j d i   j d i   j d  S)Nr   r,   location)r   ro   )r   r/   r/   r0   region  s    zDataSourceAzure.region)0r'   r(   r)   Zdsnamer   r   r   r   ry   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'  r  r   dictr   r   r   r   r   r7  propertyr8  r:  r<  r/   r/   )r   r0   rw   J  sN   	/I.$,D707
6
rw      c             C   s   x} d D]u } g  } x\ t  d |  D]K } |  | t |  } t j j |  r# | j | t j j |  f  q# W| r | Sq Wg  S)N-partprO   r4   )r@  rA  rO   )r   rU   rz   r{   r   r   realpath)r   ZmaxnumZsuffr   ZpnumZppathr/   r/   r0   _partitions_on_device  s    #rC  c             C   s;   t  j d d d } t j d |  t j j |   | k S)Nz	TYPE=ntfsZno_cacheTzntfs_devices found = %s)r   find_devs_withrI   rJ   rz   r{   rB  )r   Zntfs_devicesr/   r/   r0   _has_ntfs_filesystem  s    rE  c             C   sj  | r) d d j  t  t f } d | f St j j |   sI d d |  f St j d |  t j j |    t	 |   } t
 |  d k r d d |  f St
 |  d k r d	 |  d
 j  d d   | D  f } d | f St
 |  d k r | d \ } } n | d \ } } t |  s4d | | |  f } d | f St d d    } d | | |  f } t j d d d d d t   } y( t j | | d d d d d i }	 Wni t j k
 r}
 zF d | _ d t |
  k rd | d f Sd | d | |
 f f SWYd  d  }
 ~
 Xn X|	 d k rUd! |	 | _ t j d" d j  t  t  d | d# |	 f SWd  QRXd | d$ f S)%a  Determine if the ephemeral drive at devpath should be reformatted.

    A fresh ephemeral disk is formatted by Azure and will:
      a.) have a partition table (dos or gpt)
      b.) have 1 partition that is ntfs formatted, or
          have 2 partitions with the second partition ntfs formatted.
          (larger instances with >2TB ephemeral disk have gpt, and will
           have a microsoft reserved partition as part 1.  LP: #1686514)
      c.) the ntfs partition will have no files other than possibly
          'dataloss_warning_readme.txt'

    User can indicate that NTFS should never be destroyed by setting
    DS_CFG_KEY_PRESERVE_NTFS in dscfg.
    If data is found on NTFS, user is warned to set DS_CFG_KEY_PRESERVE_NTFS
    to make sure cloud-init does not accidentally wipe their data.
    If cloud-init cannot mount the disk to check for data, destruction
    will be allowed, unless the dscfg key is set.z:config says to never destroy NTFS (%s.%s), skipping checksr5   Fzdevice %s does not existzResolving realpath of %s -> %sr   zdevice %s was not partitionedr%   z&device %s had 3 or more partitions: %srG   c             S   s   g  |  ] } | d   q S)r4   r/   )r   rA  r/   r/   r0   r     s   	 z*can_dev_be_reformatted.<locals>.<listcomp>r4   z5partition %s (%s) on device %s was not ntfs formattedc                s5   t  d g    t   f d d   t j |   D  S)Nzdataloss_warning_readme.txtc                s(   g  |  ] } | j      k r |  q Sr/   )r   )r   f)ignoredr/   r0   r     s   	 z?can_dev_be_reformatted.<locals>.count_files.<locals>.<listcomp>)setr:   rz   listdir)Zmpr/   )rG  r0   count_files  s    z+can_dev_be_reformatted.<locals>.count_filesz1partition %s (%s) on device %s was ntfs formattedr   zmount-ntfs-and-countr   r   r   ZntfsZupdate_env_for_mountZLANGCzcannot mount ntfszunknown filesystem type 'ntfs'Tz^ but this system cannot mount NTFS, assuming there are no important files. Formatting allowed.z but mount of %s failed: %sNzmounted and counted %d fileszxit looks like you're using NTFS on the ephemeral disk, to ensure that filesystem does not get wiped, set %s.%s in configz but had %d files on it.z3 and had no important files. Safe for reformatting.)rK   r   r6  rz   r{   r   rI   rJ   rB  rC  r:   rE  r   r   r   r   r   r   r   r   rU   rr   )r   r4  r   Z
partitionsZ	cand_partZ	cand_pathrJ  bmsgevtZ
file_countru   r/   r/   r0   can_dev_be_reformatted  sZ    
#

			+	rN  c       	      C   sM  t  j j |   s- t d |  d t j d  St d |  d t j d } d  } | re d \ } } n t |  |  \ } } t j d | |  | s d  Sx d d	 g D] } d
 | } d | | f } t  j j |  r5y! t  j |  t j d |  WqEt k
 r1} z t j	 d | |  WYd  d  } ~ XqEXq t j d |  q Wd  S)Nz,Ephemeral resource disk '%s' does not exist.rm   z$Ephemeral resource disk '%s' exists.FTFirst instance boot.zreformattable=%s: %srd   Zmountsz#/var/lib/cloud/instance/sem/config_zMarker "%s" for module "%s"z%s removed.z%s: remove failed! (%s)z%s did not exist.)TrO  )
rz   r{   r   r   rI   rJ   rN  unlinkrq   rr   )	r   r   r4  resultr   modZsempathrL  ru   r/   r/   r0   r5  	  s6    




)r5  c       	      C   s  | d } | d } | d } d |  | | f } t  j j   } | | d <|  | d <| | d <| d k r t j   r t } n) t j d  r t } n t	 j
 d	  d
 St	 j
 d |  t | t t f  } t j d t	 j
 d d d d d t j d d | d | d d
 d | i  d S)Nr]   r[   r\   z"hostname=%s policy=%s interface=%sr`   Zold_hostnamer^   Zifupz7Skipping network bounce: ifupdown utils aren't present.Fz"pubhname: publishing hostname [%s]r   r   zpublishing hostnameZ
get_uptimeTr   kwargsr   shellrg   env)rz   environcopyr   r   BOUNCE_COMMAND_FREEBSDr   ZwhichBOUNCE_COMMAND_IFUPrI   rJ   rh   ri   rj   r   )	r`   rt   r   r]   r[   r\   r   rU  rT  r/   r/   r0   r   0  s0    





		r   c             C   s=   d } t  j  d d | |  g d d d | \ } } | j   S)NzHopenssl x509 -noout -pubkey < "$0" |ssh-keygen -i -m PKCS8 -f /dev/stdinr$   z-crg   Tr   )r   rstrip)fnamer   ZpipelineoutZ_errr/   r/   r0   crtfile_to_pubkeyT  s    r]  c             C   sz   g  } g  } xJ |  D]B } y | j  t |   Wq t j k
 rT | j  |  Yq Xq W| rv t d | d t j | S)Nz-failed to convert the crt files to pubkey: %srm   )r   r]  r   rH   r   rI   rr   )Zflistpubkeyserrorsr[  r/   r/   r0   r   ]  s    

r   c             C   s   d d   } |  s d  S| s" i  } t  j |  |  xf | j   D]X \ } } t j j |  |  } d | k r{ | | |  } t  j d | d | d d  q? Wd  S)Nc             S   s   y^ t  j |   } x; | j   D]- } d | j k r | j t k r t | _ q Wt  j |  SWn& t k
 r t j	 d |  |  SYn Xd S)z>Azure provides the UserPassword in plain text. So we redact itZUserPasswordz#failed to redact userpassword in %sN)
ETZ
fromstringitertagtextDEF_PASSWD_REDACTIONZtostringrq   rI   Zcritical)Zcntr[  r   elemr/   r/   r0   _redact_passwordr  s    z%write_files.<locals>._redact_passwordzovf-env.xmlfilenamecontentmodei  )r   Z
ensure_dirrB   rz   r{   rK   r  )Zdatadirr   r   rf  r   rh  r[  r/   r/   r0   r   o  s    r   c             C   sG   |  r6 t  j d |   t j |  d t |  t  n t  j d  d  S)Nzinvoking agent: %srT  znot invoking agent)rI   rJ   r   rh   ri   )rL   r/   r/   r0   r     s     r   c             C   sG   g  } |  j    s | Sx* |  j D] } | |  r  | j |  q  W| S)N)hasChildNodes
childNodesr   )ZnodeZfilter_funcr   childr/   r/   r0   
find_child  s    rm  c       
      C   s  t  |  d d    } t |  d k r+ g  St |  d k rS t d t |    | d } t  | d d    } t |  d k r g  Sg  } t j j } x | D] } | j   s q d d d	 d d
 d i } x | j D] } | j | k s | j	 r q | j	 j
   }	 |	 | j   k rq t | j  d k s | j d j | k rLq | j d j j   | |	 <q W| j |  q W| S)Nc             S   s   |  j  d k S)NZ
PublicKeys)	localName)nr/   r/   r0   <lambda>  s    z(load_azure_ovf_pubkeys.<locals>.<lambda>r   r4   z%Multiple 'PublicKeys'(%s) in SSH nodec             S   s   |  j  d k S)NZ	PublicKey)rn  )ro  r/   r/   r0   rp    s    r   rO   r{   r   )rm  r:   r   r   ZDocument	TEXT_NODErj  rk  nodeTypern  r   keys	wholeTextrk   r   )
ZsshnoderesultsZpubkeys_noder^  r   Z	text_nodeZpk_nodeZcurrl  r   r/   r/   r0   load_azure_ovf_pubkeys  s8    
rv  c             C   sL  y t  j |   } WnQ t k
 rf } z1 d | } t | d t j t |  |  WYd  d  } ~ Xn Xt | j d d    } t	 |  d k r t
 d   t	 |  d k r t d t	 |    | d } t | d	 d    } t	 |  d k rt
 d
   t	 |  d k r0t d t	 |  d f   | d } | j   sRt d   d } d i  i }	 i  }
 d } d  } d  } x#| j D]} | j | j k s| j rq| j j   } d } d } t	 | j  d k r
| j d j | j k r
d } | j d j } t d d   | j j   D  } | d k sD| d k r| j d  d* k rzt j d j | j     } q| } q| d k r| } q| d k r| } q| d k r| |	 d <q| d k r0| j d  d+ k rt j d j | j     } n | } t t j | d i  i |
 d <q| d  k rOt |  |
 d! <q| d" k rqt j |  |
 d# <q| r| | k r| |	 | <q| |	 d | <qWi  } | r| | d$ <| rd | d% <t | k rt  |  | d& <|
 d' <| rd( | i |
 d) <d# |
 k r| rd |
 d# <t! |  } t j" |
 | g  }
 |	 | |
 f S),NzInvalid ovf-env.xml: %srm   c             S   s   |  j  d k S)NZProvisioningSection)rn  )ro  r/   r/   r0   rp    s    z read_azure_ovf.<locals>.<lambda>r   zNo ProvisioningSectionr4   z$found '%d' ProvisioningSection itemsc             S   s   |  j  d k S)N!LinuxProvisioningConfigurationSet)rn  )ro  r/   r/   r0   rp    s    z$No LinuxProvisioningConfigurationSetzfound '%d' %ssrw  z#no child nodes of configuration setZseedfromZ
azure_datarO   FTc             S   s"   g  |  ] \ } } | | f  q Sr/   r/   )r   kvr/   r/   r0   r   
  s   	 z"read_azure_ovf.<locals>.<listcomp>ZuserdataZ
customdataencodingbase64usernameZuserpasswordr`   zlocal-hostnamedscfgdefaultrf   Zsshr   Z disablesshpasswordauthenticationZ
ssh_pwauthr   Zlock_passwdZpasswdpasswordZdefault_userZsystem_info)Nbase64)Nr  )#r   ZparseStringrq   r   rI   rr   r   rm  documentElementr:   r   rj  rk  rr  rq  rn  r   rt  r=  Z
attributesrB   ro   r{  Z	b64decoderK   r9   DS_NAMEr   Z	load_yamlrv  rp   rd  encrypt_pass_get_preprovisioning_cfgsr~   )r%  domru   Z	error_strru  ZprovSectionZ
lpcs_nodesZlpcsZmd_propsr   rt   r0  r  r|  rl  r   Zsimpler   Zattrsr}  ZdefuserZpreprovisioning_cfgr/   r/   r0   r/    s    
"	
	
"!			!"


r/  c             C   s   d d d d i } t  |  j d d    } | sC t |  d k rT t j d  | St  | d d	 d    } | s t |  d k r t j d
  | St |  | d <t |  | d <| S)a  Read the preprovisioning related flags from ovf and populates a dict
    with the info.

    Two flags are in use today: PreprovisionedVm bool and
    PreprovisionedVMType enum. In the long term, the PreprovisionedVm bool
    will be deprecated in favor of PreprovisionedVMType string/enum.

    Only these combinations of values are possible today:
        - PreprovisionedVm=True and PreprovisionedVMType=Running
        - PreprovisionedVm=False and PreprovisionedVMType=Savable
        - PreprovisionedVm is missing and PreprovisionedVMType=Running/Savable
        - PreprovisionedVm=False and PreprovisionedVMType is missing

    More specifically, this will never happen:
        - PreprovisionedVm=True and PreprovisionedVMType=Savable
    r.  Fr*  Nc             S   s   |  j  d k S)NZPlatformSettingsSection)rn  )ro  r/   r/   r0   rp  V  s    z+_get_preprovisioning_cfgs.<locals>.<lambda>r   z!PlatformSettingsSection not foundc             S   s   |  j  d k S)NZPlatformSettings)rn  )ro  r/   r/   r0   rp  \  s    zPlatformSettings not found)rm  r  r:   rI   rJ   _get_preprovisionedvm_cfg_value#_get_preprovisionedvmtype_cfg_value)r  rt   Zplatform_settings_sectionplatform_settingsr/   r/   r0   r  =  s&    r  c             C   s}   d } t  |  d d d    } | s8 t |  d k rI t j d  | St j | d j j  } t d | d t j	 | S)NFr   c             S   s   |  j  d k S)Nr.  )rn  )ro  r/   r/   r0   rp  u  s    z1_get_preprovisionedvm_cfg_value.<locals>.<lambda>zPreprovisionedVm not foundzPreprovisionedVm: %srm   )
rm  r:   rI   rJ   r   Ztranslate_bool
firstChild	nodeValuer   r   )r  ZpreprovisionedVmZpreprovisionedVmValr/   r/   r0   r  l  s    r  c             C   s   d  } t  |  d d d    } | sK t |  d k sK | d j d  k r\ t j d  | S| d j j } t d | d t j | S)Nr   c             S   s   |  j  d k S)Nr*  )rn  )ro  r/   r/   r0   rp    s    z5_get_preprovisionedvmtype_cfg_value.<locals>.<lambda>zPreprovisionedVMType not foundzPreprovisionedVMType: %srm   )rm  r:   r  rI   rJ   r  r   r   )r  ZpreprovisionedVMTypeZpreprovisionedVMTypeValr/   r/   r0   r    s    

r  z$6$c             C   s    t  j  |  | t j d d   S)NZstrlenr?  )cryptr   Zrand_str)r  Zsalt_idr/   r/   r0   r    s    r  c             C   sT   y+ t  |    } | j d  d SWd QRXWn" t k
 rO t j d |   Yn Xd S)z;Return boolean indicating path to cdrom device has content.i   TNzcdrom (%s) is not configuredF)openreadIOErrorrI   rJ   )	cdrom_devfpr/   r/   r0   _check_freebsd_cdrom  s    r  c             C   sD   |  d k r d St  j |  d d d d } t j |  j   } | S)zLReturn content random seed file if available, otherwise,
       return None.NquietTdecodeF)r   r   r{  Z	b64encoder  )sourcer}   r/   r/   r0   r     s
    r   c              C   sm   g  }  t  j   r. d } t |  rY | g Sn+ x( d D]  } |  j t  j d |   q5 W|  j d d  |  S)Nz/dev/cd0iso9660r   zTYPE=%sreverseT)r  zudf)r   r   r  r   rD  sort)rR   r  Zfstyper/   r/   r0   r     s    
r   c             C   s   t  j j |  d  } t  j j |  s3 t d   t | d   } | j   } Wd  QRXt |  \ } } } | | | d | i f S)Nzovf-env.xmlzNo ovf-env file foundrb)rz   r{   rK   r   r   r  r  r/  )Z
source_dirZovf_filer  r%  r   r0  rt   r/   r/   r0   r     s    r   )r(  c             C   s   |  t  j k ra |  ra y t |   SWn; t k
 r` } z t j d t |   WYd d } ~ Xn Xy t   SWn; t k
 r } z t j d t |   WYd d } ~ Xn Xi  S)a_  Convert imds_metadata dictionary to network v2 configuration.
    Parses network configuration from imds metadata if present or generate
    fallback network config excluding mlx4_core devices.

    @param: imds_metadata: Dict of content read from IMDS network service.
    @return: Dictionary containing network version 2 standard configuration.
    z?Failed generating network config from IMDS network metadata: %sNz-Failed generating fallback network config: %s)r   r   +_generate_network_config_from_imds_metadatarq   rI   r   rU   -_generate_network_config_from_fallback_config)imds_metadataru   r/   r/   r0   r9    s    	 )r9  c          	   C   s  d d d i  i } |  d } xt  | d  D]\ } } d } d j d |  } d	 | d
 d i } d d d | d d i } x d& D] }	 | j |	 i   j d g   }
 |
 s q d } |	 d k r d } n  d } |
 r d | d <| | d <x| |
 d
 d  D]j } | |	 d d j d |  } | d } | j d  sDg  | d <| d j d j d | d |   q Wq W| r- | r- d j t j d | d    } | j d! d" | j   i d# | i  t	 |  } | r| d$ k r| | d! d% <| | d | <q- W| S)'a  Convert imds_metadata dictionary to network v2 configuration.
    Parses network configuration from imds metadata.

    @param: imds_metadata: Dict of content read from IMDS network service.
    @return: Dictionary containing network version 2 standard configuration.
    versionr%   Z	ethernetsr-   r[   Fzeth{idx}idxzroute-metricr4   re   Zdhcp4Tzdhcp4-overridesZdhcp6ipv4ipv6Z	ipAddressZ24Z128zdhcp6-overridesNZsubnetr   prefixZprivateIpAddress	addressesz{ip}/{prefix}Zip:z..Z
macAddressmatchZ
macaddresszset-nameZ	hv_netvscdriver)r  r  )
	enumerater*   ro   r   rK   r7   findallr   r   r   )r  Z	netconfigZnetwork_metadatar  ZintfZhas_ip_addressZnicnameZdhcp_overrideZ
dev_configZ	addr_typer  Zdefault_prefixZaddrZ	netPrefixZ	privateIpZmacr  r/   r/   r0   r    sL    
	




	r  c               C   s   t  j d t d d  S)zGenerate fallback network config excluding blacklisted devices.

    @return: Dictionary containing network version 2 standard configuration.
    r   Zconfig_driverT)r	   Zgenerate_fallback_configr   r/   r/   r/   r0   r  :  s    	r  c             C   s   d t  j d d d t d | | | f i } t j |   rF t j |   Sy( t t |    t j |   SWd QRXWn? t	 k
 r } z t
 d | d t  j   WYd d } ~ Xn Xd S)	a  Query Azure's instance metadata service, returning a dictionary.

    If network is not up, setup ephemeral dhcp on fallback_nic to talk to the
    IMDS. For more info on IMDS:
        https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service

    @param fallback_nic: String. The name of the nic which requires active
        network in order to query IMDS.
    @param retries: The number of retries of the IMDS_URL.
    @param md_type: Metadata type for IMDS request.
    @param api_version: IMDS api-version to use in the request.

    @return: A dict of instance metadata containing compute and network
        info.
    r   r   z/Crawl of Azure Instance Metadata Service (IMDS)r   r   Nz$exception while getting metadata: %srm   )rI   rJ   _get_metadata_from_imdsr	   r   r   r   r   r   rq   r   rr   )r   r   r   r   rS  ru   r/   r/   r0   r   D  s    	

r   c       	   &   C   sK  d j  | j |  } d d i } y( t | d t d | d |  d t } Wnd t k
 r } zD t | t  r | j d k r   n t	 d	 | d
 t
 j i  SWYd  d  } ~ Xn Xy d d l m } | } Wn t k
 r t } Yn Xy t j t |   SWnH | k
 rF} z( t	 d t |  | f d
 t
 j WYd  d  } ~ Xn Xi  S)Nz{}?api-version={}r  r  r   r!  r   r"  i  zBIgnoring IMDS instance metadata. Get metadata from IMDS failed: %srm   r   )JSONDecodeErrorz`Ignoring non-json IMDS instance metadata response: %s. Loading non-json IMDS response failed: %s)r*   r   r   r$  r   rq   rh   r   r   r   rI   rr   Zjson.decoderr  ImportError
ValueErrorr   Z	load_jsonrU   )	r   r   r   r&  r!  Zresponseru   r  Zjson_decode_errorr/   r/   r0   r  j  s6    

r  c             C   s   |  s t  }  d } xn |  D]f } t j j |  r | sP t j d t j  d } t j j |  rr t	 j
 |  q t	 j |  q Wd S)a(  Remove Azure-specific ubuntu network config for non-primary nics.

    @param paths: List of networking scripts or directories to remove when
        present.

    In certain supported ubuntu images, static udev rules or netplan yaml
    config is delivered in the base ubuntu image to support dhcp on any
    additional interfaces which get attached by a customer at some point
    after initial boot. Since the Azure datasource can now regenerate
    network configuration as metadata reports these new devices, we no longer
    want the udev rules or netplan's 90-hotplug-azure.yaml to configure
    networking on eth1 or greater as it might collide with cloud-init's
    configuration.

    Remove the any existing extended network scripts if the datasource is
    enabled to write network per-boot.
    Fz{Removing Ubuntu extended network scripts because cloud-init updates Azure network configuration on the following event: %s.TN)UBUNTU_EXTENDED_NETWORK_SCRIPTSrz   r{   r   rI   r   r
   r   isdirr   Zdel_dirr3  )r   Zloggedr{   r/   r/   r0   r     s    
r   c             C   s   t  j d d d d d t  u } t j d  } | t k r@ d Sd | } | | _ t | d	 t j	 t
 j j t
 j j |  d
   r d Sd SWd QRXd S)z@Check platform environment to report if this datasource may run.r   zcheck-platform-viabilityr   zfound azure asset tagr   zchassis-asset-tagTz(Non-Azure DMI asset tag '%s' discovered.rm   zovf-env.xmlFN)r   r   r   r   r   AZURE_CHASSIS_ASSET_TAGr   r   rI   rJ   rz   r{   r   rK   )r|   rM  Z	asset_tagr   r/   r/   r0   r     s    		
	!r   c               @   s   e  Z d  Z d S)r   N)r'   r(   r)   r/   r/   r/   r0   r     s   r   c               @   s   e  Z d  Z d S)r   N)r'   r(   r)   r/   r/   r/   r0   r     s   r   c             C   s   t  j |  t  S)N)r   Zlist_from_dependsdatasources)Zdependsr/   r/   r0   get_datasource_list  s    r  )r{  
contextlibr  	functoolsr   rz   os.pathr7   r   r   Zxml.domr   Zxml.etree.ElementTreeZetreeZElementTreer`  Zenumr   Z	cloudinitr   r   Zloggingr	   Zcloudinit.eventr
   Zcloudinit.netr   Zcloudinit.net.dhcpr   r   Zcloudinit.sources.helpersr   r   Zcloudinit.url_helperr   r   r   r   Zcloudinit.reportingr   Zcloudinit.sources.helpers.azurer   r   r   r   r   r   r   r   r   r   r   r    Z	getLoggerr'   rI   r  r   ZAGENT_STARTr2  rY  rX  r   ZDEFAULT_PRIMARY_NICZ
LEASE_FILEZ
DEFAULT_FSr  r   r   r  r
  ZAGENT_SEED_DIRr$  r+   r   r   r&   ZPLATFORM_ENTROPY_SOURCEr  r   r@   rC   rF   rN   rP   rS   rT   rV   r   Zres_diskrJ   r   r   r   r6  ZDEF_EPHEMERAL_LABELrd  rl   rY   contextmanagerrv   rx   rw   rC  rE  rN  r5  r   r]  r   r   r   rm  rv  r/  r  r  r  r  r  r   r   r   r=  r9  r  r  r,   r   r  r   r   rq   r   r   ZDataSourceAzureNetZDEP_FILESYSTEMr  r  r/   r/   r/   r0   <module>   s(  R			+				    [T%$

5i/=	"!$