
    i_                        d dl Z d dlmZ d dlmZmZmZmZmZm	Z	 d dl
mZmZ d dlmZmZ d dlmZ  e j$                  e      Zdeeee   f   deeee   f   fd	Zdedefd
Z G d d      Z G d dej2                        ZddZy)    N)defaultdict)AnyCallableDictListOptionalTuple)subputil)renderershould_add_gateway_onlink_flag)NetworkStatedatareturnc                 V    i }| j                         D ]  \  }}t        |      ||<    |S )z
    Normalize a dictionary of lists.
    - Assumes top-level keys map to lists.
    - Each list and any nested dicts/lists will be recursively normalized.
    )items_normalize_value)r   
normalizedkeyvalues       8/usr/lib/python3/dist-packages/cloudinit/net/networkd.py	normalizer      s6     Jjjl 2
U*51
32    c                 F   t        | t              r%i }t        |       D ]  }t        | |         ||<    |S t        | t              rJg }| D ]7  }t        |t        t        f      rt        |      }n|}|j                  |       9 	 t        |      S | S # t        $ r |cY S w xY w)z
    Recursively normalize a dictionary or list:
    - Dicts: keys sorted, values normalized
    - Lists: items normalized and sorted (if comparable)
    )
isinstancedictsortedr   listappend	TypeError)r   r   r   normalized_itemsitemnormalized_items         r   r   r      s     $
$< 	:C.tCy9JsO	:	D$	 	5D$t-"24"8"&##O4	5	$*++ K  	$##	$s   
B B B c                   $    e Zd Zd Zd Zd Zd Zy)	CfgParserc                 ,    g g g g g g i g g g g i d| _         y )N)MatchLinkNetworkDHCPv4DHCPv6AddressRouteNetDevVLANBondBridgeRoutingPolicyRule)	conf_dict)selfs    r   __init__zCfgParser.__init__:   s/    !#
r   c                 >   | j                   j                         D ]  }||k(  s	| j                   |   j                  | d|        t        t        j                  | j                   |               | j                   |<   | j                   |   j                           y )N=r3   keysr   r   r   fromkeyssort)r4   secr   valks        r   update_sectionzCfgParser.update_sectionJ   s    $$& 	)ACxq!((C5#8$(t~~a7H)I$Jq!q!&&(		)r   c                    | j                   j                         D ]  }||k(  s	|| j                   |   vrg | j                   |   |<   | j                   |   |   j                  | d|        t        t        j                  | j                   |   |               | j                   |   |<   | j                   |   |   j                           y)z
        For each route section we use rid as a key, this allows us to isolate
        this route from others on subsequent calls.
        r7   Nr8   )r4   r<   ridr   r=   r>   s         r   update_route_sectionzCfgParser.update_route_sectionQ   s    
 $$& 		.ACxdnnQ//-/DNN1%c*q!#&--Qsen=)-MM$.."3C"89*q!#& q!#&++-		.r   c                    d}t        | j                        | _        t        | j                  j                               D ]  \  }}|s	|dk(  rt        |      D ]  }|d| d| dz  } +|dv r:t        |      D ]+  }|d| dz  }t        ||         D ]
  }|| dz  } |dz  }- i|d| dz  }t        |      D ]
  }|| dz  } |dz  } |S )N r,   [z]


)r-   r2   
)r   r3   r   r   )r4   contentsr>   vens         r   get_final_confzCfgParser.get_final_confa   s   "4>>24>>//12 	!DAqI~ 2A!A3c!D 11H244 %A!A3c
*H#AaD\ - qcH,-$H	% as#J& )A1#R(H)D !	!$ r   N)__name__
__module____qualname__r5   r?   rB   rL    r   r   r%   r%   9   s    
 ). r   r%   c                       e Zd ZdZddZdefdZdefdZdefdZdefdZ	defd	Z
ded
efdZdefdZddZ	 	 ddedee   ddfdZdefdZdefdZd
efdZd
edefdZd
edefdZd
edefdZy)Rendererz
    Renders network information in /etc/systemd/network

    This Renderer is currently experimental and doesn't support all the
    use cases supported by the other renderers yet.
    Nc                 h    |si }|j                  dd      | _        |j                  dd      | _        y )Nresolve_conf_fnz/etc/systemd/resolved.confnetwork_conf_dirz/etc/systemd/network/)getrT   rU   )r4   configs     r   r5   zRenderer.__init__   s:    F%zz; 
 !'

 7!
