U
    Ld=                     @   s:  d dl Z d dlZd dlZd dlZd dlm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 d dlmZ d dlmZmZmZmZ d d	l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  e!e"Z#ddgZ$dZ%dZ&dZ'G dd dej(j)Z*dd Z+dd Z,G dd dej-Z.e.ej/ffgZ0dd Z1dS )    N)urlparse)ConnectionError)HTTPConnection)PoolManager)dmi)log)netsources
url_helperutil)
EventScope	EventType)NoDHCPLeaseError)EphemeralDHCPv4EphemeralIPv6Network)DataSourceHostname)ProcessExecutionErrorzhttp://169.254.42.42zhttp://[fd00:42::42]      
   c                       s*   e Zd ZdZ fddZdddZ  ZS )SourceAddressAdapterzF
    Adapter for requests to choose the local address to bind to.
    c                    s   || _ tt| jf | d S N)source_addresssuperr   __init__)selfr   kwargs	__class__ F/usr/lib/python3/dist-packages/cloudinit/sources/DataSourceScaleway.pyr   ,   s    zSourceAddressAdapter.__init__Fc                 C   s0   t jtjtjdfg }t|||| j|d| _d S )N   )Z	num_poolsmaxsizeblockr   socket_options)r   Zdefault_socket_optionssocketZ
SOL_SOCKETZSO_REUSEPORTr   r   Zpoolmanager)r   Zconnectionsr"   r#   r$   r   r   r    init_poolmanager0   s    z%SourceAddressAdapter.init_poolmanager)F)__name__
__module____qualname____doc__r   r&   __classcell__r   r   r   r    r   '   s   r   c              
   C   sh   z(t j| d|d|dd d}t|jW S  t jk
rb } z|jdkrPW Y 
dS  W 5 d}~X Y nX dS )aQ  
    Retrieve user data or vendor data.

    Scaleway user/vendor data API returns HTTP/404 if user/vendor data is not
    set.

    This function calls `url_helper.readurl` but instead of considering
    HTTP/404 as an error that requires a retry, it considers it as empty
    user/vendor data.

    Also, be aware the user data/vendor API requires the source port to be
    below 1024 to ensure the client is root (since non-root users can't bind
    ports below 1024). If requests raises ConnectionError (EADDRINUSE), the
    caller should retry to call this function on an other port.
    Nr   c                 S   s   |j dkot|jtjj S )N  )code
isinstancecauserequests
exceptionsr   )_excr   r   r    <lambda>X   s   
z%query_data_api_once.<locals>.<lambda>)datatimeoutretriesZsessionZexception_cbr,   )r
   readurlr   decode_binarycontentsUrlErrorr-   )api_addressr6   requests_sessionrespr3   r   r   r    query_data_api_once=   s    

r?   c                 C   s(  t dt|dD ]}ztd| | t }d}zRt|j}|}|d dkrZ|dd }tj	|dtj
d	d d }	|	tjkrd
}W n tk
r   Y nX |dt||fd t|||d}
td|  |
W   S  tjk
r } z(td| | td |}W Y qW 5 d}~X Y qX q|dS )a/  Get user or vendor data.

    Handle the retrying logic in case the source port is used.

    Scaleway metadata service requires the source port of the client to
    be a privileged port (<1024).  This is done to ensure that only a
    privileged user on the system can access the metadata service.
    r!   r   z*Trying to get %s data (bind on port %d)...z0.0.0.0r   [Nprotoz0::zhttp://)r   )r6   r=   z%s-data downloadedz%Error while trying to get %s data: %s   )rangemaxLOGdebugr0   ZSessionr   netlocr%   getaddrinfoIPPROTO_TCPAF_INET6
ValueErrorZmountr   r?   r
   r;   warningtimesleep)Zapi_typer<   r7   r6   Zportr=   Z	localhostZurl_addressaddress
addr_protor5   r3   last_excr   r   r    query_data_apie   sX      
  
  

