o
    f>                     @   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 ddl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)NoDHCPLeaseErrormaybe_perform_dhcp_discovery)ProcessExecutionErrorc                   @   sL   e Zd ZdZ		dde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interface_addrs_before_dhcpc	           
   
   C   s   t ||||gstd||||zt|| _W n ty. }	 ztd|	|	d}	~	ww || _|| _|| _|| _	|| _
g | _|| _| j d| j | _|| ji | _dS )a  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 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prefix	interfaceip	broadcastrouterstatic_routescleanup_cmdsdistrocidrgetr   )
selfr   r   r   prefix_or_maskr   r   r   r   e r    9/usr/lib/python3/dist-packages/cloudinit/net/ephemeral.py__init__   s8   
zEphemeralIPv4Network.__init__c              
   C   s   z?z|    W n! ty( } zdt|jvrdt|jvr W Y d}~nd}~ww | jr3|   W dS | jr=|   W dS W dS  tyN   | ddd  w )zSet up ephemeral network if interface is not connected.

        This context manager handles the lifecycle of the network interface,
        addresses, routes, etc
        zFile existszAddress already assignedN)	_bringup_devicer
   strstderrr   _bringup_static_routesr   _bringup_router__exit__)r   r   r    r    r!   	__enter__M   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(   q   s   
zEphemeralIPv4Network.__exit__c                 C   s:  t d| j| j| j t | ji }|d}| jd}| j	dd |di D v }| j	dd | jdi D v }|rHt d| j| j	 n| j
j| j| j| j |r^t d| j n
| j
jj| jd	d
 |rrt d| j n| jt| j
jj| jd	d
 |rt d| j	 dS | jt| j
jj| j| j dS )af  Perform the ip commands to fully set up the device.

        Dhcp clients behave differently in how they leave link state and ip
        address assignment.

        Attempt assigning address and setting up link if needed to be done.
        Set cleanup_cmds to return the interface state to how it was prior
        to execution of the dhcp client.
        z:Attempting setup of ephemeral network on %s with %s brd %supc                 S      g | ]}| d qS r   r   .0r   r    r    r!   
<listcomp>   s    
z8EphemeralIPv4Network._bringup_device.<locals>.<listcomp>ipv4c                 S   r/   r0   r1   r2   r    r    r!   r4      s    z1Skip adding ip address: %s already has address %sz9Skip bringing up network link: interface %s is already upinet)familyzLNot queueing link down: link [%s] was up prior before receiving a dhcp leasezSNot queueing address removal: address %s was assigned before receiving a dhcp leaseN)LOGdebugr   r   r   netinfonetdev_infor   r   r   r   net_opsadd_addrlink_upr   appendr   	link_downdel_addr)r   interface_addrs_after_dhcphas_linkhad_linkhas_iphad_ipr    r    r!   r#   v   sl   




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   r<   append_router   r   insertr   	del_route)r   net_addressrH   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   rG   )r   r<   get_default_router8   r9   r   strip	add_router   r   r   rJ   r   rK   )r   outr    r    r!   r'      s6   	
z$EphemeralIPv4Network._bringup_router)NN)__name__
__module____qualname____doc__dictr"   r)   r(   r#   r&   r'   r    r    r    r!   r      s    
0$I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
        	operstater.   N)r   read_sys_netr   r   r<   r>   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)rS   rT   rU   rV   r"   r)   r(   r    r    r    r!   rX      s
    rX   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 )EphemeralDHCPv4Nconnectivity_url_datac                 C   s2   || _ d | _d | _|| _|| _|| _t | _d S N)	iface_ephipv4leasedhcp_log_funcr_   r   r:   r;   r   )r   r   ra   r_   rd   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   has_url_connectivityr8   r9   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(   4  s   zEphemeralDHCPv4.__exit__c                 C   s$   d| _ | jr| jddd dS dS )z@Exit _ephipv4 context to teardown of ip configuration performed.N)rc   rb   r(   r[   r    r    r!   rg   8  s   zEphemeralDHCPv4.clean_networkc                 C   s   | j r| j S t| j| j| j| _ | j st td| j d | j d | j d  ddddg ddd}| |}|d	 sGt	
|d
 |d |d	< |d rV| jj|d |d< t| jfd| j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-address)zrfc3442-classless-static-routeszclassless-static-routesr   zunknown-121routers)r   r   r   r   r   r   r   r   r   r   r   )rc   r	   r   ra   rd   r   r8   r9   extract_dhcp_options_mappingr   mask_and_ipv4_to_bcast_addrdhcp_clientparse_static_routesr   r   r)   rb   )r   nmapkwargsephipv4r    r    r!   rf   >  sP   	
zEphemeralDHCPv4.obtain_leasec                 C   sD   i }|  D ]\}}t|tr| ||| q| j|||< q|S r`   )items
isinstancelistget_first_option_valuerc   r   )r   rm   resultinternal_referencelease_option_namesr    r    r!   ri   u  s   
z,EphemeralDHCPv4.extract_dhcp_options_mappingc                 C   s(   |D ]}| |s| j |||< qd S r`   )r   rc   )r   internal_mappingrv   rt   different_namesr    r    r!   rs     s
   
z&EphemeralDHCPv4.get_first_option_value)NNN)rS   rT   rU   r   r   r$   r   r"   r)   r(   rg   rf   ri   rs   r    r    r    r!   r^     s    
7r^   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 )EphemeralIPNetworkah  Combined ephemeral context manager for IPv4 and IPv6

    Either ipv4 or ipv6 ephemeral network may fail to initialize, but if either
    succeeds, then this context manager will not raise exception. This allows
    either ipv4 or ipv6 ephemeral network to succeed, but requires that error
    handling for networks unavailable be done within the context.
    FTipv6r5   c                 C   s,   || _ || _|| _t | _d| _|| _d S )N )r   r5   rz   
contextlib	ExitStackstack	state_msgr   )r   r   r   rz   r5   r    r    r!   r"     s   

zEphemeralIPNetwork.__init__c              
   C   s  | j s| js| S g }d}| j r>z| jt| j| j d}W n ttfy= } zt	
d|  || W Y d }~nd }~ww | jrvz| jt| j| j d}|sT| j sWd| _W n tyu } zt	
d|  || W Y d }~nd }~ww |st	d |d | S )NFTzFailed to bring up %s for ipv4.zusing link-local ipv6zFailed to bring up %s for ipv6.zGFailed to bring up EphemeralIPNetwork. Datasource setup cannot continuer   )r5   rz   r~   enter_contextr^   r   r   r
   r   r8   infor?   rX   r   error)r   
exceptionsephemeral_obtainedr   r    r    r!   r)     sR   
zEphemeralIPNetwork.__enter__c                 G   s   | j   d S r`   )r~   closer\   r    r    r!   r(     s   zEphemeralIPNetwork.__exit__N)FT)rS   rT   rU   rV   boolr"   r)   r(   r    r    r    r!   ry     s    
,ry   )rV   r|   logging	functoolsr   typingr   r   r   r   r   cloudinit.netr   cloudinit.netinfor:   cloudinit.net.dhcpr   r	   cloudinit.subpr
   	getLoggerrS   r8   r   rX   r^   ry   r    r    r    r!   <module>   s   
 f q