o
    fl                     @   s6  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mZm	Z	m
Z
mZ d dlmZ d dlmZ eeZddd dfd	eji fd
dd dfdZdZdZdZdZdZdZdZdZdZdZeeeeeeeefZdZ G dd de!Z"G dd dZ#G dd de j$dZ%G dd  d e%Z&G d!d" d"e%Z'd%d#d$Z(dS )&    N)netsourcessubp
url_helperutil)BrokenMetadata)ec2network_configc                 C      | S N xr   r   E/usr/lib/python3/dist-packages/cloudinit/sources/helpers/openstack.py<lambda>       r    meta_jsauthorized_keysc                 C   r
   r   r   r   r   r   r   r      r   )zetc/network/interfaceszmeta.jszroot/.ssh/authorized_keys))zlocal-hostnamehostnameF)instance-iduuidTlatestz
2012-08-10z
2013-04-04z
2013-10-17z
2015-10-15z
2016-06-30z
2016-10-06z
2017-02-22z
2018-08-27)Nbgpovsbridge	cascadingdvsethernethw_vebhypervovsphytap	vhostuservifc                   @   s   e Zd ZdS )NonReadableN)__name__
__module____qualname__r   r   r   r   r%   Q   s    r%   c                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )SourceMixinc                 C   s>   | j sd S | j di }| D ]\}}||kr|  S qd S )Nzblock-device-mapping)ec2_metadatagetitems)selfnamebdment_namedevicer   r   r   _ec2_name_to_deviceV   s   zSourceMixin._ec2_name_to_devicec                 C   s$   d}| j dkr	d}t| j|S )Npublic_keys   public-keys)versionr   normalize_pubkey_datametadatar+   )r-   r.   r   r   r   get_public_ssh_keys_   s   
zSourceMixin.get_public_ssh_keysc                 C   sV   d }zd| }|dkrd| }t |}|r|d }W |S W |S  tjy*   Y |S w )NzLABEL=%sswapzTYPE=%sr   )r   find_devs_withr   ProcessExecutionError)r-   r.   r1   criteriadev_entriesr   r   r   _os_name_to_devicee   s   

zSourceMixin._os_name_to_devicec                 C   sV   |sd S | dsd| }tj|r|S | tj|}|r)td|| |S d S )N/z/dev/%szRemapped device name %s => %s)
startswithospathexists_remap_devicebasenameLOGdebug)r-   r1   remappedr   r   r   _validate_device_namer   s   
z!SourceMixin._validate_device_namec                 C   s   |sd S |g}|dkr| dd |dkr|d d }td| |D ]}| |}| |}|r4 nq$|sPtd| |D ]}| |}| |}|rO nq?|sTd S td|| |S )Nrootr   amiz(Using ec2 style lookup to find device %sz.Using openstack style lookup to find device %szMapped %s to device %s)insertappendrG   rH   r2   rJ   r?   )r-   r.   namesr1   nr   r   r   device_name_to_device   s6   




z!SourceMixin.device_name_to_deviceN)r&   r'   r(   r2   r9   r?   rJ   rQ   r   r   r   r   r)   U   s    	r)   c                   @   sh   e Zd Zdd Zejdd ZejdddZejdd	 Zejd
d Z	dd Z
dddZdd ZdS )
BaseReaderc                 C   s
   || _ d S r   )	base_pathr-   rS   r   r   r   __init__   s   
