U
    Ad%                     @   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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 d d
lmZ eeZdZed ed ed dZdZdZ d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)HTTPConnection)PoolManager)dmi)log)netsources
url_helperutil)
EventScope	EventType)NoDHCPLeaseError)EphemeralDHCPv4)DataSourceHostnamezhttp://169.254.42.42z/conf?format=jsonz/user_data/cloud-initz/vendor_data/cloud-init)metadata_urluserdata_urlvendordata_url   
   c                  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-manufacturerScalewayTz/var/run/scalewayZscalewayF)r   Zread_dmi_dataospathexistsr	   Zget_cmdline)Zvendor_nameZcmdline r   F/usr/lib/python3/dist-packages/cloudinit/sources/DataSourceScaleway.pyon_scaleway)   s    	
r   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__r   r   r   E   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_poolmanagerI   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
exceptionsConnectionError)_excr   r   r   <lambda>q   s   
z%query_data_api_once.<locals>.<lambda>)datatimeoutretriesZsessionZexception_cbr/   )r   readurlr	   decode_binarycontentsUrlErrorr0   )api_addressr:   requests_sessionrespr7   r   r   r   query_data_api_onceV   s    

rC   c           	      C   s   t dt|dD ]}zPtd| | t }|dtd|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$      z*Trying to get %s data (bind on port %d)...zhttp://z0.0.0.0)r   )r:   rA   z%s-data downloadedz%Error while trying to get %s data: %sr   N)rangemaxLOGdebugr3   ZSessionZmountr   rC   r   r?   warningtimesleep)	Zapi_typer@   r;   r:   ZportrA   r9   r7   last_excr   r   r   query_data_api~   s2        

rM   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ed
d Zdd Zdd ZdddZedd Zedd Z  ZS )DataSourceScalewayr   c                    s   t t| ||| tt|ddgi tg| _| jd | _| jd | _	| jd | _
t| jdt| _t| jdt| _d | _tj| _d S )NZ
datasourcer   r   r   r   r;   r:   )r   rN   r   r	   ZmergemanydictZget_cfg_by_pathBUILTIN_DS_CONFIGZds_cfgmetadata_addressuserdata_addressvendordata_addressintgetDEF_MD_RETRIESr;   DEF_MD_TIMEOUTr:   _fallback_interfacer   UNSET_network_config)r    Zsys_cfgdistropathsr"   r   r   r      s    zDataSourceScaleway.__init__c                 C   sZ   t j| j| j| jd}tt|j	| _
td| j| j| j| _td| j| j| j| _d S )N)r:   r;   z	user-datazvendor-data)r   r<   rP   r:   r;   jsonloadsr	   r=   r>   metadatarM   rQ   Zuserdata_rawrR   Zvendordata_raw)r    rB   r   r   r   _crawl_metadata   s$            z"DataSourceScaleway._crawl_metadatac              
   C   s   t  s
dS | jd krt | _z8t| j| j d tjt	j
d| jd W 5 Q R X W n8 tk
r } ztt	t| W Y dS d }~X Y nX dS )NF)Ztmp_dirzCrawl of metadata service)ZlogfuncmsgfuncT)r   rW   r   find_fallback_nicr   rZ   Zget_tmp_exec_pathr	   Zlog_timerG   rH   r_   r   Zlogexcstr)r    er   r   r   	_get_data   s$    

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 | _d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| _ | j S )z`
        Configure networking according to data received from the
        metadata API.
        Nz5Found None as cached _network_config. Resetting to %sZphysicalz%s)typenamerf   Zdhcp4Zipv6Zstaticaddressnetmaskz::0gateway)Znetworkprefixrk   )rf   rh   ri   Zroutessubnetsr$   )versionZconfig)	rY   rG   rI   r   rX   rW   r   rb   r^   )r    Znetcfgrm   r   r   r   network_config   s6    




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)r^   rp   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   ).0rt   r   r   r   
<listcomp>  s     z:DataSourceScaleway.get_public_ssh_keys.<locals>.<listcomp>Zssh_public_keyszAUTHORIZED_KEY=Ztagsr6    )r^   lenrT   
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   r^   )r    ZfqdnZ
resolve_ipZmetadata_onlyr   r   r   get_hostname  s    zDataSourceScaleway.get_hostnamec                 C   s   d S r   r   rp   r   r   r   availability_zone!  s    z$DataSourceScaleway.availability_zonec                 C   s   d S r   r   rp   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   r_   re   propertyro   rq   rs   r~   r   r   r   r.   r   r   r"   r   rN      s*   
'


rN   c                 C   s   t | tS r   )r   Zlist_from_dependsdatasources)Zdependsr   r   r   get_datasource_list/  s    r   ),r\   r   r(   rJ   r3   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   Zcloudinit.sourcesr   Z	getLoggerr*   rG   ZDS_BASE_URLrO   rU   rV   r   ZadaptersZHTTPAdapterr   rC   rM   Z
DataSourcerN   ZDEP_FILESYSTEMr   r   r   r   r   r   <module>   s<   
(& 
