U
    L¬÷d9  ã                   @   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ddddd	g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rêdd„ Zeƒ  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 )NZmaas)r   Ú
DataSourceÚ__init__Úbase_urlÚosÚpathÚjoinÚseed_dirÚget_id_from_ds_cfgÚds_cfgÚid_hash)ÚselfÚsys_cfgZ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k
r4   Y n4 tk
rf } zt d| j|¡ ‚ W 5 d }~X Y nX | dd ¡}|s|dS z4|  	|¡sŽW dS |  |t
|| jj| jdd¡ W dS  tk
rÔ   t td|¡ Y dS X d S )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<   s8    
üþ	zDataSourceMAAS._get_datac              
   C   sp   || _ |\}}}|| _|| _|| _|rlzt |¡| _W n4 tk
rj } zt 	d|¡ d | _W 5 d }~X Y nX d S )Nz"Invalid content in vendor-data: %s)
r   Zuserdata_rawÚmetadataZvendordata_purer   Zconvert_vendordataZvendordata_rawÚ
ValueErrorr+   r,   )r   r5   ÚdataZ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k
r@   t td|¡ Y nX |dkrNdS d}z||krlt| d|¡ƒ}W n  tk
rŽ   t d|¡ Y nX t ¡ }| 	d	¡r®|d d
… }d|t
f }|g}| jj|||d\}}|rèt d|¡ nt d|tt ¡ | ƒ¡ t|ƒS )Néx   Úmax_waitz Failed to get max wait. using %sr   Fé2   ÚtimeoutzFailed to get timeout, using %sú/éÿÿÿÿz%s/%s/meta-data/instance-id)Úurlsr?   rA   zUsing metadata source: '%s'z(Giving up on md from %s after %i seconds)r   Úintr-   r1   r   r2   r+   r,   ÚtimeÚendswithÚ
MD_VERSIONr    Zwait_for_urlÚdebugZcriticalÚbool)	r   r5   r3   r?   rA   Z	starttimeZ	check_urlrD   Z	_responser   r   r   r.   u   s@    
  ÿ
ýz(DataSourceMAAS.wait_for_metadata_servicec                 C   s0   | j dk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   Zget_cfg_by_pathÚdsnamer   )r   r   Zncfgr   r   r   Úcheck_instance_id›   s    
z DataSourceMAAS.check_instance_id)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rL   r   r   r   Úpropertyr    r!   r6   r'   r=   r.   rM   r   r   r   r   r      s   

'&r   c                    s&   d}t ‡ fdd„|D ƒƒ}tjf |ŽS )zªReturn 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>)Údictr   ZOauthUrlHelper)r[   ÚkeysÚkwargsr   rZ   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.)rS   rU   rV   ú c                    s   g | ]}ˆ   |d ¡‘qS )Ú rW   )rX   Úf©r   r   r   r\   ´   s     z&get_id_from_ds_cfg.<locals>.<listcomp>zv1:zutf-8)r   ÚhashlibZsha256ÚencodeZ	hexdigest)r   ZfieldsZidstrr   rc   r   r   ±   s    r   c                 C   sL   |   d¡r| dd … } tj | ¡r4t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)   r/   )Zseed_dr   r   r   r(   º   s
    
r(   c                 C   s  |dkrt j}|  d¡r$| dd… } i }tD ]à\}}}	}
|dkrNd| |f }nd| ||f }zXt |¡}|||||d}| ¡ r¢|	r|j||< q²t |j¡||< nt	 
d||j¡ W q, t jk
r
 } z4|jdkrì|
sìtd	||f ƒ|‚n|jdkrú|‚W 5 d}~X Y q,X q,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.
    NrB   rC   z%s/%sz%s/%s/%s)r&   rA   Ússl_detailsz4Fetching from %s resulted in an invalid http code %si”  zMissing required %s: %s)r   r%   rG   Ú	DS_FIELDSr   Zfetch_ssl_detailsÚokÚcontentsZdecode_binaryr+   r,   ÚcodeZUrlErrorr*   Úcheck_seed_contents)Zseed_urlr%   rA   rh   r   r&   r:   r   Z	_dictnameÚbinaryÚoptionalr5   rm   Zrespr<   r   r   r   r/   Ä   sH    

   ÿý