zBaseReader.__init__c                 G      d S r   r   r-   baseadd_onsr   r   r   
_path_join      zBaseReader._path_joinFc                 C   rV   r   r   r-   rC   decoder   r   r   
_path_read   r[   zBaseReader._path_readc                 C   rV   r   r   r-   r   r   r   _fetch_available_versions   r[   z$BaseReader._fetch_available_versionsc                 C   rV   r   r   r_   r   r   r   _read_ec2_metadata   r[   zBaseReader._read_ec2_metadatac              
   C   s   z|   }W n ty" } ztd| j| g }W Y d }~nd }~ww dd tttD }t}|D ]	}||vr9q2|} td|| |S )Nz4Unable to read openstack versions from %s due to: %sc                 S   s   g | ]}|qS r   r   ).0vr   r   r   
<listcomp>   s    z4BaseReader._find_working_version.<locals>.<listcomp>zSelected version '%s' from %s)	r`   	ExceptionrG   rH   rS   reversedlistOS_VERSIONS	OS_LATEST)r-   versions_availablee	supportedselected_versionpotential_versionr   r   r   _find_working_version   s0   
z BaseReader._find_working_versionc                 C   s^   | ddd}|d}dd |D }|std| | j| jdg|R  }| j||dS )	Ncontent_pathr   r@   c                 S   s   g | ]}t |r|qS r   )len)rb   pr   r   r   rd      s    z1BaseReader._read_content_path.<locals>.<listcomp>z!Item %s has no valid content path	openstackr]   )r+   lstripsplitr   rZ   rS   r^   )r-   itemr]   rC   path_piecesvalid_piecesr   r   r   _read_content_path   s   
zBaseReader._read_content_pathc                    s  t jtjtttfd  fdd}ddd}| }| D ]o\}\}}}	j
|}d}d}z|}W n# ty] }	 z|sLtd	||	 ntd
||	 W Y d}	~	nd}	~	ww d}|rj|sjtd| |r|rz||}W n ty }	 z	td||	f |	d}	~	ww |r|||< q!|d }
d|
v r|
d }z	t||
d< W n ttfy }	 ztd|	 |	d}	~	ww i }|
dg }|D ])}d|vrq|d }z	|||< W q ty }	 z	td||	f |	d}	~	ww ||d< |
dd}|rzj|dd}||d< W n ty }	 ztd|	 |	d}	~	ww z
|
d d |d< W n
 ty3   Y nw  |d< tD ] \}}}|rO||
vrOtd| ||
v r[|
||
|< q<|S )zReads a version 2 formatted location.

        Return a dict with metadata, userdata, ec2-metadata, dsmode,
        network_config, files and version (2).

        If not a valid location, raise a NonReadable exception.
        )
root_typesc                    s   i } d| ddtjf|d<  d| dddd f|d	<  d| d
d f|d<  d| dd f|d<  d| dd f|d< |S )Nrs   zmeta_data.jsonTr8   	user_dataFc                 S   r
   r   r   r   r   r   r   r      r   z7BaseReader.read_v2.<locals>.datafiles.<locals>.<lambda>userdatazvendor_data.json
vendordatazvendor_data2.jsonvendordata2znetwork_data.jsonnetworkdata)rZ   r   	load_json)r6   filesload_json_anytyper-   r   r   	datafiles   s,   	z%BaseReader.read_v2.<locals>.datafilesr      )r}   r6   NFz*Failed reading optional path %s due to: %sz+Failed reading mandatory path %s due to: %sTzMissing mandatory path: %sFailed to process path %s: %sr8   random_seedz.Badly formatted metadata random_seed entry: %sr   rC   z#Failed to read provided file %s: %sr	   rt   z(Failed to read network configuration: %smetadsmodezec2-metadatazNo '%s' entry in metadata)	functoolspartialr   r   dictrg   strro   r,   rZ   rS   r^   IOErrorrG   rH   r%   re   r   base64	b64decode
ValueError	TypeErrorr+   rz   KeyErrorra   
KEY_COPIES)r-   r   resultsdatar.   rC   required
translatorfoundrk   r8   r   r   metadata_filesrw   net_itemcontent
target_key
source_keyis_requiredr   r   r   read_v2   s   	!


	
zBaseReader.read_v2NF)r&   r'   r(   rU   abcabstractmethodrZ   r^   r`   ra   ro   rz   r   r   r   r   r   rR      s    



	rR   )	metaclassc                       sF   e Zd Z fddZdd ZdddZdd	 Zd
d Zdd Z  Z	S )ConfigDriveReaderc                    s   t t| | d | _d S r   )superr   rU   	_versionsrT   	__class__r   r   rU   f  s   
zConfigDriveReader.__init__c                 G   s   |gt | }tjj| S r   )rg   rB   rC   join)r-   rX   rY   
componentsr   r   r   rZ   j  s   zConfigDriveReader._path_joinFc                 C   s   |rt |S t |S r   )r   load_text_fileload_binary_filer\   r   r   r   r^   n  s
   
zConfigDriveReader._path_readc                    s@   | j d u r| | jd  fddt D }t|| _ | j S )Nrs   c                    s$   g | ]}t jt j r|qS r   )rB   rC   isdirr   rb   drC   r   r   rd   x  s    z?ConfigDriveReader._fetch_available_versions.<locals>.<listcomp>)r   rZ   rS   rB   listdirsorted)r-   r   r   r   r   r`   u  s   


z+ConfigDriveReader._fetch_available_versionsc              
   C   s`   |  | jddd}tj|si S z	t| |W S  ty/ } z	t	d||f |d }~ww )Nr   r   zmeta-data.jsonr   )
