o
    w7ef                     @   s:  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	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)log)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/   r2   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.   r2   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appendrH   rI   r3   rK   r@   )r.   r/   namesr2   nr   r   r   device_name_to_device   s6   




z!SourceMixin.device_name_to_deviceN)r'   r(   r)   r3   r:   r@   rK   rR   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.   rT   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   rW   r   r   r.   rD   decoder   r   r   
_path_read   r\   zBaseReader._path_readc                 C   rW   r   r   r.   r   r   r   _fetch_available_versions   r\   z$BaseReader._fetch_available_versionsc                 C   rW   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)	ra   	ExceptionrH   rI   rT   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   rA   c                 S   s   g | ]}t |r|qS r   )len)rc   pr   r   r   re      s    z1BaseReader._read_content_path.<locals>.<listcomp>z!Item %s has no valid content path	openstackr^   )r,   lstripsplitr   r[   rT   r_   )r.   itemr^   rD   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 )Nrt   zmeta_data.jsonTr9   	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)r[   r   	load_json)r7   filesload_json_anytyper.   r   r   	datafiles   s,   	z%BaseReader.read_v2.<locals>.datafilesr      )r~   r7   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: %sr9   random_seedz.Badly formatted metadata random_seed entry: %sr   rD   z#Failed to read provided file %s: %sr
   ru   z(Failed to read network configuration: %smetadsmodezec2-metadatazNo '%s' entry in metadata)	functoolspartialr   r   dictrh   strrp   r-   r[   rT   r_   IOErrorrH   rI   r&   rf   r   base64	b64decode
ValueError	TypeErrorr,   r{   KeyErrorrb   
KEY_COPIES)r.   r   resultsdatar/   rD   required
translatorfoundrl   r9   r   r   metadata_filesrx   net_itemcontent
target_key
source_keyis_requiredr   r   r   read_v2   s   	!


	
zBaseReader.read_v2NF)r'   r(   r)   rV   abcabstractmethodr[   r_   ra   rb   rp   r{   r   r   r   r   r   rS      s    



	rS   )	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   rV   	_versionsrU   	__class__r   r   rV   f  s   
zConfigDriveReader.__init__c                 G   s   |gt | }tjj| S r   )rh   rC   rD   join)r.   rY   rZ   
componentsr   r   r   r[   j  s   zConfigDriveReader._path_joinFc                 C   s   t j||dS )Nru   )r   	load_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 )Nrt   c                    s$   g | ]}t jt j r|qS r   )rC   rD   isdirr   rc   drD   r   r   re   t  s    z?ConfigDriveReader._fetch_available_versions.<locals>.<listcomp>)r   r[   rT   rC   listdirsorted)r.   r   r   r   r   ra   q  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   )
r[   rT   rC   rD   rE   r   r   r_   rf   r   )r.   rD   rl   r   r   r   rb   |  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   r6   c                 S   s"   g | ]}t |r|d s|qS )#)rr   rB   )rc   liner   r   r   re     s    z-ConfigDriveReader.read_v1.<locals>.<listcomp>r   r5   )r7   r9   r   z	user-datar   r~   r   )FILES_V1keysr[   rT   rC   rD   rE   rr   r&   r-   r_   r   r   rf   copydeepcopyr,   
splitlines)r.   r   r/   rD   mdkeyr   defaultcontentsrl   keydatar   linesr   r   r   r   read_v1  s^   

zConfigDriveReader.read_v1r   )
r'   r(   r)   rV   r[   r_   ra   rb   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   rV   ssl_detailsfloattimeoutintretriesr   )r.   base_urlr   r   r   r   r   r   rV     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 )Nrt   Tru   )r   r[   rT   r_   r   striprO   )r.   r   version_pathr   r   r   r   r   ra     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.   rD   r^   r   responser   r   r   r_     s   

zMetadataReader._path_readc                 G   s   t j|g|R  S r   )r   combine_urlrX   r   r   r   r[     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   rb     s
   z!MetadataReader._read_ec2_metadata)Nr   r   r   )	r'   r(   r)   rV   ra   r_   r[   rb   r   r   r   r   r   r     s    
r   c              
      s"  | du rdS 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 rId |
d< d} dr] d }|d < |
 d|d d d}fdd|D D ]}tfdd| D }|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 }|r||d"< |d d#v r|
dd$i |d d%krd$|d%< |d d&krd$|d&< |	| qt|
d'|	i d d(v rki }|r*||d)<  D ]\}}|d*kr9q.|d+rF|||i q.|| }|d,7 }||
d-d.td* f |
||d/ ||d< nZd d0v rd1d2 d3 f }|
|d3 d4 d5 ||
d2d.d2 f ||
dd6d3  d2 f |d4 |d7 nd t	vrt
d8d  |
d9|d: ||
 ||d < q-d;d |D }|s|rX|du rt } D ]\}}| drq| d<|v r||d<  |d< q|D ]"}| d)}|std=| ||vr&td>| || |d< q|D ]'\}
} }t|ttfrL fd?d|D |
|< q0 | d  |
|< q0t }|rx|D ]}
|
d |v rv||
d  |
d)< d@|
d< qa|D ]}|}
|
ddAi ||
 qzd,|dBS )Ca)  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 superflous 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routes)physicalsubnetlinksnetworksserviceszbond%dr   c                 3   (    | ]\}}| d  v r||fV  qdS )r   Nr   rc   krd   
valid_keysr   r   	<genexpr>P      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   )rc   rQ   )r   r   r   re   f  s     z$convert_net_json.<locals>.<listcomp>c                 3   r   )r   Nr   r   r   r   r   r   g  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   s"   g | ]}| d dkr|d qS )r   dnsr   r,   )rc   servicer   r   r   re     s
    r   )r   r   Tr   r   r   )bondr   
bond_linksr  r5   bond_interfacesz%s)r   r/   )vlanz%s.%s	vlan_linkvlan_idvlan_mac_address)r/   r	  r   z%%s.%s)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   re     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   )rc   target)fmtlink_id_infor   r   re     s    
infiniband
nameserver)r7   config)r,   r   r-   lowerupdaterO   rB   r   r   KNOWN_PHYSICAL_TYPESrH   warningr   get_interfaces_by_macr   
isinstancerh   tupleget_ib_hwaddrs_by_interface)network_json
known_macsr   r   r   link_updatesbond_name_fmtbond_numberr  r   cfglink_mac_addrcurinfonetworkr   r   r   r   rd   	link_namer/   
need_names_link_idinfor   r   r   targetsib_known_hwaddrsr  r   )r  r   r  r   r   convert_net_json  s   









r(  )NN)*r   r   r   r   rC   	cloudinitr   loggingr   r   r   r   r   cloudinit.sourcesr   cloudinit.sources.helpersr	   	getLoggerr'   rH   r   r   r   rj   	OS_FOLSOM
OS_GRIZZLY	OS_HAVANA
OS_LIBERTYOS_NEWTON_ONEOS_NEWTON_TWOOS_OCATAOS_ROCKYri   r  r   r&   r*   ABCMetarS   r   r   r(  r   r   r   r   <module>   sR   

L Eo: