
    *Ce"q                         d dl mZ d dlZd dlZd dlmZ d dlmZ d dlm	Z	m
Z
mZ d dlmZmZ  G d dej                        Z G d	 d
      Zy)    )defaultdictN)AbstractSet)NetplanRoute)SystemConfigStateNetplanConfigStateDEVICE_TYPES)is_valid_macaddressroute_table_lookupc                       e Zd Zd Zy)DiffJSONEncoderc                     t        |t              r|j                         S t        j                  j                  | |      S N)
isinstancer   to_dictjsonJSONEncoderdefault)selfobjs     0/usr/share/netplan/netplan_cli/cli/state_diff.pyr   zDiffJSONEncoder.default   s3    c<(;;=  ''c22    N)__name__
__module____qualname__r    r   r   r   r      s    3r   r   c                      e Zd ZdZdedefdZdefdZd*de	defdZ
defd	Zd
e	de	dedefdZdededdfdZdedefdZdedefdZde	de	fdZdededdfdZdededdfdZdededdfdZdededdfdZdede	ddfdZdededdfdZdedefdZd ee   d!ee	   dedefd"Zdefd#Zdeddfd$Zdefd%Z d&edefd'Z!d(e	defd)Z"y)+NetplanDiffStatez
    DiffState is mainly responsible for getting both system's and Netplan's configuration
    state, compare them and provide a data-structure containing the differences it found.
    system_statenetplan_statec                 .    || _         || _        i | _        y r   )r   r   route_lookup_table_names)r   r   r   s      r   __init__zNetplanDiffState.__init__+   s    (*(*%r   returnc                    di i}| j                         }| j                         }t        t        |j	                               t        |j	                               z         }|D ]
  }i |d   |<    |j                         D ]  \  }}|d   |   j                  |        |j                         D ]  \  }}|d   |   j                  |        |S )z
        Return the states of both the system and Netplan in a common representation
        that makes it easier to compare them.
        
