U
    Lde                     @   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mZ d dlm	Z	m
Z
 d dlmZmZmZmZmZ d dlmZmZmZ d dlmZ d dlmZ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" d dl#m$Z$ d dl%m&Z& d dl'm(Z( d dl)m*Z* dZ+dZ,dZ-dZ.e+e,e-gZ/dZ0dZ1dZ2dZ3dZ4dZ5dZ6dZ7e8e9Z:ddd fd d!d fd"d#d fd$Z;e
G d%d& d&e	Z<G d'd( d(e=Z>G d)d* d*e=Z?G d+d, d,e=Z@dYd/d0ZAe4fd1d2ZBed3d4d5d6d7gZCed8d9d:gZDG d;d de(e jEd<ZFd=d> ZGeeFeHf d?d@dAZIdBdC ZJdZeHeKdEdFdGZLdHdI ZMd[dKdLZNG dMdN dNeOZPdOdP ZQeFeHeKdQdRdSZReHeeF dTdUdVZSeHd?dWdXZTdS )\    N)
namedtuple)Enumunique)AnyDictListOptionalTuple)atomic_helperdmiimporter)log)net
type_utils)	user_data)util)
write_json)Distro)
EventScope	EventType)launch_index)Paths)CloudInitPickleMixin)eventsZdisabledlocalr   passZ
FILESYSTEMNETWORK
DataSourcez|EXPERIMENTAL: The structure and format of content scoped under the 'ds' key may change in subsequent releases of cloud-init.zredacted for non-root user
cloud-nameZ_unsetunknownz	aws-chinac                 C   s   | dkS NZaws cr!   r!   </usr/lib/python3/dist-packages/cloudinit/sources/__init__.py<lambda>@       r%   zaws-govc                 C   s   | dkS r    r!   r"   r!   r!   r$   r%   A   r&   zazure-chinac                 C   s   | dkS )NZazurer!   r"   r!   r!   r$   r%   B   r&   )zcn-zus-gov-Zchinac                   @   s2   e Zd ZdZdZdZdZdZdZe	ddd	Z
d
S )NetworkConfigSourcezb
    Represents the canonical list of network config sources that cloud-init
    knows about.
    cmdlinedsZ
system_cfgZfallbackZ	initramfsreturnc                 C   s   | j S Nvalueselfr!   r!   r$   __str__S   s    zNetworkConfigSource.__str__N)__name__
__module____qualname____doc__CMD_LINEDS
SYSTEM_CFGZFALLBACK	INITRAMFSstrr1   r!   r!   r!   r$   r'   F   s   r'   c                   @   s   e Zd ZdZdS )DatasourceUnpickleUserDataErrorzERaised when userdata is unable to be unpickled due to python upgradesNr2   r3   r4   r5   r!   r!   r!   r$   r;   W   s   r;   c                   @   s   e Zd ZdS )DataSourceNotFoundExceptionNr2   r3   r4   r!   r!   r!   r$   r=   [   s   r=   c                   @   s   e Zd ZdZdS )InvalidMetaDataExceptionz8Raised when metadata is broken, unavailable or disabled.Nr<   r!   r!   r!   r$   r?   _   s   r?    r!   c           
      C   s   t | }g }g }|  D ]\}}|r4|d | }n|}| |ksP| |krZ|| t|tr|dr|| |dd||< t|t	rt
|||}	||	d ||	d |	||< qt||d< t||d< |S )zProcess all instance metadata cleaning it up for persisting as json.

    Strip ci-b64 prefix and catalog any 'base64_encoded_keys' as a list

    @return Dict copy of processed metadata.
    /zci-b64:r@   base64_encoded_keyssensitive_keys)copydeepcopyitemslowerappend
