
"T`'8                 @   sh  d  d l  Z  d  d l Z d  d l Z d  d l m Z d  d l m Z d  d l m Z d  d l m Z e j	 e
  Z d Z d$ d% d& d' d( g Z Gd d   d e j  Z d d   Z d d   Z d d   Z d d e d d d d  Z d d   Z Gd d   d e  Z Gd d   d e  Z e e j e j f f g Z d d    Z e
 d! k rdd" d#   Z e   d S))    N)log)sources)
url_helper)utilz
2012-03-01meta-data/instance-idFmeta-data/local-hostnamemeta-data/public-keysTmeta-data/vendor-datavendor-data	user-datac               @   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   sS   t  j j |  | | |  d  |  _ t j 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_helper4   s    	zDataSourceMAAS.oauth_helperc             C   s#   t  j 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  } y$ |  j |  j t |  j   d SWnO t k
 rA Yn> t k
 r~ } z t j d |  j |    WYd  d  } ~ Xn X| j d d   } | s d SyL |  j	 |  s d S|  j | t
 | d |  j j d |  j d d  d SWn) t k
 rt j t d	 |  d SYn Xd  S)
NTz%s was malformed: %smetadata_urlFread_file_or_urlr   retries   z$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   s   | |  _  | \ } } } | |  _ | |  _ | |  _ | r y t j |  |  _ Wn> t k
 r } z t j	 d |  d  |  _ WYd  d  } ~ Xn Xd  S)Nz"Invalid content in vendor-data: %s)
r   Zuserdata_rawmetadataZvendordata_purer   Zconvert_vendordataZvendordata_raw
ValueErrorr*   r+   )r   r4   dataZudmdvder   r   r   r&   `   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_subplatformn   s    zDataSourceMAAS._get_subplatformc       	      C   sg  |  j  } d } y t | j d |   } Wn% t k
 rR t j t d |  Yn X| d k rc d Sd } y( | | k r t | j d |   } Wn" t k
 r t j d |  Yn Xt j   } | j	 d	  r | d  d  } d | t
 f } | g } |  j j d | d | d |  \ } } | r:t j d |  n# t j d | t t j   |   t |  S)Nx   max_waitz Failed to get max wait. using %sr   F2   timeoutzFailed to get timeout, using %s/r%   z%s/%s/meta-data/instance-idurlszUsing metadata source: '%s'z(Giving up on md from %s after %i seconds)r   intr,   r0   r   r1   r*   r+   timeendswith
MD_VERSIONr   Zwait_for_urldebugZcriticalbool)	r   r4   r2   r>   r@   Z	starttimeZ	check_urlrB   Z	_responser   r   r   r-   r   s4    			z(DataSourceMAAS.wait_for_metadata_servicec             C   sD   |  j  d k r d St j | 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__rK   r   r   r   propertyr   r    r5   r&   r<   r-   rL   r   r   r   r   r      s   	""r   c                s2   d } t    f d d   | D  } t j |   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  |  ] } |   j  |  f  q Sr   )r,   ).0r)cfgr   r   
<listcomp>   s   	 z$get_oauth_helper.<locals>.<listcomp>)rR   rS   rT   rU   )dictr   ZOauthUrlHelper)rX   keyskwargsr   )rX   r   r      s    r   c                sH   d	 } d j    f d d   | D  } d t j | j d   j   S)
z;Given a config, generate a unique identifier for this node.rR   rT   rU    c                s"   g  |  ] }   j  | d    q S) )r,   )rV   f)r   r   r   rY      s   	 z&get_id_from_ds_cfg.<locals>.<listcomp>zv1:zutf-8)zconsumer_keyz	token_keyztoken_secret)r   hashlibZsha256encodeZ	hexdigest)r   ZfieldsZidstrr   )r   r   r      s    "r   c             C   sm   |  j  d  r |  d d   }  t j j |   sM t t j |    d k rY t d   t d |  d d  S)Nz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 } |  j d  r4 |  d d  }  i  } x@t D]8\ } } }	 }
 | d k rr d |  | f } n d |  | | f } y t j |  } | | d | d | d | } | j   r |	 r | j | | <qt j | j  | | <n t	 j
 d	 | | j  WqA t  j k
 rx} zL | j d
 k rQ|
 rQt d | | f  |  n | j d
 k rf|  WYd d } ~ XqA XqA Wt | |   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.
    NrA   r%   z%s/%sz%s/%s/%sr$   r@   ssl_detailsz4Fetching from %s resulted in an invalid http code %si  zMissing required %s: %srC   )r   r#   rF   	DS_FIELDSr   Zfetch_ssl_detailsokcontentsZdecode_binaryr*   r+   codeZUrlErrorr)   check_seed_contents)Zseed_urlr#   r@   rc   r   r$   r9   r   Z	_dictnamebinaryoptionalr4   rh   Zrespr;   r   r   r   r.      s6    				r.   c             C   s_  i  } g  } x t  D] \ } } } } | |  k rG | s | j |  q d | k r | j d  \ } }	 }
 | | k r i  | | <|  | | | |
 <q |  | | | <q Wt |  d k r t d |   | r t d | | f   d } | j d  r@t   } t j	 | j d  d | d t } | | k r@t d	   | j d
  | j 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
    rA   r   z%s: no data files foundz%s: missing files %sNzvendor-datadefaultZallowedz%vendor-data was not loadable as yaml.z	user-dataz	meta-data)
ri   append	partitionrf   r(   r)   r,   objectr   Z	load_yaml)ZcontentZseedZretZmissingZspathZdpathZ_binaryro   top_pZvd_dataerrr   r   r   rm      s2    
		rm   c               @   s   e  Z d  Z d S)r(   N)rM   rN   rO   r   r   r   r   r(     s   r(   c               @   s   e  Z d  Z d S)r)   N)rM   rN   rO   r   r   r   r   r)     s   r)   c             C   s   t  j |  t  S)N)r   Zlist_from_dependsdatasources)Zdependsr   r   r   get_datasource_list"  s    ry   __main__c           	      sy  d d l  }  d d l } d d l } |  j d d  } | j d d d d d	 d
 d | j d d d d d d
 d | j d d d d d d
 d | j d d d d d d
 d | j d d d d d d
 d | j d d d d d d
 t | j d d d d  } xH dI D]@ \ } } | j | d | } | j d# d d$ d% d& d
 d qW| j   } d' | j	 d( | j
 d) | j d* | j i }	 | j d k rx` dJ D]X }
 d- |
 d. } t j j |  rt j | t j  r| j j d/ |  | | _ qW| j rt j | j  } d0 | k r0| d0 d1 } x> |	 j   D]0 } | | k r=|	 | d k r=| | |	 | <q=W| j d k rd2 | k r| d2 | _ | j d k r| j j d3  | j d4  t |	    f d5 d6     f d7 d8        f d9 d:     | j d! k r| j j d; | j   j } | j d d< k sa| j j d=  r|t | j  \ } } } n- t | j d | j  d> | d? d@ \ } } } t! dA  t! | d k rdB n	 | j"    t! dC  | j |  t! dD  | j | d k rdB n |  n] | j d k r7 | j  n> | j d k ru| j j# d<  shdE | j | _   | j  d S)Kz
        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descriptionzInteract with MAAS DSz--configmetavarfilehelpzspecify DS config filerp   z--ckeykeyzthe consumer key to auth withz--tkeyzthe token key to auth withz--csecZsecretzthe consumer secret (likely '')r^   z--tseczthe token secret to auth withz--apiverrc   z the apiver to use ( can be used)titleZsubcommandsdestsubcmdcrawlcrawl the datasourcer,   do a single GET of provided url