interfaces)_get_system_interfaces_get_netplan_interfacessetlistkeysitemsupdate)r   
full_statesystem_interfacesnetplan_interfacesall_interfaces	interfaceconfigs          r   get_full_statezNetplanDiffState.get_full_state1   s     "

 !779!99; T"3"8"8":;dCUCZCZC\>]]^' 	5I24J|$Y/	5 "3!8!8!: 	?Iv|$Y/66v>	? "4!9!9!; 	?Iv|$Y/66v>	? r   r1   c                    | j                         }| j                  |j                  di             }|r|j                  |      x}r||i}ni }| j                         }| j	                  ||       |j                         D ]  \  }}|j                  di       j                  d      }|j                  di       j                  d      }| j                  |||      }| j                  ||       | j                  ||       | j                  ||       | j                  ||       | j                  ||       | j                  ||       |d   j                  |        t        t        |d   j                         d             |d<   |S )a  
        Compare the configuration of interfaces currently found in the system against Netplan configuration.
        A number of heuristics are used to eliminate configuration that is automatically set in the system,
        such as certain routes and IP addresses. That is necessary because this configuration will not be found
        in Netplan. For example, if Netplan is enabling DHCP on an interface and not defining any extra IP addresses,
        we don't count the IPs automatically assigned to the interface as a difference. We do though count the eventual
        absence of addresses that should be assigned by DHCP as a difference.
        r%   r   idindexc                 *    | d   j                  d      S )N   r6   )get)ifaces    r   <lambda>z+NetplanDiffState.get_diff.<locals>.<lambda>q   s    [`ab[c[g[gho[p r   key)r3   _get_comparable_interfacesr9   _create_new_report_analyze_missing_interfacesr+   _create_new_iface_analyze_ip_addresses_analyze_nameservers_analyze_search_domains_analyze_mac_addresses_analyze_routes_analyze_parent_linksr,   dictsorted)	r   r1   r-   r%   r2   report	netdef_idr6   r:   s	            r   get_diffzNetplanDiffState.get_diffK   sx    ((*
44Z^^LRT5UV
#	22v2'0

((*((;!+!1!1!3 	/Iv

>26::4@IJJ~r266w?E**9iGE&&vu5%%fe4((7''6  /&&vu5< ''.	/  $F6,+?+E+E+GMp$qr|r   c                     i i i dS )N)r%   missing_interfaces_systemmissing_interfaces_netplanr   )r   s    r   r?   z#NetplanDiffState._create_new_reportt   s    )+*,
 	
r   rK   r6   c                     ||||i i diS )N)r6   namer5   r   r   r   )r   rK   r1   r6   s       r   rA   z"NetplanDiffState._create_new_iface{   s#    ! "!#
 	
r   r2   r:   Nc                 r   t        |j                               d   }|j                  di       j                  dg       D ch c]  }| }}| j                  |      }|j                  di       j                  dd      }|j                  di       j                  dd      }|j                  di       j                  dg       }t	               }	|j                  di       j                  di       j                         D ]  \  }
}t        j                  |
      }|j                  d	g       }d
|vrd|vr|	j                  |
       d|v r~|j                  rrt        |j                  t        j                        rd|vr|	j                  |
       t        |j                  t        j                        rd|vr|	j                  |
       d
|v st        |j                  t        j                        rd}t        |j                  t        j                        sd} |j                  |	      }|	j                  |      }|rd||   d   d<   |rd||   d   d<   |r+||   d   j                  dt        t!        |            i       |r,||   d   j                  dt        t!        |            i       y y c c}w )Nr   r   	addressesdhcp4Fdhcp6
link_localr   flagsdhcplinkipv4ipv6Tmissing_dhcp4_addressmissing_dhcp6_addressmissing_addresses)r)   r*   r9   _normalize_ip_addressesr(   r+   	ipaddressip_interfaceaddis_link_localr   ipIPv4AddressIPv6Address
differencer,   rI   )r   r2   r:   rQ   rd   netplan_ipsr\   r]   rV   
system_ipsaddr	addr_datarW   present_only_in_netplanpresent_only_in_systems                  r   rB   z&NetplanDiffState._analyze_ip_addresses   s~   EJJL!!$$*JJ$C$G$GUW$XYbrYY22;? &

?B ? C CGU S &

?B ? C CGU SZZ488rJ
U
%zz."=AA+rRXXZ 	2OD)''-BMM'2.E U"vU':t$
 2#3#3beeY%:%:;j@XNN4(beeY%:%:;j@XNN4( beeY%:%:;,1)beeY%:%:;,1)/	22 #."8"8"D!+!6!6{!C CGE$K'(?@ CGE$K'(?@!$K(//#T&1G*H%I1  #$K'..#T&1H*I%J0  #] Zs   	J4r%   c                     i }|j                         D ]O  \  }}|j                  d      |j                  d      )|j                  di       j                  d      sK|||<   Q |S )a   In order to compare interfaces, they must exist in the system AND in Netplan.
            Here we filter out interfaces that don't have a system_state, a netplan_state
            or a netdef ID.

            There is a special case where the interface will have a system_state and a netdef_id
            but will be missing in Netplan. That will happen when the user removes the interface
            only from Netplan but doesn't run netplan apply.
        r   r   r5   )r+   r9   )r   r%   filteredr1   r2   s        r   r>   z+NetplanDiffState._get_comparable_interfaces   ss     !+!1!1!3 	)Ivzz.)1VZZ5P5X::nb155d;"(HY	) r   rS   c                 l    t               }|D ]$  }| j                  |      }|j                  |       & |S )zm Apply some transformations to IP addresses so their representation
        will match the system's.
        )r(   _compress_ipv6_addressrb   )r   rS   new_ips_setrd   s       r   r_   z(NetplanDiffState._normalize_ip_addresses   s>     e 	 B,,R0BOOB	  r   addressc                     	 t        j                  |      }d|v r|j                  S t        |j                        S # t
        $ r |cY S w xY w)z
        Compress IPv6 addresses to match the system representation
        Example: 1:2:0:0::123/64 -> 1:2::123/64
                 1:2:0:0::123 -> 1:2::123
        If "address" is not an IPv6Address, return the original value
        /)r`   ra   with_prefixlenstrrd   
ValueError)r   rs   rj   s      r   rq   z'NetplanDiffState._compress_ipv6_address   sL    	))'2Dg~***tww< 	N	s   $< < A
	A
c                 6   t        |j                               d   }t        |j                  di       j                  dg             }t        |j                  di       j                  dg             }|j                  di       j                  dg       }|D cg c]+  }|j                  dk(  s|j
                  s |j
                  - }}|D 	ch c]	  }	|	|vs|	 }}	|s|j                  di       j                  d      r<|D 	ch c]1  }	t        t        j                  |	      t        j                        s|	3 }}	|j                  di       j                  d      r<|D 	ch c]1  }	t        t        j                  |	      t        j                        s|	3 }}	|j                  |      }
