
    }fE              	       b   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jD                  e#      Z$dZ%dZ&dZ'dddddddZ(de)fdZ*	 d2deee)      dee)ef   fdZ+ G d de      Z, G d de      Z- G d de      Z.de)de/fdZ0 G d dejb                        Z2de3fd Z4	 d3d!ejj                  d"e)d#e3fd$Z6	 d3d!ejj                  d"e)d#e3dejn                  fd%Z8 G d& d'e      Z9 G d( d)      Z:e&e9jv                  fd*e)d+e9de/fd,Z<e2ejz                  ffgZ>d- Z?e#d.k(  rSddl@Z@d/ZA e@j                  eA0      ZCeCj                           eE ej                   e<e9jv                  1                   yy)4a  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://lxd	user-datanetwork-configvendor-data)cloud-init.user-datazcloud-init.network-configcloud-init.vendor-datauser.user-datazuser.network-configuser.vendor-datareturnc                  J   d} t        j                  d      rS	 t        j                   dg      \  }}|j                         dv r't        j                         d   d   }|dk(  ry|d	k(  ry
y| S # t         j                  $ r"}t        j	                  d|       | cY d }~S d }~ww xY w)Neth0zsystemd-detect-virtzHUnable to run systemd-detect-virt: %s. Rendering default network config.)kvmqemuuname   ppc64leenp0s5s390xenc9enp5s0)r   whichProcessExecutionErrorLOGwarningstripr   system_info)default_name	virt_type_errarchs        A/usr/lib/python3/dist-packages/cloudinit/sources/DataSourceLXD.py_get_fallback_interface_namer5   /   s    Lzz'(	 99&;%<=LIq ?? !
 
 ##%g.q1Dy % )) 	 KK5
  	 s   A- -B" BB"B"nicsc                     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   physicaldhcpr   )typecontrol)r;   namesubnets)versionconfig)r   r+   debugr5   )r6   primary_nics     r4   generate_network_configrC   I   sm     $%K			
 34		+	
  ##%+?@
	 	    c                   $     e Zd Z fdZd Z xZS )SocketHTTPConnectionc                 @    t         |   d       || _        d | _        y N	localhost)super__init__socket_pathsockselfrL   	__class__s     r4   rK   zSocketHTTPConnection.__init__p   s    %&	rD   c                     t        j                   t         j                  t         j                        | _        | j                  j	                  | j
                         y N)socketAF_UNIXSOCK_STREAMrM   connectrL   rO   s    r4   rV   zSocketHTTPConnection.connectu   s6    MM&..&2D2DE			$**+rD   )__name__
__module____qualname__rK   rV   __classcell__rP   s   @r4   rF   rF   o   s    
,rD   rF   c                   $     e Zd Z fdZd Z xZS )SocketConnectionPoolc                 2    || _         t        | 	  d       y rH   )rL   rJ   rK   rN   s     r4   rK   zSocketConnectionPool.__init__{   s    &%rD   c                 ,    t        | j                        S rR   )rF   rL   rW   s    r4   	_new_connzSocketConnectionPool._new_conn   s    #D$4$455rD   )rX   rY   rZ   rK   ra   r[   r\   s   @r4   r^   r^   z   s    &6rD   r^   c                       e Zd ZddZ	 ddZy)LXDSocketAdapterNc                      t        t              S rR   )r^   LXD_SOCKET_PATH)rO   urlproxiess      r4   get_connectionzLXDSocketAdapter.get_connection   s    #O44rD   c                 :    | j                  |j                  |      S rR   )rh   rf   )rO   requestverifyrg   certs        r4   get_connection_with_tls_contextz0LXDSocketAdapter.get_connection_with_tls_context   s     ""7;;88rD   rR   )NN)rX   rY   rZ   rh   rm    rD   r4   rc   rc      s    5 379rD   rc   metadata_typec                    t        |t              r|S |i S 	 t        j                  |      }|&t        j                  dj                  | |            |S # t        $ r,}t        j                  dj                  | |            |d}~ww xY w)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})md_typevaluez:Invalid {md_type} format. Expected YAML but found: {value})
isinstancedictr   	load_yamlAttributeErrorr   InvalidMetaDataExceptionformat)ro   metadata_valueparsed_metadataexcs       r4   _raw_instance_data_to_dictr|      s     .$'	..8 ..vm>vJ
 	
   ..vm>vJ
 	s   A 	B 'BBc                   &    e Zd ZU dZej
                  Zeee	f   e
d<   ej
                  Zeeee	f      e
