o
    f                     @   s  d dl Z d dlZd dlZd dlZ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mZ d dlmZ d dlmZmZmZmZmZmZ d dlZd dlmZmZmZ d dlmZmZ eeZ dZ!d	Z"d
Z#dZ$G dd de%Z&G dd de&Z'G dd de&Z(G dd de&Z)	d%dee*ef fddZ+dd Z,d&ddZ-d&ddZ.G dd de j/Z0G dd  d e0Z1G d!d" d"e0Z2G d#d$ d$e0Z3e2e1e3gZ4dS )'    N)suppress)StringIO)TimeoutExpired)AnyCallableDictListOptionalTuple)subp
temp_utilsutil)get_interface_macis_ib_interfacez/run/systemd/netif/leasesz/var/lib/dhclientz.+\.leases?$aN  #!/bin/sh
log() {
    echo "udhcpc[$PPID]" "$interface: $2"
}
[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
case $1 in
    bound|renew)
    cat <<JSON > "$LEASE_FILE"
{
    "interface": "$interface",
    "fixed-address": "$ip",
    "subnet-mask": "$subnet",
    "routers": "${router%% *}",
    "static_routes" : "${staticroutes}"
}
JSON
    ;;
    deconfig)
    log err "Not supported"
    exit 1
    ;;
    leasefail | nak)
    log err "configuration failed: $1: $message"
    exit 1
    ;;
    *)
    echo "$0: Unknown udhcpc command: $1" >&2
    exit 1
    ;;
esac
c                   @      e Zd ZdZdS )NoDHCPLeaseErrorz'Raised when unable to get a DHCP lease.N__name__
__module____qualname____doc__ r   r   4/usr/lib/python3/dist-packages/cloudinit/net/dhcp.pyr   A       r   c                   @   r   )InvalidDHCPLeaseFileErrorzRaised when parsing an empty or invalid dhclient.lease file.

    Current uses are DataSourceAzure and DataSourceEc2 during ephemeral
    boot to scrape metadata.
    Nr   r   r   r   r   r   E   r   r   c                   @   r   )NoDHCPLeaseInterfaceErrorz7Raised when unable to find a viable interface for DHCP.Nr   r   r   r   r   r   M   r   r   c                   @   r   )NoDHCPLeaseMissingDhclientErrorz$Raised when unable to find dhclient.Nr   r   r   r   r   r   Q   r   r   returnc                 C   s2   |p| j }|du rtd t | j||| S )a  Perform dhcp discovery if nic valid and dhclient command exists.

    If the nic is invalid or undiscoverable or dhclient command is not found,
    skip dhcp_discovery and return an empty dict.

    @param nic: Name of the network interface we want to run dhclient on.
    @param dhcp_log_func: A callable accepting the dhclient output and error
        streams.
    @return: A list of dicts representing dhcp options for each lease obtained
        from the dhclient discovery if run, otherwise an empty list is
        returned.
    Nz1Skip dhcp_discovery: Unable to find fallback nic.)fallback_interfaceLOGdebugr   dhcp_clientdhcp_discovery)distronicdhcp_log_func	interfacer   r   r   maybe_perform_dhcp_discoveryU   s
   

r'   c                 C   s   t tjt| ddS )zParse a systemd lease file content as in /run/systemd/netif/leases/

    Parse this (almost) ini style file even though it says:
      # This is private data. Do not parse.

    Simply return a dictionary of key/values.F)list_values)dict	configobj	ConfigObjr   )contentr   r   r   networkd_parse_leasel   s   r-   c                 C   sP   | du rt } i }tj| s|S t| D ]}tttj| |||< q|S )zReturn a dictionary of dictionaries representing each lease
    found in lease_d.i

    The top level key will be the filename, which is typically the ifindex.N)	NETWORKD_LEASES_DIRospathisdirlistdirr-   r   load_text_filejoin)leases_dretlfiler   r   r   networkd_load_leasesw   s   
r8   c                 C   sF   |d u rt }t|d}t| D ]\}}|| r ||    S qd S )N)r5   )r.   r8   sorteditemsget)keynamer5   leases_ifindexdatar   r   r   networkd_get_option_from_leases   s   

r@   c                
   @   s   e Zd ZdZdZdd Zedd Zedd Zed	e	fd
