U
    Ӈgi;                     @   s  d dl Z d dlZd dlZd dlZd dlmZmZmZ d dlm	Z	 d dl
mZ eeZdZdddd	d
gZG dd dejZG dd de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ffeejejffgZdd Zedkrd d! Z e   dS )"    N)sources
url_helperutil)KlibcNetworkConfigSource)NetworkConfigSourcez
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                   @   sh   e Zd Zd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
    MAASNx   2   c                 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   2   s    zDataSourceMAAS.__init__c                 C   s   | j st| j| _ | j S N)_oauth_helperget_oauth_helperr   r   r   r   r   oauth_helper8   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$   >   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| 	|sW 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   Zlogexc)r   Zmcfgexcurlr   r   r   	_get_dataB   s8    
	zDataSourceMAAS._get_datac              
   C   sj   || _ |\}}}|| _|| _|rfzt|| _W n4 tk
rd } ztd| d | _W 5 d }~X Y nX d S )Nz"Invalid content in vendor-data: %s)	r   Zuserdata_rawmetadatar   Zconvert_vendordataZvendordata_raw
ValueErrorr.   r/   )r   r6   dataZudmdvder   r   r   r*   i   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_subplatformv   s    zDataSourceMAAS._get_subplatformc                 C   s   |   }|jdkrdS t }|d}d|tf }|g}| jj||j|jd\}}|rft	
d| nt	d|tt |  t|S )Nr   F/z%s/%s/meta-data/instance-id)urlsZmax_waittimeoutzUsing metadata source: '%s'z(Giving up on md from %s after %i seconds)Zget_url_paramsZmax_wait_secondstime	monotonicrstrip
MD_VERSIONr#   Zwait_for_urlZtimeout_secondsr.   debugZcriticalintbool)r   r6   Z
url_paramsZ	starttimeZ	check_urlr@   Z	_responser   r   r   r1   z   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__rJ   r   r    Zurl_max_waitZurl_timeoutr   propertyr#   r$   r7   r*   r>   r1   rK   r   r   r   r   r      s   

'r   c                       s0   e Zd ZejejejejfZ fddZ	  Z
S )DataSourceMAASLocalc                    s,   t   std dS td t  S )NzNo initramfs applicable configFz!Found initramfs applicable config)r   Zis_applicabler.   rF   superr7   r"   	__class__r   r   r7      s
    


zDataSourceMAASLocal._get_data)rL   rM   rN   r   ZCMD_LINEZ
SYSTEM_CFGZDSZ	INITRAMFSZnetwork_config_sourcesr7   __classcell__r   r   rS   r   rQ      s   rQ   c                    s&   d}t  fdd|D }tjf |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   r0   ).0rcfgr   r   
<listcomp>   s     z$get_oauth_helper.<locals>.<listcomp>)dictr   ZOauthUrlHelper)r^   keyskwargsr   r]   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.)rV   rX   rY    c                    s   g | ]}  |d qS ) rZ   )r[   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   rf   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,   r2   )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||< qt|j||< nt	
d||j W q, t jk
r
 } z4|jdkr|
st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.
    Nr?   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(   endswith	DS_FIELDSr   Zfetch_ssl_detailsokcontentsZdecode_binaryr.   r/   codeZUrlErrorr-   check_seed_contents)Zseed_urlr(   rA   rk   r   r)   r;   r   Z	_dictnamebinaryoptionalr6   rq   Zrespr=   r   r   r   r2      sH    

   

r2   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| |rtd||f d}|drt }tj	|d|td}||krt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
    r?   r   z%s: no data files foundz%s: missing files %sNr
   )defaultZallowedz%vendor-data was not loadable as yaml.r   	meta-data)
rs   append	partitionrn   r,   r-   r0   objectr   Z	load_yaml)ZcontentZseedZretZmissingZspathZdpathZ_binaryry   top_pZvd_dataerrr   r   r   rw   	  s8    

  rw   c                   @   s   e Zd ZdS )r,   NrL   rM   rN   r   r   r   r   r,   0  s   r,   c                   @   s   e Zd ZdS )r-   Nr   r   r   r   r   r-   4  s   r-   c                 C   s   t | tS r   )r   Zlist_from_dependsdatasources)Zdependsr   r   r   get_datasource_list@  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|rt|tjr|jd$|  ||_q|jrt|j}d%|krf|d% d& }|	 D ]*}||krn|	| dkrn|| |	|< qn|jdkrd'|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rd7n|"  t!d8 || t!d9 ||dkrd7n| 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helprz   z--ckeykeyzthe consumer key to auth withz--tkeyzthe token key to auth withz--csecZsecretzthe consumer secret (likely '')rd   z--tseczthe token secret to auth withz--apiverrk   z the apiver to use ( can be used)Zsubcommandssubcmd)titledest))crawlzcrawl the datasource)r0   zdo a single GET of provided url)
check-seedzread and verify seed at url)r   r6   zthe datasource url?)r   nargsrz   )rV   rX   rY   rW   )Z91_kernel_cmdline_urlZ90_dpkg_maasz/etc/cloud/cloud.cfg.d/z.cfgzUsed config in %s.
rI   r   r&   z)Must provide a url or a config with url.
r'   c                    s    j | ddjS )Nr'   )r)   )r3   ru   r6   )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 )Nr?   z%s%sr{   z
meta-data/)rr   r   
splitlines)r6   line)r   r   r   r   r   r     s    

zmain.<locals>.crawlr   zChecking seed at %s
r?   ri      )rk   r(   r)   z=== user-data ===zN/Az=== meta-data ===z=== vendor-data ===r0   r   z%s/)$argparsepprintsysArgumentParseradd_argumentrE   Zadd_subparsersZ
add_parser
parse_argsZckeyZtkeyZtsecZcsecZconfigr   r   existsaccessR_OKstderrwriter   Z	read_confra   r6   exitr!   r   r3   rl   r+   r2   Zapiverr   r   rr   )r   r   r   parserZsubcmdsnamer   r   argsZcredsfnameZfpathr^   r   r3   Zuserdatar8   r<   r   )r   r   r#   r   r   mainF  s       



r   )!rg   Zloggingr   rB   Z	cloudinitr   r   r   Zcloudinit.net.cmdliner   Zcloudinit.sourcesr   Z	getLoggerrL   r.   rE   rs   r   r   rQ   r!   r   r+   r2   rw   r4   r,   r-   ZDEP_FILESYSTEMZDEP_NETWORKr   r   r   r   r   r   r   <module>	   sJ   

 
	
:'

 