isinstancer:   
startswithreplacedictprocess_instance_metadataextendpopsorted)
metadatakey_pathrC   md_copyrB   Z	sens_keyskeyvalZsub_key_pathZ
return_valr!   r!   r$   rM   c   s6    





  
rM   c                 C   s   |  dg s| S t| }|  dD ]V}|d}|}|D ].}||kr:t|| tr:||d kr:|| }q:||kr$|||< q$|S )zRedact any sensitive keys from to provided metadata dictionary.

    Replace any keys values listed in 'sensitive_keys' with redact_value.
    rC   rA   )getrD   rE   splitrI   rL   )rQ   Zredact_valuerS   rR   
path_partsobjpathr!   r!   r$   redact_sensitive_keys   s"    




r\   	URLParamsZmax_wait_secondsZtimeout_secondsZnum_retriessec_between_retriesDataSourceHostnamehostname
is_defaultc                	   @   s  e Zd ZU eZdZdZdZdZdZ	dZ
ejejejejfZeedf ed< dZdZdZd	ZejejejejejhiZejejhiZd
e fde fdi fddddddf	Z!eee"e#f df ed< dZ$dZ%ee"df ed< dZ&d	Z'dxe(e)dddZ*e+ddddZ,dd Z-e.dd d!Z/e.dd"d#Z0d$d% Z1d&d' Z2dyd)d*Z3e.dd+d,Z4dzd.d/Z5e.dd0d1Z6d2d3 Z7d{d4d5Z8d6d7 Z9d8d9 Z:e;d:d; Z<e;d<d= Z=e;d>d? Z>d@dA Z?e;dBdC Z@dDdE ZAe;dFdG ZBdHdI ZCe;dJdK ZDdLdM ZEdNdO ZFdPdQ ZGdRdS ZHdTdU ZIdVdW ZJdXdY ZKdZd[ ZLd\d] ZMe;d^d_ ZNe;d`da ZOdbdc ZPd|dddeZQdfdg ZReSe dhdidjZTeSe e.dkdldmZUdndo ZVeWd}dpdqZXe;drds ZYdtdu ZZdvdw Z[dS )~r   zen_US.UTF-8Z_undefN.network_config_sourcesrV   
         ec2_metadatanetwork_jsonrQ   )userdataN)userdata_rawN)
vendordataN)vendordata_rawN)vendordata2N)vendordata2_rawNcached_attr_defaultsF)
Zcombined_cloud_config
merged_cfgmerged_system_cfgzsecurity-credentialsrh   	user-datar   rj   vendor-datazds/vendor_datasensitive_metadata_keys)distropathsc                 C   s~   || _ || _|| _d | _i | _d | _d | _d | _d | _d | _	t
| j d| jfi | _| js`i | _|stt| j| _n|| _d S )NZ
datasource)sys_cfgrt   ru   rh   rQ   ri   rj   rl   rk   rm   r   Zget_cfg_by_pathdsnameds_cfgudZUserDataProcessorud_proc)r0   rv   rt   ru   rz   r!   r!   r$   __init__  s(      zDataSource.__init__)ci_pkl_versionr+   c              
   C   s   t | dsd| _t | ds d| _t | ds0d| _t | dr| jdk	rzt| j W n6 tk
r } ztd| t	 |W 5 d}~X Y nX dS )z(Perform deserialization fixes for Paths.rl   Nrm   skip_hotplug_detectFrh   z:Unable to unpickle datasource: %s. Ignoring current cache.)
hasattrrl   rm   r}   rh   r:   AttributeErrorLOGdebugr;   )r0   r|   er!   r!   r$   	_unpickle4  s    