dZ
ed	e	fddZejde	dee	ef fddZeejde	deee	e	f  fddZej		dde	dee dee	ef fddZdS )
DhcpClient 
   c                 C   s   t | j| _| jst d S N)r   whichclient_namedhcp_client_pathr   selfr   r   r   __init__   s   zDhcpClient.__init__c                 C   s   t j d| jgddgd d S )Npkillr      rcs)r   rF   )clsr   r   r   kill_dhcp_client   s   zDhcpClient.kill_dhcp_clientc                 C   s*   |    td}|D ]}t| qd S )Nz/var/lib/dhcp/*)rP   globr/   remove)rO   filesfiler   r   r   clear_leases   s
   
zDhcpClient.clear_leasesdhcp_interfacec                 C   s   |j d| j|ddgd d S )Nstartr   rL   rM   manage_servicerF   rO   rV   r#   r   r   r   start_service   s   
zDhcpClient.start_servicec                 C   s   |j d| jddgd d S )Nstopr   rL   rM   rX   rZ   r   r   r   stop_service   s   zDhcpClient.stop_servicer&   r   c                 C      i S )zGet the most recent lease from the ephemeral phase as a dict.

        Return a dict of dhcp options. The dict contains key value
        pairs from the most recent lease.
        r   rI   r&   r   r   r   get_newest_lease   s   zDhcpClient.get_newest_leaseroutesc                 C   s   g S )ap  
        parse classless static routes from string

        The tuple is composed of the network_address (including net length) and
        gateway for a parsed static route.

        @param routes: string containing classless static routes
        @returns: list of tuple(str, str) for all valid parsed routes until the
                  first parsing error.
        r   )ra   r   r   r   parse_static_routes   s   zDhcpClient.parse_static_routesNr%   c                 C   r^   )a  Run dhcp client on the interface without scripts or filesystem
        artifacts.

        @param interface: Name of the network interface on which to send a
            dhcp request
        @param dhcp_log_func: A callable accepting the client output and
            error streams.
        @param distro: a distro object for network interface manipulation
        @return: dict of lease options representing the most recent dhcp lease
            parsed from the dhclient.lease file
        r   )rI   r&   r%   r#   r   r   r   r"      s   zDhcpClient.dhcp_discoveryNN)r   r   r   rF   timeoutrJ   classmethodrP   rU   strr[   r]   abcabstractmethodr   r   r`   staticmethodr   r
   rb   r	   r   r"   r   r   r   r   rA      s6    

"
rA   c                	       s   e Zd ZdZ fddZededeeee	f  fddZ
edd	 Zd
edeee	f fddZ		dd
edee deee	f fddZededeeeef  fddZedee fddZdefddZ  ZS )IscDhclientdhclientc                    s   t    d| _d S )Nz/run/dhclient.leasesuperrJ   
lease_filerH   	__class__r   r   rJ         

zIscDhclient.__init__lease_contentr   c                 C   s   t dt j}g }t| dkrg S || D ]:}g }|dD ]}| dddd}|r8||dd qt	|}|
d	}|rKt||d	< || q|S )
zparse the content of a lease file

        @param lease_content: a string containing the contents of an
            isc-dhclient lease
        @return: a list of leases, most recent last
        zlease {(?P<lease>.*?)}\nr   ;"rB   zoption  rL   unknown-245)recompileDOTALLlenfindallsplitstripreplaceappendr)   r;   rj   get_ip_from_lease_value)rr   lease_regexdhcp_leasesleaselease_optionslineoptionsopt_245r   r   r   parse_leases   s&   
zIscDhclient.parse_leasesc                 C   sx   |  dd}t|dkr2d}|dD ]}t|dkrd| }||7 }qtdt| ddd}n|d	}t|S )
N\rB      :rL   0z>L   zutf-8)	r~   rz   r|   structpackintencodesocket	inet_ntoa)fallback_lease_valueunescaped_value
hex_stringhex_pairpacked_bytesr   r   r   r     s   


z#IscDhclient.get_ip_from_lease_valuer&   c                 C   sr   t t+ t| j}|r| |}|r'|d W  d   S W d   i S W d   i S 1 s2w   Y  i S )a  Get the most recent lease from the ephemeral phase as a dict.

        Return a dict of dhcp options. The dict contains key value
        pairs from the most recent lease.

        @param interface: an interface string - not used in this class, but
            required for function signature compatibility with other classes
            that require a distro object
        @raises: InvalidDHCPLeaseFileError on empty or unparsable leasefile
            content.
        N)r   FileNotFoundErrorr   r3   rn   r   )rI   r&   r,   r   r   r   r   r`     s   



zIscDhclient.get_newest_leaseNr%   c              
   C   sh  t d| d}d}d}t| j| }t| jd }tt t| t| j W d   n1 s4w   Y  |j	
| t|rhdt|dd  }	d||	f }
tjd	d
}tj||d }t||
 zt|| j| j|||\}}W n tjy } zt d|j|j|j t|d}~ww tj|| jg|dd}|rt dddd |D  i S d}d}d}d}t|D ]M}zt| }t|}W n ty   d| d}Y n* t y   d| d}Y nw |!|}|dkrt d| t"|t#j$ d	} nt%&| qt | |st 'd||d |dur'||| | (|}|r1|S t) )a  Run dhclient on the interface without scripts/filesystem artifacts.

        @param interface: Name of the network interface on which to send a
            dhcp request
        @param dhcp_log_func: A callable accepting the dhclient output and
            error streams.
        @param distro: a distro object for network interface manipulation
        @return: dict of lease options representing the most recent dhcp lease
            parsed from the dhclient.lease file
        !Performing a dhcp discovery on %sz/run/dhclient.pidN{Gz?   z20:%s$   z0interface "%s" {send dhcp-client-identifier %s;}T	needs_exez-dhclient.confz3dhclient exited with code: %s stderr: %r stdout: %r)maxwaitnaplenz+dhclient did not produce expected files: %sz, c                 s   s    | ]	}t j|V  qd S rD   )r/   r0   basename).0fr   r   r   	<genexpr>}  s    z-IscDhclient.dhcp_discovery.<locals>.<genexpr>unknownFrB   No PID file found at z, dhclient is still runningPID file contained [z], dhclient is still runningrL   zkilling dhclient with pid=%szCdhclient(pid=%s, parentpid=%s) failed to daemonize after %s secondsg      $@)*r   r    r   rd   r   r   r/   rR   rn   net_opslink_upr   r   r   get_tmp_ancestorr0   r4   r   
write_filer   build_dhclient_cmdrG   ProcessExecutionError	exit_codestderrstdoutr   wait_for_fileswarningranger3   r}   
ValueErrorget_proc_ppidkillsignalSIGKILLtimesleeperrorr`   r   )rI   r&   r%   r#   pid_fileconfig_file
sleep_timesleep_cyclesr   dhcp_client_identifierinterface_dhclient_contenttmp_dirouterrr   missingppid
daemonizedpid_content	debug_msg_pidr   r   r   r   r"   &  s   

	







zIscDhclient.dhcp_discoveryra   c                    s8  |  d dd td D }g }d v rdd |D } fdd}d	}t|D ]o\}}||k r3q)t|}|td
dv rzd}t||d |k rZ|||t||d  |  S d||d |d  }	d||d ||  }
|| }n|tdd
v rd}t||d |k r|||t||d  |  S d||d |d  dg }	d||d ||  }
|| }n|tddv rd}t||d |k r|||t||d  |  S d||d |d  ddg }	d||d ||  }
|| }n|tddv rNd}t||d |k r+|||t||d  |  S d||d |d  g d }	d||d ||  }
|| }n@|d	krd}t||d |k rp|||t||d  |  S d}	d||d ||  }
|| }n
t	d| |  S |
d|	|f |
f q)|S )a(  
        parse rfc3442 format and return a list containing tuple of strings.

        The tuple is composed of the network_address (including net length) and
        gateway for a parsed static route.  It can parse two formats of
        rfc3442, one from dhcpcd and one from dhclient (isc).

        @param rfc3442: string in rfc3442 format (isc or dhcpd)
        @returns: list of tuple(str, str) for all valid parsed routes until the
            first parsing error.

        e.g.:

        sr=parse_static_routes(        "32,169,254,169,254,130,56,248,255,0,130,56,240,1")
        sr=[
            ("169.254.169.254/32", "130.56.248.255"),         ("0.0.0.0/0", "130.56.240.1")
        ]

        sr2 = parse_static_routes(        "24.191.168.128 192.168.128.1,0 192.168.128.1")
        sr2 = [
            ("191.168.128.0/24", "192.168.128.1"),        ("0.0.0.0/0", "192.168.128.1")
        ]

        # unknown-121 option format
        sr3 = parse_static_routes(        "0:a:0:0:1:20:a8:3f:81:10:a:0:0:1:20:a9:fe:a9:fe:a:0:0:1")
        sr3 = [
            ("0.0.0.0/0", "10.0.0.1"),
            ("168.63.129.16/32", "10.0.0.1"),
            ("169.254.169.254/32", "10.0.0.1"),
        ]

        Python version of isc-dhclient's hooks:
           /etc/dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes
        rs   c                 S   s   g | ]}|r|qS r   r   r   tokr   r   r   
<listcomp>  s    z3IscDhclient.parse_static_routes.<locals>.<listcomp>z[, . :]r   c                 S   s   g | ]	}t t|d qS )r   )rf   r   r   r   r   r   r     s    c                    s   d| || f }t | d S )NzRFC3442 string malformed.  Current route has CIDR of %s and requires %s significant octets, but only %s remain. Verify DHCP rfc3442-classless-static-routes value: %s)r   r   )cidrrequiredremainmsgrfc3442r   r   _trunc_error  s
   
z5IscDhclient.parse_static_routes.<locals>._trunc_errorr      !   	   N.rL            r   r            r   )r   r   r   z0.0.0.0zSParsed invalid net length "%s".  Verify DHCP rfc3442-classless-static-routes value.z%s/%s)rstriprw   r|   	enumerater   r   rz   r4   r   r   r   )ra   tokensstatic_routesr   current_idxidxr   
net_lengthreq_toksnet_addressgatewayr   r   r   rb     s|   
*	 
"



zIscDhclient.parse_static_routesc           	   	   C   s   d}| j | jfttffD ]C\}}|sqg }zt|}W n	 ty%   Y qw d}|D ]}t||s3q*tj	
||}tj	|}||krH|}|}q*|rO|  S qdS )zGet the latest lease file from a distro-managed dhclient

        Doesn't consider the ephemeral timeframe lease.

        @param distro: used for distro-specific lease location and filename
        @return: The most recent lease file, or None
        Ng      )dhclient_lease_directorydhclient_lease_file_regexDHCLIENT_FALLBACK_LEASE_DIRDHCLIENT_FALLBACK_LEASE_REGEXr/   r2   r   rw   searchr0   r4   getmtime)	r#   latest_file	directoryregexlease_fileslatest_mtimefnameabs_pathmtimer   r   r   !get_newest_lease_file_from_distro%  s8   	z-IscDhclient.get_newest_lease_file_from_distrokeyc                 C   sR   |  |}|r#t|}|r%t| |D ]}||}|r"|  S qdS dS dS )a8  Get a key from the latest lease from distro-managed dhclient

        Doesn't consider the ephemeral timeframe lease.

        @param lease_dir: distro-specific lease to check
        @param lease_file_regex: distro-specific regex to match lease name
        @return: The most recent lease file, or None
        N)r   r   r3   reversedr   r;   )rI   r#   r   rn   r,   r   serverr   r   r   get_key_from_latest_leaseQ  s   
	

z%IscDhclient.get_key_from_latest_leaserc   )r   r   r   rF   rJ   ri   rf   r   r   r   r   r   r`   r	   r   r"   r
   rb   r   r   __classcell__r   r   ro   r   rj      s.     


  w+rj   c                	   @   s   e Zd ZdZdZ		ddedee deee	f fddZ
ed	ed
edee fddZedededefddZdedeee	f fddZededeeeef  fddZdS )Dhcpcddhcpcdi,  Nr&   r%   r   c              
   C   s  t d| d}t| j| }g }|j| zt|rdg}| jdddddg||}tj|| jd	\}}	|d
ur?|||	 | 	|}
|
rtg |dj
 }d
}d}d}t|D ]b}z't| }t|}||}|rt d|| t|tj W  |
W S W n. ty   t d| Y  |
W S  ty   d| d}Y n ty   d| d}Y nw |
  W S t| q\t | |
W S td ty } zt d|j|j|j
 t|d
}~w tjy } zt d|j|j|j
 t|d
}~ww )a  Run dhcpcd on the interface without scripts/filesystem artifacts.

        @param interface: Name of the network interface on which to send a
            dhcp request
        @param dhcp_log_func: A callable accepting the client output and
            error streams.
        @param distro: a distro object for network interface manipulation
        @return: dict of lease options representing the most recent dhcp lease
            parsed from the dhclient.lease file
        r   r   z
--clientid
--ipv4onlyz--waitipz--persistentz--noarpz--script=/bin/true)rd   Nz-PFrB   z!killing dhcpcd with pid=%s gid=%sz9Process group id [%s] has already exited, nothing to killr   z, dhcpcd is still runningr   z], dhcpcd is still runningzNo lease foundz8dhcpcd timed out after %s seconds: stderr: %r stdout: %r1dhcpcd exited with code: %s stderr: %r stdout: %r)r   r    r   rd   r   r   r   rG   r   r`   r   r}   r   r   r3   get_proc_pgidr/   killpgr   r   ProcessLookupErrorr   r   r   r   r   r   r   r   r   )rI   r&   r%   r#   r   r   infiniband_argumentcommandr   r   r   r   r   gidr   r   r   r   r   r   r   r"   h  s   








zDhcpcd.dhcp_discoveryr?   dhcp_option_numberc                 C   s>   d}dt dtfdd}|| |D ]\}}||kr|  S qdS )aV  get a specific option from a binary lease file

        This is required until upstream dhcpcd supports unknown option 245
        upstream bug: https://github.com/NetworkConfiguration/dhcpcd/issues/282

        @param data: Binary lease data
        @param number: Option number to return
        @return: the option (bytes) or None
           r?   indexc                 s   sl    t | |d kr4| | }| d|  }| d| d| |  }||fV  d| | }t | |d ks	dS dS )zoptions are variable length, and consist of the following format

            option number: 1 byte
            option length: 1 byte
            option data: variable length (see length field)
            r   rL   N)rz   )r?   r  codelengthoptionr   r   r   iter_options  s   
z>Dhcpcd.parse_unknown_options_from_packet.<locals>.iter_optionsN)bytesr   )r?   r
  INDEXr  r  r  r   r   r   !parse_unknown_options_from_packet  s   z(Dhcpcd.parse_unknown_options_from_packet
lease_dumpc           
   
   C   s  t d||  z$tdd |  dddD }|s*d}t ||  t||  W n ty@ } z	t d|  t|d	}~ww ||d
< dd |	 D }ddd}|	 D ]\}}||v rf|
|||< qWtd| d}t|d}	|	rt|	|d< |S )a`  parse the output of dhcpcd --dump

        map names to the datastructure we create from dhclient

        example dhcpcd output:

        broadcast_address='192.168.15.255'
        dhcp_lease_time='3600'
        dhcp_message_type='5'
        dhcp_server_identifier='192.168.0.1'
        domain_name='us-east-2.compute.internal'
        domain_name_servers='192.168.0.2'
        host_name='ip-192-168-0-212'
        interface_mtu='9001'
        ip_address='192.168.0.212'
        network_number='192.168.0.0'
        routers='192.168.0.1'
        subnet_cidr='20'
        subnet_mask='255.255.240.0'
        z)Parsing dhcpcd lease for interface %s: %rc                 S   s"   g | ]}d |v r|j d ddqS )=rL   )maxsplit)r|   )r   ar   r   r   r   (  s
    z-Dhcpcd.parse_dhcpcd_lease.<locals>.<listcomp>'rB   
z;No valid DHCP lease configuration found in dhcpcd lease: %rzError parsing dhcpcd lease: %rNr&   c                 S   s   i | ]\}}| d d|qS )r   -)r~   )r   r   valuer   r   r   
<dictcomp>=  s    z-Dhcpcd.parse_dhcpcd_lease.<locals>.<dictcomp>zfixed-addressr   )z
ip-addresszclassless-static-routesz/var/lib/dhcpcd/z.lease   rv   )r   r    r)   r}   r~   r|   r   r   r   r:   popr   load_binary_filer   r  r   r   )
r  r&   r   r   r   name_mapsourcedestinationdhcp_messager   r   r   r   parse_dhcpcd_lease  sH   	
zDhcpcd.parse_dhcpcd_leasec              
   C   sX   z|  t| jdd|gj|W S  tjy+ } ztd|j|j|j t	|d}~ww )zReturn a dict of dhcp options.

        @param interface: which interface to dump the lease from
        @raises: InvalidDHCPLeaseFileError on empty or unparsable leasefile
            content.
        z--dumpleaser  r  N)
r$  r   rG   r   r   r   r    r   r   r   )rI   r&   r   r   r   r   r`   T  s,   zDhcpcd.get_newest_leasera   c                 C   sD   |   }|rdd t|ddd |ddd D S td|  g S )a  
        classless static routes as returned from dhcpcd --dumplease and return
        a list containing tuple of strings.

        The tuple is composed of the network_address (including net length) and
        gateway for a parsed static route.

        @param routes: string containing classless static routes
        @returns: list of tuple(str, str) for all valid parsed routes until the
                  first parsing error.

        e.g.:

        sr=parse_static_routes(
            "0.0.0.0/0 10.0.0.1 168.63.129.16/32 10.0.0.1"
        )
        sr=[
            ("0.0.0.0/0", "10.0.0.1"),
            ("169.63.129.16/32", "10.0.0.1"),
        ]
        c                 S      g | ]}|qS r   r   r   ir   r   r   r         z.Dhcpcd.parse_static_routes.<locals>.<listcomp>Nr   rL   z'Malformed classless static routes: [%s])r|   zipr   r   ra   r   r   r   r   rb   q  s
   (zDhcpcd.parse_static_routesrc   )r   r   r   rF   rd   rf   r	   r   r   r   r"   ri   r  r   r  r$  r`   r   r
   rb   r   r   r   r   r   d  s2    

w+H$r   c                	       s   e Zd ZdZ fddZ		ddedee deee	f fdd	Z
dedeee	f fd
dZededeeeef  fddZ  ZS )Udhcpcudhcpcc                    s   t    d | _d S rD   rl   rH   ro   r   r   rJ     rq   zUdhcpc.__init__Nr&   r%   r   c           
      C   sF  t d| tjdd}tj||d | _tt	 t
| j W d   n1 s+w   Y  |j| tj|d}t|td | jdd	d
|d|ddddg}t|rj|ddt|dd ddg ztj|d| jidd\}}W n tjy }	 zt d|	j|	j|	j t|	d}	~	ww |dur||| | |S )ar  Run udhcpc on the interface without scripts or filesystem artifacts.

        @param interface: Name of the network interface on which to run udhcpc.
        @param dhcp_log_func: A callable accepting the udhcpc output and
            error streams.
        @return: A list of dicts of representing the dhcp leases parsed from
            the udhcpc lease file.
        r   Tr   z.lease.jsonNudhcpc_scripti  z-Ostaticroutesz-iz-sz-nz-qz-fz-vz-xz	0x3d:20{}r   r   rB   
LEASE_FILE)
update_envcapturez1udhcpc exited with code: %s stderr: %r stdout: %r)r   r    r   r   r/   r0   r4   rn   r   r   rR   r   r   r   r   UDHCPC_SCRIPTrG   r   extendformatr   r~   r   r   r   r   r   r   r`   )
rI   r&   r%   r#   r   r-  cmdr   r   r   r   r   r   r"     s\   
	

zUdhcpc.dhcp_discoveryc                 C   s   t t | jS )a  Get the most recent lease from the ephemeral phase as a dict.

        Return a dict of dhcp options. The dict contains key value
        pairs from the most recent lease.

        @param interface: an interface name - not used in this class, but
            required for function signature compatibility with other classes
            that require a distro object
        @raises: InvalidDHCPLeaseFileError on empty or unparsable leasefile
            content.
        )r   	load_jsonr3   rn   r_   r   r   r   r`     s   zUdhcpc.get_newest_leasera   c                 C   s8   |   }|rdd t|d d d |dd d D S g S )Nc                 S   r%  r   r   r&  r   r   r   r     r(  z.Udhcpc.parse_static_routes.<locals>.<listcomp>r   rL   )r|   r)  r*  r   r   r   rb     s   (zUdhcpc.parse_static_routesrc   )r   r   r   rF   rJ   rf   r	   r   r   r   r"   r`   ri   r   r
   rb   r   r   r   ro   r   r+    s    

H(r+  rc   rD   )5rg   rQ   loggingr/   rw   r   r   r   r   
contextlibr   ior   
subprocessr   typingr   r   r   r   r	   r
   r*   	cloudinitr   r   r   cloudinit.netr   r   	getLoggerr   r   r.   r   r   r2  	Exceptionr   r   r   r   rf   r'   r-   r8   r@   ABCrA   rj   r   r+  ALL_DHCP_CLIENTSr   r   r   r   <module>   sT    
!




K     .f