d<   ej                  j                  dz   Zee	df   e
d<   dZded	d
f fdZed	efd       Zd	efdZd	e	fdZd	e	fdZed	efd       Z xZS )DataSourceLXDLXD_network_config_crawled_metadata)user.meta-datar   r   r   r   .sensitive_metadata_keysTci_pkl_versionr   Nc                 2    t         |   |       d| _        y )NT)rJ   	_unpickleskip_hotplug_detect)rO   r   rP   s     r4   r   zDataSourceLXD._unpickle   s    .)#' rD   c                      t               S )z@Check platform environment to report if this datasource may run.)is_platform_viablern   rD   r4   	ds_detectzDataSourceLXD.ds_detect   s     "##rD   c                    t        j                  t        j                  dt              | _        t        d| j
                  j                  d            | _        | j
                  j                  di       }|j                  di       }|rt        d|      }d| j
                  v r| j
                  d   | _	        d| j
                  v rt        d| j
                  d         | _
        d| j
                  v r| j
                  d   | _        y	)
z=Crawl LXD socket API instance data and return True on successzCrawl of metadata service)logfuncmsgfunc	meta-datar@   r   r   r   r   T)r   log_timer+   rA   read_metadatar   r|   getmetadatauserdata_rawr   vendordata_raw)rO   r@   user_metadatas      r4   	_get_datazDataSourceLXD._get_data   s    !%II+"

 3//33K@
 ''++Hb9

#3R86 -M $000 $ 6 6{ CDt555#= $"8"89I"J$D  D222"&"8"8"GDrD   c                 8    dj                  t        t              S )z.Return subplatform details for this datasourcez"LXD socket API v. {ver} ({socket}))verrS   )rx   LXD_SOCKET_API_VERSIONre   rW   s    r4   _get_subplatformzDataSourceLXD._get_subplatform   s    3::& ; 
 	
rD   c                     t        t        j                        }|j                  di       }t	        |t
              st        j                  |      }|j                  d      | j                  j                  d      k(  S )z%Return True if instance_id unchanged.metadata_keysr   zinstance-id)	r   MetaDataKeys	META_DATAr   rs   rt   r   ru   r   )rO   sys_cfgresponsemds       r4   check_instance_idzDataSourceLXD.check_instance_id   s]     |/E/EF\\+r*"d##Bvvm$(9(9-(HHHrD   c                    | j                   t        j                  k(  r| j                  t        j                  k(  r| j	                          t        | j                  t              r| j                  j                  d      r*t        j                  d       | j                  d   | _         nb| j                  j                  d      rG| j                  d   j                         D cg c]  \  }}|d   dk(  r| }}}t        |      | _         | j                   t        j                  k(  r$t        j                  d       t               | _         t        t        | j                         S c c}}w )zNetwork config read from LXD socket config/user.network-config.

        If none is present, then we generate fallback configuration.
        r   z,LXD datasource using provided network configdevicesr;   nicz8LXD datasource generating network config using fallback.)r   r   UNSETr   r   rs   rt   r   r+   rA   itemsrC   r   )rO   kvr   s       r4   network_configzDataSourceLXD.network_config   s)    7==0%%6 $00$7))--.>?IILM+/+A+A(,D( ++//	:
 %)$:$:9$E$K$K$M* AqV9- *G *
 ,C7+KD(7==0IIJ $;#<D D$..//*s   %E')rX   rY   rZ   dsnamer   r   r   r   r   str__annotations__r   r	   
DataSourcer   r
   r   intr   staticmethodboolr   r   r   r   propertyrt   r   r[   r\   s   @r4   r~   r~      s    F(/OU49%54;MMxdCi 01A 	22 6 	 US  ( ( ( $t $ $4 4
# 
IC I 0 0 0rD   r~   c                      t         j                  j                  t              r6t	        j
                  t        j                  t              j                        S y)z=Return True when this platform appears to have an LXD socket.F)ospathexistsre   statS_ISSOCKlstatst_modern   rD   r4   r   r     s3    	ww~~o&}}RXXo6>>??rD   sessionrf   do_raisec           	      r   t        | ||      }|j                  s=t        j                  d||j                  |j
                  j                  d             i S 	 |j                         S # t        $ rE}t        j                  dj                  ||j
                  j                  d                  |d }~ww xY w)NSkipping %s on [HTTP:%d]:%sutf-8zFUnable to process LXD config at {url}. Expected JSON but found: {resp})rf   resp)_do_requestokr+   rA   status_codecontentdecodejsonr   r   rw   rx   )r   rf   r   url_responser{   s        r4   _get_json_responser     s     wX6L??		)$$  ''0		
 	  "" ..//5vl2299'B 06 0

 	s   A( (	B61A B11B6c           	         t        ddd      D ][  }| j                  |      }d|j                  k(  r8t        j                  d       t
        j                  d|j                  ||       [ n t
        j                  dj                  |       |rV|j                  sJt        j                  dj                  |j                  ||j                  j                  d	      
            |S )N   r   i  g?z,[GET] [HTTP:%d] %s, retrying %d more time(s)z[GET] [HTTP:%d] %sz3Invalid HTTP response [{code}] from {route}: {resp}r   )coderouter   )ranger   r   timesleepr+   r,   rA   r   r   rw   rx   r   r   )r   rf   r   retriesr   s        r4   r   r   0  s     Q# ;;s#(&&& JJsOKK>$$	  II"H$8$8#>..AHH))%%,,W5 I 
 	
 OrD   c                   T    e Zd Z e       Z e       Z e       Z e       Zeez  ez  Zy)r   N)	rX   rY   rZ   r   NONECONFIGDEVICESr   ALLrn   rD   r4   r   r   M  s-    6DVFfGI