zDataSource._unpicklec                 C   s
   t | S r,   r   obj_namer/   r!   r!   r$   r1   L  s    zDataSource.__str__r*   c                 C   s   dS )z#Check if running on this datasourceTr!   r/   r!   r!   r$   	ds_detectO  s    zDataSource.ds_detectc                 C   sX   | j  t  kr$td|  dS | jdg | j g| j dgfkrTtd|  dS dS )aI  Override if either:
        - only a single datasource defined (nothing to fall back to)
        - commandline argument is used (ci.ds=OpenStack)

        Note: get_cmdline() is required for the general case - when ds-identify
        does not run, _something_ needs to detect the kernel command line
        definition.
        zOMachine is configured by the kernel commandline to run on single datasource %s.TZdatasource_listNonez5Machine is configured to run on single datasource %s.F)rw   rG   parse_cmdliner   r   rv   rW   r/   r!   r!   r$   override_ds_detectS  s     	 zDataSource.override_ds_detectc                 C   s@   |   r|  S |  r,td|  |  S td|  dS dS )z&Overrides runtime datasource detectionz8Detected platform: %s. Checking for active instance dataz#Datasource type %s is not detected.FN)r   	_get_datar   r   r   r/   r!   r!   r$   _check_and_get_datam  s    zDataSource._check_and_get_datac                 C   s   |   j}|  }| j}|d }ddg||t| j| j| j| j| j|d d |d d |d d | j|  |d |||d	 d |||d	 d
 | j| j	|d |d diS )z2Return a dictionary of standardized metadata keys.sys_infov1subplatformZdistr   re      pythonuname   platformvariant)Z
