o
    im2                     @   s0  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mZmZ d dlmZ d dl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dZG dd dZG dd dej Z!G dd de!Z"dd Z#dd Z$dd Z%de&fddZ'e"ej(ffe!ej(ej)ffgZ*dd Z+dS )    N)suppress)gaierrorgetaddrinfo	inet_ntoa)pack)dminetperformancesources)
url_helper)util)dhcp)NoDHCPLeaseError)EphemeralIPNetwork)ec2
CloudStackc                   @   s6   e Zd ZdZdd Zdd Zejddd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__/      
z'CloudStackPasswordServerClient.__init__c                 C   sH   d| j  d}d|i}tj||ddd}| std|jd S )	Nhttp://z:8080DomU_Request      )headerstimeoutretriesz+Failed to fetch VM password from CloudStackzutf-8)r   uhelpreadurlokRuntimeErrorcontentsdecodestrip)r   domu_requesturlr   respr   r   r   _do_request2   s   z*CloudStackPasswordServerClient._do_requestzGetting passwordalwayslog_modec                 C   s4   |  d}|dv rd S |dkrtd|  d |S )Nsend_my_password) saved_passwordbad_requestz-Error when attempting to fetch root password.r1   )r+   r$   )r   passwordr   r   r   get_password=   s   

z+CloudStackPasswordServerClient.get_passwordN)	__name__
__module____qualname____doc__r   r+   r	   timedr4   r   r   r   r   r   #   s    r   c                       s   e Zd ZdZdZdZdZ fddZdd Z			d fd	d
	Z	dd Z
dd ZedefddZdd Zejddddd Zdd Zedd Z  ZS )DataSourceCloudStackFr   x   2   c                    s8   t  ||| tj|jd| _d| _i | _d | _d S )Ncslatest)	superr   ospathjoinseed_dirapi_vercfgvr_addr)r   sys_cfgdistropaths	__class__r   r   r   P   s
   
zDataSourceCloudStack.__init__c              
   C   s   t d dD ]}t|}|r|   S qt d ttj t | j	d}|r8| W  d   S W d   n1 sBw   Y  t d| j	j
j z| j	j
| j	j}|d}|rf| W S W n tttfys   Y nw t d dS )	zTry obtaining a "domain-name" DHCP lease parameter:
        - From systemd-networkd lease (case-insensitive)
        - From ISC dhclient
        - From dhcpcd (ephemeral)
        - Return empty string if not found (non-fatal)
        z.Try obtaining domain name from networkd leases)
DOMAINNAMEDomaindomain-namezHCould not obtain FQDN from networkd leases. Falling back to ISC dhclientrN   NzBCould not obtain FQDN from ISC dhclient leases. Falling back to %sz7No domain name found in any DHCP lease; returning emptyr0   )LOGdebugr   networkd_get_option_from_leasesr'   r   NoDHCPLeaseMissingDhclientErrorIscDhclientget_key_from_latest_leaserH   dhcp_clientclient_nameget_newest_leasefallback_interfacegetr   FileNotFoundErrorAttributeError)r   key
domainnamedomain_namelatest_leaser   r   r   _get_domainnameY   sF   




