o
    w7e9                     @   s   d dl Z d dlZd dlZd dlmZ d dlmZmZmZ e	e
ZdZg dZG dd dejZdd	 Zd
d Zdd ZddeddfddZdd ZG dd deZG dd deZeejejffgZdd Ze
dkrtdd Ze  dS dS )    N)log)sources
url_helperutilz
2012-03-01))meta-data/instance-idr   FF)meta-data/local-hostnamer   FF)meta-data/public-keysr   FT)zmeta-data/vendor-datavendor-dataTT)	user-datar
   TTc                   @   s`   e Zd ZdZdZdZdZdd Zedd Z	dd	 Z
d
d Zdd Zdd Zdd Zdd ZdS )DataSourceMAASz
    DataSourceMAAS reads instance information from MAAS.
    Given a config metadata_url, and oauth tokens, it expects to find
    files under the root named:
      instance-id
      user-data
      hostname
      vendor-data
    MAASNc                 C   s:   t j| ||| d | _tj|jd| _t| j	| _
d S )Nmaas)r   
DataSource__init__base_urlospathjoinseed_dirget_id_from_ds_cfgds_cfgid_hash)selfsys_cfgdistropaths r   B/usr/lib/python3/dist-packages/cloudinit/sources/DataSourceMAAS.pyr   ,   s   zDataSourceMAAS.__init__c                 C   s   | j s	t| j| _ | j S N)_oauth_helperget_oauth_helperr   r   r   r   r   oauth_helper2   s   zDataSourceMAAS.oauth_helperc                 C   s   t j| }d|| jf S )Nz%s [%s])r   r   __str__r   )r   rootr   r   r   r#   8   s   zDataSourceMAAS.__str__c              
   C   s   | j }z| | jt| j W dS  ty   Y n ty- } z	td| j|  d }~ww |dd }|s8dS z| 	|sAW dS | |t
|| jj| jdd W dS  tyc   ttd| Y dS w )NTz%s was malformed: %smetadata_urlF   )read_file_or_urlr   retriesz$Failed fetching metadata from url %s)r   	_set_datar   read_maas_seed_dirMAASSeedDirNoneMAASSeedDirMalformedLOGwarninggetwait_for_metadata_serviceread_maas_seed_urlr"   readurlr   	Exceptionr   logexc)r   mcfgexcurlr   r   r   	_get_data<   s>   
	zDataSourceMAAS._get_datac              
   C   sv   || _ |\}}}|| _|| _|| _|r9z	t|| _W d S  ty8 } zt	d| d | _W Y d }~d S d }~ww d S )Nz"Invalid content in vendor-data: %s)
r   userdata_rawmetadatavendordata_purer   convert_vendordatavendordata_raw
ValueErrorr-   r.   )r   r7   dataudmdvder   r   r   r)   c   s   
zDataSourceMAAS._set_datac                 C   s
   d| j  S )z/Return the subplatform metadata source details.zseed-dir (%s))r   r!   r   r   r   _get_subplatformq   s   
zDataSourceMAAS._get_subplatformc           	      C   s  | j }d}z
t|d|}W n ty   ttd| Y nw |dkr&dS d}z||v r5t|d|}W n tyE   td| Y nw t }|	d	rU|d d
 }d|t
f }|g}| jj|||d\}}|rutd| t|S td|tt |  t|S )Nx   max_waitz Failed to get max wait. using %sr   F2   timeoutzFailed to get timeout, using %s/z%s/%s/meta-data/instance-id)urlsrF   rH   zUsing metadata source: '%s'z(Giving up on md from %s after %i seconds)r   intr/   r3   r   r4   r-   r.   timeendswith
MD_VERSIONr"   wait_for_urldebugcriticalbool)	r   r7   r5   rF   rH   	starttime	check_urlrK   	_responser   r   r   r0   u   sD   

z(DataSourceMAAS.wait_for_metadata_servicec                 C   s0   | j du rdS t|d| jfi }| j t|kS )a  locally check if the current system is the same instance.

        MAAS doesn't provide a real instance-id, and if it did, it is
        still only available over the network.  We need to check based
        only on local resources.  So compute a hash based on Oauth tokens.NF
datasource)r   r   get_cfg_by_pathdsnamer   )r   r   ncfgr   r   r   check_instance_id   s   
z DataSourceMAAS.check_instance_id)__name__
__module____qualname____doc__rY   r   r   r   propertyr"   r#   r8   r)   rD   r0   r[   r   r   r   r   r      s    

'&r   c                    s*   d}t  fdd|D }tjdi |S )zReturn an oauth helper instance for values in cfg.

    @raises ValueError from OauthUrlHelper if some required fields have
            true-ish values but others do not.)consumer_keyconsumer_secret	token_keytoken_secretc                    s   g | ]	}|  |fqS r   r/   ).0rcfgr   r   
<listcomp>   s    z$get_oauth_helper.<locals>.<listcomp>Nr   )dictr   OauthUrlHelper)ri   keyskwargsr   rh   r   r       s   r    c                    s4   d}d  fdd|D }dt|d  S )z;Given a config, generate a unique identifier for this node.)ra   rc   rd    c                    s   g | ]}  |d qS ) re   )rf   fr   r   r   rj      s    z&get_id_from_ds_cfg.<locals>.<listcomp>zv1:zutf-8)r   hashlibsha256encode	hexdigest)r   fieldsidstrr   rr   r   r      s   r   c                 C   sL   |  dr| dd  } tj| rtt| dkrtdtd|  d dS )Nfile://   r   z%s: not a directoryz	file://%s)version)
startswithr   r   isdirlenlistdirr+   r1   )seed_dr   r   r   r*      s
   
r*   c                 C   s  |du rt j}| dr| dd } i }tD ]n\}}}	}
|du r'd| |f }nd| ||f }z,t|}|||||d}| rQ|	rH|j||< nt|j||< nt	
d||j W q t jy } z|jdkrs|
sstd	||f ||jdkrz|W Y d}~qd}~ww t|| S )
a  
    Read the maas datasource at seed_url.
      read_file_or_url is a method that should provide an interface
      like util.read_file_or_url

    Expected format of seed_url is are the following files:
      * <seed_url>/<version>/meta-data/instance-id
      * <seed_url>/<version>/meta-data/local-hostname
      * <seed_url>/<version>/user-data
    If version is None, then <version>/ will not be used.
    NrI   rJ   z%s/%sz%s/%s/%s)r(   rH   ssl_detailsz4Fetching from %s resulted in an invalid http code %si  zMissing required %s: %s)r   r'   rN   	DS_FIELDSr   fetch_ssl_detailsokcontentsdecode_binaryr-   r.   codeUrlErrorr,   check_seed_contents)seed_urlr'   rH   r{   r   r(   rA   r   	_dictnamebinaryoptionalr7   r   resprC   r   r   r   r1      sJ   




r1   c                 C   s   i }g }t D ]5\}}}}|| vr|s|| qd|v r5|d\}}	}
||vr,i ||< | | || |
< q| | ||< qt|dkrHtd| |rRtd||f d}|drot }tj	|d|td}||u rotd|d	|d
|fS )zValidate if dictionary content valid as a return for a datasource.
    Either return a (userdata, metadata, vendordata) tuple or
    Raise MAASSeedDirMalformed or MAASSeedDirNone
    rI   r   z%s: no data files foundz%s: missing files %sNr	   )defaultallowedz%vendor-data was not loadable as yaml.r
   	meta-data)
r   append	partitionr~   r+   r,   r/   objectr   	load_yaml)contentseedretmissingspathdpath_binaryr   top_pvd_dataerrr   r   r   r      s4   

r   c                   @      e Zd ZdS )r+   Nr\   r]   r^   r   r   r   r   r+   %      r+   c                   @   r   )r,   Nr   r   r   r   r   r,   )  r   r,   c                 C   s   t | tS r   )r   list_from_dependsdatasources)dependsr   r   r   get_datasource_list4  s   r   __main__c                     s  ddl } ddl}ddl}| jdd}|jddddd |jd	d
ddd |jdd
ddd |jddddd |jddddd |jdddtd |jddd}dD ]\}}|j||d}|jddddd qQ| }|j	|j
|j|jd }	|jdu rd!D ] }
d"|
 d# }tj|rt|tjr|jd$|  ||_q||jrt|j}d%|v r|d% d& }|	 D ]}||v r|	| du r|| |	|< q|jdu rd'|v r|d' |_|jdu r|jd( |d) t|	fd*d+fd,d- fd.d/ |jd0krc|jd1|j  j}|jd d2ks|jd3r't|j\}}}nt|j|j |d4d5\}}}t!d6 t!|du r@d7n|"  t!d8 || t!d9 ||du r^d7 dS | dS |jd:krp|j dS |jd;kr|j#d2sd<|j |_ |j dS dS )=z
        Call with single argument of directory or http or https url.
        If url is given additional arguments are allowed, which will be
        interpreted as consumer_key, token_key, token_secret, consumer_secret
        r   NzInteract with MAAS DS)descriptionz--configfilezspecify DS config file)metavarhelpr   z--ckeykeyzthe consumer key to auth withz--tkeyzthe token key to auth withz--csecsecretzthe consumer secret (likely '')rp   z--tseczthe token secret to auth withz--apiverr{   z the apiver to use ( can be used)subcommandssubcmd)titledest))crawlzcrawl the datasource)r/   zdo a single GET of provided url)
check-seedzread and verify seed at url)r   r7   zthe datasource url?)r   nargsr   )ra   rc   rd   rb   )91_kernel_cmdline_url90_dpkg_maasz/etc/cloud/cloud.cfg.d/z.cfgzUsed config in %s.
rW   r   r%   z)Must provide a url or a config with url.
r&   c                    s    j | ddjS )Nr&   )r(   )r2   r   r7   )r"   r   r   geturl  s   zmain.<locals>.geturlc                    s   t d|  |  f  d S )Nz== %s ==
%s
)printdecoder   )r   r   r   printurl  s   zmain.<locals>.printurlc                    sv   |  dr5|   D ]%}| dr d| |f  q|dkr* d| df  qd| |f  qd S |  d S )NrI   z%s%sr   z
meta-data/)rN   r   
splitlines)r7   line)r   r   r   r   r   r     s   

	zmain.<locals>.crawlr   zChecking seed at %s
rI   ry      )r{   r'   r(   z=== user-data ===zN/Az=== meta-data ===z=== vendor-data ===r/   r   z%s/)$argparsepprintsysArgumentParseradd_argumentrO   add_subparsers
add_parser
parse_argsckeytkeytseccsecconfigr   r   existsaccessR_OKstderrwriter   	read_confrm   r7   exitr    r   r2   r|   r*   r1   apiverr   r   rN   )r   r   r   parsersubcmdsnamer   r   argscredsfnamefpathri   r   r2   userdatar:   rB   r   )r   r   r"   r   r   main:  s   




"r   )rs   r   rM   	cloudinitr   loggingr   r   r   	getLoggerr\   r-   rO   r   r   r   r    r   r*   r1   r   r3   r+   r,   DEP_FILESYSTEMDEP_NETWORKr   r   r   r   r   r   r   <module>   s>   

 
	
:' 
 