U
    0h>                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlmZ d dl	m
Z
mZ d dlmZmZmZmZmZmZmZ d dlmZ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  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Z0dZ1e.e/e0gZ2dZ3dZ4dZ5dZ6dZ7dZ8dZ9dZ:e;e<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(eAZBG d)d* d*eAZCG d+d, d,eAZDd^d/d0ZEe7fd1d2ZFed3d4d5d6d7gZGed8d9d:gZHG d;d< d<eZIG d=d de+e jJd>ZKd?d@ ZLeeKeMf dAdBdCZNdDdE ZOd_eMePdGdHdIZQdJdK ZRd`dMdNZSG dOdP dPeTZUdQdR ZVeKeMePdSdTdUZWeMeeK dVdWdXZXeMdAdYdZZYeMeMd[d\d]ZZdS )a    N)
namedtuple)Enumunique)AnyDictList
NamedTupleOptionalTupleUnion)atomic_helperdmiimporter	lifecyclenetperformance
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>G       r(   zaws-govc                 C   s   | dkS r#   r$   r%   r$   r$   r'   r(   H   r)   zazure-chinac                 C   s   | dkS )NZazurer$   r%   r$   r$   r'   r(   I   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.
    ZcmdlinedsZ
system_cfgZfallbackZ	initramfsreturnc                 C   s   | j S Nvalueselfr$   r$   r'   __str__Z   s    zNetworkConfigSource.__str__N)__name__
__module____qualname____doc__CMD_LINEDS
SYSTEM_CFGZFALLBACK	INITRAMFSstrr3   r$   r$   r$   r'   r*   M   s   r*   c                   @   s&   e Zd ZdZdZdZedddZdS )NicOrderzRepresents ways to sort NICsZmacZnic_namer,   c                 C   s   | j S r.   r/   r1   r$   r$   r'   r3   d   s    zNicOrder.__str__N)r4   r5   r6   r7   ZMACZNIC_NAMEr<   r3   r$   r$   r$   r'   r=   ^   s   r=   c                   @   s   e Zd ZdZdS )DatasourceUnpickleUserDataErrorzERaised when userdata is unable to be unpickled due to python upgradesNr4   r5   r6   r7   r$   r$   r$   r'   r>   h   s   r>   c                   @   s   e Zd ZdS )DataSourceNotFoundExceptionNr4   r5   r6   r$   r$   r$   r'   r@   l   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'   rB   p   s   rB    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:rC   base64_encoded_keyssensitive_keys)copydeepcopyitemslowerappend
isinstancer<   
startswithreplacedictprocess_instance_metadataextendpopsorted)
metadatakey_pathrF   md_copyrE   Z	sens_keyskeyvalZsub_key_pathZ
return_valr$   r$   r'   rP   t   s6    





  
rP   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.
    rF   rD   )getrG   rH   splitrL   rO   )rT   Zredact_valuerV   rU   
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 dZeed< eed< eed< dS )HotplugRetrySettingsz
in secondsZforce_retryZsleep_periodZsleep_totalN)r4   r5   r6   r7   bool__annotations__intr$   r$   r$   r'   re      s   
re   c                	   @   s  e Zd ZU eZdZdZdZee	 e
d< dZdZdZeeee	f  e
d< 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)e*dddZ+dZ,ee	 e
d< dZ-d}e.e/dddZ0e1dddd Z2d!d" Z3e4d#d$d%Z5e4d#d&d'Z6d(d) Z7d*d+ Z8d~d-d.Z9e:j;d/d0d1e4d#d2d3Z<dd5d6Z=e4d#d7d8Z>d9d: Z?dd;d<Z@d=d> ZAd?d@ ZBeCdAdB ZDeCdCdD ZEdEdF ZFeCdGdH ZGdIdJ ZHeCdKdL ZIdMdN ZJdOdP ZKdQdR ZLdSdT ZMdUdV ZNdWdX ZOdYdZ ZPd[d\ ZQd]d^ ZRd_d` ZSeCdadb ZTeCdcdd ZUdedf ZVddgdhZWdidj ZXeYe dkdldmZZeYe e4dndodpZ[dqdr Z\dsdt Z]e^ddudvZ_eCdwdx Z`dydz Zad{d| ZbdS )r    zen_US.UTF-8Z_undefN_cloud_name_crawled_metadata.network_config_sourcesrY   
         ec2_metadatanetwork_jsonrT   )userdataN)userdata_rawN)
vendordataN)vendordata_rawN)vendordata2N)vendordata2_rawNcached_attr_defaultsF)
Zcombined_cloud_config
merged_cfgmerged_system_cfgzsecurity-credentialsrq   	user-datar   rs   vendor-datazds/vendor_datasensitive_metadata_keysr   extra_hotplug_udev_rules)distropathsc                 C   s   || _ || _|| _d | _i | _d | _d | _d | _d | _d | _	d | _
t| _t| _t| j d| jfi | _| jsri | _|st| j| _n|| _d S )NZ
datasource)sys_cfgr~   r   rq   rT   rr   rs   ru   rt   rv   metadata_addressUNSETrp   ro   r   Zget_cfg_by_pathdsnameds_cfgudZUserDataProcessorud_proc)r2   r   r~   r   r   r$   r$   r'   __init__T  s.      zDataSource.__init__)ci_pkl_versionr-   c                 C   s   dddt ddt dddtdddd}| D ]\}}t| |s,t| || q,t| dsft| ddd  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.NFr   )rj   _platform_type_subplatformro   r}   r   rp   skip_hotplug_detectru   rv   hotplug_retry_settingscheck_if_fallback_is_allowedc                   S   s   dS NFr$   r$   r$   r$   r'   r(     r)   z&DataSource._unpickle.<locals>.<lambda>rq   z:Unable to unpickle datasource: %s. Ignoring current cache.)r   re   rI   hasattrsetattrrq   r<   AttributeErrorLOGdebugr>   )r2   r   Zexpected_attrsrW   r0   er$   r$   r'   	_unpicklen  s4    


zDataSource._unpicklec                 C   s
   t | S r.   r   obj_namer1   r$   r$   r'   r3     s    zDataSource.__str__r,   c                 C   s   dS )z#Check if running on this datasourceTr$   r1   r$   r$   r'   	ds_detect  s    zDataSource.ds_detectc                 C   sN   | j  t  kr$td|  dS | jdg | j gkrJtd|  dS dS )aJ  Override if either:
        - only a single datasource defined (nothing to fall back to)
        - command line 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.
        z6Kernel command line set to use a single datasource %s.TZdatasource_listz2Datasource list set to use a single datasource %s.F)r   rJ   parse_cmdliner   r   r   rZ   r1   r$   r$   r'   override_ds_detect  s    	 zDataSource.override_ds_detectc                 C   s@   |   r|  S |  r,td|  |  S td|  dS dS )z&Overrides runtime datasource detectionzDetected %szDid not detect %sFN)r   	_get_datar   r   r   r1   r$   r$   r'   _check_and_get_data  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   rn      pythonuname   platformvariant)Z
_beta_keysavailability-zoneavailability_zonecloud_idr!   
cloud_namer~   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_hostnamerc   get_instance_idr   canonical_cloud_idr   r   platform_typeget_public_ssh_keysr   )r2   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_cacherw   r   r   )r2   Zattr_defaultsZattr_valuesZ	attributer0   r$   r$   r'   clear_cached_attrs  s    
zDataSource.clear_cached_attrszGetting metadataalways)Zlog_modec                 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)r2   Zreturn_valuer$   r$   r'   get_data  s    zDataSource.get_dataTc              
   C   s`  |r&t j| jjr&t| | jd | jdk	r^t	| j}|
