o
    i                     @   s  U 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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+e+e+gdf  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 j0Z1G d d! d!e1Z2G d"d# d#e1Z3G d$d% d%e1Z4e3e2e4gZ5eee1  e6d&< dS ))    N)suppress)StringIO)TimeoutExpired)AnyCallableDictListOptionalTupleType)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   dhcp_log_func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: Callable accepting the interface and client's
        stdout, stderr 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nicr   	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_leasen   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_leasesy   s   
r9   c                 C   sF   |d u rt }t|d}t| D ]\}}|| r ||    S qd S )N)r6   )r/   r9   sorteditemsget)keynamer6   leases_ifindexdatar   r   r   networkd_get_option_from_leases   s   

rA   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e	e	e	gdf  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   rG   )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/*)rQ   globr0   remove)rP   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   rM   rN   manage_servicerG   rP   rW   r%   r   r   r   start_service   s   
zDhcpClient.start_servicec                 C   s   |j d| jddgd d S )Nstopr   rM   rN   rY   r[   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   rJ   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   )rb   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: Callable accepting the interface and client's
            stdout, stderr 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   )rJ   r'   r   r%   r   r   r   r$      s   zDhcpClient.dhcp_discoveryNN)r   r   r   rG   timeoutrK   classmethodrQ   rV   strr\   r^   abcabstractmethodr   r   ra   staticmethodr   r
   rc   r	   r   r$   r   r   r   r   rB      s6    

"
rB   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eeegdf  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                       t    d| _d S )Nz/run/dhclient.leasesuperrK   
lease_filerI   	__class__r   r   rK         

zIscDhclient.__init__lease_contentr   c                 C   s   t dt j}g }| sg S || D ]:}g }|dD ]}| dddd}|r4||dd qt|}|	d}|rGt
||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>.*?)}\n;"rC   zoption  rM   unknown-245)recompileDOTALLfindallsplitstripreplaceappendr*   r<   rk   get_ip_from_lease_value)rt   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\rC      :rM   0z>L   zutf-8)	r   lenr}   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   r4   rp   r   )rJ   r'   r-   r   r   r   r   ra     s   



zIscDhclient.get_newest_leaseNr   c              
   C   sj  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(|||| | (|}|r2|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: Callable accepting the interface and client's
            stdout, stderr 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 rE   )r0   r1   basename).0fr   r   r   	<genexpr>  s    z-IscDhclient.dhcp_discovery.<locals>.<genexpr>unknownFrC   No PID file found at z, dhclient is still runningPID file contained [z], dhclient is still runningrM   zkilling dhclient with pid=%szCdhclient(pid=%s, parentpid=%s) failed to daemonize after %s secondsg      $@)*r!   r"   r   re   r   r   r0   rS   rp   net_opslink_upr   r   r   get_tmp_ancestorr1   r5   r   
write_filer   build_dhclient_cmdrH   ProcessExecutionError	exit_codestderrstdoutr   wait_for_fileswarningranger4   r~   
ValueErrorget_proc_ppidkillsignalSIGKILLtimesleeperrorra   r   )rJ   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_discoveryrb   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
        ru   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   )rg   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.rM            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)rstripry   r}   	enumerater   r   r   r5   r!   r   r   )rb   tokensstatic_routesr   current_idxidxr   
net_lengthreq_toksnet_addressgatewayr   r   r   rc     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_REGEXr0   r3   r   ry   searchr1   r5   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   r4   reversedr   r<   )rJ   r%   r   rp   r-   r   serverr   r   r   get_key_from_latest_leaseS  s   
	

z%IscDhclient.get_key_from_latest_leaserd   )r   r   r   rG   rK   rj   rg   r   r   r   r   r   ra   r	   r   r$   r
   rc   r   r   __classcell__r   r   rq   r   rk      s.     


  w+rk   c                	   @   s   e Zd ZdZdZ		ddedeeeeegdf  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d	g||}tj|| jd
\}}	|durA||||	 | 	|}
|
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: Callable accepting the interface and client's
            stdout, stderr 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--debugz--script=/bin/true)re   Nz-PFrC   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   re   r   r   r   rG   r   ra   r   r~   r   r   r4   get_proc_pgidr0   killpgr   r   ProcessLookupErrorr   r   r   r   r   r   r   r   r   )rJ   r'   r   r%   r   r   infiniband_argumentcommandr   r   r   r   r   gidr   r   r   r   r   r   r   r$   j  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   rM   N)r   )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 )=rM   )maxsplit)r}   )r   ar   r   r   r   +  s
    z-Dhcpcd.parse_dhcpcd_lease.<locals>.<listcomp>'rC   
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   rx   )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   )rJ   r'   r   r   r   r   ra   W  s,   zDhcpcd.get_newest_leaserb   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   rM   z'Malformed classless static routes: [%s])r}   zipr!   r   rb   r   r   r   r   rc   t  s
   (zDhcpcd.parse_static_routesrd   )r   r   r   rG   re   rg   r	   r   r   r   r$   rj   r  r   r  r&  ra   r   r
   rc   r   r   r   r   r  f  s2    

x+H$r  c                	       s   e Zd ZdZ fddZ		ddedeeeeegdf  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                    rm   )NrC   rn   rI   rq   r   r   rK     rs   zUdhcpc.__init__Nr'   r   r   c           
      C   sH  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 )a~  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: Callable accepting the interface and client's
            stdout, stderr 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   rC   
LEASE_FILE)
update_envcapturez1udhcpc exited with code: %s stderr: %r stdout: %r)r!   r"   r   r   r0   r1   r5   rp   r   r   rS   r   r   r   r   UDHCPC_SCRIPTrG   r   extendformatr   r   r   r   r   r   r   r   ra   )
rJ   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_jsonr4   rp   r`   r   r   r   ra     s   zUdhcpc.get_newest_leaserb   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   rM   )r}   r+  r,  r   r   r   rc     s   (zUdhcpc.parse_static_routesrd   )r   r   r   rG   rK   rg   r	   r   r   r   r$   ra   rj   r   r
   rc   r  r   r   rq   r   r-    s    

H(r-  ALL_DHCP_CLIENTSrd   rE   )7rh   rR   loggingr0   ry   r   r   r   r   
contextlibr   ior   
subprocessr   typingr   r   r   r   r	   r
   r   r+   	cloudinitr   r   r   cloudinit.netr   r   	getLoggerr   r!   r/   r   r   r4  	Exceptionr   r   r   r   rg   r(   r.   r9   rA   ABCrB   rk   r  r-  r9  __annotations__r   r   r   r   <module>   sZ   
$
!




K     /f