U
    Ld\5                     @   s   d Z ddlZddlZddlmZ ddlmZmZmZm	Z	m
Z
 ddlmZ ddlmZ ddlmZmZmZ eeZG dd dZG d	d
 d
ZG dd dZG dd dZdS )z.Module for ephemeral network context managers
    N)partial)AnyCallableDictListOptional)subp)IscDhclientNoDHCPLeaseErrormaybe_perform_dhcp_discoveryc                   @   sT   e Zd ZdZdeeeef  dddZdd Z	dd	 Z
d
d Zdd Zdd ZdS )EphemeralIPv4Networka  Context manager which sets up temporary static network configuration.

    No operations are performed if the provided interface already has the
    specified configuration.
    This can be verified with the connectivity_url_data.
    If unconnected, bring up the interface with valid ip, prefix and broadcast.
    If router is provided setup a default route for that interface. Upon
    context exit, clean up the interface leaving no configuration behind.
    Nconnectivity_url_datac	           
   
   C   s   t ||||gs$td||||zt|| _W n2 tk
rf }	 ztd|	|	W 5 d}	~	X Y nX || _|| _|| _|| _	|| _
|| _g | _|| _dS )aX  Setup context manager and validate call signature.

        @param interface: Name of the network interface to bring up.
        @param ip: IP address to assign to the interface.
        @param prefix_or_mask: Either netmask of the format X.X.X.X or an int
            prefix.
        @param broadcast: Broadcast address for the IPv4 network.
        @param router: Optionally the default gateway IP.
        @param connectivity_url_data: Optionally, a URL to verify if a usable
           connection already exists.
        @param static_routes: Optionally a list of static routes from DHCP
        z5Cannot init network on {0} with {1}/{2} and bcast {3}z4Cannot setup network, invalid prefix or netmask: {0}N)all
ValueErrorformatnetZipv4_mask_to_net_prefixprefixr   	interfaceip	broadcastrouterstatic_routescleanup_cmdsdistro)
selfr   r   r   prefix_or_maskr   r   r   r   e r   9/usr/lib/python3/dist-packages/cloudinit/net/ephemeral.py__init__    s6       zEphemeralIPv4Network.__init__c                 C   s   | j r(t| j r(td| j d  dS z*|   | jrB|   n| jrP| 	  W n0 t
jk
r   td | ddd  Y nX dS )z>Perform ephemeral network setup if interface is not connected.z=Skip ephemeral network setup, instance has connectivity to %sZurlNzHError bringing up EphemeralIPv4Network. Datasource setup cannot continue)r   r   has_url_connectivityLOGdebug_bringup_devicer   _bringup_static_routesr   _bringup_routerr   ProcessExecutionErrorerror__exit__r   r   r   r   	__enter__O   s&    
zEphemeralIPv4Network.__enter__c                 C   s   | j D ]
}|  qdS )zTeardown anything we set up.N)r   )r   	excp_type
excp_valueexcp_tracebackcmdr   r   r   r)   u   s    
zEphemeralIPv4Network.__exit__c              
   C   s   d | j| j}td| j|| j z| jj	| j|| j W nF t
jk
r } z&dt|jkrb td| j| j W 5 d}~X Y nPX | jjj| jdd | jt| jjj| jdd | jt| jjj| j| dS )z1Perform the ip comands to fully setup the device.z{0}/{1}z:Attempting setup of ephemeral network on %s with %s brd %szFile existsz7Skip ephemeral network setup, %s already has address %sNZinet)Zfamily)r   r   r   r"   r#   r   r   r   net_opsZadd_addrr   r'   strstderrlink_upr   appendr   Z	link_downZdel_addr)r   Zcidrr   r   r   r   r$   z   s8    z$EphemeralIPv4Network._bringup_devicec              
   C   sJ   | j D ]>\}}| jj| j|| | jdt| jjj| j||d qd S )Nr   gateway)	r   r   r0   Zappend_router   r   insertr   	del_route)r   Znet_addressr6   r   r   r   r%      s      z+EphemeralIPv4Network._bringup_static_routesc              	   C   s   | j j }d|kr,td| j|  dS | j jj| j| j| j	d | j
dt| j jj| j| j| j	d | j jj| jd| jd | j
dt| j jj| jd dS )z<Perform the ip commands to fully setup the router if needed.defaultz<Skip ephemeral route setup. %s already has default route: %sN)Zsource_addressr   r5   )r   r0   Zget_default_router"   r#   r   stripZ	add_router   r   r   r7   r   r8   )r   outr   r   r   r&      s>      	  z$EphemeralIPv4Network._bringup_router)NNN)__name__
__module____qualname____doc__r   r   r1   r   r    r+   r)   r$   r%   r&   r   r   r   r   r      s      /&!r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	EphemeralIPv6NetworkzContext manager which sets up a ipv6 link local address

    The linux kernel assigns link local addresses on link-up, which is
    sufficient for link-local communication.
    c                 C   s"   |st d||| _|| _dS )zSetup context manager and validate call signature.

        @param interface: Name of the network interface to bring up.
        @param ip: IP address to assign to the interface.
        @param prefix: IPv6 uses prefixes, not netmasks
        zCannot init network on {0}N)r   r   r   r   )r   r   r   r   r   r   r       s    zEphemeralIPv6Network.__init__c                 C   s&   t | jddkr"| jj| j dS )zlinux kernel does autoconfiguration even when autoconf=0

        https://www.kernel.org/doc/html/latest/networking/ipv6.html
        Z	operstateZupN)r   Zread_sys_netr   r   r0   r3   r*   r   r   r   r+      s    zEphemeralIPv6Network.__enter__c                 G   s   dS )z%No need to set the link to down stateNr   r   Z_argsr   r   r   r)      s    zEphemeralIPv6Network.__exit__N)r<   r=   r>   r?   r    r+   r)   r   r   r   r   r@      s   r@   c                   @   sX   e Zd Zdeeeef  dddZdd Zdd Z	d	d
 Z