_beta_keysavailability-zoneavailability_zonecloud_idr   
cloud_namert   Zdistro_versionZdistro_releaser   Zpublic_ssh_keysZpython_versioninstance-idinstance_idZkernel_releaselocal-hostnamelocal_hostnamemachineregionr   Zsystem_platformr   )
get_hostnamer`   get_instance_idr   canonical_cloud_idr   r   platform_typeget_public_ssh_keysr   )r0   instance_datar   r   r   Zsysinfor!   r!   r$   _get_standardized_metadata{  sB    
  




z%DataSource._get_standardized_metadatar!   c                 C   sL   | j s
dS |r|}n| j}|D ]\}}t| |rt| || q|sHd| _ dS )zReset any cached metadata attributes to datasource defaults.

        @param attr_defaults: Optional tuple of (attr, value) pairs to
           set instead of cached_attr_defaults.
        NF)_dirty_cachern   r~   setattr)r0   Zattr_defaultsZattr_valuesZ	attributer.   r!   r!   r$   clear_cached_attrs  s    
zDataSource.clear_cached_attrsc                 C   s"   d| _ |  }|s|S |   |S )zDatasources implement _get_data to setup metadata and userdata_raw.

        Minimally, the datasource should return a boolean True on success.
        T)r   r   persist_instance_data)r0   Zreturn_valuer!   r!   r$   get_data  s    zDataSource.get_dataTc              
   C   s  |r&t j| jjr&t| | jd t| drbt	t
| d}|dd |dd d|i}n^dd| jii}t| drt
| d}|tkr||d d< t| d	rt
| d	}|tkr||d d	< t|d d
< t	| j|d< d|d d
< t	|d |d< d|d d
< t |d< || | z"t|}tt|| jd}W nr tk
r~ } ztdt| W Y dS d}~X Y n: tk
r } ztdt| W Y dS d}~X Y nX | jd}	|d  dd}
t j!| jj"d}t#| d|
 |
 d d}| d|
 }t j$|r.t j%|}tj&||dd |rX||krXt'| t(|	|dd | jd}t(|t)| dS )aP  Process and write INSTANCE_JSON_FILE with all instance metadata.

        Replace any hyphens with underscores in key names for use in template
        processing.

        :param write_cache: boolean set True to persist obj.pkl when
            instance_link exists.

        @return True on successful write, False otherwise.
        Zobj_pklZ_crawled_metadatarq   Nrr   r)   Z	meta_datarg   rf   Z_docro   z<DEPRECATED: Use merged_system_cfg. Will be dropped from 24.1rp   zUMerged cloud-init system config from /etc/cloud/cloud.cfg and /etc/cloud/cloud.cfg.d/r   )rC   z'Error persisting instance-data.json: %sFZinstance_data_sensitiver   r   Znonezcloud-id-
T)Zforcei  )moder   )*osr[   lexistsru   Zinstance_link	pkl_storeZget_ipath_curr~   rD   rE   getattrrO   rQ   UNSETEXPERIMENTAL_TEXTrv   r   Zsystem_infoupdater   r
   Z
json_dumpsrM   jsonloadsrs   	TypeErrorr   warningr:   UnicodeDecodeErrorZget_runpathrW   joinZrun_dir
write_fileexistsrealpathZsym_linkZdel_filer   r\   )r0   Zwrite_cacheZcrawled_metadatar   rg   rf   ZcontentZprocessed_datar   Zjson_sensitive_filer   Zcloud_id_fileZprev_cloud_id_fileZnew_cloud_id_fileZ	json_filer!   r!   r$   r     st    









z DataSource.persist_instance_datac                 C   s   t ddS )z@Walk metadata sources, process crawled data and save attributes.zlSubclasses of DataSource must implement _get_data which sets self.metadata, vendordata_raw and userdata_raw.N)NotImplementedErrorr/   r!   r!   r$   r     s    zDataSource._get_datac              
   C   sL  | j }zt| jd| j }W n, tk
rJ   ttd| jd| Y nX | j}zt	dt| jd| j}W n2 tk
r   | j}ttd| jd| Y nX | j
}zt| jd| j
}W n, tk
r   ttd| jd| Y nX | j}zt| jd| j}W n. tk
r<   ttd	| jd| Y nX t||||S )
zReturn the Datasource's preferred url_read parameters.

        Subclasses may override url_max_wait, url_timeout, url_retries.

        @return: A URLParams object with max_wait_seconds, timeout_seconds,
            num_retries.
        max_waitz6Config max_wait '%s' is not an int, using default '%s'r   timeoutz5Config timeout '%s' is not an int, using default '%s'retriesz5Config retries '%s' is not an int, using default '%s'r^   zAConfig sec_between_retries '%s' is not an int, using default '%s')url_max_waitintrx   rW   
ValueErrorr   logexcr   url_timeoutmaxurl_retries	Exceptionurl_sec_between_retriesr]   )r0   r   r   r   r^   r!   r!   r$   get_url_params  s^    





 

zDataSource.get_url_paramsc                 C   s2   | j d kr| j|  | _ |r,| | j S | j S r,   )rh   rz   processget_userdata_raw_filter_xdata)r0   Zapply_filterr!   r!   r$   get_userdataU  s
    
zDataSource.get_userdatac                 C   s"   | j d kr| j|  | _ | j S r,   )rj   rz   r   get_vendordata_rawr/   r!   r!   r$   get_vendordata\  s    
zDataSource.get_vendordatac                 C   s"   | j d kr| j|  | _ | j S r,   )rl   rz   r   get_vendordata2_rawr/   r!   r!   r$   get_vendordata2a  s    
zDataSource.get_vendordata2c                 C   s2   | j dkr,t | _ | j dkr,td| j | j S )zADetermine the network interface used during local network config.Nz(Did not find a fallback interface on %s.)_fallback_interfacer   Zfind_fallback_nicr   r   r   r/   r!   r!   r$   fallback_interfacef  s    


 zDataSource.fallback_interfacec                 C   s.   t | ds| j | _| js(| j | _| jS )N_platform_type)r~   rw   rG   r   r/   r!   r!   r$   r   q  s
    
zDataSource.platform_typec                 C   s*   t | ds|  | _| js$|  | _| jS )a  Return a string representing subplatform details for the datasource.

        This should be guidance for where the metadata is sourced.
        Examples of this on different clouds:
            ec2:       metadata (http://169.254.169.254)
            openstack: configdrive (/dev/path)
            openstack: metadata (http://169.254.169.254)
            nocloud:   seed-dir (/seed/dir/path)
            lxd:   nocloud (/seed/dir/path)
        _subplatform)r~   _get_subplatformr   r/   r!   r!   r$   r   z  s
    


zDataSource.subplatformc                 C   s   t | drdt| d S tS )z?Subclasses should implement to return a "slug (detail)" string.Zmetadata_addresszmetadata (%s))r~   r   METADATA_UNKNOWNr/   r!   r!   r$   r     s    
zDataSource._get_subplatformc                 C   sv   | j r| j S | jrb| jtrb| jt}t|tr@| | _ qp|   | _ t	dtt
| n|   | _ | j S )zReturn lowercase cloud name as determined by the datasource.

        Datasource can determine or define its own cloud product name in
        metadata.
        z5Ignoring metadata provided key %s: non-string type %s)_cloud_namerQ   rW   METADATA_CLOUD_NAME_KEYrI   r:   rG   _get_cloud_namer   r   type)r0   r   r!   r!   r$   r     s    
zDataSource.cloud_namec                 C   s   | j S )zReturn the datasource name as it frequently matches cloud name.

        Should be overridden in subclasses which can run on multiple
        cloud names, such as DatasourceEc2.
        )rw   r/   r!   r!   r$   r     s    zDataSource._get_cloud_namec                 C   s"   | j s
d S d| j kr| j d S d S )Nzlaunch-index)rQ   r/   r!   r!   r$   r     s
    

zDataSource.launch_indexc                 C   s0   t t| j g}|}|D ]}||}q|S r,   )r   ZFilterr   Zsafe_intZapply)r0   Zprocessed_udfiltersZnew_udfr!   r!   r$   r     s    zDataSource._filter_xdatac                 C   s   dS NFr!   r/   r!   r!   r$   is_disconnected  s    zDataSource.is_disconnectedc                 C   s   | j S r,   )ri   r/   r!   r!   r$   r     s    zDataSource.get_userdata_rawc                 C   s   | j S r,   )rk   r/   r!   r!   r$   r     s    zDataSource.get_vendordata_rawc                 C   s   | j S r,   )rm   r/   r!   r!   r$   r     s    zDataSource.get_vendordata2_rawc                 C   s   i S r,   r!   r/   r!   r!   r$   get_config_obj  s    zDataSource.get_config_objc                 C   s   t | jdS )Nzpublic-keys)normalize_pubkey_datarQ   rW   r/   r!   r!   r$   r     s    zDataSource.get_public_ssh_keysc                 C   s   dS )a5  Publish the public SSH host keys (found in /etc/ssh/*.pub).

        @param hostkeys: List of host key tuples (key_type, key_value),
            where key_type is the first field in the public key file
            (e.g. 'ssh-rsa') and key_value is the key itself
            (e.g. 'AAAAB3NzaC1y...').
        Nr!   )r0   Zhostkeysr!   r!   r$   publish_host_keys  s    zDataSource.publish_host_keysc                 C   sd   ddi}|  D ]N\}}||s$q|D ]4}d||t|d  f }tj|r(|    S q(qd S )NZsd)ZvdZxvdZvtbz	/dev/%s%s)rF   rJ   lenr   r[   r   )r0   Z
short_nameZmappingsZnfromZtlistZntoZcandr!   r!   r$   _remap_device  s    
zDataSource._remap_devicec                 C   s   d S r,   r!   )r0   _namer!   r!   r$   device_name_to_device  s    z DataSource.device_name_to_devicec                 C   s.   | j }z| j }W n tk
r(   Y nX |S )z<Default locale is en_US.UTF-8, but allow distros to override)default_localert   
get_localer   )r0   Zlocaler!   r!   r$   r     s    zDataSource.get_localec                 C   s2   | j d| j d}|r|S | j di dS )Nr   r   Z	placementrQ   rW   )r0   Ztop_level_azr!   r!   r$   r     s     
zDataSource.availability_zonec                 C   s   | j dS )Nr   r   r/   r!   r!   r$   r     s    zDataSource.regionc                 C   s"   | j rd| j krdS t| j d S )Nr   ziid-datasource)rQ   r:   r/   r!   r!   r$   r     s    zDataSource.get_instance_idc                 C   s^  d}d}|}d}| j r"| j ds|r0td|S g }t }	|	dkrHd}t|	}
|
rt|
ddkrtt|
d}n8|	r|	ddkrt|	d}n|	r|	|g}n||g}nX| j d }t	
|rg }|rt|}|rt|d}nd	|dd
 g}n
|d}t|dkr0|d }	d|dd }n|d }	|rT||krTd|	|f }	t|	|S )a  Get hostname or fqdn from the datasource. Look it up if desired.

        @param fqdn: Boolean, set True to return hostname with domain.
        @param resolve_ip: Boolean, set True to attempt to resolve an ipv4
            address provided in local-hostname meta-data.
        @param metadata_only: Boolean, set True to avoid looking up hostname
            if meta-data doesn't have local-hostname present.

        @return: a DataSourceHostname namedtuple
            <hostname or qualified hostname>, <is_default> (str, bool).
            is_default is a bool and
            it's true only if hostname is localhost and was
            returned by util.get_hostname() as a default.
            This is used to differentiate with a user-defined
            localhost hostname.
            Optionally return (None, False) when
            metadata_only is True and local-hostname data is not available.
        ZlocaldomainZ	localhostFr   NT.r   zip-%sr   re   z%s.%s)rQ   rW   r_   r   r   Zget_fqdn_from_hostsfindr:   rX   r   Zis_ipv4_addressZgethostbyaddrrK   r   r   )r0   ZfqdnZ
resolve_ipZmetadata_onlyZ	defdomainZdefhostZdomainra   Ztoksr`   Z
hosts_fqdnZlhostr!   r!   r$   r     sF    







zDataSource.get_hostnamec                 C   s   | j j| dS )N)Zdata_source)rt   get_package_mirror_infor/   r!   r!   r$   r   _  s    z"DataSource.get_package_mirror_info)source_event_typesc                 C   sP   i }|D ]B}| j  D ]2\}}||kr||s:t ||< || | qq|S r,   )supported_update_eventsrF   rW   setadd)r0   r   supported_eventseventZupdate_scopeZupdate_eventsr!   r!   r$   get_supported_eventsb  s    

zDataSource.get_supported_events)r   r+   c              	   C   s   |  |}| D ]<\}}td|jddd |D  | d| tff q|rl|   |  }|rldS td| ddd |D  d	S )
a  Refresh cached metadata if the datasource supports this event.

        The datasource has a list of supported_update_events which
        trigger refreshing all cached metadata as well as refreshing the
        network configuration.

        @param source_event_types: List of EventTypes which may trigger a
            metadata update.

        @return True if the datasource did successfully update cached metadata
            due to source_event_type.
        z:Update datasource metadata and %s config due to events: %s, c                 S   s   g | ]
}|j qS r!   r-   .0r   r!   r!   r$   
<listcomp>  s     z;DataSource.update_metadata_if_supported.<locals>.<listcomp>z
_%s_configTz(Datasource %s not updated for events: %sc                 S   s   g | ]
}|j qS r!   r-   r   r!   r!   r$   r     s     F)	r   rF   r   r   r.   r   r   r   r   )r0   r   r   ZscopeZmatched_eventsresultr!   r!   r$   update_metadata_if_supportedo  s&    
z'DataSource.update_metadata_if_supportedc                 C   s   dS r   r!   )r0   rv   r!   r!   r$   check_instance_id  s    zDataSource.check_instance_idc                 C   sV   |d krt }|d krt}| D ]4}|d kr*q||kr:|  S td|| |  S q|S )Nz%invalid dsmode '%s', using default=%s)DSMODE_NETWORKVALID_DSMODESr   r   )Z
candidatesdefaultZvalid	candidater!   r!   r$   _determine_dsmode  s       
zDataSource._determine_dsmodec                 C   s   d S r,   r!   r/   r!   r!   r$   network_config  s    zDataSource.network_configc                 C   s   dS )a(  setup(is_new_instance)

        This is called before user-data and vendor-data have been processed.

        Unless the datasource has set mode to 'local', then networking
        per 'fallback' or per 'network_config' will have been written and
        brought up the OS at this point.
        Nr!   )r0   is_new_instancer!   r!   r$   setup  s    	zDataSource.setupc                 C   s   dS )a  activate(cfg, is_new_instance)

        This is called before the init_modules will be called but after
        the user-data and vendor-data have been fully processed.

        The cfg is fully up to date config, it contains a merged view of
           system config, datasource config, user config, vendor config.
        It should be used rather than the sys_cfg passed to __init__.

        is_new_instance is a boolean indicating if this is a new instance.
        Nr!   )r0   Zcfgr  r!   r!   r$   activate  s    zDataSource.activate)N)r!   )T)F)FFF)NN)\r2   r3   r4   r   Zdsmoder   rw   r   r   r   r   r'   r6   r9   r8   r7   rb   r	   __annotations__r   r   r   r   r   r   r   BOOT_NEW_INSTANCEZBOOTZBOOT_LEGACYZHOTPLUGr   Zdefault_update_eventsr   rn   r:   r   r   rs   r}   Z_ci_pkl_versionr   r   r{   r   r   r1   boolr   r   r   r   r   r   r   r   r   r   r   r   propertyr   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   staticmethodr  r  r  r  r!   r!   r!   r$   r      s   
	
&

R<






	
		


H&
)	metaclassc                 C   s   g }| s|S t | tr|  S t | ttfr4t| S t | tr|  D ]>\}}t |tr^|g}t |ttfrF|D ]}|rp|| qpqF|S r,   )rI   r:   
splitlineslistr   rL   rF   rH   )Zpubkey_datakeysZ_keynameZklistZpkeyr!   r!   r$   r     s     


r   r*   c                 C   s"  t |||}dd |D }t|kr&dnd}	td|	| t||D ]\}
}tjd|
dd d	|	|
f d
|	|
f |d}zh|Z td| || ||}|t	j
grd|	|
f |_|t|fW  5 Q R  W   S W 5 Q R X W qB tk
r   ttd| Y qBX qBdd| }t|d S )Nc                 S   s   g | ]}t |qS r!   r   )r   r   r!   r!   r$   r     s     zfind_source.<locals>.<listcomp>Znetworkr   z#Searching for %s data source in: %sz	search-%sr   r@   zsearching for %s data from %szno %s data found from %s)nameZdescriptionmessageparentz%Seeing if we can get any data from %szfound %s data from %szGetting data from %s failedz4Did not find any data source, searched classes: (%s)r   )list_sourcesDEP_NETWORKr   r   zipr   ZReportEventStackrK   r   r   r  r  r   r   r   r   r   r   r=   )rv   rt   ru   Zds_depscfg_listpkg_listZreporterds_listZds_namesr   r  clsZmyrepsmsgr!   r!   r$   find_source  s4    

.r  c                 C   s   g }t d| || | D ]j}t|}t||dg\}}|sJt d| |D ]2}t|}	t|	d}
|
|}|rN||  qqNq|S )zReturn a list of classes that have the same depends as 'depends'
    iterate through cfg_list, loading "DataSource*" modules
    and calling their "get_datasource_list".
    Return an ordered list of classes that match (if any)
    zLLooking for data source in: %s, via packages %s that matches dependencies %sZget_datasource_listzDCould not import %s. Does the DataSource exist and is it importable?)	r   r   r   Z"match_case_insensitive_module_namefind_moduleerrorimport_moduler   rN   )r  dependsr  Zsrc_listr)   Zds_nameZm_locsZ_looked_locsZm_locmodZlisterZmatchesr!   r!   r$   r    s6    
  


r  system-uuid)fieldr+   c                 C   s*   | sdS t |}|sdS |  | kS r   )r   Zread_dmi_datarG   )r   r"  Z	dmi_valuer!   r!   r$   instance_id_matches_system_uuid/  s    
r#  c                 C   sl   | st } |st }|t kr(| t kr$| S |S t D ]*\}}|\}}||r0|| r0|  S q0| t krh| S |S )z@Lookup the canonical cloud-id for a given cloud_name and region.)r   CLOUD_ID_REGION_PREFIX_MAPrF   rJ   )r   r   r   prefixZcloud_id_testr   Zvalid_cloudr!   r!   r$   r   =  s    
r   Tc                 C   sj   | sdS t | tr| S t | tr*t| S t | trV|dkrNt| dddS tdtdt	|  dS )aL  data: a loaded object (strings, arrays, dicts).
    return something suitable for cloudinit vendordata_raw.

    if data is:
       None: return None
       string: return string
       list: return data
             the list is then processed in UserDataProcessor
       dict: return convert_vendordata(data.get('cloud-init'))
    NTz