rZ   rS   rB   rC   rD   r   r   r^   re   r   )r-   rC   rk   r   r   r   ra     s   

z$ConfigDriveReader._read_ec2_metadatac                 C   s  i }t  D ]}| | j|}tj|r|||< qt|dkr'td| j i }t 	 D ]O\}\}}}||v ru|| }z| 
|}W n tyV }	 ztd| |	d}	~	ww z||||< W q- tyt }	 z	td||	f |	d}	~	ww t|||< q-|d }
|d }|d|
}
|
r|
 }d	d
 |D |d< d|v r|d |d< d|d}d|v r|d |d< |dd|d< i |d< |S )zReads a version 1 formatted location.

        Return a dict with metadata, userdata, dsmode, files and version (1).

        If not a valid path, raise a NonReadable exception.
        r   z%s: no files foundzFailed to read: %sNr   r   r   r5   c                 S   s"   g | ]}t |r|d s|qS )#)rq   rA   )rb   liner   r   r   rd     s    z-ConfigDriveReader.read_v1.<locals>.<listcomp>r   r4   )r6   r8   r   z	user-datar   r}   r   )FILES_V1keysrZ   rS   rB   rC   rD   rq   r%   r,   r^   r   r   re   copydeepcopyr+   
splitlines)r-   r   r.   rC   mdkeyr   defaultcontentsrk   keydatar   linesr   r   r   r   read_v1  s^   

zConfigDriveReader.read_v1r   )
r&   r'   r(   rU   rZ   r^   r`   ra   r   __classcell__r   r   r   r   r   e  s    
r   c                       s@   e Zd Zd fdd	Zdd Zddd	Zd
d Zdd Z  ZS )MetadataReaderN   c                    s4   t t| | || _t|| _t|| _d | _d S r   )	r   r   rU   ssl_detailsfloattimeoutintretriesr   )r-   base_urlr   r   r   r   r   r   rU     s
   


zMetadataReader.__init__c                 C   sb   | j d ur| j S g }| | jd}| j|dd}| D ]}| }|s%q|| q|| _ | j S )Nrs   Trt   )r   rZ   rS   r^   r   striprN   )r-   r   version_pathr   r   r   r   r   r`     s   
z(MetadataReader._fetch_available_versionsFc                 C   s6   dd }t j|| j| j| j|d}|r|j S |jS )Nc              	   S   s8   zt |j}|dkrW dS W dS  ttfy   Y dS w )Ni  FT)r   coder   r   )_request_argscauser   r   r   r   should_retry_cb  s   
z2MetadataReader._path_read.<locals>.should_retry_cb)r   r   r   exception_cb)r   readurlr   r   r   r   r]   )r-   rC   r]   r   responser   r   r   r^     s   

zMetadataReader._path_readc                 G   s   t j|g|R  S r   )r   combine_urlrW   r   r   r   rZ     s   zMetadataReader._path_joinc                 C   s   t j| j| j| jdS )N)r   r   r   )r   get_instance_metadatar   r   r   r_   r   r   r   ra   	  s
   z!MetadataReader._read_ec2_metadata)Nr   r   r   )	r&   r'   r(   rU   r`   r^   rZ   ra   r   r   r   r   r   r     s    