|j                  |      }|r"||   d   j                  d	t        |      i       |
r#||   d   j                  d	t        |
      i       y y c c}w c c}	w c c}	w c c}	w )
Nr   r   nameservers_addressesr   routesrarT   rU   missing_nameservers_addresses)r)   r*   r(   r9   protocolviar   r`   
ip_addressre   rf   rg   r,   )r   r2   r:   rQ   netplan_nameserverssystem_nameserverssystem_routesr	ra_routesnsrl   rm   s               r   rC   z%NetplanDiffState._analyze_nameservers   s
   EJJL!!$ "&**_b"A"E"EF]_a"bc NB!?!C!CD[]_!`a 

>26::8RH$1RqQZZ45GAEEQUUR	R+=UR9ATbUU #zz/2.227;3E &jR-7	8L8LR8PR[RgRg-h ') &j" &jzz/2.227;3E &jR-7	8L8LR8PR[RgRg-h ') &j" &j #6"@"@AS"T!3!>!>?R!S!$K(///6L1M1  #$K'../6M1N0  #3 SU&j&js*   H.H;H	HH6H#6Hc                 Z   t        |j                               d   }t        |j                  di       j                  dg             }t        |j                  di       j                  dg             }|sL|j                  di       j                  d      s!|j                  di       j                  d      r
t               }|j	                  |      }|j	                  |      }|r"||   d   j                  dt        |      i       |r#||   d   j                  dt        |      i       y y )Nr   r   nameservers_searchr   rT   rU   missing_nameservers_search)r)   r*   r(   r9   rg   r,   )r   r2   r:   rQ   netplan_search_domainssystem_search_domainsrl   rm   s           r   rD   z(NetplanDiffState._analyze_search_domains  s    EJJL!!$!$VZZ%D%H%HI]_a%b!c #FJJ~r$B$F$FG[]_$` a &zz/2.227;vzz/[]?^?b?bcj?k(+%"8"C"CDY"Z!6!A!ABX!Y!$K(//,d3I.J1  #$K'..,d3J.K0  #r   c                 X   t        |j                               d   }|j                  di       j                  d      }|j                  di       j                  d      }|rt        |      sy |r<|r9||k7  r3||   d   j	                  d|i       ||   d   j	                  d|i       y y y y )Nr   r   
macaddressr   missing_macaddress)r)   r*   r9   r	   r,   )r   r2   r:   rQ   system_macaddressnetplan_macaddresss         r   rE   z'NetplanDiffState._analyze_mac_addresses.  s    EJJL!!$"JJ~r:>>|L#ZZ<@@N &9:L&M!3 $66dN+22(*<4  dO,33(*;5 	 7 "4r   c                    t        |j                               d   }t        |j                  di       j                  dg             }t        |j                  di       j                  dg             }| j	                  |      }|j                  di       j                  di       D cg c]  }| }}| j                  |||      }|j                  |      }|j                  |      }	|	r3||   d   j                  dt        |	d       D 
cg c]  }
|
 c}
i       |r4||   d   j                  dt        |d	       D 
cg c]  }
|
 c}
