o x[hk,@sdZddlZddlZddlZddlZddlmZddlmZm Z ddl m Z ddl m Z mZmZddlmZddlmZd ZeeZdd d Zd d ZdefddZdedededefddZddZddZ edkrqe dSdS)aTQuery standardized instance metadata provided to machine, returning a JSON structure. Some instance-data values may be binary on some platforms, such as userdata and vendordata. Attempt to decompress and decode UTF-8 any binary values. Any binary values in the instance metadata will be base64-encoded and prefixed with "ci-b64:" in the output. userdata and, where applicable, vendordata may be provided to the machine gzip-compressed (and therefore as binary data). query will attempt to decompress these to a string before emitting the JSON output; if this fails, they are treated as binary. N)EACCES) atomic_helperutil)read_cfg_paths)convert_jinja_instance_dataget_jinja_variable_aliasrender_jinja_payload)REDACT_SENSITIVE_VALUE)JinjaSyntaxParsingExceptionquerycCs|s tjttd}|jdddddd|jdd td td d |jd ddddd|jddtdd |jddtdd |jdtddd|jddddddd|jdd td!d"d#|S)$a#Build or extend an arg parser for query utility. @param parser: Optional existing ArgumentParser instance representing the query subcommand which will be extended to support the args of this utility. @returns: ArgumentParser with proper argument configuration. )prog descriptionz-dz--debug store_trueFz+Add verbose messages during template render)actiondefaulthelpz-iz--instance-dataz,Path to instance-data.json file. Default is instance_data)typerz-lz --list-keyszBList query keys available at the provided instance-data .z-uz --user-datazHPath to user-data file. Default is /var/lib/cloud/instance/user-data.txtz-vz --vendor-datazLPath to vendor-data file. Default is /var/lib/cloud/instance/vendor-data.txtvarname?zA dot-delimited specific variable to query from instance-data. For example: v1.local_hostname. If the value is not JSON serializable, it will be base64-encoded and will contain the prefix "ci-b64:". )rnargsrz-az--alldump_allz Dump all available instance-data)rrdestrz-fz--formatformatzOptionally specify a custom output format string. Any instance-data variable can be specified between double-curly braces. For example -f "{{ v2.cloud_name }}")rrr)argparseArgumentParserNAME__doc__ add_argumentstrr get_runpathparserr#5/usr/lib/python3/dist-packages/cloudinit/cmd/query.py get_parser&st        r%cCs>tj|dd}z|dWStytj|dddYSw)zAttempt to return a string of user-data from ud_file_path Attempt to decode or decompress if needed. If unable to decode the content, raw bytes will be returned. @returns: String of uncompressed userdata if possible, otherwise bytes. T)quietzutf-8F)r&decode)rload_binary_filer'UnicodeDecodeError decomp_gzip) ud_file_pathbdatar#r#r$ load_userdata~s   r-returnc Cst}t}|r |}n#|d}|dkr-|d}tj|r#|}n td|||}n|}|r4|}ntj|j d}|rA|} ntj|j d} |d} zt |} Wn!t t fyv} z| jtkrktd|td |d } ~ wwt | }z t t | } Wn t t fyd } Ynw|dkrd t|f|d <d t| f|d <d t| f|d<|St||d <t| |d <| |d<|S)aReturn a dict of merged instance-data, vendordata and userdata. The dict will contain supplemental userdata and vendordata keys sourced from default user-data and vendor-data files. Non-root users will have redacted INSTANCE_JSON_FILE content and redacted vendordata and userdata values. :raise: IOError/OSError on absence of instance-data.json file or invalid access perms. rrinstance_data_sensitivez4Missing root-readable %s. Using redacted %s instead.z user-data.txtzvendor-data.txtcombined_cloud_configz$No read permission on '%s'. Try sudozMissing instance-data file: %sNz <%s> file:%suserdata vendordata)osgetuidrr pathexistsLOGwarningjoin instance_linkrload_text_fileIOErrorOSErrorerrnorerror load_jsonr r-)r user_data vendor_datauidpathsinstance_data_fnredacted_data_fnsensitive_data_fn user_data_fnvendor_data_fncombined_cloud_config_fn instance_jsoner0r#r#r$_read_instance_datasv             rMjinja_vars_without_aliasesjinja_vars_with_aliasesr list_keysc Csd}|}|dD]M}z||}Wn ty1}z|r#dj||d}nd|}t||d}~ww||vr;||}n|D]} t| |krK|| }nq=|rR|d7}||7}q |S)aReturn the value of the dot-delimited varname path in instance-data Split a dot-delimited jinja variable name path into components, walk the path components into the instance_data and look up a matching jinja variable name or cloud-init's underscore-delimited key aliases. :raises: ValueError when varname represents an invalid key name or path or if list-keys is provided by varname isn't a dict object. .z*instance-data '{key_path}' has no '{leaf}')leafkey_pathz Undefined instance-data key '{}'N)splitKeyErrorr ValueErrorr) rNrOrrPwalked_key_pathresponse key_path_partrLmsgkeyr#r#r$(_find_instance_data_leaf_by_varname_paths2      r]c Cst|j|j|j|jgstdtdSz t |j |j |j }Wn t tfy/YdSw|jrodj|jd}zt|d||jrDdndd}Wntyd}ztd t|WYd }~dSd }~ww|rmt|d SdSt|}|jrt|dd }z t|||j|jd }Wnttfy}z t|WYd }~dSd }~ww|jrt|tstd|jdSdt|}t|tst|}t|d S)z3Handle calls to 'cloud-init query' as a subcommand.zDExpected one of the options: --all, --format, --list-keys or varnamez## template: jinja {fmt})fmtzquery command lineTF)payload payload_fnrdebugz#Failed to render templated data. %sNr)include_key_aliases)rNrOrrPz+--list-keys provided but '%s' is not a dict )anyrPrrrr7r?r% print_helprMrrArBr<r=rrbr rprintrr]rVrW isinstancedictr9sortedkeysr json_dumps)nameargsrr`rendered_payloadrLrYrOr#r#r$ handle_argss|         rpcCst}ttt|dS)z,Tool to query specific instance-data values.N)r%sysexitrpr parse_argsr!r#r#r$mainKsrt__main__)N)!rrloggingr3rqr>r cloudinitrrcloudinit.cmd.develr!cloudinit.handlers.jinja_templaterrrcloudinit.sourcesr cloudinit.templaterr r getLogger__name__r7r%r-rirMrboolr]rprtr#r#r#r$s<       XP +C