a '¡DgÖ�ã@s–ddlZddlZddlZddlZddlZddlZddlZddlZddlZddl m Z ddl m Z ddl mZddlmZmZmZmZmZmZddlZddlmZmZmZddlmZmZe e¡Z dZ!d Z"d Z#d Z$Gd d „d e%ƒZ&Gdd„de&ƒZ'Gdd„de&ƒZ(Gdd„de&ƒZ)d%ee*efdœdd„Z+dd„Z,d&dd„Z-d'dd„Z.Gdd„dej/ƒZ0Gdd „d e0ƒZ1Gd!d"„d"e0ƒZ2Gd#d$„d$e0ƒZ3e2e1e3gZ4dS)(é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 < "$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@seZdZdZdS)ÚNoDHCPLeaseErrorz'Raised when unable to get a DHCP lease.N©Ú__name__Ú __module__Ú __qualname__Ú__doc__©rrú6/usr/lib/python3.9/site-packages/cloudinit/net/dhcp.pyrAsrc@seZdZdZdS)ÚInvalidDHCPLeaseFileErrorz§Raised when parsing an empty or invalid dhclient.lease file. Current uses are DataSourceAzure and DataSourceEc2 during ephemeral boot to scrape metadata. NrrrrrrEsrc@seZdZdZdS)ÚNoDHCPLeaseInterfaceErrorz7Raised when unable to find a viable interface for DHCP.NrrrrrrMsrc@seZdZdZdS)ÚNoDHCPLeaseMissingDhclientErrorz$Raised when unable to find dhclient.NrrrrrrQsr©ÚreturncCs2|p|j}|dur"t d¡tƒ‚|j |||¡S)aPerform 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.)Zfallback_interfaceÚLOGÚdebugrZ dhcp_clientÚdhcp_discovery)ÚdistroZnicÚ dhcp_log_funcÚ interfacerrrÚmaybe_perform_dhcp_discoveryUs   r#cCsttjt|ƒdd�ƒS)zÛParse 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)ÚcontentrrrÚnetworkd_parse_leaselsr'cCsP|dur t}i}tj |¡s |St |¡D] }tt tj ||¡¡ƒ||<q*|S)zŸReturn 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ÚretZlfilerrrÚnetworkd_load_leasesws ÿ r1cCsF|dur t}t|d�}t| ¡ƒD]\}}| |¡r"||Sq"dS)N)r/)r(r1ÚsortedÚitemsÚget)Zkeynamer/ZleasesZ_ifindexÚdatarrrÚnetworkd_get_option_from_leasesŠs  r6c@sÂeZdZdZdZdd„Zedd„ƒZedd„ƒZee d œd d „ƒZ ee d œd d „ƒZ e j e ee efdœdd„ƒZee j e eee e fdœdd„ƒƒZe j de eeee efdœdd„ƒZdS)Ú DhcpClientÚé cCst |j¡|_|jstƒ‚dS©N)r ÚwhichÚ client_nameÚdhcp_client_pathr©ÚselfrrrÚ__init__˜szDhcpClient.__init__cCstjd|jgddgd�dS)NZpkillré©Zrcs)r r<)ÚclsrrrÚkill_dhcp_client�szDhcpClient.kill_dhcp_clientcCs*| ¡t d¡}|D]}t |¡qdS)Nz/var/lib/dhcp/*)rDÚglobr)Úremove)rCÚfilesÚfilerrrÚ clear_leases¡s zDhcpClient.clear_leases)Údhcp_interfacecCs|jd|j|ddgd�dS)NÚstartrrArB©Zmanage_servicer<©rCrJr rrrÚ start_service¨sÿzDhcpClient.start_servicecCs|jd|jddgd�dS)NÚstoprrArBrLrMrrrÚ stop_service®szDhcpClient.stop_service©r"rcCsiS)z´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. r©r?r"rrrÚget_newest_lease²szDhcpClient.get_newest_lease©ÚroutesrcCsgS)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)rUrrrÚparse_static_routes»s zDhcpClient.parse_static_routesN©r"r!rcCsiS)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 rrrrÊszDhcpClient.dhcp_discovery)NN)rrrr<Útimeoutr@Ú classmethodrDrIÚstrrNrPÚabcÚabstractmethodrrrSÚ staticmethodrr rVr rrrrrrr7”s0   ü ûr7csÈeZdZdZ‡fdd„Zeeeeee fdœdd„ƒZ edd„ƒZ eeee fd œd d „Z dee eeee fd œdd„Zeeeeeefdœdd„ƒZee edœdd„ƒZedœdd„Z‡ZS)Ú IscDhclientZdhclientcstƒ ¡d|_dS)Nz/run/dhclient.lease©Úsuperr@Ú lease_filer>©Ú __class__rrr@âs zIscDhclient.__init__)Ú lease_contentrcCs¦t dtj¡}g}t|ƒdkr"gS| |¡D]t}g}| d¡D]2}| ¡ dd¡ dd¡}|r>| | dd¡¡q>t |ƒ}|  d ¡}|r–t   |¡|d <| |¡q,|S) zÃparse 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 zlease {(?P.*?)}\nrú;ú"r8zoption ú rAú unknown-245) ÚreÚcompileÚDOTALLÚlenÚfindallÚsplitÚstripÚreplaceÚappendr$r4r^Úget_ip_from_lease_value)rdZ lease_regexÚ dhcp_leasesÚleaseZ lease_optionsÚlineÚoptionsÚopt_245rrrÚ parse_leasesæs$  ÿ zIscDhclient.parse_leasescCsx| dd¡}t|ƒdkrdd}| d¡D] }t|ƒdkr>d|}||7}q&t dt| dd¡dƒ¡}n | d ¡}t |¡S) Nú\r8éú:rAÚ0z>Lézutf-8) rprlrnÚstructÚpackÚintÚencodeÚsocketÚ inet_ntoa)Zfallback_lease_valueZunescaped_valueZ hex_stringZhex_pairZ packed_bytesrrrrrs    ÿ z#IscDhclient.get_ip_from_lease_valuerQcCs`ttƒ�Dt |j¡}|r>| |¡}|r>|dWdƒSWdƒn1sR0YiS)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 r-rarx)r?r"r&rsrrrrSs   4zIscDhclient.get_newest_leaseNrWc Cs„t d|¡d}d}d}t|j|ƒ}t|jdƒ}ttƒ�&t |¡t |j¡Wdƒn1sh0Y|j   |¡t |ƒrÐdt |ƒdd…} d|| f} t jd d �} tj | |d ¡}t || ¡z$t | |j|j|||¡¡\} } WnDtj�y8}z(t d |j|j|j¡t|‚WYd}~n d}~00tj||jg|dd �}|�rvt dd dd„|Dƒ¡¡iSd}d}d}d}t|ƒD]¢}zt |¡ ¡}t|ƒ}Wn>t�yÌd|›d�}YnXt �yêd|›d�}Yn:0| !|¡}|dk�r$t d|¡t "|t#j$¡d }�q}óz-IscDhclient.dhcp_discovery..ÚunknownFr8úNo PID file found at z, dhclient is still runningúPID file contained [z], dhclient is still runningrAzkilling dhclient with pid=%szCdhclient(pid=%s, parentpid=%s) failed to daemonize after %s secondsg$@)*rrr€rXrr…r)rFraÚnet_opsÚlink_uprrr Úget_tmp_ancestorr*r.r Ú write_filer Zbuild_dhclient_cmdr=ÚProcessExecutionErrorÚ exit_codeÚstderrÚstdoutrZwait_for_filesÚwarningÚranger-roÚ ValueErrorZ get_proc_ppidÚkillÚsignalÚSIGKILLÚtimeÚsleepÚerrorrSr)r?r"r!r Úpid_fileZ config_fileÚ sleep_timeÚ sleep_cyclesr‹Zdhcp_client_identifierZinterface_dhclient_contentÚtmp_dirÚoutÚerrr¤ÚmissingZppidZ daemonizedÚ pid_contentÚ debug_msgÚ_Úpidrtrrrr&s¤   * ÿþÿ  ûÿ ü  ÿþ   ÿ ÿ    û   zIscDhclient.dhcp_discoveryrTc sB| d¡‰dd„t dˆ¡Dƒ}g}dˆvr:dd„|Dƒ}‡fdd„}d }t|ƒD�]è\}}||krfqRt|ƒ}|td d ƒvrôd }t||d …ƒ|kr´|||t||d …ƒƒ|Sd ||d|d…¡} d ||d||…¡} ||}�n2|tdd ƒv�r„d}t||d …ƒ|k�r>|||t||d …ƒƒ|Sd ||d|d…dg¡} d ||d||…¡} ||}�n¢|td dƒv�rd}t||d …ƒ|k�rÎ|||t||d …ƒƒ|Sd ||d|d…ddg¡} d ||d||…¡} ||}�n|tdd ƒv�r¦d}t||d …ƒ|k�r`|||t||d …ƒƒ|Sd ||d|d…gd¢¡} d ||d||…¡} ||}n€|d k�rd}t||d …ƒ|k�rê|||t||d …ƒƒ|Sd} d ||d||…¡} ||}nt  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 recSsg|] }|r|‘qSrr©r�ÚtokrrrÚ Ør�z3IscDhclient.parse_static_routes..z[, . :]r{cSsg|]}tt|dƒƒ‘qS)r})rZr€r°rrrr²Ýr�csd|||ˆf}t |¡dS)Nz¥RFC3442 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)rr¤)ZcidrÚrequiredZremainÚmsg©Zrfc3442rrÚ _trunc_errorßs  ýÿz5IscDhclient.parse_static_routes.._trunc_errorréé!é NÚ.rAééérzr|ééérˆ)r|r|r|z0.0.0.0zSParsed invalid net length "%s". Verify DHCP rfc3442-classless-static-routes value.z%s/%s) ÚrstriprirnÚ enumerater€r�rlr.rr¤rq) rUÚtokensÚ static_routesr¶Z current_idxÚidxr±Z net_lengthZreq_toksZ net_addressZgatewayrrµrrV­s|*     " ÿ   ýÿzIscDhclient.parse_static_routesrc Cs¨d}|j|jfttffD]Š\}}|s&qg}zt |¡}WntyNYqYn0d}|D]<}t ||¡sjqXtj   ||¡}tj   |¡}||krX|}|}qX|r|SqdS)züGet 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ð¿) Zdhclient_lease_directoryZdhclient_lease_file_regexÚDHCLIENT_FALLBACK_LEASE_DIRÚDHCLIENT_FALLBACK_LEASE_REGEXr)r,r…riÚsearchr*r.Úgetmtime) r Z latest_fileZ directoryZregexZ lease_filesZ latest_mtimeÚfnameZabs_pathÚmtimerrrÚ!get_newest_lease_file_from_distro%s2 þû      z-IscDhclient.get_newest_lease_file_from_distro)ÚkeycCsJ| |¡}|rFt |¡}|rFt| |¡ƒD]}| |¡}|r*|Sq*dS)a8Get 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-Úreversedrxr4)r?r rÍrar&rtZserverrrrÚget_key_from_latest_leaseQs   z%IscDhclient.get_key_from_latest_lease)NN)rrrr<r@r]rZrrrrxrrrSr rrr rVrÌrÏÚ __classcell__rrrbrr^ßs(  ü û w+r^c@sœeZdZdZdZdeeeeee fdœdd„Z e e e ee dœdd „ƒZe eeed œd d „ƒZeeee fd œdd„Ze eeeeefdœdd„ƒZdS)ÚDhcpcdZdhcpcdi,NrWc Cs.t d|¡d}t|j|ƒ}g}|j |¡�ztt|ƒr@dg}|jdddddg|¢|‘}tj||jd �\}} |d ur€||| ƒ|  |¡} | �ršt g|¢d ‘¡j   ¡} d } d } d }t |ƒD]Ì}zNt  | ¡  ¡} t| ƒ}| |¡} | �r t d|| ¡t | tj¡W�q”Wndt�y6t d| ¡Y�q”YnHt�yTd| ›d�}Yn*t�yrd| ›d�}Yn 0| WSt |¡q¼t |¡| WStdƒ‚Wn„t�yæ}z(t d|j|j|j ¡t|‚WYd }~nLd }~0tj�y(}z(t d|j|j|j ¡t|‚WYd }~n d }~00d 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)rXNz-PFr8z!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 runningzNo lease foundz8dhcpcd timed out after %s seconds: stderr: %r stdout: %rú1dhcpcd exited with code: %s stderr: %r stdout: %r)rrr€rXr”r•rr<r rSr›ror�r r-Z get_proc_pgidr)Úkillpgr r¡ÚProcessLookupErrorr…ržr¢r£rrršr˜r™)r?r"r!r r¦r§Zinfiniband_argumentZcommandr©rªrtr¥r¬Úgidr­r®r¯r¤rrrrhs–   úùø þ     ÿ ý  ÿ ÿ    üüzDhcpcd.dhcp_discovery)r5Údhcp_option_numberrcCs<d}ttdœdd„}|||ƒD]\}}||kr|SqdS)aVget 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 éð)r5ÚindexcssXt|ƒ|dkrT||}|d|}|d|d||…}||fVd||}qdS)zÎoptions 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ˆrAN)rl)r5rÙÚcodeÚlengthÚoptionrrrÚ iter_optionsøs   z>Dhcpcd.parse_unknown_options_from_packet..iter_optionsN)Úbytesr€)r5r×ZINDEXrÝrÚrÜrrrÚ!parse_unknown_options_from_packetßs  z(Dhcpcd.parse_unknown_options_from_packet)Ú lease_dumpr"rc Cst d||¡zHtdd„| ¡ dd¡ d¡Dƒƒ}|sTd}t ||¡t||ƒ‚Wn6tyŒ}zt d|¡t|‚WYd }~n d }~00||d <d d „|  ¡Dƒ}d ddœ}|  ¡D]\}}||vrº|  |¡||<qºt   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: %rcSs"g|]}d|vr|jddd�‘qS)ú=rA)Úmaxsplit)rn)r�Úarrrr²(sþz-Dhcpcd.parse_dhcpcd_lease..ú'r8Ú z;No valid DHCP lease configuration found in dhcpcd lease: %rzError parsing dhcpcd lease: %rNr"cSsi|]\}}| dd¡|“qS)r®ú-)rp)r�rÍÚvaluerrrÚ =r�z-Dhcpcd.parse_dhcpcd_lease..z fixed-addressrÄ)z ip-addresszclassless-static-routesz/var/lib/dhcpcd/z.leaseéõrh)rrr$rorprnr¤rržr3Úpopr Zload_binary_filerÑrßr‚rƒ) ràr"rtr´r¤Zname_mapÚsourceZ destinationZ dhcp_messagerwrrrÚparse_dhcpcd_lease s@ÿþÿÿ   þ ÿ zDhcpcd.parse_dhcpcd_leaserQc Cshz | t |jdd|g¡j|¡WStjyb}z(t d|j|j|j¡t |‚WYd}~n d}~00dS)zÊReturn 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˜rrr™ršr)r?r"r¤rrrrSTs&üÿ÷ üzDhcpcd.get_newest_leaserTcCsD| ¡}|r4dd„t|ddd…|ddd…ƒDƒSt d|¡gS)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"), ] cSsg|]}|‘qSrr©r�Úirrrr²‹r�z.Dhcpcd.parse_static_routes..NrˆrAz'Malformed classless static routes: [%s])rnÚziprrœ©rUrÄrrrrVqs ( zDhcpcd.parse_static_routes)NN)rrrr<rXrZr rrrrr]rÞr€rßrìrSrr rVrrrrrÑds$ü û wþ+HrÑcsxeZdZdZ‡fdd„Zdeeeeee fdœdd„Z eeee fdœd d „Z e ee eeefd œd d „ƒZ‡ZS)ÚUdhcpcZudhcpccstƒ ¡d|_dS)Nr8r_r>rbrrr@“s zUdhcpc.__init__NrWc CsVt d|¡tjdd�}tj ||d¡|_tt ƒ�t  |j¡Wdƒn1sV0Y|j   |¡tj |d¡}t  |td¡|jdd d |d |d d ddg }t|ƒrÔ| dd t|ƒdd… dd¡¡g¡ztj|d|jidd�\}}WnDtj�y6} z(t d| j| j| j¡t| ‚WYd} ~ n d} ~ 00|du�rL|||ƒ| |¡S)arRun 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-OZ staticroutesz-iz-sz-nz-qz-fz-vz-xz 0x3d:20{}r‰r{r8Z LEASE_FILE)Z update_envZcapturez1udhcpc exited with code: %s stderr: %r stdout: %r)rrr r–r)r*r.rarr…rFr”r•r r—Ú UDHCPC_SCRIPTr<rÚextendÚformatrrpr r˜r™ršr›rrS) r?r"r!r r¨ròÚcmdr©rªr¤rrrr—sV   * õÿþÿ ÿü  zUdhcpc.dhcp_discoveryrQcCst 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-rarRrrrrSßs zUdhcpc.get_newest_leaserTcCs8| ¡}|r4dd„t|ddd…|ddd…ƒDƒSgS)NcSsg|]}|‘qSrrrírrrr²òr�z.Udhcpc.parse_static_routes..rˆrA)rnrïrðrrrrVís(zUdhcpc.parse_static_routes)NN)rrrr<r@rZr rrrrrSr]rr rVrÐrrrbrrñ�s ü û Hrñ)NN)N)N)5r[rEZloggingr)rir r‚r~r¢Ú contextlibrÚiorÚ subprocessrÚtypingrrrrr r r%Z cloudinitr r r Z cloudinit.netrrZ getLoggerrrr(rÆrÇróÚ ExceptionrrrrrZr#r'r1r6ÚABCr7r^rÑrñZALL_DHCP_CLIENTSrrrrÚsR     !ÿ þ   K.f