o
    x[hç:  ã                   @   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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„ Z0dS )é    N)Úurlparse)ÚConnectionError)ÚHTTPConnection)ÚPoolManager)ÚdmiÚperformanceÚ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_cbr0   )r	   Úreadurlr
   Údecode_binaryÚcontentsÚUrlErrorr1   )Ú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Údebugr4   Ú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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Ú
datasourcer`   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_WAITrb   r   ÚUNSETÚ_network_configÚDS_BASE_URLSrc   Ú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)rr   rs   rb   rc   rp   rq   )r   Ú	_unpicklerk   rn   ÚhasattrÚsetattr)r   rx   Úattr_defaultsÚattrr   r   r   rz   ¸   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)Úurlsrb   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)rU   Ú	monotonicr	   Úwait_for_urlrb   r9   rK   rL   ro   rp   rq   rg   r   )r   r   Ú
start_timeÚ	avail_urlÚ_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=   ro   r9   r:   ÚjsonÚloadsr
   r>   r?   Úmetadatar^   rp   Úuserdata_rawrq   Ú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-manufacturerr`   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   sp  | j rgzCt| j| jjƒ�1}t d¡� |  | j¡ W d   ƒ n1 s#w   Y  |  ¡  |d | _	d| j
d< W d   ƒ n1 s@w   Y  W n  tttfyf } zt tt|ƒ¡ d| _ W Y d }~nd }~ww | j s¶zAt| j| jjƒ�. t d¡� |  | j¡ W d   ƒ n1 sŠw   Y  |  ¡  d| j
d< W d   ƒ W dS 1 s¤w   Y  W dS  tyµ   Y dS w dS )	Nz7Setting api-metadata URL depending on IPv4 availabilityzfixed-addressÚipv4Ú
net_in_useFz7Setting api-metadata URL depending on IPv6 availabilityÚipv6T)rs   r   rv   Úfallback_interfacer   ÚTimedr†   rc   rŒ   rr   r‰   r   r   r   r
   ÚlogexcrK   Ústrr   )r   r–   Úer   r   r   Ú	_get_data  s^   þÿü
õ€ý€øþÿüöóþÿ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 r©i }i }| jd D ]r}|d | jkrRd|d< ddd	d
œ}d| ¡ v rL|d  |g7  < q)|g|d< q)d| ¡ v rk|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)zon-linkÚ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)rm   rK   rT   r   rl   r‰   rr   rt   rv   r™   rL   )r   ÚnetcfgÚip_cfgÚipÚrouter´   r   r   r   Únetwork_config4  sr   
þý
ÿÿ
€
þ

ÿýÿüÿ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=Útagsr…   ú )r‰   Úlenrh   Ú
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   rg   rz   r†   rŒ   Ústaticmethodr•   rž   Úpropertyrº   r¾   rÁ   rÐ   rÕ   rÖ   r×   r/   r   r   r   r   r_   ˜   s4    ýÿ
2
O


r_   c                 C   s   t  | t¡S r¼   )r   Úlist_from_dependsÚdatasources)Údependsr   r   r   Úget_datasource_list¨  s   rã   )1r‡   Úloggingr�   r%   rU   Úurllib.parser   r4   Úrequests.exceptionsr   Úurllib3.connectionr   Úurllib3.poolmanagerr   Ú	cloudinitr   r   r   r	   r
   Úcloudinit.eventr   r   Úcloudinit.net.dhcpr   Úcloudinit.net.ephemeralr   r   Úcloudinit.sourcesr   Úcloudinit.subpr   Ú	getLoggerr+   rK   rn   ri   rk   rj   ÚadaptersÚHTTPAdapterr   rD   r^   Ú
DataSourcer_   ÚDEP_FILESYSTEMrá   rã   r   r   r   r   Ú<module>   s<   
(4  
ÿ