7
Y
&CrD   r   c                   P    e Zd ZefdefdZdej                  defdZ	de
defdZy)	_MetaDataReaderapi_versionc                 d    || _         t        j                  t        | j                         | _        y rR   )r   r   combine_urlLXD_URL_version_url)rO   r   s     r4   rK   z_MetaDataReader.__init__V  s%    &&227D<L<LMrD   r   r   c           
      4   di i}t        j                  | j                  d      }t        ||      }t	        |      D ]  }t        j                  t
        |      }t        ||d      }|j                  j                  d      }|j                  s#t        j                  d||j                  |       u|j                  d      d   }	||d   |	<   |	t        v st        |	   |vr||t        |	   <   t        j                  d|	|	j!                  d	d
d              |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r   r   r   /r   z,Ignoring LXD config %s in favor of %s value.userz
cloud-initr8   )r   r   r   r   sortedr   r   r   r   r   r+   rA   r   
rpartitionCONFIG_KEY_ALIASESr,   replace)
rO   r   r@   
config_urlconfig_routesconfig_routeconfig_route_urlconfig_route_responseresponse_textcfg_keys
             r4   _process_configz_MetaDataReader._process_configZ  s+    !"~++D,=,=xH
 +7J?
 #=1  	L)55g|L$/)E%! 299@@IM(++		1$)55!	 "--c226G )6F8W%,, &g.f<:GF-g67KKFa@9 	B rD   r   c                d   t        j                         5 }|j                  | j                  t	                      d| j
                  i}t        j                  |v rHt        j                  | j                  d      }t        ||      j                  j                  d      |d<   t        j                  |v r |j                  | j                  |             t        j                   |v r5t        j                  | j                  d      }t#        ||d      }|r||d<   |cd d d        S # 1 sw Y   y xY w)N_metadata_api_versionr   r   r   Fr   )requestsSessionmountr   rc   r   r   r   r   r   r   r   r   r   updater   r   r   )rO   r   r   r   md_routerf   r   s          r4   __call__z_MetaDataReader.__call__  s    	7MM$++-=-?@/1A1ABB%%6%11%%{ #.X#'&&/ ; ""m3		$..w78##}4 ,,T->->	J,WcEJ$+ByM%	 	 	s   DD&&D/N)rX   rY   rZ   r   r   rK   r   r   rt   r   r   r   rn   rD   r4   r   r   U  s@    *@ NC N4x'7'7 4D 4l $ rD   r   r   r   c                 (     t        |       |      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   s     r4   r   r     s    F 4?{3# rD   c                 6    t        j                  | t              S rR   )r   list_from_dependsdatasources)dependss    r4   get_datasource_listr     s    $$Wk::rD   __main__z*Query LXD metadata and emit a JSON object.)descriptionr   rR   )T)G__doc__loggingr   rS   r   r   enumr   r   json.decoderr   typingr   r   r   r	   r
   r   r   r   requests.adaptersr   urllib3.connectionr   urllib3.connectionpoolr   	cloudinitr   r   r   r   r   cloudinit.netr   	getLoggerrX   r+   re   r   r   r   r   r5   rC   rF   r^   rc   rt   r|   r   r~   r   r   r   r   Responser   r   r   r   r   DEP_FILESYSTEMr   r   argparser   ArgumentParserparser
parse_argsprint
json_dumpsrn   rD   r4   <module>r     s,    	     ( @ @ @  ) . 5 D D +g!! 
 (!1+!+% c 6 !%#
49
#	#s(^#L,> ,6- 6	9{ 	9c d :c0G&& c0LD  ;?$'370 ;?$'37:'4 'N Nd ."."2"2%%% 
%T W++-.; zBK$X$$=F
	   \=M=M!NO rD   