check-seedread and verify seed at urlr4   zthe datasource urlnargs?rR   rT   rU   rS   91_kernel_cmdline_url90_dpkg_maasz/etc/cloud/cloud.cfg.d/z.cfgzUsed config in %s.
rJ   r   r"   z)Must provide a url or a config with url.
r%   c                s     j  |  d d j S)Nr$   r%   )r/   rk   )r4   )r   r   r   geturld  s    zmain.<locals>.geturlc                s$   t  d |    |   j   f  d  S)Nz== %s ==
%s
)printdecode)r4   )r   r   r   printurlh  s    zmain.<locals>.printurlc                s   |  j  d  r x  |   j   j   D]c } | j  d  rT   d |  | f  q( | d k rw   d |  d f  q(  d |  | f  q( Wn
  |   d  S)NrA   z%s%sz	meta-dataz
meta-data/)rF   r   
splitlines)r4   line)r   r   r   r   r   r   k  s    zmain.<locals>.crawlzChecking seed at %s
rA   zfile://r#   r$      z=== user-data ===zN/Az=== meta-data ===z=== vendor-data ===z%s/zcrawlr   zgetr   r   r   )r   r   r   )r   r   )$argparsepprintsysArgumentParseradd_argumentrG   Zadd_subparsersZ
add_parser
parse_argsZckeyZtkeyZtsecZcsecconfigr   r   existsaccessR_OKstderrwriter   Z	read_confr[   r4   exitr   r   r/   rd   r'   r.   Zapiverr   r   rF   )r   r   r   parserZsubcmdsnamer}   rv   argsZcredsfnameZfpathrX   r~   r/   Zuserdatar6   r:   r   )r   r   r   r   r   main'  s     '		%
"

"r   )r   r   FF)r   r   FF)r   r   FT)r	   r
   TT)r   r   TT)r`   r   rE   Z	cloudinitr   Zloggingr   r   r   Z	getLoggerrM   r*   rG   ri   r   r   r   r   r'   r.   rm   r0   r(   r)   ZDEP_FILESYSTEMZDEP_NETWORKrx   ry   r   r   r   r   r   <module>	   s6   	
	
/&i