U
    Ӈg֏                     @   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%ee*ef d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                   @   s   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   s   r   c                   @   s   e Zd ZdZdS )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   s   r   c                   @   s   e Zd ZdZdS )NoDHCPLeaseInterfaceErrorz7Raised when unable to find a viable interface for DHCP.Nr   r   r   r   r   r   M   s   r   c                   @   s   e Zd ZdZdS )NoDHCPLeaseMissingDhclientErrorz$Raised when unable to find dhclient.Nr   r   r   r   r   r   Q   s   r   returnc                 C   s2   |p| j }|dk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.)Zfallback_interfaceLOGdebugr   Zdhcp_clientdhcp_discovery)distroZ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)Zlist_values)dict	configobjZ	ConfigObjr   )contentr   r   r   networkd_parse_leasel   s    r'   c                 C   sP   | dk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_dZretZlfiler   r   r   networkd_load_leasesw   s    
r0   c                 C   sF   |d krt }t|d}t| D ]\}}|| r"||    S q"d S )N)r/   )r(   r0   sorteditemsget)Zkeynamer/   ZleasesZ_ifindexdatar   r   r   networkd_get_option_from_leases   s    

r5   c                   @   s   e Zd ZdZdZdd Zedd Zedd Zee	d	d
dZ
ee	d	ddZeje	ee	ef dddZeeje	eee	e	f  dddZejde	ee ee	ef dddZdS )
DhcpClient 
   c                 C   s   t | j| _| jst d S N)r   Z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 )NZpkillr      Zrcs)r   r:   )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/*)rB   globr)   remove)rA   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   r?   r@   Zmanage_servicer:   rA   rH   r    r   r   r   start_service   s       zDhcpClient.start_servicec                 C   s   |j d| jddgd d S )Nstopr   r?   r@   rJ   rK   r   r   r   stop_service   s    zDhcpClient.stop_servicer"   r   c                 C   s   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   r=   r"   r   r   r   get_newest_lease   s    zDhcpClient.get_newest_leaseroutesr   c                 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   )rS   r   r   r   parse_static_routes   s    zDhcpClient.parse_static_routesNr"   r!   r   c                 C   s   i S )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   )r=   r"   r!   r    r   r   r   r      s    zDhcpClient.dhcp_discovery)NN)r   r   r   r:   timeoutr>   classmethodrB   rG   strrL   rN   abcabstractmethodr   r   rQ   staticmethodr   r
   rT   r	   r   r   r   r   r   r   r6      s0   

   
r6   c                       s   e Zd ZdZ fddZeeeeee	f  dddZ
edd Zeeee	f d	d
dZdeee eee	f dddZeeeeeef  dddZeee dddZedddZ  ZS )IscDhclientZdhclientc                    s   t    d| _d S )Nz/run/dhclient.leasesuperr>   
lease_filer<   	__class__r   r   r>      s    
zIscDhclient.__init__)lease_contentr   c                 C   s   t dt j}g }t| dkr"g S || D ]t}g }|dD ]2}| dddd}|r>||dd q>t	|}|
d	}|rt||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   ;"r7   zoption  r?   unknown-245)recompileDOTALLlenfindallsplitstripreplaceappendr$   r3   r\   get_ip_from_lease_value)rb   Zlease_regexdhcp_leasesleaseZlease_optionslineZoptionsopt_245r   r   r   parse_leases   s$    
zIscDhclient.parse_leasesc                 C   sx   |  dd}t|dkrdd}|dD ] }t|dkr>d| }||7 }q&tdt| ddd}n
|d	}t|S )
N\r7      :r?   0z>L   zutf-8)	rn   rj   rl   structZpackintencodesocket	inet_ntoa)Zfallback_lease_valueZunescaped_valueZ
hex_stringZhex_pairZpacked_bytesr   r   r   rp     s    
 
z#IscDhclient.get_ip_from_lease_valuerO   c              
   C   sJ   t t8 t| j}|r<| |}|r<|d W  5 Q R  S W 5 Q R X 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.
        )r   FileNotFoundErrorr   r-   r_   ru   )r=   r"   r&   rq   r   r   r   rQ     s    

zIscDhclient.get_newest_leaseNrU   c              
   C   sr  t d| d}d}d}t| j| }t| jd }tt t| t| j W 5 Q R X |j	
| t|rdt|dd  }	d||	f }
tjd	d
}tj||d }t||
 z$t|| j| j|||\}}W nB tjk
r" } z t d|j|j|j t|W 5 d}~X Y nX tj|| jg|dd}|r`t dddd |D  i S d}d}d}d}t|D ]}zt| }t|}W nB tk
r   d| d}Y nZ t k
r   d| d}Y n:X |!|}|dkrt d| t"|t#j$ d	} q*t%&| qxt | |s@t 'd||d |dk	rT||| | (|}|rh|S t) dS )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Z	needs_exez-dhclient.confz3dhclient exited with code: %s stderr: %r stdout: %r)maxwaitZnaplenz+dhclient did not produce expected files: %sz, c                 s   s   | ]}t j|V  qd S r9   )r)   r*   basename).0fr   r   r   	<genexpr>}  s     z-IscDhclient.dhcp_discovery.<locals>.<genexpr>unknownFr7   No PID file found at z, dhclient is still runningPID file contained [z], dhclient is still runningr?   zkilling dhclient with pid=%szCdhclient(pid=%s, parentpid=%s) failed to daemonize after %s secondsg      $@)*r   r   r|   rV   r   r   r)   rD   r_   net_opslink_upr   r   r   get_tmp_ancestorr*   r.   r   
write_filer   Zbuild_dhclient_cmdr;   ProcessExecutionError	exit_codestderrstdoutr   Zwait_for_fileswarningranger-   rm   
ValueErrorZget_proc_ppidkillsignalSIGKILLtimesleeperrorrQ   r   )r=   r"   r!   r    pid_fileZconfig_file
sleep_timesleep_cyclesr   Zdhcp_client_identifierZinterface_dhclient_contenttmp_dirouterrr   ZmissingZppidZ
daemonizedpid_content	debug_msg_pidrr   r   r   r   r   &  s    

		  







zIscDhclient.dhcp_discoveryrR   c                    sD  |  d dd td D }g }d kr:dd |D } fdd}d	}t|D ]\}}||k rfqRt|}|td
dkrd}t||d |k r|||t||d  |  S d||d |d  }	d||d ||  }
|| }n4|tdd
krd}t||d |k r>|||t||d  |  S d||d |d  dg }	d||d ||  }
|| }n|tddkrd}t||d |k r|||t||d  |  S d||d |d  ddg }	d||d ||  }
|| }n|tddkrd}t||d |k r`|||t||d  |  S d||d |d  dddg }	d||d ||  }
|| }n|d	krd}t||d |k r|||t||d  |  S d}	d||d ||  }
|| }nt	d| |  S |
d|	|f |
f qR|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
        rc   c                 S   s   g | ]}|r|qS r   r   r   tokr   r   r   
<listcomp>  s      z3IscDhclient.parse_static_routes.<locals>.<listcomp>z[, . :]rx   c                 S   s   g | ]}t t|d qS )rz   )rX   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   )ZcidrZrequiredZremainmsgZrfc3442r   r   _trunc_error  s
    
z5IscDhclient.parse_static_routes.<locals>._trunc_errorr      !   	   N.r?            rw   ry            r   z0.0.0.0zSParsed invalid net length "%s".  Verify DHCP rfc3442-classless-static-routes value.z%s/%s)rstriprg   rl   	enumerater|   r   rj   r.   r   r   ro   )rS   tokensstatic_routesr   Zcurrent_idxidxr   Z
net_lengthZreq_toksZnet_addressZgatewayr   r   r   rT     s|    *
	 "


zIscDhclient.parse_static_routesr   c           	   	   C   s   d}| j | jfttffD ]\}}|s&qg }zt|}W n tk
rP   Y qY nX d}|D ]<}t||slqZtj	
||}tj	|}||krZ|}|}qZ|r|  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      )Zdhclient_lease_directoryZdhclient_lease_file_regexDHCLIENT_FALLBACK_LEASE_DIRDHCLIENT_FALLBACK_LEASE_REGEXr)   r,   r   rg   searchr*   r.   getmtime)	r    Zlatest_fileZ	directoryZregexZlease_filesZlatest_mtimefnameZabs_pathmtimer   r   r   !get_newest_lease_file_from_distro%  s2    	

z-IscDhclient.get_newest_lease_file_from_distro)keyc                 C   sJ   |  |}|rFt|}|rFt| |D ]}||}|r*|  S q*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   r-   reversedru   r3   )r=   r    r   r_   r&   rr   Zserverr   r   r   get_key_from_latest_leaseQ  s    	


z%IscDhclient.get_key_from_latest_lease)NN)r   r   r   r:   r>   r[   rX   r   r   r   ru   rp   rQ   r	   r   r   r
   rT   r   r   __classcell__r   r   r`   r   r\      s(   
  
 w+r\   c                   @   s   e Zd ZdZdZdeee eee	f dddZ
eeeee ddd	Zeeeed
ddZeeee	f dddZeeeeeef  dddZdS )DhcpcdZdhcpcdi,  NrU   c              
   C   s,  t d| d}t| j| }g }|j| zvt|r@dg}| jdddddf||f}tj|| jd	\}}	|d
k	r|||	 | 	|}
|
rt|dj
 }d
}d}d}t|D ]}zNt| }t|}||}|rt d|| t|tj W  qW nj tk
r4   t d| Y  qY nL tk
rT   d| d}Y n, tk
rt   d| d}Y nX |
  W S t| qt | |
W S tdW n tk
r } z t d|j|j|j
 t|W 5 d
}~X Y nB tjk
r& } z t d|j|j|j
 t|W 5 d
}~X Y nX d
S )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)rV   N-PFr7   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   r|   rV   r   r   r   r:   r   rQ   r   rm   r   r   r-   Zget_proc_pgidr)   killpgr   r   ProcessLookupErrorr   r   r   r   r   r   r   r   r   )r=   r"   r!   r    r   r   Zinfiniband_argumentZcommandr   r   rr   r   r   gidr   r   r   r   r   r   r   r   h  s    




  



zDhcpcd.dhcp_discovery)r4   dhcp_option_numberr   c                 C   s<   d}t td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
           )r4   indexc                 s   sX   t | |d krT| | }| d|  }| d| d| |  }||fV  d| | }q 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   r?   N)rj   )r4   r   codeZlengthoptionr   r   r   iter_options  s    
z>Dhcpcd.parse_unknown_options_from_packet.<locals>.iter_optionsN)bytesr|   )r4   r   ZINDEXr   r   r   r   r   r   !parse_unknown_options_from_packet  s    
z(Dhcpcd.parse_unknown_options_from_packet)
lease_dumpr"   r   c           
   
   C   s  t d||  zHtdd |  dddD }|sTd}t ||  t||  W n4 tk
r } zt d|  t|W 5 d	}~X Y nX ||d
< dd |	 D }ddd}|	 D ]\}}||kr|
|||< qt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 |kr|j d ddqS )=r?   )maxsplit)rl   )r   ar   r   r   r   (  s   z-Dhcpcd.parse_dhcpcd_lease.<locals>.<listcomp>'r7   
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   -)rn   )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   rf   )r   r   r$   rm   rn   rl   r   r   r   r2   popr   Zload_binary_filer   r   r~   r   )
r   r"   rr   r   r   Zname_mapsourceZdestinationZdhcp_messagert   r   r   r   parse_dhcpcd_lease  sD      	
zDhcpcd.parse_dhcpcd_leaserO   c              
   C   sf   z |  t| jdd|gj|W S  tjk
r` } z td|j|j|j t	|W 5 d}~X Y nX dS )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   r:   r   r   r   r   r   r   r   )r=   r"   r   r   r   r   rQ   T  s&    zDhcpcd.get_newest_leaserR   c                 C   sD   |   }|r4d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   s   g | ]}|qS r   r   r   ir   r   r   r     s     z.Dhcpcd.parse_static_routes.<locals>.<listcomp>Nr   r?   z'Malformed classless static routes: [%s])rl   zipr   r   rS   r   r   r   r   rT   q  s
    (zDhcpcd.parse_static_routes)NN)r   r   r   r:   rV   rX   r	   r   r   r   r   r[   r   r|   r   r   rQ   r   r
   rT   r   r   r   r   r   d  s&     
w +Hr   c                       sx   e Zd ZdZ fddZdeee eee	f dddZ
eeee	f dd	d
Zeeeeeef  dddZ  ZS )UdhcpcZudhcpcc                    s   t    d| _d S )Nr7   r]   r<   r`   r   r   r>     s    
zUdhcpc.__init__NrU   c           
      C   s@  t d| tjdd}tj||d | _tt	 t
| j W 5 Q R X |j| tj|d}t|td | jddd	|d
|ddddg}t|r|ddt|dd ddg ztj|d| jidd\}}W nB tjk
r  }	 z t d|	j|	j|	j t|	W 5 d}	~	X Y nX |dk	r6||| | |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.jsonudhcpc_scripti  z-OZstaticroutesz-iz-sz-nz-qz-fz-vz-xz	0x3d:20{}r   Nrx   r7   Z
LEASE_FILE)Z
update_envZcapturez1udhcpc exited with code: %s stderr: %r stdout: %r)r   r   r   r   r)   r*   r.   r_   r   r   rD   r   r   r   r   UDHCPC_SCRIPTr:   r   extendformatr   rn   r   r   r   r   r   r   rQ   )
r=   r"   r!   r    r   r   cmdr   r   r   r   r   r   r     sZ    
  

zUdhcpc.dhcp_discoveryrO   c                 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   Z	load_jsonr-   r_   rP   r   r   r   rQ     s    zUdhcpc.get_newest_leaserR   c                 C   s8   |   }|r4dd t|d d d |dd d D S g S )Nc                 S   s   g | ]}|qS r   r   r   r   r   r   r     s     z.Udhcpc.parse_static_routes.<locals>.<listcomp>r   r?   )rl   r   r   r   r   r   rT     s    (zUdhcpc.parse_static_routes)NN)r   r   r   r:   r>   rX   r	   r   r   r   r   rQ   r[   r   r
   rT   r   r   r   r`   r   r     s     
Hr   )NN)N)N)5rY   rC   Zloggingr)   rg   r   r~   r{   r   
contextlibr   ior   
subprocessr   typingr   r   r   r   r	   r
   r%   Z	cloudinitr   r   r   Zcloudinit.netr   r   Z	getLoggerr   r   r(   r   r   r   	Exceptionr   r   r   r   rX   r#   r'   r0   r5   ABCr6   r\   r   r   ZALL_DHCP_CLIENTSr   r   r   r   <module>   sT    
!   



K     .f