*Ce"qddlmZddlZddlZddlmZddlmZddlm Z m Z m Z ddl m Z mZGddejZGd d Zy) ) defaultdictN) AbstractSet) NetplanRoute)SystemConfigStateNetplanConfigState DEVICE_TYPES)is_valid_macaddressroute_table_lookupceZdZdZy)DiffJSONEncoderct|tr|jStjj ||SN) isinstancerto_dictjson JSONEncoderdefault)selfobjs 0/usr/share/netplan/netplan_cli/cli/state_diff.pyrzDiffJSONEncoder.defaults3 c< (;;= ''c22N)__name__ __module__ __qualname__rrrr r s3rr ceZdZdZdedefdZdefdZd*de defdZ defd Z d e de d e defd Z d ededdfdZdedefdZdedefdZde de fdZd ededdfdZd ededdfdZd ededdfdZd ededdfdZdede ddfdZd ededdfdZdedefdZd eed!ee d edefd"Zdefd#Zdeddfd$Zdefd%Z d&edefd'Z!d(e de fd)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|_yr)rrroute_lookup_table_names)rrrs r__init__zNetplanDiffState.__init__+s(*(*%rreturncdii}|j}|j}tt|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_interfacessetlistkeysitemsupdate)r full_statesystem_interfacesnetplan_interfacesall_interfaces interfaceconfigs rget_full_statezNetplanDiffState.get_full_state1s " !779!99;T"3"8"8":;dCUCZCZC\>]]^' 5I24J| $Y / 5"3!8!8!: ? Iv | $Y / 6 6v > ?"4!9!9!; ? Iv | $Y / 6 6v > ?rr1c|j}|j|jdi}|r|j|x}r||i}ni}|j}|j |||j D]\}}|jdijd}|jdijd}|j |||}|j|||j|||j|||j|||j|||j|||dj|tt|dj 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%ridindexc*|djdS)Nr6)get)ifaces rz+NetplanDiffState.get_diff..qs[`ab[c[g[gho[prkey)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,dictsorted) rr1r-r%r2report netdef_idr6r:s rget_diffzNetplanDiffState.get_diffKsx((* 44Z^^LRT5UV # 22v2'0  ((* ((;!+!1!1!3 / Iv >26::4@IJJ~r266w?E**9iGE  & &vu 5  % %fe 4  ( ( 7  ' ' 6   /  & &vu 5 < ' ' . / $F6,+?+E+E+GMp$qr| rciiidS)N)r%missing_interfaces_systemmissing_interfaces_netplanr)rs rr?z#NetplanDiffState._create_new_reportts)+*,  rrKr6c||||iidiS)N)r6namer5rrr)rrKr1r6s rrAz"NetplanDiffState._create_new_iface{s# ! "!#   rr2r:Ncrt|jd}|jdijdgDchc]}|}}|j|}|jdijdd}|jdijdd}|jdijdg}t } |jdijdij D]\} } t j| }| jd g} d | vrd | vr| j| d | vr~|jrrt|jt jrd |vr| j| t|jt jrd |vr| j| d | vst|jt jrd}t|jt jsd}|j| } | j|}|r d||dd<|r d||dd<|r+||djdtt!|i| r,||djdtt!| iyycc}w)Nrr addressesdhcp4Fdhcp6 link_localrflagsdhcplinkipv4ipv6Tmissing_dhcp4_addressmissing_dhcp6_addressmissing_addresses)r)r*r9_normalize_ip_addressesr(r+ ipaddress ip_interfaceadd is_link_localrip IPv4Address IPv6Address differencer,rI)rr2r:rQrd netplan_ipsr\r]rV system_ipsaddr addr_datarWpresent_only_in_netplanpresent_only_in_systems rrBz&NetplanDiffState._analyze_ip_addressess~EJJL!!$$*JJ$C$G$G UW$XYbrY Y22;? & ?B ? C CGU S & ?B ? C CGU SZZ488rJ U %zz."=AA+rRXXZ 2OD)''-BMM'2.EU"vU':t$ 2#3#3beeY%:%:;j@XNN4(beeY%:%:;j@XNN4(beeY%:%:;,1)beeY%:%:;,1)/ 22#."8"8"D!+!6!6{!C CGE$K '(? @ CGE$K '(? @ ! $K ( / /#T&1G*H%I1  # $K ' . .#T&1H*I%J0  #]Zs J4r%ci}|jD]O\}}|jd|jd)|jdijdsK|||<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. rrr5)r+r9)rr%filteredr1r2s rr>z+NetplanDiffState._get_comparable_interfacesss!+!1!1!3 ) Ivzz.)1VZZ5P5X::nb155d;"(HY  )rrSclt}|D]$}|j|}|j|&|S)zm Apply some transformations to IP addresses so their representation will match the system's. )r(_compress_ipv6_addressrb)rrS new_ips_setrds rr_z(NetplanDiffState._normalize_ip_addressess>e  B,,R0B OOB  raddressc tj|}d|vr |jSt|jS#t $r|cYSwxYw)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`rawith_prefixlenstrrd ValueError)rrsrjs rrqz'NetplanDiffState._compress_ipv6_addresssL ))'2Dg~***tww<  N s$<< A  A c6t|jd}t|jdijdg}t|jdijdg}|jdijdg}|Dcgc]+}|jdk(s|j s |j -}}|D chc] } | |vs|  }} |s|jdijdr<|D chc]1} t tj| tjs| 3}} |jdijdr<|D chc]1} t tj| tjs| 3}} |j|} |j|} | r"||djd t| i| r#||djd t| iyycc}wcc} wcc} wcc} w) Nrrnameservers_addressesrroutesrarTrUmissing_nameservers_addresses) r)r*r(r9protocolviarr` ip_addressrerfrgr,) rr2r:rQnetplan_nameserverssystem_nameservers system_routesr ra_routesnsrlrms rrCz%NetplanDiffState._analyze_nameserverss EJJL!!$"&**_b"A"E"EF]_a"bc NB!?!C!CD[]_!`a  >26::8RH $1RqQZZ45GAEEQUUR R+=UR9ATbUU#zz/2.227;3E&jR-7 8L8LR8PR[RgRg-h')&j"&jzz/2.227;3E&jR-7 8L8LR8PR[RgRg-h')&j"&j#6"@"@AS"T!3!>!>?R!S ! $K ( / //6L1M1  # $K ' . ./6M1N0  #3SU&j&js*H. H;H H H 6H#6HcZt|jd}t|jdijdg}t|jdijdg}|sL|jdijds!|jdijdr t}|j |}|j |}|r"||dj dt|i|r#||dj dt|iyy)Nrrnameservers_searchrrTrUmissing_nameservers_search)r)r*r(r9rgr,)rr2r:rQnetplan_search_domainssystem_search_domainsrlrms rrDz(NetplanDiffState._analyze_search_domainss EJJL!!$!$VZZ%D%H%HI]_a%b!c #FJJ~r$B$F$FG[]_$` a&zz/2.227;vzz/[]?^?b?bcj?k(+%"8"C"CDY"Z!6!A!ABX!Y ! $K ( / /,d3I.J1  # $K ' . .,d3J.K0  #rcXt|jd}|jdijd}|jdijd}|r t|sy|r<|r9||k7r3||dj d|i||dj d|iyyyy)Nrr macaddressrmissing_macaddress)r)r*r9r r,)rr2r:rQsystem_macaddressnetplan_macaddresss rrEz'NetplanDiffState._analyze_mac_addresses.sEJJL!!$"JJ~r:>>|L#ZZ<@@N &9:L&M  !3 $66d N+22(*<4d O,33(*;5 7"4 rct|jd}t|jdijdg}t|jdijdg}|j |}|jdijdiDcgc]}|}}|j |||}|j |}|j |} | r3||djdt| dD cgc]} | c} i|r4||djdt|d D cgc]} | c} iyycc}wcc} wcc} w) Nrrr{rrSmissing_routesc|jSrtors rr;z2NetplanDiffState._analyze_routes..Ps cdcgcgrr<c|jSrrrs rr;z2NetplanDiffState._analyze_routes..Us dedhdhr) r)r*r(r9_normalize_routes_filter_system_routesrgr,rI) rr2r:rQnetplan_routesrrdsystem_addressesrlrmroutes rrFz NetplanDiffState._analyze_routesAs[EJJL!!$VZZ<@@2NOFJJ~r:>>xLM //?*0NB)G)K)KKY[)\]2B]]22=BRTZ[ "0";";M"J!.!9!9.!I ! $K ( / / f=SYg6h"iU5"i1  # $K ' . . f=TZh6i"jU5"j0  #^#j #ks( E E  E rJcjjDchc]}|}}jjDchc]}|js|j}}|j |}t tfd|}g}jjD],}|j|vs|j|j.t|}t|}rtfd|}tfd|}jj}|D]O}jjj|j} dtj| di|d|<Q|D]J}|j|jdd|j|jdd|d |<Lycc}wcc}w) Nchjjj|jdk7S)Nwifis)rnetdefsr9type)irs rr;z>NetplanDiffState._analyze_missing_interfaces.._s*T-?-?-G-G-K-KA-N-S-SW^-^rc|k(Srrrr1s rr;z>NetplanDiffState._analyze_missing_interfaces..js ANrc|k(Srrrs rr;z>NetplanDiffState._analyze_missing_interfaces..ks 1 >rrotherrNr6)rr6rO)rrrinterface_listrKrgr)filterappendrQrIget_datar9rr) rrJr1r:r/system_interfaces_netdef_ids netplan_only system_onlyr iface_types ` ` rr@z,NetplanDiffState._analyze_missing_interfacesXs151C1C1K1KLeLLEIEVEVEeEe'yEinixix'y$'y)445QR F#^`lmn  &&55 /E&88""5::. /l+ [) !":LIL !9;GK((113 ! E++3377>CCJ ((W=:F. / 6  ! E$((/33FGD%))%044W=;F/ 0 7 9M'ys GG G cbt|jd}|jdijd|jdijdg}|jdijd|jdijdg}|jdijd|jdijdg}|jdijdg|jdijdgg}|ddgk7r1|d|d k7r&|dr|d||dd <|d r|d ||dd <|ddgk7r1|d|d k7r&|dr|d||dd <|d r|d ||dd <|ddgk7r1|d|d k7r&|dr|d||dd <|d r|d ||dd <|gggk7rZt|d}t|d } || k7r8| |z x} rt| ||dd <|| z x} rt| ||dd <yyyy)z Analyze if interfaces such as bonds, bridges and VRFs are correctly attached to their members and vice versa. rrbondrbridgevrfr%Nr8missing_bond_linkmissing_bridge_linkmissing_vrf_linkmissing_interfaces)r)r*r9r() rr2r:rQrrrr%systemnetplanmissing_systemmissing_netplans rrGz&NetplanDiffState._analyze_parent_links{s EJJL!!$ >2.226:FJJXZ<[<_<_`f ?\^@_@c@cdl@mnzz."-11%8&**_VX:Y:]:]^c:dejj488rJFJJWfhjLkLoLop|AMBC D$< DGtAw$6AwDHGd O,-@AAwCG7d N+,?@ dD\ !fQi6!9&<ayFLQid O,-BCayEKAYd N+,AB 4, 3q6SV#31vCFq6d O,-?@1vBEa&d N+,>? "b !A'F*Q-(G %,v%55>5HL^H\E$K/0DE&,w&66?6IMoI^E$K01EF7 ! "rr{ct}|D]}|jtjk(r|j d|_|j |j |_|j |j|_|j |j|_|j dk7r5|j jd}|ddk(s|ddk(r |d|_|j||S)zo Apply some transformations to Netplan routes so their representation will match the system's. mainrrur832128r) r(tabler_TABLE_UNSPEC_$_default_route_tables_name_to_numberrqr from_addrrsplitrb)rr{new_routes_setr ip_prefixs rrz"NetplanDiffState._normalize_routess &E{{l999"GGO 22588EIxx9$!HHNN3/ Q<4'9Q<5+@(|EH   u %# &&rrrc|Dcgc]*}ttj|j,}}t t d|}|Dcgc]*}ttj|j ,}}|jdijdg}t}|D]} | jdk(r9| jdk7r*tj| jjsL| jdk(s| jdk(rk| jdk7rStj| j} | jr(| jdk(rd |vr| jd k(rd |vr| jd k(rH| jd k(r9| j|vs)tj| jjr$| jdk(r | jdk(r| jdk(rS| jdk(r| j|vs| j|vr|j!| |Scc}wcc}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 |dk7S)Nz fe80::/64r)ns rr;z8NetplanDiffState._filter_system_routes..s qK/?rrrVrYrrXr| r[rZhostlocal multicastzff00::/8)rwr`ranetworkr)rrdr9r(scoperrcr~familyr is_loopbackrb) rrrr2rdlocal_networksrSrVr{rroute_tos rrz&NetplanDiffState._filter_system_routessM]]b#i44R8@@A]]f%?PQBRSBS//3667S SZZ488rJ " E{{f$Y)>yG]G]^c^f^fGgGuGu~~'5>>T+Axx9$$11%((;))||r)f .B ||q(Vz-A  v%%***?XX*i.D.DUXX.N.Z.Z||r!ejjK&?EHHPZDZ||r!uxx>'AUXXQZEZ JJu A B O^Ts /I/I c|jj}i}|jjj D]0\}}i}dd|ii||<||d}t j |jd|d<|j|d<|j|d<|j|d<|jDcgc]}|}}|rWi|d<|D]M}i} |jr|j| d <|jr|j| d <d | i|dt|<Ot|j x} r| |d <t|j"x} r| |d <t|j$x} r| |d<|j&x} r| |d<|j(j dx}r|j*|d<|j(j dx}r|j*|d<|j(j dx}r|j*|d<||vrUd}|j D])\}}|j dx}s||k(s d}||||<+|r |j-| |j-|3|j/||Scc}w)Nrr5rrrTrUrVrSlabellifetimerWrzrr{rrrrFT)rrrrr+rr9rrTrUrVrSrrrwr)nameserver_addressesnameserver_searchr{rlinksr5r,_netplan_state_find_parents)rr.r%r1r2r: iface_refrjrSrW nameserverssearchr{macrrr found_somer=valuerKs rr'z(NetplanDiffState._get_netplan_interfacess --668 !%!3!3!;!;!A!A!CA ) IvE /$ 1BCE) i(9I , 0 0g FIf !'Ig !'Ig &,&7&7Il #*0*:*:;$;I;)+ +&%IDEzz)-g}},0MMj)9@%8HIk*3t95 I#6#>#>??{?5@ 12f6677v728 ./fmm,,v,&, (#'''s'*- ,'))(33v3&,ii (#||''//t/$(GG &!ll&&u--s-#&66 %  11# "3"9"9";?JC$)IIdO3y3$ 1)-J.3I.>JsO ?"%%e,!!%(CA )F ((4oG 9%n5d;"9-n=I 7++u+%* '"I ;3 P$))+&q)"))(3!d!F8, (/"1A1A'21N'O )$  P )2 +&$jj99{95@ 12L11v128 ./H--v-Y_&`PUt'D'DU'K&` (#jj..s.*- ,'$*JJ|$<< <*; ,'zz&))t)$( &!H--v-&, (#jj''s'#& % _/ 'b#'as G= system_routeci}|jdx}r||d<|jdx}r||d<|jdx}r||d<|jdx}r||d<|jdx}r||d<|jdx}r||d<|jdx} r| |d<|jd x} r| |d <|jd x} r|j| |d <td i|S) Nrrrfromrmetricrrr~rr)r9rr) rrrrrrrrr route_typer~rs rrz)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 -!FFuME'N$e$$rrQc|jr t|S|jst|_|jj |dS)Nr)isdigitintr!r r9)rrQs rrz5NetplanDiffState._default_route_tables_name_to_numbersB <<>t9 ,,,>,@D ),,00q99r))#rrr__doc__rrr"rHr3rwrLr?rrArBr>r(r_rqrCrDrErFr@rGrrrr)rr'rr&rrrrrrr%s +%6+GY+ 4'#'t'R D   3  3  s  t  3D33$3jTd,    c c )4)))Vd4D0T$4&d4D.!$!3!4!F&_D&_&_$&_P40;|3L0`deh`i0sw0|0dGGR Qd Qt Q44l%T%l%0:::rr) collectionsrr`rtypingrnetplan.netdefrnetplan_cli.cli.staterrrnetplan_cli.cli.utilsr r rr rrrrrs=$$ 'UUI3d&&3v :v :r