o
    f>                     @   s*  d dl Z 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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Z.dd Z/dS )    N)urlparse)ConnectionError)HTTPConnection)PoolManager)dmi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di | d S )N )source_addresssuperr   __init__)selfr   kwargs	__class__r   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   )	num_poolsmaxsizeblockr   socket_options)r   default_socket_optionssocket
SOL_SOCKETSO_REUSEPORTr   r   poolmanager)r   connectionsr    r!   r"   r   r   r   init_poolmanager/   s   z%SourceAddressAdapter.init_poolmanager)F)__name__
__module____qualname____doc__r   r)   __classcell__r   r   r   r   r   &   s    r   c              
   C   s^   zt j| d|d|dd d}t|jW S  t jy. } z|jdkr)W Y d}~dS  d}~ww )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>W   s   
 z%query_data_api_once.<locals>.<lambda>)datatimeoutretriessessionexception_cbr/   )r   readurlr	   decode_binarycontentsUrlErrorr0   )api_addressr9   requests_sessionrespr6   r   r   r   query_data_api_once<   s    
rD   c                 C   s  t dt|dD ]}z]td| | t }d}z)t|j}|}|d dkr,|dd }tj	|dtj
d	d d }	|	tjkr@d
}W n	 tyJ   Y nw |dt||fd t|||d}
td|  |
W   S  tjy } ztd| | td |}W Y d}~qd}~ww |)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   )r9   rB   z%s-data downloadedz%Error while trying to get %s data: %s   )rangemaxLOGdebugr3   Sessionr   netlocr$   getaddrinfoIPPROTO_TCPAF_INET6
ValueErrormountr   rD   r   r@   warningtimesleep)api_typerA   r:   r9   portrB   	localhosturl_addressaddress
addr_protor8   r6   last_excr   r   r   query_data_apid   sT   



r_   c                       s   e Zd ZdZejejejej	hiZ
 fddZdeddf 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| _tj| _t| _d | _d | _d | _d | _d| _d| j v r_|  j| jd 7  _d S d S )N
