o
    x[hk,  ã                   @   sæ   d 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	 ddl
mZ ddlmZmZmZ ddlmZ ddlmZ d	Ze e¡Zdd
d„Zdd„ Zdefdd„Zdedededefdd„Zdd„ Zdd„ Z edkrqe ƒ  dS dS )aT  Query 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_helperÚutil)Úread_cfg_paths)Úconvert_jinja_instance_dataÚget_jinja_variable_aliasÚrender_jinja_payload)ÚREDACT_SENSITIVE_VALUE)ÚJinjaSyntaxParsingExceptionÚqueryc                 C   s¾   | s	t jttd�} | jdddddd� | jdd	td
tƒ  d¡› �d� | jdddddd� | jddtdd� | jddtdd� | jdtddd� | jddddddd� | jdd td!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)ÚactionÚdefaultÚhelpz-iz--instance-dataz,Path to instance-data.json file. Default is Úinstance_data)Útyper   z-lz--list-keyszBList query keys available at the provided instance-data <varname>.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.txtÚvarnameú?zÇA 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:". )r   Únargsr   z-az--allÚdump_allz Dump all available instance-data)r   r   Údestr   z-fz--formatÚformatzŸOptionally specify a custom output format string. Any instance-data variable can be specified between double-curly braces. For example -f "{{ v2.cloud_name }}")r   r   r   )ÚargparseÚArgumentParserÚNAMEÚ__doc__Úadd_argumentÚstrr   Úget_runpath©Úparser© r#   ú5/usr/lib/python3/dist-packages/cloudinit/cmd/query.pyÚ
get_parser&   st   	û
ÿû	ú
û	û	ûúúr%   c                 C   s>   t j| dd�}z| d¡W S  ty   t j|ddd� Y S w )züAttempt 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)Úquietzutf-8F)r&   Údecode)r   Úload_binary_filer'   ÚUnicodeDecodeErrorÚdecomp_gzip)Úud_file_pathÚbdatar#   r#   r$   Úload_userdata~   s   ÿr-   Úreturnc              
   C   sˆ  t  ¡ }tƒ }| r| }n#| d¡}|dkr-| d¡}t j |¡r#|}nt d||¡ |}n|}|r4|}nt j |j	d¡}|rA|}	nt j |j	d¡}	| d¡}
zt
 |¡}W n! ttfyv } z|jtkrkt d|¡ ‚ t d	|¡ ‚ d
}~ww t
 |¡} z
t
 t
 |
¡¡}W n ttfy“   d
}Y nw |dkr²dt|f | d< dt|	f | d< dt|
f | d< | S t|ƒ| d< t|	ƒ| d< || d< | S )aš  Return 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.
    r   r   Úinstance_data_sensitivez4Missing root-readable %s. Using redacted %s instead.zuser-data.txtzvendor-data.txtÚcombined_cloud_configz$No read permission on '%s'. Try sudozMissing instance-data file: %sNz<%s> file:%sÚuserdataÚ
vendordata)ÚosÚgetuidr   r    ÚpathÚexistsÚLOGÚwarningÚjoinÚinstance_linkr   Úload_text_fileÚIOErrorÚOSErrorÚerrnor   ÚerrorÚ	load_jsonr	   r-   )r   Ú	user_dataÚvendor_dataÚuidÚpathsÚinstance_data_fnÚredacted_data_fnÚsensitive_data_fnÚuser_data_fnÚvendor_data_fnÚcombined_cloud_config_fnÚinstance_jsonÚer0   r#   r#   r$   Ú_read_instance_data�   sv   

ý

ÿ€û
ÿý
þ
þ
þýrM   Újinja_vars_without_aliasesÚjinja_vars_with_aliasesr   Ú	list_keysc           
      C   s²   d}| }|  d¡D ]M}z|| }W n  ty1 } z|r#dj||d�}nd |¡}t|ƒ|‚d}~ww ||v r;|| }n|D ]}	t|	ƒ|krK||	 } nq=|rR|d7 }||7 }q	|S )a³  Return 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}')ÚleafÚkey_pathz Undefined instance-data key '{}'N)ÚsplitÚKeyErrorr   Ú
ValueErrorr   )
rN   rO   r   rP   Úwalked_key_pathÚresponseÚkey_path_partrL   ÚmsgÚkeyr#   r#   r$   Ú(_find_instance_data_leaf_by_varname_pathÝ   s2   ÿ

€ù
þ
r]   c              
   C   sš  t |j|j|j|jgƒst d¡ tƒ  ¡  dS zt	|j
|j|jƒ}W n ttfy/   Y dS w |jrodj|jd�}zt|d||jrDdndd�}W n tyd } zt d	t|ƒ¡ W Y d
}~dS d
}~ww |rmt|ƒ dS dS t|ƒ}|jr£t|dd�}zt|||j|jd�}W n ttfy¢ } zt |¡ W Y d
}~dS d
}~ww |jr½t|tƒs´t d|j¡ dS d t| ¡ ƒ¡}t|tƒsÇt |¡}t|ƒ dS )z3Handle calls to 'cloud-init query' as a subcommand.zDExpected one of the options: --all, --format, --list-keys or varnameé   z## template: jinja
{fmt})Úfmtzquery command lineTF)ÚpayloadÚ
payload_fnr   Údebugz#Failed to render templated data. %sNr   )Úinclude_key_aliases)rN   rO   r   rP   z+--list-keys provided but '%s' is not a dictÚ
)ÚanyrP   r   r   r   r7   r?   r%   Ú
print_helprM   r   rA   rB   r<   r=   r   rb   r
   r   Úprintr   r]   rV   rW   Ú
isinstanceÚdictr9   ÚsortedÚkeysr   Ú
json_dumps)ÚnameÚargsr   r`   Úrendered_payloadrL   rY   rO   r#   r#   r$   Úhandle_args  s|   ÿ
ÿÿ
üþ€ûÿ
ü
€þ
ÿ

rp   c                  C   s   t ƒ } t tt|  ¡ ƒ¡ dS )z,Tool to query specific instance-data values.N)r%   ÚsysÚexitrp   r   Ú
parse_argsr!   r#   r#   r$   ÚmainK  s   rt   Ú__main__)N)!r   r   Úloggingr3   rq   r>   r   Ú	cloudinitr   r   Úcloudinit.cmd.develr   Ú!cloudinit.handlers.jinja_templater   r   r   Úcloudinit.sourcesr	   Úcloudinit.templaterr
   r   Ú	getLoggerÚ__name__r7   r%   r-   ri   rM   r   Úboolr]   rp   rt   r#   r#   r#   r$   Ú<module>   s<   

XPÿþý
ü+C
ÿ