U
    Ӈg,                     @   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 d dl	m
Z
 d dlmZmZ d dlmZ d dlmZ d dlmZ d d	lmZ e eZG d
d dZG dd dejZdd Zdd Zdd ZeejejffgZ dd Z!dS )    N)suppress)gaierrorgetaddrinfo	inet_ntoa)pack)sourcessubp)
url_helper)util)dhcp)ec2c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	CloudStackPasswordServerClienta  
    Implements password fetching from the CloudStack password server.

    http://cloudstack-administration.readthedocs.org/
       en/latest/templates.html#adding-password-management-to-your-templates
    has documentation about the system.  This implementation is following that
    found at
    https://github.com/shankerbalan/cloudstack-scripts/
       blob/master/cloud-set-guest-password-debian
    c                 C   s
   || _ d S N)virtual_router_address)selfr    r   H/usr/lib/python3/dist-packages/cloudinit/sources/DataSourceCloudStack.py__init__+   s    z'CloudStackPasswordServerClient.__init__c                 C   s:   t  ddddddddd	d
|d| jg\}}| S )NZwgetz--quietz--tries3z	--timeoutZ20z--output-document-z--headerzDomU_Request: {0}z{0}:8080)r   formatr   strip)r   Zdomu_requestoutput_r   r   r   _do_request.   s    
z*CloudStackPasswordServerClient._do_requestc                 C   s4   |  d}|dkrd S |dkr&td|  d |S )NZsend_my_password) saved_passwordZbad_requestz-Error when attempting to fetch root password.r   )r   RuntimeError)r   passwordr   r   r   get_passwordC   s    

z+CloudStackPasswordServerClient.get_passwordN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r      s   r   c                       sf   e Zd ZdZdZdZdd Zdd Zd fd	d
	Zdd Z	dd Z
dd Zdd Zedd Z  ZS )DataSourceCloudStackZ
CloudStackx   2   c                 C   sd   t j| ||| tj|jd| _d| _|| _t	| j| _
| j
sJtdd| j
 d| _i | _d S )NZcsZlatestzNo virtual router found!zhttp:///)r   
DataSourcer   ospathjoinseed_dirapi_verdistroget_vr_addressvr_addrr   metadata_addresscfg)r   Zsys_cfgr.   pathsr   r   r   r   U   s    zDataSourceCloudStack.__init__c              
   C   s   t d td}|r|S t d ttj, t | jd}|rX|W  5 Q R  S W 5 Q R X t d| jj	j
 tt2 | jj	| jj}|dpd}|W  5 Q R  S Q R X t d dS )z
        Try obtaining a "domain-name" DHCP lease parameter:
        - From systemd-networkd lease
        - From dhclient lease
        z.Try obtaining domain name from networkd leasesZ
DOMAINNAMEzHCould not obtain FQDN from networkd leases. Falling back to ISC dhclientzdomain-namezBCould not obtain FQDN from ISC dhclient leases. Falling back to %sNzNo dhcp leases found)LOGdebugr   networkd_get_option_from_leasesr   NoDHCPLeaseMissingDhclientErrorIscDhclientget_key_from_latest_leaser.   dhcp_clientclient_nameFileNotFoundErrorget_newest_leaseZfallback_interfaceget)r   
domainnameZdomain_namelatest_leaser   r   r   _get_domainnamec   s4    

 

z$DataSourceCloudStack._get_domainnameFc                    sn   t  |||}|rjd|jkrjtd |  }|r^|j d| }td| t||jS td| |S )z
        Returns instance's hostname / fqdn
        First probes the parent class method.

        If fqdn is requested, and the parent method didn't return it,
        then attach the domain-name from DHCP response.
        .zFQDN requestedzObtained the following FQDN: %szNCould not determine domain name for FQDN. Fall back to hostname as an FQDN: %s)	superget_hostnamehostnamer4   r5   rA   r   ZDataSourceHostnameZ