r   cfgc                     d}ddd}|d   dk(  rd|d<   |sy |j                         D ]&  \  }}||v s||   s|j                  ||||          ( |d	   S )
Nr'   NameDriver)namedrivertypephysical
MACAddressmac_addressr\   )r   r?   )r4   ifacerX   r<   
match_dictr>   rI   s          r   generate_match_sectionzRenderer.generate_match_section   s}    


 =J&(4J}%$$& 	5DAqEzeAh""3584	5 V}r   c                     d}|sy |j                  d      r|j                  |d|d          |d   dk7  r'|j                  d      r|j                  |d|d          d|v r|d   r|j                  |d	d
       y y y )Nr(   mtuMTUBytesr^   r_   ra   r`   optionalRequiredForOnlineno)rV   r?   )r4   rb   rX   r<   s       r   generate_link_sectionzRenderer.generate_link_section   s    99UsJe==J&599]+CsL%2FG5#4s$7> $5r   c                     d}ddddd}d}d|v rd	|d    }|j                         D ]+  \  }}||vr|d
k(  r||z  }|j                  ||||   |       - y)zy
        Parse a route and use rid as a key in order to isolate the route from
        others in the route dict.
        r-   GatewayDestinationMetricTable)gatewaynetworkmetrictablerD   prefix/rr   N)r   rB   )	r4   rA   confrX   r<   route_cfg_mapru   r>   rI   s	            r   parse_routeszRenderer.parse_routes   s    
  $	
 th()FJJL 	DDAq%I~V$$S#}Q/?C	Dr   c           	      P   d}d}d}|j                  dg       D ];  }|d   }|dv r|dk(  rd}n|dk(  rd	}n|d
k(  r|dk(  rd}n|dk(  rd	}d|v r*|d   r%|d   D ]  }| j                  d| ||       |dz   } d|v sd|d   }	d|v r|	d|d    z  }	ddddd}
|j                         D ]  \  }}|dk(  r|j                  d|
|   |	       "|dk(  rZ|j	                  dd| |
|   |       t        ||	      r.t        j                  d||	       |j	                  dd| dd	       |dz   }|dv s|j                  ||
|   dj                  |              > |j                  |d|       t        |j                  d      t              rd}|d   rd	}|j                  |d|       |S ) Nrj   r)   r   subnetsr^   >   dhcpdhcp4ipv4ipv6yesdhcp6routesr   addressru   rv   r,   rm   DNSDomains)r   rq   dns_nameservers
dns_searchrq   r-   azGGateway %s is not contained within subnet %s, adding GatewayOnLink flagGatewayOnLink>   r   r    DHCPz	accept-raIPv6AcceptRA)rV   ry   r   r?   rB   r   LOGdebugjoinr   bool)r4   rb   rX   r|   r<   rA   rJ   tiaddrsubnet_cfg_mapr>   rI   r=   s                 r   parse_subnetszRenderer.parse_subnets   s&   9b) 1	PA&	A%%4<!DV^ Dg4<!DV^ D1}88 "A %%#iC8'C	"
 A~|q=a(}--D((',"+	" GGI PDAqI~**9nQ6GNi 00#qYq0A1 :!TBII!= ! $	  44 '1SEOU "Ag??**3q0A388A;O+P91	Pf 	3-eii,d3C[!sNC8r   c                    dD ]\  }||vrt        ||         j                         }	 t        j                  |      }|rdnd}|dk(  rd}nd}|j                  |d	|       ^ y # t        $ r  |dk7  rt
        j                  d|       d}Y Hw xY w)
N)dhcp4domaindhcp6domainr   rj   routezInvalid dhcp4domain value - %sr   r*   r+   
UseDomains)strcasefoldr   translate_bool
ValueErrorr   warningr?   )r4   drX   r"   retsections         r   dhcp_domainzRenderer.dhcp_domain
  s    2 	;D1}ag,'')C))#."e
 }$""wc:	;  '>KK @#FCs   A##&BBnsc                 ~   d}|j                  d      }|s)|j                  dk(  r|j                  |j                  d}n|s|j                  dk(  ry |j                  d      r%|j	                  |ddj                  |d                |j                  d	      r&|j	                  |d
dj                  |d	                y y )Nr)   dnsr   )searchnameservers   r   r   r   r   r   )rV   versiondns_searchdomainsr   r?   r   )r4   rb   rX   r   r<   r   s         r   	parse_dnszRenderer.parse_dns  s    iirzzQ..!11C q778sIsxxH/FG77=!sE388C4F+GH "r   c                     ddddd}|dk(  r|j                  ddd	d
dd       d| d|v rJ|dd| fv r@|d| d   }|j                         D ]#  \  }}||v s|j                  d| |||          % y y y )Nzuse-dnsuse-domainszuse-hostnamezuse-ntp)UseDNSr   UseHostnameUseNTP4zsend-hostnamehostnamezroute-metriczuse-mtuz
use-routes)SendHostnameHostnameRouteMetricUseMTU	UseRoutesr|   
-overridesr   ipvDHCPv)updater   r?   )	r4   rX   devicer|   r   dhcp_config_mapsdhcp_overridesr>   rI   s	            r   parse_dhcp_overrideszRenderer.parse_dhcp_overrides-  s    ')	
 c>##$3 *#1'!- '*%/D'O=
 5
 $d7):$>?N(..0 P1&&&wi'8!^A=NOP5
/r   c                     d}t         j                  d|       | d| | }|j                  d      r|d d }t        j                  ||       t        j
                  |||       y )Nzsystemd-networkz Setting Networking Config for %sz10-cloud-init-rF   )r   r   endswithr   
write_filechownbyname)r4   linkrw   nwk_dirextnet_fn_ownernet_fns          r   create_network_filezRenderer.create_network_fileI  sa    (		4d;9N4&6== 9D%|<r   network_state	templatesr   c                 l   | j                   }|rt        j                  |      |z   }t        j                  |       | j                  |      }|j                  di       }|j                  di       }|j                  di       }|j                         D ]  \  }	}
| j                  |	|
|        |j                         D ]  \  }	}
| j                  |	|
|d        |j                         D ]  \  }	}
| j                  |	|
|d        |j                         D ]  \  }	}
| j                  |	|
|d        y )Nvlan_netdevbond_netdevbridge_netdevz.netdev)r   )	rU   r
   target_pathr   
ensure_dir_render_contentpopr   r   )r4   r   r   targetnetwork_dirrr   r   r   r   r>   rI   s              r   render_network_statezRenderer.render_network_stateT  sC    ++**62[@K$&&}5kk-4kk-4OR8MMO 	8DAq$$Q;7	8  %%' 	GDAq$$Q;I$F	G  %%' 	GDAq$$Q;I$F	G "'') 	GDAq$$Q;I$F	Gr   c                     d}d}|D ]A  }|j                         D ]'  \  }}|j                  |||j                         |       ) |dz  }C y )Nr   r2   r   )r   rB   
capitalize)r4   policyrX   rA   r   r=   r>   rI   s           r   parseRoutingPolicyzRenderer.parseRoutingPolicyq  sY    ! 	C		 F1((c1<<>1EF1HC	r   nsCfgc                 v    i }d}dD ]/  }||vr||   j                         D ]  \  }}||v s||   ||<    1 |S )Nzrouting-policy)	ethernetsbondsvlansbridges)r   )r4   r   routingPoliciesr   r   rb   settingss          r   extractRoutingPolicieszRenderer.extractRoutingPoliciesy  sc    A 	;Ge##(>#7#7#9 ;x(?-5c]OE*;	; r   c                 Z   i }| j                  |      }|d   }|d   }||d<   | j                  |      }|d   }|d   }||d<   | j                  |      }	|	d   }
|	d   }|
|d<   | j                  |j                        }|j                         D ]  }t               }|d   }|j                  |g       }|D ]  }|j                  dd	|        |j                  |      }|r| j                  ||       |j                  |      }|r|j                  dd
|       |j                  |      }|r|d   j                  |i       j                  |      }|r|j                  dd|       |d   j                  |i       j                  |      }|r|j                  dd|       |j                  dd|       | j                  ||      }| j                  ||       | j                  ||      }| j                  |||       d}|j                         D ]  }| j                  d| ||       |dz   } |j                   dk(  r|d   }|j                  d   j#                         D ]"  \  }}d|v s|j                  d      |k(  s |} n ||j                  d   v ru|j                  d   |   }| j%                  ||       dD ]L  }d| d|v r.d|j                  d| di       v r| d| d| d}t'        |      | j)                  ||||       N |j+                  ||j-                         i        |S )Nr   	vlan_linkr   	bond_linkr   bridge_linkr\   r)   r/   r0   	path-costr1   Costport-priorityPriorityr   cr   r   r   zset-name)r   6r|   domainr   r   z has both dhcpzdomain and dhcpz*-overrides.use-domains configured. Use one)render_vlansrender_bondsrender_bridgesr   rW   iter_interfacesr%   rV   r?   r   rd   rk   r   r   iter_routesry   r   r   r   RuntimeErrorr   r   rL   ) r4   r   ret_dict	vlan_dictr   r   	bond_dictr   r   bridge_dictr   r   r   rb   rX   
iface_namevlan_link_namer   rPolicybond_link_namebridge_link_namer=   r   r|   rA   r   r\   dev_namedev_cfgr   r   	exceptions                                    r   r   zRenderer._render_content  s   %%b)	.k*	"-%%b)	.k*	"-))"-#O4!-0$1!55bii@'') W	:E+CvJ&]]:r:N# 9""9fa89 &))*5G''5&]]:6N""9fnE*z:,S)2.S_ 
 &&x=  0S)2.S_ 
 &&xSA""9h8HI..uc:D&&uc2%%eS1DNN5#r*C)  !!AcU)UC8Ag	 zzQ&+Fm *,;)?)E)E)G "%Hg!W,";;z2d:#+D!	"
 299[11YY{3D9F $$VS1#- N"7)62f< -%zzD	*DbI!J $(&wi @,,39 57!8 &
 #/y"9911#vtWMN OOT3#5#5#789oW	:r r   c                    t        t              }i }t        j                  d      }|j	                  |      D ]	  }|d   }|j                  d      }|j                  d      }||t        j                  d|       F||   j                  |       t               }	|	j                  dd|       |	j                  ddd       |j                  d	      }
|
r|	j                  dd
|
       |j                  d      }
|
r!|	j                  dd|
j                                |	j                  dd|       |	j                         ||<    ||dS )Nvlanr\   vlan_idzvlan-raw-devicez)Skipping VLAN %s - missing 'id' or 'link'r.   rZ   Kindrf   rg   ra   r`   r/   Id)r   r   )r   r   r   filter_by_typer   rV   r   r   r   r%   r?   lowerrL   )r4   r   vlan_link_infovlan_ndev_configsvlan_filterrb   r   r  parentrX   r=   s              r   r   zRenderer.render_vlans  sG   $T*--f5''4 	AEvJii	*GYY01F&.? 6"))*5 +Cx<x8))E"C""8Z=))M*C""8\399;GvtW5,/,>,>,@j)7	A< -'
 	
