
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
3
\me7D                 @   s:  d 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 ddl	m
Z
 ddlmZmZmZmZmZmZmZ ddlZddlmZ ddlmZ ddlmZ dd	lmZmZmZmZmZ dd
l m!Z! ej"e#Z$dZ%dZ&dZ'dddddddZ(e)dddZ*d9eee)  ee)ef dddZ+G dd deZ,G dd deZ-G dd deZ.e)e/ddd Z0G d!d" d"ej1Z2e3dd#d$Z4d:ej5e)e3d&d'd(Z6d;ej5e)e3ej7d)d*d+Z8G d,d- d-eZ9G d.d/ d/Z:e&e9j;fe)e9e/d0d1d2Z<e2ej=ffgZ>d3d4 Z?e#d5kr6ddl@Z@d6ZAe@jBeAd7ZCeCjD  eEejFe<e9j;d8 dS )<a  Datasource for LXD, reads /dev/lxd/sock representation of instance data.

Notes:
 * This datasource replaces previous NoCloud datasource for LXD.
 * Older LXD images may not have updates for cloud-init so NoCloud may
   still be detected on those images.
 * Detect LXD datasource when /dev/lxd/sock is an active socket file.
 * Info on dev-lxd API: https://documentation.ubuntu.com/lxd/en/latest/dev-lxd/
    N)Flagauto)JSONDecodeError)AnyDictListOptionalTupleUnioncast)HTTPAdapter)HTTPConnection)HTTPConnectionPool)atomic_helpersourcessubp
url_helperutil)find_fallback_nicz/dev/lxd/sockz1.0z
http://lxdz	user-dataznetwork-configzvendor-data)zcloud-init.user-datazcloud-init.network-configzcloud-init.vendor-datazuser.user-datazuser.network-configzuser.vendor-data)returnc              C   s   d} t jdryt j dg\}}W n. t jk
rP } ztjd| | S d }~X nX |j dkrtj d d }|dkrzd	S |d
krdS dS | S )NZeth0zsystemd-detect-virtzHUnable to run systemd-detect-virt: %s. Rendering default network config.kvmqemuuname   Zppc64leZenp0s5Zs390xZenc9Zenp5s0)r   r   )r   ZwhichZProcessExecutionErrorLOGwarningstripr   Zsystem_info)Zdefault_nameZ	virt_type_errZarch r   #/usr/lib/python3.6/DataSourceLXD.py_get_fallback_interface_name/   s&    
 r!   )nicsr   c             C   sF   t  }|rtjd| nt }tjd| dd|dddgdgd	S )
zCReturn network config V1 dict representing instance network config.zCLXD datasource generating network from discovered active device: %szVLXD datasource generating network from systemd-detect-virt platform default device: %s   ZphysicalZdhcpr   )typeZcontrol)r$   nameZsubnets)versionconfig)r   r   debugr!   )r"   Zprimary_nicr   r   r    generate_network_configI   s    r)   c                   s$   e Zd Z fddZdd Z  ZS )SocketHTTPConnectionc                s   t  jd || _d S )N	localhost)super__init__socket_path)selfr.   )	__class__r   r    r-   p   s    zSocketHTTPConnection.__init__c             C   s$   t j t jt j| _| jj| j d S )N)socketZAF_UNIXZSOCK_STREAMZsockconnectr.   )r/   r   r   r    r2   t   s    zSocketHTTPConnection.connect)__name__
__module____qualname__r-   r2   __classcell__r   r   )r0   r    r*   o   s   r*   c                   s$   e Zd Z fddZdd Z  ZS )SocketConnectionPoolc                s   || _ t jd d S )Nr+   )r.   r,   r-   )r/   r.   )r0   r   r    r-   z   s    zSocketConnectionPool.__init__c             C   s
   t | jS )N)r*   r.   )r/   r   r   r    	_new_conn~   s    zSocketConnectionPool._new_conn)r3   r4   r5   r-   r8   r6   r   r   )r0   r    r7   y   s   r7   c               @   s   e Zd ZdddZdS )LXDSocketAdapterNc             C   s   t tS )N)r7   LXD_SOCKET_PATH)r/   urlZproxiesr   r   r    get_connection   s    zLXDSocketAdapter.get_connection)N)r3   r4   r5   r<   r   r   r   r    r9      s   r9   )metadata_typer   c             C   s   t |tr|S |dkri S ytj|}W n8 tk