dd |
dd d|i}n>dd| jii}| jtkr| j|d d< | jtkr| j|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
rZ } 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 |
r4|
|kr4t(|
 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_pklNrz   r{   r+   Z	meta_datarp   ro   Z_docrx   z<DEPRECATED: Use merged_system_cfg. Will be dropped from 24.1ry   zUMerged cloud-init system config from /etc/cloud/cloud.cfg and /etc/cloud/cloud.cfg.d/r   )rF   z'Error persisting instance-data.json: %sFZinstance_data_sensitiver   r   Znonezcloud-id-
T)Zforcei  )moder   )+osr^   lexistsr   Zinstance_link	pkl_storeZget_ipath_currj   rG   rH   rR   rT   rp   r   ro   EXPERIMENTAL_TEXTr   r   Zsystem_infoupdater   r   Z
json_dumpsrP   jsonloadsr|   	TypeErrorr   warningr<   UnicodeDecodeErrorZget_runpathrZ   joinZrun_dir
write_fileexistsrealpathZsym_linkZdel_filer   r_   )r2   Zwrite_cacheZcrawled_metadatar   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   
  sh    







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)NotImplementedErrorr1   r$   r$   r'   r   V  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'ra   zAConfig sec_between_retries '%s' is not an int, using default '%s')url_max_waitrh   r   rZ   
ValueErrorr   logexcr   url_timeoutmaxurl_retries	Exceptionurl_sec_between_retriesr`   )r2   r   r   r   ra   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.   )rq   r   processget_userdata_raw_filter_xdata)r2   Zapply_filterr$   r$   r'   get_userdata  s
    
zDataSource.get_userdatac                 C   s"   | j d kr| j|  | _ | j S r.   )rs   r   r   get_vendordata_rawr1   r$   r$   r'   get_vendordata  s    
zDataSource.get_vendordatac                 C   s"   | j d kr| j|  | _ | j S r.   )ru   r   r   get_vendordata2_rawr1   r$   r$   r'   get_vendordata2  s    
zDataSource.get_vendordata2c                 C   s   | j s| j | _ | j S r.   )r   r   rJ   r1   r$   r$   r'   r     s    zDataSource.platform_typec                 C   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)
        )r   _get_subplatformr1   r$   r$   r'   r     s    
zDataSource.subplatformc                 C   s   | j rd| j  dS tS )z?Subclasses should implement to return a "slug (detail)" string.z
metadata ())r   METADATA_UNKNOWNr1   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)ri   rT   rZ   METADATA_CLOUD_NAME_KEYrL   r<   rJ   _get_cloud_namer   r   type)r2   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.
        )r   r1   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)rT   r1   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)r2   Zprocessed_udfiltersZnew_udfr$   r$   r'   r     s    zDataSource._filter_xdatac                 C   s   | j S r.   )rr   r1   r$   r$   r'   r     s    zDataSource.get_userdata_rawc                 C   s   | j S r.   )rt   r1   r$   r$   r'   r     s    zDataSource.get_vendordata_rawc                 C   s   | j S r.   )rv   r1   r$   r$   r'   r     s    zDataSource.get_vendordata2_rawc                 C   s   i S r.   r$   r1   r$   r$   r'   get_config_obj  s    zDataSource.get_config_objc                 C   s   t | jdS )Nzpublic-keys)normalize_pubkey_datarT   rZ   r1   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$   )r2   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)rI   rM   lenr   r^   r   )r2   Z
short_nameZmappingsZnfromZtlistZntoZcandr$   r$   r'   _remap_device  s    
zDataSource._remap_devicec                 C   s   d S r.   r$   )r2   _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_localer~   
get_localer   )r2   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rT   rZ   )r2   Ztop_level_azr$   r$   r'   r   3  s     
zDataSource.availability_zonec                 C   s   | j dS )Nr   r   r1   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)rT   r<   r1   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   rn   z%s.%s)rT   rZ   rb   r   r   Zget_fqdn_from_hostsfindr<   r[   r   Zis_ipv4_addressZgethostbyaddrrN   r   r   )r2   ZfqdnZ
resolve_ipZmetadata_onlyZ	defdomainZdefhostZdomainrd   Ztoksrc   Z
hosts_fqdnZlhostr$   r$   r'   r   F  sF    







zDataSource.get_hostnamec                 C   s   | j j| dS )N)Zdata_source)r~   get_package_mirror_infor1   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_eventsrI   rZ   setadd)r2   r   supported_eventseventZupdate_scopeZupdate_eventsr$   r$   r'   get_supported_events  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   rI   r   r   r0   r   r   r   r   )r2   r   r   ZscopeZmatched_eventsresultr$   r$   r'   update_metadata_if_supported  s&    
z'DataSource.update_metadata_if_supportedc                 C   s   dS r   r$   )r2   r   r$   r$   r'   check_instance_id  s    zDataSource.check_instance_idc                 C   s   dS )a  check_if_fallback_is_allowed()
        Checks if a cached ds is allowed to be restored when no valid ds is
        found in local mode by checking instance-id and searching valid data
        through ds list.

        @return True if a ds allows fallback, False otherwise.
        Fr$   r1   r$   r$   r'   r     s    z'DataSource.check_if_fallback_is_allowedc                 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$   r1   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$   )r2   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$   )r2   Zcfgr  r$   r$   r'   activate  s    zDataSource.activate)N)r$   )T)F)FFF)NN)cr4   r5   r6   r  Zdsmoder   r   ri   r	   r<   rg   r   r   rj   r   r   r*   r8   r;   r:   r9   rk   r
   r   r   r   r   r   r   r   BOOT_NEW_INSTANCEZBOOTZBOOT_LEGACYZHOTPLUGr   Zdefault_update_eventsr   rw   r   r   r|   r   re   r   r}   Z_ci_pkl_versionr   r   r   rh   r   r3   rf   r   r   r   r   r   r   Ztimedr   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   staticmethodr	  r
  r  r  r$   r$   r$   r'   r       s   
 
%&

L<




			


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.   )rL   r<   
splitlineslistr   rO   rI   rK   )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    rC   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ReportEventStackrN   r  r   r  r  r   r   r   r   r   r   r@   )r   r~   r   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_modulegetattrrQ   )r  dependsr  Zsrc_listr+   Zds_nameZm_locsZ_looked_locsZm_locmodZlisterZmatchesr$   r$   r'   r  D  s6    
  


r  system-uuid)fieldr-   c                 C   s*   | sdS t |}|sdS |  | kS r   )r   Zread_dmi_datarJ   )r   r)  Z	dmi_valuer$   r$   r'   instance_id_matches_system_uuidh  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_MAPrI   rM   )r   r   r   prefixZcloud_id_testr   Zvalid_cloudr$   r$   r'   r   v  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)
rL   r<   r  rG   rH   rO   convert_vendordatarZ   r   r   )datar-  r$   r$   r'   r.    s    



r.  c                   @   s   e Zd ZdS )BrokenMetadataNrA   r$   r$   r$   r'   r0    s   r0  c                 C   s4   g }t | }|D ]\}}|t |kr|| q|S r.   )r   rK   )r&  r  Zret_listZdepsetr  Zdepsr$   r$   r'   list_from_depends  s    r1  )r]   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   )r]   r2  Zpk_contentsr$   r$   r'   r     s    r   )r2  r-   c              
   C   s   d}zt | }W n< tk
rN } ztj| r>td| | W 5 d}~X Y nX |sXdS zt	|W S  t
k
rz   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.Nzfailed loading pickle in %s: %sz#Failed loading pickled blob from %s)r   Zload_binary_filer   r   r^   isfiler   r   r5  r   r>   r   )r2  Zpickle_contentsr   r$   r$   r'   pkl_load  s     r8  c                   C   s   t t S )zCheck if command line argument for this datasource was passed
    Passing by command line overrides runtime datasource detection
    )parse_cmdline_or_dmir   Zget_cmdliner$   r$   r$   r'   r     s    r   )inputr-   c                 C   s   t d| }t d| }t d| }|p.|p.|}|p6|}|rn|d }tjd| d| dd| d	d
 |r|dr|dS dS )Nz(?:^|\s)ds=([^\s;]+)z(?:^|\s)ci\.ds=([^\s;]+)z (?:^|\s)ci\.datasource=([^\s;]+)rn   z8Defining the datasource on the command line using ci.ds=z or ci.datasource=z23.2zUse ds=z instead)
deprecatedZdeprecated_versionZextra_messagerC   )researchgroupstripr   Z	deprecate)r:  Z
ds_parse_0Z
ds_parse_1Z
ds_parse_2r+   r;  r   r$   r$   r'   r9    s    
	
r9  )rC   r$   )r(  )T)[abcrG   r   Zloggingr   r5  r<  collectionsr   enumr   r   typingr   r   r   r   r	   r
   r   Z	cloudinitr   r   r   r   r   r   r   r   r   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	getLoggerr4   r   r+  r*   r=   r   r>   r@   rB   rP   r_   r`   rb   re   ABCMetar    r   r<   r!  r  rf   r*  r   r.  IOErrorr0  r1  r   r8  r   r9  r$   r$   r$   r'   <module>   s   $$	






#
      @
!% 
	