r   c           
          i }i }d}t        j                  d      }t        j                  d      }|j                  |      D ];  }|d   }|j                  |      D 	cg c]  }	|	d   |k(  r|	d    }
}	|
st        j                  d|       K|j                  |
D ci c]  }|| c}       t               }|j                  dd|       |j                  ddd       j                  d	      }|r|j                  dd
|       |j                  d      }|r!|j                  dd|j                                t        t        t        t        t        t        gt        f   f   f   }i ddt        fddd fddt        fddd fddt        fddt        fddd fddt        fd d!t        fd"d#t        fd$d%t        fd&d'd( fd)d*t        fd+d,d- fd.d/t        fd0d1t        fd2d3t        f}|j!                         D ])  \  }\  }}||v s|j                  || |||                + d4|v r:|d4   }t#        |t              r|g}|j                  |d5d6j%                  |             |j'                         ||<   > ||d7S c c}	w c c}w )8Nr0   bondzbond-masterr\   z'Skipping bond %s - missing 'interfaces'r.   rZ   r  rf   rg   ra   r`   zbond-ad-selectAdSelectzbond-arp-intervalARPIntervalSecc                     |  dS NmsrP   rI   s    r   <lambda>z'Renderer.render_bonds.<locals>.<lambda>C  s    QCr( r   zbond-arp-validateARPValidatezbond-downdelayDownDelaySecc                     |  dS r  rP   r  s    r   r  z'Renderer.render_bonds.<locals>.<lambda>E  s    s"X r   zbond-fail-over-macFailOverMACPolicyzbond-lacp-rateLACPTransmitRatezbond-miimonMIIMonitorSecc                     |  dS r  rP   r  s    r   r  z'Renderer.render_bonds.<locals>.<lambda>H  s    aS8 r   zbond-min-linksMinLinksz	bond-modeModezbond-num-grat-arpGratuitousARPzbond-primary-reselectPrimaryReselectPolicyzbond-updelay
UpDelaySecc                     |  dS r  rP   r  s    r   r  z'Renderer.render_bonds.<locals>.<lambda>M  s    A3b r   zbond-xmit-hash-policyTransmitHashPolicyzbond-all-slaves-activeAllSlavesActivec                 4    t        |       j                         S N)r   r  r  s    r   r  z'Renderer.render_bonds.<locals>.<lambda>Q  s    c!flln r   zbond-arp-all-targetsARPAllTargetszbond-learn-packet-intervalLearnPacketIntervalSeczbond-packets-per-slavePacketsPerSlavezarp-ip-targetsARPIPTargetsr   )r   r   )r   r
  filter_by_attrr   r   r   r   r%   r?   rV   r  r   r   r	   r   objectr   r   r   rL   )r4   r   bond_link_infobond_ndev_configsr   bond_filterslave_filterrb   r   slave_ifacebond_slavesrX   r=   ParamMapType	param_mapr   option	formattertargetss                      r   r   zRenderer.render_bonds  sZ   )+--f5..}=''4 @	AEvJ $&#5#5l#C}-; F#K 
 =z !!+"N5*#4"NO +Cx<x8))E"C""8Z=))M*C""8\399;G  U3&30G+G%H HIL' :s"3'#&68J%K' $mS%9' !>3E"F	'
 %':C&@' !#5s";' 1CD' !:s"3' fc]' $os%;' (*A3)G' /A B' (*>)D' )%,+'$ '#(>%'& -/G.M''( )+<c*B)'I. -6OO,= O((fi%<&&w	%*8MNO  5( 01gs+&iG""7NCHHW<MN,/,>,>,@j)A@	AF -'
 	