r` } ztjdj| |d|W Y dd}~X nX |dkr~tjdj| |d|S )a6  Convert raw instance data from str, bytes, YAML to dict

    :param metadata_type: string, one of as: meta-data, vendor-data, user-data
        network-config

    :param metadata_value: str, bytes or dict representing or instance-data.

    :raises: InvalidMetaDataError on invalid instance-data content.
    NzAInvalid {md_type}. Expected str, bytes or dict but found: {value})Zmd_typevaluez:Invalid {md_type} format. Expected YAML but found: {value})
isinstancedictr   	load_yamlAttributeErrorr   InvalidMetaDataExceptionformat)r=   Zmetadata_valueZparsed_metadataexcr   r   r    _raw_instance_data_to_dict   s     


rF   c                   s   e Zd ZU dZejZeee	f ejZ
eee	f 
ejjd Zee	df dZed	d
 fddZeedddZedddZe	dddZe	dddZeedddZ  ZS )DataSourceLXDZLXDuser.meta-datauser.vendor-datauser.user-datacloud-init.user-datacloud-init.vendor-data.TN)ci_pkl_versionr   c                s   t  j| d| _d S )NT)r,   	_unpickleskip_hotplug_detect)r/   rM   )r0   r   r    rN      s    zDataSourceLXD._unpickle)r   c               C   s   t  S )z@Check platform environment to report if this datasource may run.)is_platform_viabler   r   r   r    	ds_detect   s    zDataSourceLXD.ds_detectc             C   s   t jtjdtd| _td| jjd| _| jjdi }|jdi }|rPtd|}t	| jt
stt jt j| j|g| _d| jkr| jd | _d| jkrtd| jd | _d| jkr| jd | _d	S )
z=Crawl LXD socket API instance data and return True on successzCrawl of metadata service)Zlogfuncmsgfuncz	meta-datar'   zuser.meta-dataz	user-dataznetwork-configzvendor-dataT)r   Zlog_timer   r(   read_metadata_crawled_metadatarF   getmetadatar?   r@   ZmergemanydictrA   Zuserdata_raw_network_configZvendordata_raw)r/   r'   Zuser_metadatar   r   r    	_get_data   s,    



zDataSourceLXD._get_datac             C   s   dj ttdS )z.Return subplatform details for this datasourcez"LXD socket API v. {ver} ({socket}))Zverr1   )rD   LXD_SOCKET_API_VERSIONr:   )r/   r   r   r    _get_subplatform   s    zDataSourceLXD._get_subplatformc             C   sB   t tjd}|jdi }t|ts,tj|}|jd| jjdkS )z%Return True if instance_id unchanged.)metadata_keysz	meta-datazinstance-id)	rT   MetaDataKeys	META_DATArV   r?   r@   r   rA   rW   )r/   Zsys_cfgresponsemdr   r   r    check_instance_id   s
    

zDataSourceLXD.check_instance_idc             C   s   | j tjkr~| jtjkr | j  t| jtr~| jjdrPtj	d | jd | _ n.| jjdr~dd | jd j
 D }t|| _ | j tjkrtj	d t | _ tt| j S )zNetwork config read from LXD socket config/user.network-config.

        If none is present, then we generate fallback configuration.
        znetwork-configz,LXD datasource using provided network configdevicesc             S   s    g | ]\}}|d  dkr|qS )r$   Znicr   ).0kvr   r   r    
<listcomp>   s   z0DataSourceLXD.network_config.<locals>.<listcomp>z8LXD datasource generating network config using fallback.)rX   r   UNSETrU   rY   r?   r@   rV   r   r(   itemsr)   r   )r/   rb   r   r   r    network_config   s"    


zDataSourceLXD.network_config)rH   rI   rJ   rK   rL   )r3   r4   r5   Zdsnamer   rg   rX   r
   r   strrU   
DataSourceZsensitive_metadata_keysr	   rO   intrN   staticmethodboolrQ   rY   r[   ra   propertyr@   ri   r6   r   r   )r0   r    rG      s$   
    rG   c               C   s"   t jjtrtjt jtjS dS )z=Return True when this platform appears to have an LXD socket.F)ospathexistsr:   statS_ISSOCKlstatst_moder   r   r   r    rP     s    rP   T)sessionr;   do_raisec             C   sr   t | ||}|js*tjd||j|j i S y|j S  tk
rl } ztj	dj
||jd|W Y d d }~X nX d S )NzSkipping %s on [HTTP:%d]:%szFUnable to process LXD config at {url}. Expected JSON but found: {resp})r;   resp)_do_requestokr   r(   status_codetextZjsonr   r   rC   rD   )rw   r;   rx   Zurl_responserE   r   r   r    _get_json_response  s    r~   )rw   r;   rx   r   c             C   s   xHt ddd
D ]8}| j|}d|jkrDtjd tjd|j|| qP qW tjd|j| |r|j rt	j
dj|j||jd	|S )N   r   r#   i  g?z,[GET] [HTTP:%d] %s, retrying %d more time(s)z[GET] [HTTP:%d] %sz3Invalid HTTP response [{code}] from {route}: {resp})codeZroutery   )rangerV   r|   timeZsleepr   r   r(   r{   r   rC   rD   r}   )rw   r;   rx   Zretriesr_   r   r   r    rz   ,  s$    


rz   c               @   s0   e Zd Ze Ze Ze Ze ZeeB eB ZdS )r]   N)	r3   r4   r5   r   ZNONECONFIGDEVICESr^   ALLr   r   r   r    r]   I  s
   r]   c               @   s@   e Zd ZefedddZejedddZ	e
eddd	Zd
S )_MetaDataReader)api_versionc             C   s   || _ tjt| j | _d S )N)r   r   combine_urlLXD_URL_version_url)r/   r   r   r   r    r-   R  s    z_MetaDataReader.__init__)rw   r   c       	      C   s   di i}t j| jd}t||}xt|D ]}t jt|}t||dd}|jsdtj	d||j
|j q*|jdd
 }|j|d |< |tkr*t| |kr|j|t| < q*tjd||jdd	d q*W |S )a  Iterate on LXD API config items. Promoting CONFIG_KEY_ALIASES

        Any CONFIG_KEY_ALIASES which affect cloud-init behavior are promoted
        as top-level configuration keys: user-data, network-data, vendor-data.

        LXD's cloud-init.* config keys override any user.* config keys.
        Log debug messages if any user.* keys are overridden by the related
        cloud-init.* key.
        r'   F)rx   zSkipping %s on [HTTP:%d]:%s/r#   z,Ignoring LXD config %s in favor of %s value.userz
cloud-initr   )r   r   r   r~   sortedr   rz   r{   r   r(   r|   r}   
rpartitionCONFIG_KEY_ALIASESr   replace)	r/   rw   r'   Z
config_urlZconfig_routesZconfig_routeZconfig_route_urlZconfig_route_responseZcfg_keyr   r   r    _process_configV  s0    

z_MetaDataReader._process_config)r\   r   c            C   s   t j }|j| jt  d| ji}tj|krLtj	| jd}t
||j|d< tj|krf|j| j| tj|krtj	| jd}t||dd}|r||d< |S Q R X d S )NZ_metadata_api_versionz	meta-datarb   F)rx   )requestsSessionZmountr   r9   r   r]   r^   r   r   rz   r}   r   updater   r   r~   )r/   r\   rw   r`   Zmd_router;   rb   r   r   r    __call__  s    