cloud-initF)recursez'vendordata['cloud-init'] cannot be dictz$Unknown data type for vendordata: %s)
rI   r:   r  rD   rE   rL   convert_vendordatarW   r   r   )datar&  r!   r!   r$   r'  P  s    



r'  c                   @   s   e Zd ZdS )BrokenMetadataNr>   r!   r!   r!   r$   r)  h  s   r)  c                 C   s4   g }t | }|D ]\}}|t |kr|| q|S r,   )r   rH   )r  r  Zret_listZdepsetr  Zdepsr!   r!   r$   list_from_dependss  s    r*  )rZ   fnamer+   c                 C   st   zt | }W n$ tk
r2   ttd|  Y dS X ztj||ddd W n$ tk
rn   ttd| Y dS X dS )z[Use pickle to serialize Datasource to a file as a cache.

    :return: True on success
    zFailed pickling datasource %sFwb   )Zomoder   z Failed pickling datasource to %sT)pickledumpsr   r   r   r   r   )rZ   r+  Zpk_contentsr!   r!   r$   r   |  s    r   )r+  r+   c              
   C   s   d}zt j| dd}W n< tk
rR } ztj| rBtd| | W 5 d}~X Y nX |s\dS zt	|W S  t
k
r~   Y dS  tk
r   t td|  Y dS X dS )zBUse pickle to deserialize a instance Datasource from a cache file.NF)decodezfailed loading pickle in %s: %sz#Failed loading pickled blob from %s)r   Z	load_filer   r   r[   isfiler   r   r.  r   r;   r   )r+  Zpickle_contentsr   r!   r!   r$   pkl_load  s     r2  c                  C   s   t  } td| }td| }td| }|p6|p6|}|p>|}|rv|d }t jd| d| dd| d	d
 |r|dr|dS dS )zCheck if command line argument for this datasource was passed
    Passing by command line overrides runtime datasource detection
    zds=([^\s;]+)zci\.ds=([^\s;]+)zci\.datasource=([^\s;]+)re   z7Defining the datasource on the commandline using ci.ds=z or ci.datasource=z23.2zUse ds=z instead)
deprecatedZdeprecated_versionZextra_messager@   )r   Zget_cmdlineresearchgroupstripZ	deprecate)r(   Z
ds_parse_0Z
ds_parse_1Z
ds_parse_2r)   r3  rw   r!   r!   r$   r     s     
	
r   )r@   r!   )r!  )T)UabcrD   r   r   r.  r4  collectionsr   enumr   r   typingr   r   r   r   r	   Z	cloudinitr
   r   r   r   Zloggingr   r   r   ry   r   Zcloudinit.atomic_helperr   Zcloudinit.distrosr   Zcloudinit.eventr   r   Zcloudinit.filtersr   Zcloudinit.helpersr   Zcloudinit.persistencer   Zcloudinit.reportingr   ZDSMODE_DISABLEDZDSMODE_LOCALr   ZDSMODE_PASSr   ZDEP_FILESYSTEMr  Z	DS_PREFIXr   ZREDACT_SENSITIVE_VALUEr   r   r   Z	getLoggerr2   r   r$  r'   r   r;   r=   r?   rM   r\   r]   r_   ABCMetar   r   r:   r  r  r  r#  r   r'  IOErrorr)  r*  r   r2  r   r!   r!   r!   r$   <module>   s   





#
       
!% 
	