U
    Ӈgk,                     @   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edddZeeeedddZdd Zdd Z edkre   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)JinjaSyntaxParsingExceptionZ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.
    )progZ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?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:". )r   nargsr   z-az--alldump_allz Dump all available instance-data)r   r   destr   z-fz--formatformatzOptionally 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&   sp    		
		r#   c                 C   sD   t j| dd}z|dW S  tk
r>   t j|ddd Y S X dS )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)quietzutf-8F)r$   decodeN)r   Zload_binary_filer%   UnicodeDecodeErrorZdecomp_gzip)Zud_file_pathZbdatar!   r!   r"   load_userdata~   s
    r'   )returnc              
   C   s  t  }t }| r| }nF|d}|dkrZ|d}t j|rF|}q^td|| |}n|}|rh|}nt j|j	d}|r|}	nt j|j	d}	|d}
zt
|}W nL ttfk
r } z*|jtkrtd| ntd	|  W 5 d
}~X Y nX t
|} zt
t
|
}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   Zload_text_file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   sl    








r8   jinja_vars_without_aliasesjinja_vars_with_aliasesr   	list_keysc           
      C   s   d}| }| dD ]}z|| }W nJ tk
rl } z,|rHdj||d}n
d|}t||W 5 d}~X Y nX ||kr|| }n"|D ]}	t|	|kr||	 } qq|r|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}')ZleafZkey_pathz Undefined instance-data key '{}'N)splitKeyErrorr   
ValueErrorr   )
r:   r;   r   r<   Zwalked_key_pathresponseZkey_path_partr7   msgkeyr!   r!   r"   (_find_instance_data_leaf_by_varname_path   s.     


rE   c              
   C   s  t |j|j|j|jgs0td t   dS zt	|j
|j|j}W n ttfk
r`   Y dS X |jrdj|jd}zt|d||jrdndd}W n8 tk
r } ztd	t| W Y dS d
}~X Y nX |rt| dS dS t|}|jrPt|dd}zt|||j|jd}W n8 ttfk
rN } zt| W Y dS d
}~X Y nX |jrt|tsvtd|j dS dt| }t|tst|}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 command lineTF)payloadZ
payload_fnr   debugz#Failed to render templated data. %sNr   )Zinclude_key_aliasesr9   z+--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   rH   r
   r   printr   rE   r@   rA   
isinstancedictr/   sortedkeysr   Z
json_dumps)nameargsr   rG   Zrendered_payloadr7   rB   r;   r!   r!   r"   handle_args  sz    
  
 

 
rR   c                  C   s   t  } ttt|   dS )z,Tool to query specific instance-data values.N)r#   sysexitrR   r   
parse_argsr   r!   r!   r"   mainK  s    rV   __main__)N)!r   r   Zloggingr*   rS   r2   r   Z	cloudinitr   r   Zcloudinit.cmd.develr   Z!cloudinit.handlers.jinja_templater   r   r   Zcloudinit.sourcesr	   Zcloudinit.templaterr
   r   Z	getLogger__name__r.   r#   r'   rM   r8   r   boolrE   rR   rV   r!   r!   r!   r"   <module>   s0   

XQ+C