o
    w7e\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                   @   sZ   e Zd ZdZ			ddeeeef  f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 n ty. }	 ztd|	|	d}	~	ww || _|| _|| _|| _	|| _
|| _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net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__    s2   
zEphemeralIPv4Network.__init__c                 C   s   | j rt| j rtd| j d  dS z|   | jr#|   W dS | jr-| 	  W dS W dS  t
jyD   td | ddd  w )z>Perform ephemeral network setup if interface is not connected.z=Skip ephemeral network setup, instance has connectivity to %s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 n% t
jyD } zdt|jvr0 td| j| j W Y d}~dS d}~ww | 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 %sNinet)family)r   r   r   r#   r$   r   r   r   net_opsadd_addrr   r(   strstderrlink_upr   appendr   	link_downdel_addr)r   cidrr   r   r   r   r%   z   s<   
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   r3   append_router   r   insertr   	del_route)r   net_addressr=   r   r   r   r&      s   z+EphemeralIPv4Network._bringup_static_routesc              	   C   s   | j j }d|v 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)source_addressr   r<   )r   r3   get_default_router#   r$   r   strip	add_router   r   r   r?   r   r@   )r   outr   r   r   r'      s6   	
z$EphemeralIPv4Network._bringup_routerNNN)__name__
__module____qualname____doc__r   r   r5   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 dS )zlinux kernel does autoconfiguration even when autoconf=0

        https://www.kernel.org/doc/html/latest/networking/ipv6.html
        	operstateupN)r   read_sys_netr   r   r3   r7   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   _argsr   r   r   r*      s    zEphemeralIPv6Network.__exit__N)rI   rJ   rK   rL   r    r,   r*   r   r   r   r   rM      s
    rM   c                   @   s^   e Zd Z			ddeeeef  f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   rU   r   rX   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)rW   rV   r*   r+   r   r   r   rZ     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 sJt	
|d |d |d< |d rWt|d |d< | jr_| j|d< t| jfi |}|  || _| 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-routesrouters)r   r   r   r   r   r   r   r   r   r   r   )rW   r   r   rU   rX   r
   r#   r$   extract_dhcp_options_mappingr   mask_and_ipv4_to_bcast_addrr	   parse_static_routesr   r   r,   rV   )r   leasesnmapkwargsephipv4r   r   r   rY     sL   	


zEphemeralDHCPv4.obtain_leasec                 C   sD   i }|  D ]\}}t|tr| ||| q| j|||< q|S rT   )items
isinstancelistget_first_option_valuerW   get)r   ra   resultinternal_referencelease_option_namesr   r   r   r]   M  s   
z,EphemeralDHCPv4.extract_dhcp_options_mappingc                 C   s(   |D ]}| |s| j |||< qd S rT   )rh   rW   )r   internal_mappingrk   ri   different_namesr   r   r   rg   X  s
   
z&EphemeralDHCPv4.get_first_option_valuerH   )rI   rJ   rK   r   r   r5   r   r    r,   r*   rZ   rY   r]   rg   r   r   r   r   rS      s    
2rS   c                   @   s8   e Zd ZdZ		ddedef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   rp   ro   
contextlib	ExitStackstack	state_msgr   )r   r   r   ro   rp   r   r   r   r    c  s   

zEphemeralIPNetwork.__init__c              
   C   s~   z"| j r| jt| j| j | jr | jt| j| j W | S W | S  ty> } z| jr1d| _	n|W Y d }~| S d }~ww )Nzusing link-local ipv6)
rp   rt   enter_contextrS   r   r   ro   rM   r
   ru   )r   r   r   r   r   r,   q  s(   

zEphemeralIPNetwork.__enter__c                 G   s   | j   d S rT   )rt   closerQ   r   r   r   r*     s   zEphemeralIPNetwork.__exit__N)FT)rI   rJ   rK   rL   boolr    r,   r*   r   r   r   r   rn   `  s    
rn   )rL   rr   logging	functoolsr   typingr   r   r   r   r   cloudinit.netr   	cloudinitr   cloudinit.net.dhcpr	   r
   r   	getLoggerrI   r#   r   rM   rS   rn   r   r   r   r   <module>   s   
 ? m