r   c               
      s  | du rdS g dg dg dd|  dg }|  dg }|  dg }g }i d	}d
}g }|D ]g }	tfdd D }
dv rLd |
d< d} dr` d }|d < |
 d|d d d}fdd|D D ]}tfdd| D }fdd| dg D }|r|d|i |d dkr|ddi nH|d dkr|ddi n:|d dv r|d|d i n*|d dv r|d| dd n|d d v r|
d!d"i |d#| dd d$d | dg D }| dg D ]}| dd%krq|d& |v rq||d&  q|r(||d'< |d d(v r6|
d!d)i |d d*krAd)|d*< |d d+krLd)|d+< |	| qw|
d,|	i d d-v ri }|rl|
d.|i  D ]$\}}|d/kr{qp|d0rd1|d2d3d4 }|||i qp|| }|d37 }||
d5d6t	
d/ f |
||d7 ||d< nWd d8v rd9d: d; f }|
|d; d< ||
d:d6d: f ||
dd=d;  d: f |d> |d? nd tvrtd@d  |
dA|dB ||
 ||d < q0dCd |D }|s(|r|du r1t } D ]\}}| drAq5| dD|v rQ||dD  |d< q5|D ]"}| d.}|setdE| ||vrptdF| || |d< qU|D ]'\}
} }t|ttfr fdGd|D |
|< qz | d  |
|< qzt }|r|D ]}
|
d |v r||
d  |
d.< dH|
d< q|D ]}t	
|}
|
ddIi ||
 qd3|dJS )Ka*  Return a dictionary of network_config by parsing provided
       OpenStack ConfigDrive NetworkData json format

    OpenStack network_data.json provides a 3 element dictionary
      - "links" (links are network devices, physical or virtual)
      - "networks" (networks are ip network configurations for one or more
                    links)
      -  services (non-ip services, like dns)

    networks and links are combined via network items referencing specific
    links via a 'link_id' which maps to a links 'id' field.

    To convert this format to network_config yaml, we first iterate over the
    links and then walk the network list to determine if any of the networks
    utilize the current link; if so we generate a subnet entry for the device

    We also need to map network_data.json fields to network_config fields. For
    example, the network_data links 'id' field is equivalent to network_config
    'name' field for devices.  We apply more of this mapping to the various
    link types that we encounter.

    There are additional fields that are populated in the network_data.json
    from OpenStack that are not relevant to network_config yaml, so we
    enumerate a dictionary of valid keys for network_yaml and apply filtering
    to drop these superfluous keys from the network_config yaml.
    N)r.   typemac_addresssubnetsparamsmtu)
r   addressnetmask	broadcastmetricgatewaypointopointscopedns_nameservers
dns_search)networkdestinationr   r   r   )physicalsubnetrouteslinksnetworksserviceszbond%dr   c                 3   (    | ]\}}| d  v r||fV  qdS )r   Nr   rb   krc   
valid_keysr   r   	<genexpr>T      z#convert_net_json.<locals>.<genexpr>r.   ethernet_mac_addressidr   )r.   macr   r   c                    s    g | ]}|d   d kr|qS )linkr   r   )rb   rP   )r   r   r   rd   j  s     z$convert_net_json.<locals>.<listcomp>c                 3   r   )r   Nr   r   r   r   r   r   k  r   c                    s&   g | ]}t  fd d| D qS )c                 3   r   )r   Nr   r   r   r   r   r   r  s    z.convert_net_json.<locals>.<listcomp>.<genexpr>)r   r,   )rb   router   r   r   rd   q  s    r   	ipv4_dhcpdhcp4	ipv6_dhcpdhcp6)
ipv6_slaaczipv6_dhcpv6-statelessipv6_dhcpv6-stateful)ipv4staticr   
ip_address)r   r   )ipv6static6z	accept-raFr  c                 S   s4   g | ]}| d g D ]}| ddkr
|d q
qS )r   r   dnsr   r+   )rb   r   servicer   r   r   rd     s    
r  r   r   )r   r   Tr   r  r   )bondr   
bond_linksr  zbond-{}bond_r4   bond_interfacesz%s)r   r.   )vlanz%s.%s	vlan_linkvlan_id)r.   r  z%%s.%svlan_mac_address)r   r.   z9Unknown network_data link type (%s); treating as physicalr   )r   r   c                 S   s&   g | ]}| d dkrd|vr|qS )r   r   r.   r  r   r   r   r   rd     s     r   z#No mac_address or name entry for %sz"Unable to find a system nic for %sc                    s   g | ]
} | d   qS )r.   r   )rb   target)fmtlink_id_infor   r   rd     s    
infiniband
nameserver)r6   config)r+   r   r,   lowerupdaterN   rA   formatrv   r   r   KNOWN_PHYSICAL_TYPESrG   warningr   get_interfaces_by_macr   
isinstancerg   tupleget_ib_hwaddrs_by_interface) network_json
known_macsr   r   r   link_updatesbond_name_fmtbond_numberr  r   cfglink_mac_addrcurinfor   r   r   r   r  r   r   rc   translated_key	link_namer.   
need_names_link_idinfor   r   r   targetsib_known_hwaddrsr   )r  r   r  r   r   convert_net_json  s8  



	









r.  )NN))r   r   r   r   loggingrB   	cloudinitr   r   r   r   r   cloudinit.sourcesr   cloudinit.sources.helpersr   	getLoggerr&   rG   r   r   r   ri   	OS_FOLSOM
OS_GRIZZLY	OS_HAVANA
OS_LIBERTYOS_NEWTON_ONEOS_NEWTON_TWOOS_OCATAOS_ROCKYrh   r  r   r%   r)   ABCMetarR   r   r   r.  r   r   r   r   <module>   sR   

L Es: