
Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­
<!DOCTYPE html>
<html>
3
\¼me@+  ã               @   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ZejeƒZdd	d
„Zdd„ Zedœdd„Zeeeedœdd„Zdd„ Zdd„ ZedkrÌeƒ  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_VALUEZqueryc             C   s¾   | st jttd�} | jdddddd� | jdd	td
tƒ j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    ú/usr/lib/python3.6/query.pyÚ
get_parser%   s`    	r"   c             C   s>   t j| dd�}y
|jdƒS  tk
r8   t j|ddd�S X dS )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.
    F)Údecodezutf-8T)Úquietr#   N)r   Ú	load_filer#   ÚUnicodeDecodeErrorZdecomp_gzip)Zud_file_pathZbdatar    r    r!   Úload_userdata}   s
    
r'   )Úreturnc             C   s–  t jƒ }tƒ }| r| }nF|jdƒ}|dkrZ|jdƒ}t jj|ƒrF|}q^tjd||ƒ |}n|}|rh|}nt jj|j	dƒ}|r‚|}	nt jj|j	dƒ}	|jdƒ}
yt
j|ƒ}W nL ttfk
rö } z,|jtkrØtjd|ƒ ntjd	|ƒ ‚ W Y d
d
}~X nX t
j|ƒ} yt
jt
j|
ƒƒ}W n ttfk
�r4   d
}Y nX |dk�rrdt|f | d< dt|	f | d< dt|
f | d< n 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   Z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:%sZuserdataZ
vendordata)ÚosÚgetuidr   r   ÚpathÚexistsÚLOGZwarningÚjoinZinstance_linkr   r%   ÚIOErrorÚOSErrorÚerrnor   ÚerrorZ	load_jsonr	   r'   )r   Ú	user_dataÚvendor_dataZuidÚpathsZinstance_data_fnZredacted_data_fnZsensitive_data_fnZuser_data_fnZvendor_data_fnZcombined_cloud_config_fnZinstance_jsonÚer)   r    r    r!   Ú_read_instance_dataŒ   sb    






r8   )Újinja_vars_without_aliasesÚjinja_vars_with_aliasesr   Ú	list_keysc       
      C   sÂ   d}| }x´|j dƒD ]¦}y|| }W nJ tk
rn } z.|rJdj||d�}n
dj|ƒ}t|ƒ|‚W Y dd}~X nX ||kr‚|| }n$x"|D ]}	t|	ƒ|krˆ||	 }P qˆW |r²|d7 }||7 }qW |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}')ZleafZkey_pathz Undefined instance-data key '{}'N)ÚsplitÚKeyErrorr   Ú
ValueErrorr   )
r9   r:   r   r;   Zwalked_key_pathÚresponseZkey_path_partr7   ÚmsgÚkeyr    r    r!   Ú(_find_instance_data_leaf_by_varname_pathÜ   s*    


rD   c             C   sb  t |j|j|j|jgƒs0tjdƒ tƒ jƒ  dS yt	|j
|j|jƒ}W n ttfk
r^   dS X |jr¢dj|jd�}t|d||jr†dndd�}|ržt|ƒ d	S dS t|ƒ}|j�rt|dd
�}yt|||j|jd�}W n0 ttfk
�r } ztj|ƒ dS d}~X nX |j�r@t|tƒ�s.tjd|jƒ dS djt|jƒ ƒƒ}t|tƒ�sVtj|ƒ}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})Zfmtzquery commandlineTF)ÚpayloadZ
payload_fnr   Údebugr   )Zinclude_key_aliases)r9   r:   r   r;   Nz+--list-keys provided but '%s' is not a dictÚ
)Úanyr;   r   r   r   r.   r3   r"   Z
print_helpr8   r   r4   r5   r0   r1   r   rG   Úprintr   rD   r?   r@   Ú
isinstanceÚdictr/   ÚsortedÚkeysr   r   Z
json_dumps)ÚnameÚargsr   rF   Zrendered_payloadrA   r:   r7   r    r    r!   Úhandle_args  sX    




rQ   c              C   s   t ƒ } tjtt| jƒ ƒƒ dS )z,Tool to query specific instance-data values.N)r"   ÚsysÚexitrQ   r   Ú
parse_args)r   r    r    r!   ÚmainC  s    rU   Ú__main__)N)r   r   Zloggingr*   rR   r2   r   Z	cloudinitr   r   Zcloudinit.cmd.develr   Z!cloudinit.handlers.jinja_templater   r   r   Zcloudinit.sourcesr	   r   Z	getLoggerÚ__name__r.   r"   r'   rL   r8   r   ÚboolrD   rQ   rU   r    r    r    r!   Ú<module>   s,   

XQ'<