datasourcera   r:   r9   max_waitTmetadata_urls)r   r`   r   r	   mergemanydictget_cfg_by_pathds_cfgintgetDEF_MD_RETRIESr:   DEF_MD_TIMEOUTr9   DEF_MD_MAX_WAITrc   r   UNSET_network_configDS_BASE_URLSrd   metadata_urluserdata_urlvendordata_urlephemeral_fixed_addresshas_ipv4keys)r   sys_cfgdistropathsr   r   r   r      s$   zDataSourceScaleway.__init__ci_pkl_versionreturnNc                    sF   t  | d dttd d d}|D ]}t| |s t| |||  qd S )NT)rs   rt   rc   rd   rq   rr   )r   	_unpicklerl   ro   hasattrsetattr)r   ry   attr_defaultsattrr   r   r   r{      s   
zDataSourceScaleway._unpicklec                 C   sx   t  }tj|| j| jdd\}}|r-td| | d| _| d| _	| d| _
dS td|tt  |  t)	zO
        Define metadata_url based upon api-metadata URL availability.
        F)urlsrc   r9   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)rV   	monotonicr   wait_for_urlrc   r9   rL   rM   rp   rq   rr   rh   r   )r   r   
start_time	avail_urlr5   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)r9   r:   z	user-datazvendor-data)r   r=   rp   r9   r:   jsonloadsr	   r>   r?   metadatar_   rq   userdata_rawrr   vendordata_raw)r   rC   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|v 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-manufacturerra   Tz/var/run/scalewayscalewayN)r   read_dmi_dataospathexistsr	   get_cmdline)vendor_namecmdliner   r   r   	ds_detect   s   

zDataSourceScaleway.ds_detectc                 C   s   |dvrt d| g S g }|D ]>}t|j}|d dkr#|dd }tj|d tjdd d }|tjkr?|dkr?||g7 }q|tjkrN|d	krN||g7 }qq|S )
N)ipv4ipv6zInvalid IP version : %sr   rE   r   rF   rG   r   r   )	rL   rM   r   rO   r$   rP   rQ   AF_INETrR   )r   rH   r   filtered_urlsurlr\   r]   r   r   r   _set_urls_on_ip_version  s.   


z*DataSourceScaleway._set_urls_on_ip_versionc              
   C   sP  | j r_z;t| j| jj)}tjtjd| j| j	fd tjtjd| j
d |d | _d| jd< W d    n1 s8w   Y  W n  tttfy^ } zttt| d| _ W Y d }~nd }~ww | j sz9t| j| jj& tjtjd	| j| j	fd tjtjd| j
d d
| jd< W d    W dS 1 sw   Y  W dS  ty   Y dS w dS )Nz3Set api-metadata URL depending on IPv4 availability)logfuncmsgfuncargszCrawl of metadata service)r   r   r   zfixed-addressr   
net_in_useFz3Set api-metadata URL depending on IPv6 availabilityr   T)rt   r   rw   fallback_interfacer	   log_timerL   rM   r   rd   r   rs   r   r   r   r   logexcstrr   )r   r   er   r   r   	_get_data  sr   
zDataSourceScaleway._get_datac              	   C   s  | j du rtdtj tj| _ | j tjkr| j S | jd du ri }i }| jd D ]_}|d | jkr?d|d< dd	d
g|d< q)d| v rX|d  |d  d|d  f7  < n|d  d|d  f|d< |d dkr|d dd}d| v r|d  |g7  < q)|g|d< q)||| jj	< d|d| _ nBdd| j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 %s
private_ip
public_ipsr\   Tdhcp4z169.254.42.42/32z
62.210.0.1)toviaroutes	addresses/netmaskfamilyinet6gatewayz::/0)r   r   r   )version	ethernetsphysicalz%s)typenamer   r   staticz::0)networkprefixr   )r   r\   r   r   subnetsr   )r   configznetwork_config : %s)rn   rL   rU   r   rm   r   rs   ru   rw   r   rM   )r   netcfgip_cfgiprouter   r   r   r   network_configX  sh   






z!DataSourceScaleway.network_configc                 C      d S Nr   r   r   r   r   launch_index     zDataSourceScaleway.launch_indexc                 C   s
   | j d S )Nid)r   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>ssh_public_keyszAUTHORIZED_KEY=tagsr5    )r   lenri   
startswithappendreplace)r   ssh_keysakeypreplentagr   r   r   get_public_ssh_keys  s   
z&DataSourceScaleway.get_public_ssh_keysFc                 C   s   t | jd dS )NhostnameF)r   r   )r   fqdn
resolve_ipmetadata_onlyr   r   r   get_hostname  s   zDataSourceScaleway.get_hostnamec                 C   r   r   r   r   r   r   r   availability_zone  r   z$DataSourceScaleway.availability_zonec                 C   r   r   r   r   r   r   r   region  r   zDataSourceScaleway.region)FFF)r*   r+   r,   dsnamer
   NETWORKr   BOOT_NEW_INSTANCEBOOTBOOT_LEGACYdefault_update_eventsr   rh   r{   r   r   staticmethodr   r   r   propertyr   r   r   r   r   r   r   r.   r   r   r   r   r`      s6    
>
I


r`   c                 C   s   t | tS r   )r   list_from_dependsdatasources)dependsr   r   r   get_datasource_list  s   r   )0r   loggingr   r$   rV   urllib.parser   r3   requests.exceptionsr   urllib3.connectionr   urllib3.poolmanagerr   	cloudinitr   r   r   r	   cloudinit.eventr
   r   cloudinit.net.dhcpr   cloudinit.net.ephemeralr   r   cloudinit.sourcesr   cloudinit.subpr   	getLoggerr*   rL   ro   rj   rl   rk   adaptersHTTPAdapterr   rD   r_   
DataSourcer`   DEP_FILESYSTEMr   r   r   r   r   r   <module>   s<   
(4  
,