dd Zdd Zdd ZdS )EphemeralDHCPv4Nr   c                 C   s(   || _ d | _d | _|| _|| _|| _d S N)iface_ephipv4leasedhcp_log_funcr   r   )r   r   rD   r   rG   r   r   r   r       s    zEphemeralDHCPv4.__init__c                 C   s,   | j r$t| j r$td| j  dS |  S )zUSetup sandboxed dhcp context, unless connectivity_url can already be
        reached.z:Skip ephemeral DHCP setup, instance has connectivity to %sN)r   r   r!   r"   r#   obtain_leaser*   r   r   r   r+     s    zEphemeralDHCPv4.__enter__c                 C   s   |    dS )z Teardown sandboxed dhcp context.N)clean_network)r   r,   r-   r.   r   r   r   r)     s    zEphemeralDHCPv4.__exit__c                 C   s*   | j rd| _ | jsdS | jddd dS )z@Exit _ephipv4 context to teardown of ip configuration performed.N)rF   rE   r)   r*   r   r   r   rI     s
    zEphemeralDHCPv4.clean_networkc                 C   s   | j r| j S t| j| j| j}|s(t |d | _ td| j d | j d | j d  ddddddgd	d
}| |}|d st	
|d |d |d< |d rt|d |d< | jr| j|d< t| jf|}|  || _| j S )a9  Perform dhcp discovery in a sandboxed environment if possible.

        @return: A dict representing dhcp options on the most recent lease
            obtained from the dhclient discovery if run, otherwise an error
            is raised.

        @raises: NoDHCPLeaseError if no leases could be obtained.
        z#Received dhcp lease on %s for %s/%sr   zfixed-addresszsubnet-maskzbroadcast-addresszrfc3442-classless-static-routeszclassless-static-routesZrouters)r   r   r   r   r   r   r   r   r   r   r   )rF   r   r   rD   rG   r
   r"   r#   extract_dhcp_options_mappingr   Zmask_and_ipv4_to_bcast_addrr	   Zparse_static_routesr   r   r+   rE   )r   ZleasesnmapkwargsZephipv4r   r   r   rH     sR    	  

 
zEphemeralDHCPv4.obtain_leasec                 C   sD   i }|  D ]2\}}t|tr.| ||| q| j|||< q|S rC   )items
isinstancelistget_first_option_valuerF   get)r   rL   resultZinternal_referencelease_option_namesr   r   r   rK   M  s    
  z,EphemeralDHCPv4.extract_dhcp_options_mappingc                 C   s(   |D ]}| |s| j |||< qd S rC   )rR   rF   )r   Zinternal_mappingrT   rS   Zdifferent_namesr   r   r   rQ   X  s    
z&EphemeralDHCPv4.get_first_option_value)NNN)r<   r=   r>   r   r   r1   r   r    r+   r)   rI   rH   rK   rQ   r   r   r   r   rB      s      2rB   c                   @   s2   e Zd ZdZdeedddZdd Zd	d
 ZdS )EphemeralIPNetworkz9Marries together IPv4 and IPv6 ephemeral context managersFT)ipv6ipv4c                 C   s,   || _ || _|| _t | _d| _|| _d S )N )r   rW   rV   
contextlib	ExitStackstack	state_msgr   )r   r   r   rV   rW   r   r   r   r    c  s    
zEphemeralIPNetwork.__init__c              
   C   sv   z<| j r| jt| j| j | jr:| jt| j| j W n4 tk
rp } z| jr\d| _	n|W 5 d }~X Y nX | S )Nzusing link-local ipv6)
rW   r[   enter_contextrB   r   r   rV   r@   r
   r\   )r   r   r   r   r   r+   q  s    zEphemeralIPNetwork.__enter__c                 G   s   | j   d S rC   )r[   closerA   r   r   r   r)     s    zEphemeralIPNetwork.__exit__N)FT)r<   r=   r>   r?   boolr    r+   r)   r   r   r   r   rU   `  s     rU   )r?   rY   Zlogging	functoolsr   typingr   r   r   r   r   Zcloudinit.netr   Z	cloudinitr   Zcloudinit.net.dhcpr	   r
   r   Z	getLoggerr<   r"   r   r@   rB   rU   r   r   r   r   <module>   s   
 ? m