i       y y c c}w c c}
w c c}
w )
Nr   r   r{   r   rS   missing_routesc                     | j                   S r   tor   s    r   r;   z2NetplanDiffState._analyze_routes.<locals>.<lambda>P  s    cdcgcg r   r<   c                     | j                   S r   r   r   s    r   r;   z2NetplanDiffState._analyze_routes.<locals>.<lambda>U  s    dedhdh r   )	r)   r*   r(   r9   _normalize_routes_filter_system_routesrg   r,   rI   )r   r2   r:   rQ   netplan_routesr   rd   system_addressesrl   rm   routes              r   rF   z NetplanDiffState._analyze_routesA  s[   EJJL!!$VZZ<@@2NOFJJ~r:>>xLM//? *0NB)G)K)KKY[)\]2B]]22=BRTZ["0";";M"J!.!9!9.!I!$K(// f=SYg6h"iU5"i1  #$K'.. f=TZh6i"jU5"j0  # ^ #j
 #ks   (	E	E
	E
rJ   c                      j                   j                  D ch c]  }| }} j                  j                  D ch c]  }|j                  s|j                   }}|j                  |      }t        t         fd|            }g } j                  j                  D ],  }|j                  |vs|j                  |j                         . t        |      }t        |      }rt        fd|      }t        fd|      } j                  j                         }|D ]O  } j                   j                  j                  |      j                  }	dt        j                  |	d      i|d   |<   Q |D ]J  }|j                  |      j                  dd      |j                  |      j                  d      d|d	   |<   L y c c}w c c}w )
Nc                 h    j                   j                  j                  |       j                  dk7  S )Nwifis)r   netdefsr9   type)ir   s    r   r;   z>NetplanDiffState._analyze_missing_interfaces.<locals>.<lambda>_  s*    T-?-?-G-G-K-KA-N-S-SW^-^ r   c                     | k(  S r   r   r   r1   s    r   r;   z>NetplanDiffState._analyze_missing_interfaces.<locals>.<lambda>j  s    AN r   c                     | k(  S r   r   r   s    r   r;   z>NetplanDiffState._analyze_missing_interfaces.<locals>.<lambda>k  s    1	> r   r   otherrN   r6   )r   r6   rO   )r   r   r   interface_listrK   rg   r)   filterappendrQ   rI   get_datar9   r   r   )
r   rJ   r1   r:   r/   system_interfaces_netdef_idsnetplan_onlysystem_onlyr   
iface_types
   ` `       r   r@   z,NetplanDiffState._analyze_missing_interfacesX  s   151C1C1K1KLeLLEIEVEVEeEe'yEinixix'y$'y)445QR F#^`lmn&&55 	/E&88""5::.	/ l+[)!":LIL !9;GK((113! 	E++3377>CCJ((W=:F./6	 ! 	E$((/33FGD%))%044W=;F/07	9 M'ys   	GG	G	c                 b   t        |j                               d   }|j                  di       j                  d      |j                  di       j                  d      g}|j                  di       j                  d      |j                  di       j                  d      g}|j                  di       j                  d      |j                  di       j                  d      g}|j                  di       j                  dg       |j                  di       j                  dg       g}|ddgk7  r1|d   |d	   k7  r&|d   r|d   ||   d   d
<   |d	   r|d	   ||   d   d
<   |ddgk7  r1|d   |d	   k7  r&|d   r|d   ||   d   d<   |d	   r|d	   ||   d   d<   |ddgk7  r1|d   |d	   k7  r&|d   r|d   ||   d   d<   |d	   r|d	   ||   d   d<   |g g gk7  rZt        |d         }t        |d	         }	||	k7  r8|	|z
  x}
rt        |
      ||   d   d<   ||	z
  x}rt        |      ||   d   d<   yyyy)z
        Analyze if interfaces such as bonds, bridges and VRFs are correctly attached to their
        members and vice versa.
        r   r   bondr   bridgevrfr%   Nr8   missing_bond_linkmissing_bridge_linkmissing_vrf_linkmissing_interfaces)r)   r*   r9   r(   )r   r2   r:   rQ   r   r   r   r%   systemnetplanmissing_systemmissing_netplans               r   rG   z&NetplanDiffState._analyze_parent_links{  s   
 EJJL!!$

>2.226:FJJXZ<[<_<_`f<gh**^R044X>

?\^@_@c@cdl@mnzz."-11%8&**_VX:Y:]:]^c:dejj488rJFJJWfhjLkLoLop|  A  MB  C
D$<DGtAw$6AwDHGdO,-@AAwCG7dN+,?@dD\!fQi6!9&<ayFLQidO,-BCayEKAYdN+,AB4,3q6SV#31vCFq6dO,-?@1vBEa&dN+,>?"b!A'F*Q-(G %,v%55>5HL^H\E$K/0DE&,w&66?6IMoI^E$K01EF 7	 !	 "r   r{   c                    t               }|D ]  }|j                  t        j                  k(  r| j	                  d      |_        | j                  |j                        |_        | j                  |j                        |_        | j                  |j                        |_        |j                  dk7  r5|j                  j                  d      }|d   dk(  s|d   dk(  r
|d   |_        |j                  |        |S )zo Apply some transformations to Netplan routes so their representation
        will match the system's.
        mainr   ru   r8   32128r   )r(   tabler   _TABLE_UNSPEC_$_default_route_tables_name_to_numberrq   r   	from_addrr   splitrb   )r   r{   new_routes_setr   	ip_prefixs        r   r   z"NetplanDiffState._normalize_routes  s      	&E{{l999"GGO 22588<EH"99%//JEO33EII>EI xx9$!HHNN3/	Q<4'9Q<5+@(|EHu%#	&& r   r   r   c                    |D cg c]*  }t        t        j                  |      j                        , }}t	        t        d |            }|D cg c]*  }t        t        j                  |      j                        , }}|j                  di       j                  dg       }t               }|D ]  }	|	j                  dk(  r9|	j                  dk7  r*t        j                  |	j                        j                  sL|	j                  dk(  s|	j                  dk(  rk|	j                  dk7  rSt        j                  |	j                        }
|
j                  r(|	j                  dk(  rd	|v r|	j                  d
k(  rd|v r|	j                  dk(  rH|	j                  dk(  r9|	j                  |v s)t        j                  |	j                        j                  r$|	j                  dk(  r |	j                  dk(  r|	j                  dk(  rS|	j                  dk(  r|	j                  |v s|	j                  |v r|j!                  |	        |S c c}w c c}w )a  
        Some routes found in the system are installed automatically/dynamically without
        being configured in Netplan.
        Here we implement some heuristics to remove these routes from the list we want
        to compare. We do that because these type of routes will probably never be found in the
        Netplan configuration so there is no point in comparing them against Netplan.
        c                     | dk7  S )Nz	fe80::/64r   )ns    r   r;   z8NetplanDiffState._filter_system_routes.<locals>.<lambda>  s    qK/? r   r   rV   rY   r   rX   r|   
   r[      rZ   hostlocal	multicastzff00::/8)rw   r`   ra   networkr)   r   rd   r9   r(   scoper   rc   r~   familyr   is_loopbackrb   )r   r   r   r2   rd   local_networksrS   rV   r{   r   route_tos              r   r   z&NetplanDiffState._filter_system_routes  s    M]]b#i44R8@@A]]f%?PQBRSBS//3667S	SZZ488rJ
"  	E{{f$Y)>yG]G]^c^f^fGgGuGu ~~'5>>T+A xx9$$11%((;))||r)f
.B ||q(Vz-A  v%%***?XX*i.D.DUXX.N.Z.Z ||r!ejjK&?EHHPZDZ ||r!uxx>'AUXXQZEZJJuA 	B O ^ Ts   /I/I
c                    | j                   j                         }i }| j                  j                  j	                         D ]0  \  }}i }dd|ii||<   ||   d   }t        j                  |j                  d      |d<   |j                  |d<   |j                  |d<   |j                  |d<   |j                  D cg c]  }| }}|rWi |d<   |D ]M  }i }	|j                  r|j                  |	d	<   |j                  r|j                  |	d
<   d|	i|d   t        |      <   O t        |j                         x}
r|
|d<   t        |j"                        x}r||d<   t        |j$                        x}r||d<   |j&                  x}r||d<   |j(                  j                  d      x}r|j*                  |d<   |j(                  j                  d      x}r|j*                  |d<   |j(                  j                  d      x}r|j*                  |d<   ||vrUd}|j	                         D ])  \  }}|j                  d      x}s||k(  s d}||   ||<   + |r|j-                  |        |j-                  |       3 | j/                  |       |S c c}w )Nr   r5   r   r   rT   rU   rV   rS   labellifetimerW   rz   r   r{   r   r   r   r   FT)r   r   r   r   r+   r   r9   r   rT   rU   rV   rS   r   r   rw   r)   nameserver_addressesnameserver_searchr{   r   linksr5   r,   _netplan_state_find_parents)r   r.   r%   r1   r2   r:   	iface_refrj   rS   rW   nameserverssearchr{   macr   r   r   
found_somer=   valuerK   s                        r   r'   z(NetplanDiffState._get_netplan_interfaces  s    --668
!%!3!3!;!;!A!A!C A	)IvE /$	1BCE)i(9I , 0 0g FIf!'Ig!'Ig&,&7&7Il#*0*:*:;$;I;)+	+&% IDEzz)-g}},0MMj)9@%8HIk*3t95I #6#>#>??{?5@	12f6677v728	./fmm,,v,&,	(#'''s'*-	,'))(33v3&,ii	(#||''//t/$(GG	&!ll&&u--s-#&66	%  11 #
"3"9"9"; ?JC$)IIdO3y3$	1)-J.3I.>JsO	? "%%e,!!%(CA	)F 	((4o <s   9	Jc                    t        t              }|j                         D ]  \  }}|d   j                  d      x}r||   j	                  |       |d   j                  d      x}r||   j	                  |       |d   j                  d      x}sq||   j	                  |        |j                         D ]  \  }}t        |      ||   d   d<    y)z* Associates interfaces with their parents r   r   r   r   r%   N)r   r(   r+   r9   rb   r)   )r   r%   parentsr1   r2   rY   memberss          r   r   z,NetplanDiffState._netplan_state_find_parents8  s    c"!+!1!1!3 	-Ivo.228<<t<!!),o.226::t:!!),o.22599t9!!),	- #*--/ 	QIwCG=Jy!/2<@	Qr   c                    i }| j                   j                         j                         D ]  \  }}|dk(  r|j                  d      }dd|ii||<   |j                  d      x}r|||   d   d<   ||   d   }|j                  d      x}r||d<   i }|j                  dg       D ]k  }	t	        |	j                               d   }
|	j                  |
      j                  d      }|
 d	| }d
|	j                  |
      j                  d
g       i||<   m |r||d<   |j                  d      x}r||d<   |j                  d      x}r||d<   |j                  d      x}r"|D cg c]  }| j                  |       c}|d<   |j                  d      x}r||d<   |j                  d      x}r||d<   |j                  d      x}r||d<   |j                  d      x}r||d<   |j                  d      x}s||d<    |S c c}w )Nznetplan-global-stater   r   r5   r6   rS   r   prefixru   rW   dns_addressesrz   
dns_searchr   r{   r   r%   r   r   r   )r   r   r+   r9   r)   r*   _system_route_to_netplan)r   r%   r1   r2   device_typerK   r   r6   rS   rj   rd   r   	full_addrr   r   r{   r   r   uplink_interfacesr   r   r   s                         r   r&   z'NetplanDiffState._get_system_interfacesF  sa   
!%!2!2!;!;!=!C!C!E /	'Iv22 **V,K%3fk5J$KJy!"JJt,,y,>G
9%n5d;"9-n=I

7++u+%*	'"I

;3 P$))+&q)"))(3!d!F8,	(/"1A1A'21N'O	)$P )2	+&$jj99{95@	12L11v128	./H--v-Y_&`PUt'D'DU'K&`	(#jj..s.*-	,'$*JJ|$<< <*;	,'zz&))t)$(	&!H--v-&,	(#jj''s'#&	% _/	'b # 'as    G=system_routec                    i }|j                  d      x}r||d<   |j                  d      x}r||d<   |j                  d      x}r||d<   |j                  d      x}r||d<   |j                  d      x}r||d<   |j                  d      x}r||d<   |j                  d      x}	r|	|d<   |j                  d	      x}
r|
|d	<   |j                  d
      x}r| j                  |      |d
<   t        di |S )Nr   r   r   fromr   metricr   r   r~   r   r   )r9   r   r   )r   r   r   r   r   r   r   r   r   
route_typer~   r   s               r   r   z)NetplanDiffState._system_route_to_netplan|  s9   !%%h//6/$E(O!!$''2'E$K""5))3)E%L$((0090!*E+!%%h//6/$E(O $$W--5-"E'N%))&11:1&E&M#''
3383 (E* $$W--5-!FFuME'N$e$$r   rQ   c                     |j                         rt        |      S | j                  st               | _        | j                  j	                  |d      S )Nr   )isdigitintr!   r
   r9   )r   rQ   s     r   r   z5NetplanDiffState._default_route_tables_name_to_number  sB    <<>t9,,,>,@D),,00q99r   ) )#r   r   r   __doc__r   r   r"   rH   r3   rw   rL   r?   r   rA   rB   r>   r(   r_   rq   rC   rD   rE   rF   r@   rG   r   r   r   r)   r   r'   r   r&   r   r   r   r   r   r   r   %   s   
+%6 +GY + 4'# 't 'R
D 
	
3 	
3 	
s 	
t 	
3D 3 3$ 3jT d ,	 	 	c c )4 ) ) )Vd 4 D 0T $ 4 &d 4 D .!$ !3 !4 !F&_D &_ &_$ &_P  40;|3L 0`deh`i 0sw 0| 0dG GRQd Qt Q4 4l%T %l %0: : :r   r   )collectionsr   r`   r   typingr   netplan.netdefr   netplan_cli.cli.stater   r   r   netplan_cli.cli.utilsr	   r
   r   r   r   r   r   r   <module>r      s=   $ $    ' U U I3d&& 3v	: v	:r   