o x[hD @sHdZddlZddlZddlZddlZddlZddlmZmZddl m Z ddl m Z m Z mZmZmZmZmZddlZddlmZddlmZddlmZdd lmZmZmZmZmZdd l m!Z!e"e#Z$d Z%d Z&d Z'dddddddZ(de)fddZ* d9deee)de e)e ffddZ+GdddeZ,GdddeZ-GdddeZ.de)de/fdd Z0Gd!d"d"ej1Z2 #d:d$ej3d%e)d&e4fd'd(Z5 #d:d$ej3d%e)d&e4dej6fd)d*Z7Gd+d,d,eZ8Gd-d.d.Z9e&e8j:fd/e)d0e8de/fd1d2Z;e2eje#d5kr"ddl?Z?d6Z@e?jAe@d7ZBeBCeDeEe;e8j:d8dSdS);aDatasource 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)Flagauto)JSONDecodeError)AnyDictListOptionalTupleUnioncast) HTTPAdapter)HTTPConnection)HTTPConnectionPool) atomic_helpersourcessubp url_helperutil)find_fallback_nicz /dev/lxd/sockz1.0z http://lxd user-datanetwork-config vendor-data)cloud-init.user-datazcloud-init.network-configcloud-init.vendor-datauser.user-datazuser.network-configuser.vendor-datareturnc Csd}tdrIz tdg\}}Wntjy,}ztd||WYd}~Sd}~ww|dvrItdd}|dkrAdS|d krGd Sd S|S) Neth0zsystemd-detect-virtzHUnable to run systemd-detect-virt: %s. Rendering default network config.)kvmqemuunameppc64leenp0s5s390xenc9enp5s0)rwhichProcessExecutionErrorLOGwarningstripr system_info) default_name virt_type_errarchr2A/usr/lib/python3/dist-packages/cloudinit/sources/DataSourceLXD.py_get_fallback_interface_name/s(  r4nicscCsFt}|r td|n t}td|dd|dddgdgd 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: %sphysicaldhcpr)typecontrol)r9namesubnets)versionconfig)rr)debugr4)r5 primary_nicr2r2r3generate_network_configIs$  rAc$eZdZfddZddZZS)SocketHTTPConnectioncstd||_d|_dSN localhost)super__init__ socket_pathsockselfrH __class__r2r3rGps  zSocketHTTPConnection.__init__cCs$ttjtj|_|j|jdSN)socketAF_UNIX SOCK_STREAMrIconnectrHrKr2r2r3rRuszSocketHTTPConnection.connect)__name__ __module__ __qualname__rGrR __classcell__r2r2rLr3rCos rCcrB)SocketConnectionPoolcs||_tddSrD)rHrFrGrJrLr2r3rG{szSocketConnectionPool.__init__cCs t|jSrN)rCrHrSr2r2r3 _new_conns zSocketConnectionPool._new_conn)rTrUrVrGrYrWr2r2rLr3rXzs rXc@s"eZdZdddZ dddZdS)LXDSocketAdapterNcCsttSrN)rXLXD_SOCKET_PATH)rKurlproxiesr2r2r3get_connectionszLXDSocketAdapter.get_connectioncCs||j|SrN)r^r\)rKrequestverifyr]certr2r2r3get_connection_with_tls_contextsz0LXDSocketAdapter.get_connection_with_tls_contextrN)NN)rTrUrVr^rbr2r2r2r3rZs rZ metadata_typec Csxt|tr|S|dur iSzt|}Wnty+}z tdj||d|d}~ww|dur:tdj||d|S)a6Convert 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_typevaluez:Invalid {md_type} format. Expected YAML but found: {value}) isinstancedictr load_yamlAttributeErrorrInvalidMetaDataExceptionformat)rcmetadata_valueparsed_metadataexcr2r2r3_raw_instance_data_to_dicts. rocseZdZUdZejZeee fe d<ejZ e eee fe d<ej jdZee dfe d<dZded d ffd d Zed efd dZd efddZd e fddZd e fddZed efddZZS) DataSourceLXDLXD_network_config_crawled_metadata)user.meta-datarrrr.sensitive_metadata_keysTci_pkl_versionrNcst|d|_dS)NT)rF _unpickleskip_hotplug_detect)rKrvrLr2r3rws  zDataSourceLXD._unpicklecCsBtjtstdtdStttj stdtdSdS)z@Check platform environment to report if this datasource may run.z%s does not exist.Fz%s is not a socketT) ospathexistsr[r)r*statS_ISSOCKlstatst_moder2r2r2r3 ds_detects   zDataSourceLXD.ds_detectcCst|_td|jd|_|jdi}|di}|r&|jtd|d|jvr1|jd|_d|jvr?td|jd|_d|jvrJ|jd|_dS)z=Crawl LXD socket API instance data and return True on success meta-datar>rtrrrT) read_metadatarsrogetmetadataupdate userdata_rawrrvendordata_raw)rKr> user_metadatar2r2r3 _get_datas&        zDataSourceLXD._get_datacCsdjttdS)z.Return subplatform details for this datasourcez"LXD socket API v. {ver} ({socket}))verrO)rkLXD_SOCKET_API_VERSIONr[rSr2r2r3_get_subplatformszDataSourceLXD._get_subplatformcCsBttjd}|di}t|tst|}|d|jdkS)z%Return True if instance_id unchanged. metadata_keysrz instance-id) r MetaDataKeys META_DATArrfrgrrhr)rKsys_cfgresponsemdr2r2r3check_instance_ids    zDataSourceLXD.check_instance_idcCs|jtjkr?|jtjkr|t|jtr?|jdr(t d|jd|_n|jdr?dd|jd D}t ||_|jtjkrNt dt |_t t|jS)zNetwork config read from LXD socket config/user.network-config. If none is present, then we generate fallback configuration. rz,LXD datasource using provided network configdevicescSs g|] \}}|ddkr|qS)r9nicr2).0kvr2r2r3 s  z0DataSourceLXD.network_config..z8LXD datasource generating network config using fallback.) rrrUNSETrsrrfrgrr)r?itemsrAr )rKrr2r2r3network_configs(          zDataSourceLXD.network_config)rTrUrVdsnamerrrrr rstr__annotations__rsr DataSourcerur rxintrw staticmethodboolrrrrpropertyrgrrWr2r2rLr3rps"   rpTsessionr\do_raisec Csrt|||}|jstd||j|jdiSz|WSty8}zt dj ||jdd|d}~ww)NSkipping %s on [HTTP:%d]:%sutf-8zFUnable to process LXD config at {url}. Expected JSON but found: {resp})r\resp) _do_requestokr)r? status_codecontentdecodejsonrrrjrk)rr\r url_responsernr2r2r3_get_json_responses,    rcCstdddD]}||}d|jkr!tdtd|j||qtd|j||r?|js?t dj |j||j d d |S) Nrig?z,[GET] [HTTP:%d] %s, retrying %d more time(s)z[GET] [HTTP:%d] %sz3Invalid HTTP response [{code}] from {route}: {resp}r)coderouter)rangerrtimesleepr)r*r?rrrjrkrr)rr\rretriesrr2r2r3r,s*     rc@s0eZdZeZeZeZeZeeBeBZdS)rN) rTrUrVrNONECONFIGDEVICESrALLr2r2r2r3rIs rc@sDeZdZefdefddZdejdefddZ de defd d Z d S) _MetaDataReader api_versioncCs||_tt|j|_dSrN)rr combine_urlLXD_URL _version_url)rKrr2r2r3rGRsz_MetaDataReader.__init__rrc Csdii}t|jd}t||}t|D]L}tt|}t||dd}|jd}|j s6t d||j |q| dd} ||d| <| tvr`t| |vrT||t| <qt d| | d d d q|S) aIterate 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>Frrr/rz,Ignoring LXD config %s in favor of %s value.userz cloud-initr6)rrrrsortedrrrrrr)r?r rpartitionCONFIG_KEY_ALIASESr*replace) rKrr> config_url config_routes config_routeconfig_route_urlconfig_route_response response_textcfg_keyr2r2r3_process_configVs:        z_MetaDataReader._process_configrcCstT}||jtd|ji}tj|vr)t |jd}t ||j d|d<tj |vr6|||tj|vrOt |jd}t||dd}|rO||d<|WdS1s[wYdS)N_metadata_api_versionrrrFr)requestsSessionmountrrZrrrrrrrrrrrrr)rKrrrmd_router\rr2r2r3__call__s*     $z_MetaDataReader.__call__N) rTrUrVrrrGrrrgrrrr2r2r2r3rQs6rrrcCst|d|dS)a/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 /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 `ds_detect` in that case. Perform a GET of /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 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. )rr)r)rrr2r2r3rs#rcCs t|tSrN)rlist_from_depends datasources)dependsr2r2r3get_datasource_lists r__main__z*Query LXD metadata and emit a JSON object.) descriptionrrN)T)F__doc__loggingryrOr|renumrr json.decoderrtypingrrrrr r r rrequests.adaptersr urllib3.connectionr urllib3.connectionpoolr cloudinitrrrrr cloudinit.netr getLoggerrTr)r[rrrrr4rArCrXrZrgrorrprrrResponserrrrrDEP_FILESYSTEMrrargparserArgumentParserparser parse_argsprint json_dumpsr2r2r2r3s  $         &   j  R *