rT   c                       s   e Zd ZdZejejejej	hiZ
 fddZdd Zdd Zedd	 Zd
d Zdd Zedd Zedd Zdd Zdd ZdddZedd Zedd Z  ZS )DataSourceScalewayScalewayc                    s   t t| ||| tt|ddgi g| _t| jdt	| _
t| jdt| _t| jdt| _d | _tj| _t| _d | _d | _d | _d| _d| j kr|  j| jd 7  _d S )NZ
datasourcerV   r7   r6   max_waitTmetadata_urls)r   rU   r   r   ZmergemanydictZget_cfg_by_pathZds_cfgintgetDEF_MD_RETRIESr7   DEF_MD_TIMEOUTr6   DEF_MD_MAX_WAITrW   _fallback_interfacer	   UNSET_network_configDS_BASE_URLSrX   userdata_urlvendordata_urlephemeral_fixed_addresshas_ipv4keys)r   Zsys_cfgdistropathsr   r   r    r      s"    zDataSourceScaleway.__init__c                 C   s|   t   }tj|| j| jdd\}}|rZtd| | d| _| d| _| d| _	dS td|t
t   |  tdS )	zO
        Define metadata_url based upon api-metadata URL availability.
        F)urlsrW   r6   Zconnect_synchronouslyz%s is reachablez/conf?format=jsonz/user_data/cloud-initz/vendor_data/cloud-initNz3Unable to reach api-metadata at %s after %s seconds)rO   r
   Zwait_for_urlrW   r6   rG   rH   metadata_urlrb   rc   rY   r   )r   ri   Z
start_timeZ	avail_urlr2   r   r   r    _set_metadata_url   s&    
z$DataSourceScaleway._set_metadata_urlc                 C   sZ   t j| j| j| jd}tt|j	| _
td| j| j| j| _td| j| j| j| _d S )N)r6   r7   z	user-datazvendor-data)r
   r8   rj   r6   r7   jsonloadsr   r9   r:   metadatarT   rb   Zuserdata_rawrc   Zvendordata_raw)r   r>   r   r   r    _crawl_metadata   s$            z"DataSourceScaleway._crawl_metadatac                  C   s>   t d} | dkrdS tjdr&dS t }d|kr:dS dS )a   
        There are three ways to detect if you are on Scaleway:

        * check DMI data: not yet implemented by Scaleway, but the check is
          made to be future-proof.
        * the initrd created the file /var/run/scaleway.
        * "scaleway" is in the kernel cmdline.
        zsystem-manufacturerrV   Tz/var/run/scalewayZscalewayN)r   Zread_dmi_dataospathexistsr   Zget_cmdline)Zvendor_nameZcmdliner   r   r    	ds_detect   s    

zDataSourceScaleway.ds_detectc                 C   s   |dkrt d| g S g }|D ]~}t|j}|d dkrF|dd }tj|d tjdd d }|tjkr|dkr||g7 }q q |tjkr |d	kr ||g7 }q q |S )
N)ipv4ipv6zInvalid IP version : %sr   r@   r!   rA   rB   rt   ru   )	rG   rH   r   rI   r%   rJ   rK   ZAF_INETrL   )r   rC   ri   Zfiltered_urlsZurlrQ   rR   r   r   r    _set_urls_on_ip_version   s0    
  