z$DataSourceCloudStack._get_domainnamec                    sn   t  |||}|r5d|jvr5t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)	r?   get_hostnamehostnamerO   rP   r`   r
   DataSourceHostname
is_default)r   fqdn
resolve_ipmetadata_onlyrc   r]   rJ   r   r   rb      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\}}|r1t	d| t|S t	d|tt |  t|S )Nr   Fzlatest/meta-data/instance-id)urlsmax_waitr   	status_cbzUsing metadata source: '%s'z>Giving up on waiting for the metadata from %s after %s seconds)get_url_paramsmax_wait_secondsr!   combine_urlmetadata_addresstime	monotonicwait_for_urltimeout_secondsrO   warningrP   criticalintbool)r   
url_paramsri   
start_timer)   	_responser   r   r   wait_for_metadata_service   s.   

	z.DataSourceCloudStack.wait_for_metadata_servicec                 C   s   | j S r   )rE   r   r   r   r   get_config_obj   s   z#DataSourceCloudStack.get_config_objreturnc                   C   s   t  S )z#Check if running on this datasource)is_platform_viabler   r   r   r   	ds_detect   s   zDataSourceCloudStack.ds_detectc              
   C   sV  i }t j|| jd dr|d | _|d | _td| j dS | jr3t	 }td| t
| j|}nt  }zI|< t| j}t|trJ|dn|| _| jsTtd	d
| j d| _|  sj	 W d    W dS |  W  d    W S 1 syw   Y  W d S  ty   td| Y dS  ty } ztdt| W Y d }~dS d }~ww )N/)basez	user-dataz	meta-dataz%Using seeded cloudstack data from: %sTzAttempting DHCP on: %sdhcp-server-identifierzNo virtual router found!r   Fz#Unable to obtain a DHCP lease on %sz$Failed fetching metadata service: %s)r   read_optional_seedrC   userdata_rawmetadatarO   rP   perform_dhcp_setupr   find_fallback_nicr   rH   nullcontextget_vr_address
isinstancedictrY   rF   r$   ro   r{   _crawl_metadatar   rt   	Exceptionstr)r   seed_retprimary_nicnetwork_contextrF   er   r   r   	_get_data   sD   


(zDataSourceCloudStack._get_datazCrawling metadatar,   r-   c                 C   sz   t | j| j| _t | j| j| _t| j}z|	 }W n t
y/   ttd| j Y dS w |r;d|ddid| _dS )Nz/Failed to fetch password from virtual router %sTexpireF)
ssh_pwauthr3   chpasswd)r   get_instance_userdatarD   ro   r   get_instance_metadatar   r   rF   r4   r   r   logexcrO   rE   )r   password_clientset_passwordr   r   r   r      s0   
z$DataSourceCloudStack._crawl_metadatac                 C   
   | j d S )Nzinstance-idr   r|   r   r   r   get_instance_id  r   z$DataSourceCloudStack.get_instance_idc                 C   r   )Nzavailability-zoner   r|   r   r   r   availability_zone  s   
z&DataSourceCloudStack.availability_zone)FFF)r5   r6   r7   r   dsnameurl_max_waiturl_timeoutr   r`   rb   r{   r}   staticmethodrw   r   r   r	   r9   r   r   propertyr   __classcell__r   r   rJ   r   r:   H   s*    	-$
r:   c                   @   s   e Zd ZdZdZdS )DataSourceCloudStackLocalau  Run in init-local using a dhcp discovery prior to metadata crawl.

    In init-local, no network is available. This subclass sets up minimal
    networking with dhclient on a viable nic so that it can talk to the
    metadata service. If the metadata service provides network configuration
    then render the network configuration for that instance based on metadata.
    TN)r5   r6   r7   r8   r   r   r   r   r   r     s    r   c                  C   s>   zt dd} W n ty   td Y d S w | d d d S )Nzdata-serverP   zDNS Entry data-server not foundr      )r   r   rO   rP   )addrinfor   r   r   get_data_server  s   
r   c                  C   s^   t d } | D ]#}|d}|d dkr,ttdt|d d}td| |  S q	d S )	Nz/proc/net/route	   00000000z<L      z"Found default route, gateway is %s)	r   load_text_file
splitlinessplitr   r   rv   rO   rP   )lineslineitemsgwr   r   r   get_default_gateway'  s   
r   c                 C   s  t  }|rtd| |S td}|rtd| |S ttj! t | d}|r;td| |W  d    S W d    n1 sEw   Y  tt	# | j
| j}|rjtd|| j
j |W  d    S W d    n1 stw   Y  td t S )Nz4Found metadata server '%s' via data-server DNS entrySERVER_ADDRESSz-Found SERVER_ADDRESS '%s' via networkd_leasesr   z&Found SERVER_ADDRESS '%s' via dhclientz1Found SERVER_ADDRESS '%s' via ephemeral %s lease z$No DHCP found, using default gateway)r   rO   rP   r   rQ   r   rR   rS   rT   rZ   rU   rW   rX   rV   r   )rH   latest_addressr_   r   r   r   r   4  sN   


r   r~   c                  C   s&   t d} | std dS | tS )Nzsystem-product-namez-system-product-name not available in dmi dataF)r   read_dmi_datarO   rP   
startswithCLOUD_STACK_DMI_NAME)product_namer   r   r   r   f  s
   


r   c                 C   s   t | tS r   )r
   list_from_dependsdatasources)dependsr   r   r   get_datasource_listv  s   r   ),loggingr@   rp   
contextlibr   socketr   r   r   structr   	cloudinitr   r   r	   r
   r   r!   r   cloudinit.netr   cloudinit.net.dhcpr   cloudinit.net.ephemeralr   cloudinit.sources.helpersr   	getLoggerr5   rO   r   r   
DataSourcer:   r   r   r   r   rw   r   DEP_FILESYSTEMDEP_NETWORKr   r   r   r   r   r   <module>   s6   
% I2