is_default)r   ZfqdnZ
resolve_ipZmetadata_onlyrE   r?   	__class__r   r   rD      s    
z!DataSourceCloudStack.get_hostnamec                 C   s~   |   }|jdkrdS t| jdg}t }tj||j|jt	j
d\}}|r\t	d| nt	d|tt |  t|S )Nr   Fzlatest/meta-data/instance-id)urlsZmax_waitZtimeoutZ	status_cbzUsing metadata source: '%s'z>Giving up on waiting for the metadata from %s after %s seconds)Zget_url_paramsZmax_wait_secondsuhelpZcombine_urlr1   time	monotonicZwait_for_urlZtimeout_secondsr4   Zwarningr5   Zcriticalintbool)r   Z
url_paramsrH   
start_timeZurlZ	_responser   r   r   wait_for_metadata_service   s.    
 
z.DataSourceCloudStack.wait_for_metadata_servicec                 C   s   | j S r   )r2   r   r   r   r   get_config_obj   s    z#DataSourceCloudStack.get_config_objc                 C   s  i }t j|| jd dr>|d | _|d | _td| j dS z|  sNW dS t	 }t
| j| j| _t
| j| j| _tdtt	 |  t| j}z| }W n$ tk
r   t td	| j Y nX |rd|d
did| _W dS  tk
r   t td| j Y dS X d S )Nr'   )basez	user-dataz	meta-dataz%Using seeded cloudstack data from: %sTFz)Crawl of metadata service took %s secondsz/Failed to fetch password from virtual router %sZexpire)Z
ssh_pwauthr   Zchpasswdz(Failed fetching from metadata service %s)r
   Zread_optional_seedr,   Zuserdata_rawmetadatar4   r5   rO   rJ   rK   r   Zget_instance_userdatar-   r1   Zget_instance_metadatarL   r   r0   r   	ExceptionZlogexcr2   )r   Zseed_retrN   Zpassword_clientZset_passwordr   r   r   	_get_data   s\    

  

 zDataSourceCloudStack._get_datac                 C   s
   | j d S )Nzinstance-idrS   rP   r   r   r   get_instance_id   s    z$DataSourceCloudStack.get_instance_idc                 C   s
   | j d S )Nzavailability-zonerV   rP   r   r   r   availability_zone   s    z&DataSourceCloudStack.availability_zone)FFF)r    r!   r"   ZdsnameZurl_max_waitZurl_timeoutr   rA   rD   rO   rQ   rU   rW   propertyrX   __classcell__r   r   rF   r   r$   M   s   ,   0r$   c                  C   sD   zt dd} W n  tk
r.   td Y d S X | d d d S d S )Nzdata-serverP   zDNS Entry data-server not foundr      )r   r   r4   r5   )Zaddrinfor   r   r   get_data_server  s    
r]   c                  C   s^   t d } | D ]F}|d}|d dkrttdt|d d}td| |  S qd S )	Nz/proc/net/route	   Z00000000z<L      z"Found default route, gateway is %s)	r
   Zload_text_file
splitlinessplitr   r   rL   r4   r5   )lineslineitemsZgwr   r   r   get_default_gateway  s    

rg   c              
   C   s   t  }|rtd| |S td}|r8td| |S ttj6 t | d}|rttd| |W  5 Q R  S W 5 Q R X tt	8 | j
| }|rtd|| j
j |W  5 Q R  S W 5 Q R X td t S )Nz4Found metadata server '%s' via data-server DNS entryZSERVER_ADDRESSz-Found SERVER_ADDRESS '%s' via networkd_leaseszdhcp-server-identifierz&Found SERVER_ADDRESS '%s' via dhclientz1Found SERVER_ADDRESS '%s' via ephemeral %s lease z$No DHCP found, using default gateway)r]   r4   r5   r   r6   r   r7   r8   r9   r<   r:   r=   r;   rg   )r.   Zlatest_addressr@   r   r   r   r/     sB    
  

r/   c                 C   s   t | tS r   )r   Zlist_from_dependsdatasources)Zdependsr   r   r   get_datasource_listR  s    ri   )"Zloggingr)   rJ   
contextlibr   Zsocketr   r   r   Zstructr   Z	cloudinitr   r   r	   rI   r
   Zcloudinit.netr   Zcloudinit.sources.helpersr   Z	getLoggerr    r4   r   r(   r$   r]   rg   r/   ZDEP_FILESYSTEMZDEP_NETWORKrh   ri   r   r   r   r   <module>   s(   
. 72