ÿþ
r/   c                 C   sô   i }g }t D ]j\}}}}|| kr0|s| |¡ qd|krj| d¡\}}	}
||krXi ||< | | || |
< q| | ||< qt|ƒdkrtd| ƒ‚|r¤td||f ƒ‚d}| d¡rÞtƒ }tj	| d¡|td}||krÞtdƒ‚| d	¡| d
¡|fS )z·Validate if dictionary content valid as a return for a datasource.
    Either return a (userdata, metadata, vendordata) tuple or
    Raise MAASSeedDirMalformed or MAASSeedDirNone
    rB   r   z%s: no data files foundz%s: missing files %sNr	   )ÚdefaultZallowedz%vendor-data was not loadable as yaml.r
   ú	meta-data)
rn   ÚappendÚ	partitionrk   r)   r*   r-   Úobjectr   Z	load_yaml)ZcontentZseedZretZmissingZspathZdpathZ_binaryrt   ÚtopÚ_ÚpZvd_dataÚerrr   r   r   rr   þ   s8    

  ÿrr   c                   @   s   e Zd ZdS )r)   N©rN   rO   rP   r   r   r   r   r)   %  s   r)   c                   @   s   e Zd ZdS )r*   Nr~   r   r   r   r   r*   )  s   r*   c                 C   s   t  | t¡S r   )r   Zlist_from_dependsÚdatasources)Z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 q¢| ¡ }|j	|j
|j|jd œ}	|jdkr<d!D ]@}
d"|
 d# }tj |¡rút |tj¡rú|j d$| ¡ ||_qú|jrºt |j¡}d%|krf|d% d& }|	 ¡ D ]*}||krn|	| dkrn|| |	|< qn|jdkrºd'|krº|d' |_|jdkrÜ|j d(¡ | d)¡ t|	ƒ‰‡fd*d+„‰‡fd,d-„‰‡ ‡‡fd.d/„‰ |jd0krÐ|j d1|j ¡ ˆj}|jd d2ksN|j d3¡r`t|jƒ\}}}nt|j|j |d4d5\}}}t!d6ƒ t!|dkr’d7n| "¡ ƒ t!d8ƒ | |¡ t!d9ƒ | |dkrÈd7n|¡ nH|jd:krèˆ|jƒ n0|jd;kr|j #d2¡sd<|j |_ˆ |jƒ 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)Zdescriptionz--configÚfilezspecify DS config file)ÚmetavarÚhelpru   z--ckeyÚkeyzthe consumer key to auth withz--tkeyzthe token key to auth withz--csecZsecretzthe consumer secret (likely '')ra   z--tseczthe token secret to auth withz--apiverrh   z the apiver to use ( can be used)Z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„   r5   zthe datasource urlú?)r„   Únargsru   )rS   rU   rV   rT   )Z91_kernel_cmdline_urlZ90_dpkg_maasz/etc/cloud/cloud.cfg.d/z.cfgzUsed config in %s.
rK   r   r#   z)Must provide a url or a config with url.
r$   c                    s   ˆ j | ddjS )Nr$   )r&   )r0   rp   ©r5   )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                    st   |   d¡rhˆ| ƒ ¡  ¡ D ]J}|  d¡r:ˆ d| |f ƒ q|dkrTˆ d| df ƒ qˆd| |f ƒ qnˆ| ƒ d S )NrB   z%s%srv   z
meta-data/)rG   r   Ú
splitlines)r5   Úline)r‰   rŽ   r‘   r   r   r‰   œ  s    

zmain.<locals>.crawlrŠ   zChecking seed at %s
rB   rf   é   )rh   r%   r&   z=== user-data ===zN/Az=== meta-data ===z=== vendor-data ===r-   r‰   z%s/)$ÚargparseÚpprintÚsysÚArgumentParserÚadd_argumentrH   Zadd_subparsersZ
add_parserÚ
parse_argsZckeyZtkeyZtsecZcsecZconfigr   r   ÚexistsÚaccessÚR_OKÚstderrÚwriter   Z	read_confr^   r5   Úexitr   r†   r0   ri   r(   r/   Zapiverr   r   rG   )r•   r–   r—   ÚparserZsubcmdsÚnamer„   r|   ÚargsZcredsÚfnameZfpathr[   r…   r0   Zuserdatar7   r;   r   )r‰   rŽ   r    r‘   r   Úmain:  sÈ    üüüüüü   ÿü


ü
r¥   )rd   r   rF   Z	cloudinitr   Zloggingr   r   r   Z	getLoggerrN   r+   rH   rn   r   r   r   r   r(   r/   rr   r1   r)   r*   ZDEP_FILESYSTEMZDEP_NETWORKr   r€   r¥   r   r   r   r   Ú<module>	   sB   
ú
 
	ú
:'ÿ 