z_MetaDataReader.__call__N)r3   r4   r5   rZ   rj   r-   r   r   r@   r   r]   r   r   r   r   r    r   Q  s   7r   )r   r\   r   c             C   s   t | d|dS )a8  Fetch metadata from the /dev/lxd/socket routes.

    Perform a number of HTTP GETs on known routes on the devlxd socket API.
    Minimally all containers must respond to <LXD_SOCKET_API_VERSION>/meta-data
    when the LXD configuration setting `security.devlxd` is true.

    When `security.devlxd` is false, no /dev/lxd/socket file exists. This
    datasource will return False from `is_platform_viable` in that case.

    Perform a GET of <LXD_SOCKET_API_VERSION>/config` and walk all `user.*`
    configuration keys, storing all keys and values under a dict key
        LXD_SOCKET_API_VERSION: config {...}.

    In the presence of the following optional user config keys,
    create top level aliases:
      - user.user-data -> user-data
      - user.vendor-data -> vendor-data
      - user.network-config -> network-config

    :param api_version:
        LXD API version to operated with.
    :param metadata_keys:
        Instance of `MetaDataKeys` indicating what keys to fetch.
    :return:
        A dict with the following optional keys: meta-data, user-data,
        vendor-data, network-config, network_mode, devices.

        Below <LXD_SOCKET_API_VERSION> is a dict representation of all raw
        configuration keys and values provided to the container surfaced by
        the socket under the /1.0/config/ route.
    )r   )r\   )r   )r   r\   r   r   r    rT     s    #rT   c             C   s   t j| tS )N)r   Zlist_from_dependsdatasources)Zdependsr   r   r    get_datasource_list  s    r   __main__z*Query LXD metadata and emit a JSON object.)description)r\   )N)T)T)G__doc__Zloggingrp   r1   rs   r   enumr   r   Zjson.decoderr   Ztypingr   r   r   r   r	   r
   r   r   Zrequests.adaptersr   Zurllib3.connectionr   Zurllib3.connectionpoolr   Z	cloudinitr   r   r   r   r   Zcloudinit.netr   Z	getLoggerr3   r   r:   rZ   r   r   rj   r!   r)   r*   r7   r9   r@   rF   rk   rG   rn   rP   r   r~   ZResponserz   r]   r   r   rT   ZDEP_FILESYSTEMr   r   argparser   ArgumentParserparser
parse_argsprintZ
json_dumpsr   r   r   r    <module>	   sd   $
$
	j
Q
'