A #Os   J
J
c                 P   i i i d}i }t        j                  d      }|j                  |      D ]p  }|d   }|j                  dg       }|st        j                  d|       4|D ]  }|||<   	 t               }	|	j                  dd|       |	j                  ddd       |j                  d	      }
|
r|	j                  dd
|
       |j                  d      }
|
r!|	j                  dd|
j                                ddddddd}|j                         D ]B  \  }}|j                  |      }
|
st        |
t              r|
rdnd}
|	j                  d||
       D |j                  d      }
|
r|
|d   |<   |j                  d      }
|
r|
|d   |<   |	j                         ||<   s ||dS )N)
macaddressr   r   bridger\   bridge_portsz)Skipping bridge %s - missing 'interfaces'r.   rZ   r  rf   rg   ra   r`   AgeingTimeSecr   ForwardDelaySecHelloTimeSec	MaxAgeSecSTP)bridge_ageingbridge_bridgeprio	bridge_fdbridge_hellobridge_maxage
bridge_stpr   rj   r1   bridge_pathcostr   bridge_portprior   )r   r   )r   r
  r   rV   r   r   r%   r?   r  r   r   r   rL   )r4   r   bridge_link_infobridge_ndev_configsbridge_filterrb   r   r>  bridge_portrX   r=   r7  r   sysd_keys                 r   r   zRenderer.render_bridgesi  s   ,
 ! //9''6 2	CEvJ 99^R8L?   , ;0: -; +Cx<x:))E"C""8Z=))M*C""8\399;G "1%/. .!,#I "+!2 @Xiin!#t,'*e&&x3?@ ))-.C<? -j9))-.C@C 1*=.1.@.@.B
+e2	Cj 1+
 	
r   r)  )z.network)NN)rM   rN   rO   __doc__r5   r%   rd   rk   ry   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rP   r   r   rR   rR   {   s   
 &?	 ?D9 D2?	 ?D;) ;$II I< I"P	 P8	= %)	G#G D>G
 
G:i 
D 
m, m^%
| %
 %
NL
| L
 L
\A
 A
$ A
r   rR   c                 T    ddg}ddg}|D ]  }t        j                  ||      r y y)Nip	systemctlz	/usr/sbinz/bin)r   FT)r
   which)r   expectedr   ps       r   	availablerX    s;    k"H6"F zz!F+ r   r)  )loggingcollectionsr   typingr   r   r   r   r   r	   	cloudinitr
   r   cloudinit.netr   r   cloudinit.net.network_stater   	getLoggerrM   r   r   r   r   r%   rR   rX  rP   r   r   <module>r`     s     # = =   B 4g!	Dd3i( 	T#tCy.-A 	3 3 6? ?Do
x   o
dr   