U
    Ad9                     @   s   d Z ddlZddlZddl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)AnyDictListOptional)subp)NoDHCPLeaseErrormaybe_perform_dhcp_discoveryparse_static_routesc                   @   s\   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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)	selfr   r   prefix_or_maskr   r   r   r   e r   9/usr/lib/python3/dist-packages/cloudinit/net/ephemeral.py__init__   s4       zEphemeralIPv4Network.__init__c                 C   sR   | j r(t| j r(td| j d  dS |   | jr@|   n| jrN| 	  dS )z>Perform ephemeral network setup if interface is not connected.z=Skip ephemeral network setup, instance has connectivity to %sZurlN)
r   r   has_url_connectivityLOGdebug_bringup_devicer   _bringup_static_routesr   _bringup_routerr   r   r   r   	__enter__L   s    
zEphemeralIPv4Network.__enter__c                 C   s   | j D ]}tj|dd qdS )zTeardown anything we set up.TcaptureN)r   r   )r   	excp_type
excp_valueexcp_tracebackcmdr   r   r   __exit__i   s    
zEphemeralIPv4Network.__exit__c              	   C   s,   t j dddddd||f d| jgdd	 d
S )z7Perform the ip command to remove the specified address.r   -familyinetaddrdelz%s/%sdevTr&   N)r   r   )r   Zaddressr   r   r   r   _delete_addressn   s    

z$EphemeralIPv4Network._delete_addressc                 C   s   d | j| j}td| j|| j z0tjddddd|d| jd	| jg
d
ddid W nF tjk
r } z&dt	|j
krx td| j| j W 5 d}~X Y n^X tjdddddd	| jdgd
d | jdddddd	| jdg | jddddd|d	| jg 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 %sr   r-   r.   r/   addr   r1   TZLANGC)r'   Z
update_envzFile existsz7Skip ephemeral network setup, %s already has address %sNlinksetupr&   Zdownr0   )r   r   r   r   r    r   r   r   ZProcessExecutionErrorstrstderrr   append)r   Zcidrr   r   r   r   r!   ~   s    

z$EphemeralIPv4Network._bringup_devicec              	   C   st   | j D ]h\}}g }|dkr"d|g}tjdddd|g| d| jg dd	 | jd
dddd|g| d| jg  qd S )Nz0.0.0.0viar   -4router:   r1   Tr&   r   r0   )r   r   r   r   insert)r   Znet_addressZgatewayZvia_argr   r   r   r"      s(    z+EphemeralIPv4Network._bringup_static_routesc                 C   s   t j ddddgdd\}}d|kr:td| j|  d	S t j dd
dd| jd| jd| jg	dd | jddd
dd| jd| jd| jg	 t j dd
dddd| jd| jg	dd | jddd
dddd| jg d	S )z<Perform the ip commands to fully setup the router if needed.r   r=   Zshowz	0.0.0.0/0Tr&   defaultz<Skip ephemeral route setup. %s already has default route: %sNr<   r3   r1   srcr   r0   r;   )	r   r   r    r   stripr   r   r   r>   )r   out_r   r   r   r#      sf     z$EphemeralIPv4Network._bringup_router)NNN)__name__
__module____qualname____doc__r   r   r8   r   r   r%   r,   r2   r!   r"   r#   r   r   r   r   r
      s      -J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     s    zEphemeralIPv6Network.__init__c                 C   s2   t | jddkr.tjdddd| jdgdd d	S )
zlinux kernel does autoconfiguration even when autoconf=0

        https://www.kernel.org/doc/html/latest/networking/ipv6.html
        Z	operstater7   r   r5   r6   r1   Fr&   N)r   Zread_sys_netr   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   Z_argsr   r   r   r,   4  s    zEphemeralIPv6Network.__exit__N)rD   rE   rF   rG   r   r%   r,   r   r   r   r   rH     s   rH   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   tmp_dir)r   rL   r   rO   rP   r   r   r   r   9  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%   G  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,   T  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)rN   rM   r,   r$   r   r   r   rR   X  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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   )rN   r   rL   rO   rP   r   r   r    extract_dhcp_options_mappingr   Zmask_and_ipv4_to_bcast_addrr	   r   r
   r%   rM   )r   ZleasesnmapkwargsZephipv4r   r   r   rQ   `  sR    	  

 

zEphemeralDHCPv4.obtain_leasec                 C   sD   i }|  D ]2\}}t|tr.| ||| q| j|||< q|S rK   )items
isinstancelistget_first_option_valuerN   get)r   rU   resultZinternal_referencelease_option_namesr   r   r   rT     s    
  z,EphemeralDHCPv4.extract_dhcp_options_mappingc                 C   s(   |D ]}| |s| j |||< qd S rK   )r[   rN   )r   Zinternal_mappingr]   r\   Zdifferent_namesr   r   r   rZ     s    
z&EphemeralDHCPv4.get_first_option_value)NNNN)rD   rE   rF   r   r   r8   r   r   r%   r,   rR   rQ   rT   rZ   r   r   r   r   rJ   8  s       2rJ   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 managersFTN)ipv6ipv4c                 C   s,   || _ || _|| _t | _d| _|| _d S )N )r   r`   r_   
contextlib	ExitStackstack	state_msgrP   )r   r   r_   r`   rP   r   r   r   r     s    
zEphemeralIPNetwork.__init__c              
   C   st   z:| j r | jt| j| jd | jr8| jt| j W n4 tk
rn } z| jrZd| _	n|W 5 d }~X Y nX | S )N)rP   zusing link-local ipv6)
r`   rd   enter_contextrJ   r   rP   r_   rH   r   re   )r   r   r   r   r   r%     s    zEphemeralIPNetwork.__enter__c                 G   s   | j   d S rK   )rd   closerI   r   r   r   r,     s    zEphemeralIPNetwork.__exit__)FTN)rD   rE   rF   rG   boolr   r%   r,   r   r   r   r   r^     s      r^   )rG   rb   Zloggingtypingr   r   r   r   Zcloudinit.netr   Z	cloudinitr   Zcloudinit.net.dhcpr   r   r	   Z	getLoggerrD   r   r
   rH   rJ   r^   r   r   r   r   <module>   s   
  "m