z*DataSourceScaleway._set_urls_on_ip_versionc              
   C   s6  | j d krt | _ | jrz`t| j| j H}tjtj	d| j
| jfd tjtj	d| jd |d | _d| jd< W 5 Q R X W n> tttfk
r } zttt| d| _W 5 d }~X Y nX | js2zVt| j| j > tjtj	d	| j
| jfd tjtj	d| jd d
| jd< W 5 Q R X W n tk
r0   Y dS X dS )Nz3Set api-metadata URL depending on IPv4 availability)logfuncmsgfuncargszCrawl of metadata service)rw   rx   ry   zfixed-addressrt   Z
net_in_useFz3Set api-metadata URL depending on IPv6 availabilityru   T)r^   r   find_fallback_nicre   r   rg   r   Zlog_timerG   rH   rk   rX   ro   rd   rn   r   r   r   Zlogexcstrr   )r   rt   er   r   r    	_get_data  sd    


zDataSourceScaleway._get_datac              	   C   s  | j dkr tdtj tj| _ | j tjkr2| j S | jdkrFt | _| jd dkrBi }i }| jd D ]}|d | j	krd|d< dd	d
g|d< qhd|
 kr|d  |d  d|d  f7  < n|d  d|d  f|d< |d dkrh|d dd}d|
 kr|d  |g7  < qh|g|d< qh||| j< d|d| _ ndd| j d}ddig}| jd r|dd| jd d  d| jd d  ddd| jd d  dgdg7 }||d < d!|gd"| _ td#| j  | j S )$z`
        Configure networking according to data received from the
        metadata API.
        Nz5Found None as cached _network_config. Resetting to %sZ
private_ipZ
public_ipsrQ   TZdhcp4z169.254.42.42/32z
62.210.0.1)toviaroutesZ	addresses/netmaskZfamilyZinet6gatewayz::/0)r   r   r   )versionZ	ethernetsZphysicalz%s)typenamer   ru   Zstaticz::0)Znetworkprefixr   )r   rQ   r   r   subnetsr!   )r   Zconfigznetwork_config : %s)r`   rG   rN   r	   r_   r^   r   r{   rn   rd   rf   rH   )r   ZnetcfgZip_cfgZipZrouter   r   r   r    network_configN  sj    






z!DataSourceScaleway.network_configc                 C   s   d S r   r   r   r   r   r    launch_index  s    zDataSourceScaleway.launch_indexc                 C   s
   | j d S )Nid)rn   r   r   r   r    get_instance_id  s    z"DataSourceScaleway.get_instance_idc                 C   s^   dd | j d D }d}t|}| j dg D ]*}||s>q.|||d  dd q.|S )Nc                 S   s   g | ]}|d  qS )keyr   ).0r   r   r   r    
<listcomp>  s     z:DataSourceScaleway.get_public_ssh_keys.<locals>.<listcomp>Zssh_public_keyszAUTHORIZED_KEY=Ztagsr2    )rn   lenrZ   
startswithappendreplace)r   Zssh_keysZakeypreplentagr   r   r    get_public_ssh_keys  s    
z&DataSourceScaleway.get_public_ssh_keysFc                 C   s   t | jd dS )NZhostnameF)r   rn   )r   ZfqdnZ
resolve_ipZmetadata_onlyr   r   r    get_hostname  s    zDataSourceScaleway.get_hostnamec                 C   s   d S r   r   r   r   r   r    availability_zone  s    z$DataSourceScaleway.availability_zonec                 C   s   d S r   r   r   r   r   r    region  s    zDataSourceScaleway.region)FFF)r'   r(   r)   Zdsnamer   ZNETWORKr   ZBOOT_NEW_INSTANCEZBOOTZBOOT_LEGACYZdefault_update_eventsr   rk   ro   staticmethodrs   rv   r~   propertyr   r   r   r   r   r   r   r+   r   r   r   r    rU      s2   
A
L


rU   c                 C   s   t | tS r   )r	   Zlist_from_dependsdatasources)Zdependsr   r   r    get_datasource_list  s    r   )2rl   rp   r%   rO   Zurllib.parser   r0   Zrequests.exceptionsr   Zurllib3.connectionr   Zurllib3.poolmanagerr   Z	cloudinitr   r   Zloggingr   r	   r
   r   Zcloudinit.eventr   r   Zcloudinit.net.dhcpr   Zcloudinit.net.ephemeralr   r   Zcloudinit.sourcesr   Zcloudinit.subpr   Z	getLoggerr'   rG   ra   r[   r]   r\   ZadaptersZHTTPAdapterr   r?   rT   Z
DataSourcerU   ZDEP_FILESYSTEMr   r   r   r   r   r    <module>   s<   
(4  $
