o
    th_                     @   s   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 eZdeeee f deeee f fd	d
ZdedefddZG dd dZG dd dejZdddZdS )    N)defaultdict)AnyCallableDictListOptionalTuple)subputil)renderershould_add_gateway_onlink_flag)NetworkStatedatareturnc                 C   s&   i }|   D ]
\}}t|||< q|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value r   8/usr/lib/python3/dist-packages/cloudinit/net/networkd.py	normalize   s   r   c                 C   s   t | tri }t| D ]
}t| | ||< q|S t | trHg }| D ]}t |ttfr/t|}n|}|| q!zt|W S  tyG   | Y S w | S )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_itemr   r   r   r      s$   



r   c                   @   s,   e Zd Zdd Zdd Zdd Zdd Zd	S )
	CfgParserc                 C   s$   g g g g g g i g g g g i d| _ d S )N)MatchLinkNetworkDHCPv4DHCPv6AddressRouteNetDevVLANBondBridgeRoutingPolicyRule)	conf_dict)selfr   r   r   __init__:   s   zCfgParser.__init__c                 C   s^   | j  D ]'}||kr,| j | | d|  tt| j | | j |< | j |   qd S )N=r.   keysr   r   r   fromkeyssort)r/   secr   valkr   r   r   update_sectionJ   s   zCfgParser.update_sectionc                 C   s   | j  D ]=}||krB|| j | vrg | j | |< | j | | | d|  tt| j | | | j | |< | j | |   qdS )z
        For each route section we use rid as a key, this allows us to isolate
        this route from others on subsequent calls.
        r1   Nr2   )r/   r6   ridr   r7   r8   r   r   r   update_route_sectionQ   s   zCfgParser.update_route_sectionc                 C   s   d}t | j| _t| j D ]`\}}|sq|dkr-t|D ]}|d| d| d7 }qq|dv rUt|D ]}|d| d7 }t|| D ]	}|| d7 }qE|d7 }q5q|d| d7 }t|D ]	}|| d7 }qa|d7 }q|S )N r'   [z]


)r(   r-   
)r   r.   r   r   )r/   contentsr8   venr   r   r   get_final_confa   s*   

zCfgParser.get_final_confN)__name__
__module____qualname__r0   r9   r;   rD   r   r   r   r   r!   9   s
    r!   c                   @   s
  e Zd ZdZd*ddZdefddZdefdd	Zdefd
dZdefddZ	defddZ
dedefddZdefddZd+ddZ		d,dedee ddfddZdefddZdefd d!Zdefd"d#Zdedefd$d%Zdedefd&d'Zdedefd(d)ZdS )-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                 C   s(   |si }| dd| _| dd| _d S )Nresolve_conf_fnz/etc/systemd/resolved.confnetwork_conf_dirz/etc/systemd/network/)getrI   rJ   )r/   configr   r   r   r0      s   
zRenderer.__init__cfgc                 C   sf   d}ddd}|d dkrd|d< |sd S |  D ]\}}||v r.|| r.|||||  q|d	 S )
Nr"   NameDriver)namedrivertypephysical
MACAddressmac_addressrP   )r   r9   )r/   ifacerM   r6   
match_dictr8   rA   r   r   r   generate_match_section   s   zRenderer.generate_match_sectionc                 C   sz   d}|sd S | dr||d|d  |d dkr(| dr(||d|d  d|v r9|d r;||d	d
 d S d S d S )Nr#   mtuMTUBytesrR   rS   rU   rT   optionalRequiredForOnlineno)rK   r9   )r/   rV   rM   r6   r   r   r   generate_link_section   s   
zRenderer.generate_link_sectionc           	      C   sp   d}ddddd}d}d|v rd	|d  }|  D ]\}}||vr#q|d
kr+||7 }||||| | qdS )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tabler<   prefix/rd   N)r   r;   )	r/   r:   confrM   r6   route_cfg_maprg   r8   rA   r   r   r   parse_routes   s    zRenderer.parse_routesc              	   C   s  d}d}d}| dg D ]}|d }|dv r$|dkrd}n|dkr#d	}n|d
kr5|dkr/d}n|dkr5d	}d|v rR|d rR|d D ]}| d| || |d }qAd|v r|d }	d|v rg|	d|d  7 }	ddddd}
| D ]O\}}|dkr|d|
| |	 qr|dkr|dd| |
| | t||	rtd||	 |dd| dd	 |d }qr|dv r|||
| d| qrq||d| t	| dt
rd}|d rd	}||d| |S ) Nr]   r$   r   subnetsrR   >   dhcpdhcp4ipv4ipv6yesdhcp6routesr   addressrg   rh   r'   r_   DNSDomains)rv   rc   dns_nameservers
dns_searchrc   r(   azGGateway %s is not contained within subnet %s, adding GatewayOnLink flagGatewayOnLink>   rz   ry    DHCPz	accept-raIPv6AcceptRA)rK   rk   r   r9   r;   r   LOGdebugjoinr   bool)r/   rV   rM   rm   r6   r:   rB   tiaddrsubnet_cfg_mapr8   rA   r7   r   r   r   parse_subnets   sp   


zRenderer.parse_subnetsc              	   C   s   dD ]B}||vr	qt ||  }zt|}|rdnd}W n ty3   |dkr1td| d}Y nw |dkr;d}nd}||d	| qd S )
N)dhcp4domaindhcp6domainrq   r]   routezInvalid dhcp4domain value - %sr   r%   r&   
UseDomains)strcasefoldr
   translate_bool
ValueErrorr   warningr9   )r/   drM   r   retsectionr   r   r   dhcp_domain
  s$   
zRenderer.dhcp_domainnsc                 C   s   d}| d}|s|jdkr|j|jd}n	|s|jdkrd S | dr0||dd|d  | d	rC||d
d|d	  d S d S )Nr$   dnsru   )searchnameservers   r   rx   r}   r   rw   )rK   versiondns_searchdomainsry   r9   r   )r/   rV   rM   r   r6   r   r   r   r   	parse_dns  s   


zRenderer.parse_dnsc           	      C   s   ddddd}|dkr| ddd	d
dd d| d|v rH|dd| fv rJ|d| d }| D ]\}}||v rG|d| |||  q3d S d S d S )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	UseRoutesrm   
-overridesrq   ipvDHCPv)updater   r9   )	r/   rM   devicerm   r   dhcp_config_mapsdhcp_overridesr8   rA   r   r   r   parse_dhcp_overrides-  s2   
zRenderer.parse_dhcp_overrides.networkc                 C   sV   d}t d| | d| | }|dr|d d }t|| t||| d S )Nzsystemd-networkz Setting Networking Config for %sz10-cloud-init-r>   )r   r   endswithr
   
write_filechownbyname)r/   linkri   nwk_dirextnet_fn_ownernet_fnr   r   r   create_network_fileI  s   
zRenderer.create_network_filenetwork_state	templatesr   c                 C   s   | j }|rt|| }t| | |}|di }|di }|di }| D ]\}	}
| |	|
| q,| D ]\}	}
| j|	|
|dd q<| D ]\}	}
| j|	|
|dd qN| D ]\}	}
| j|	|
|dd q`d S )Nvlan_netdevbond_netdevbridge_netdevz.netdev)r   )	rJ   r	   target_pathr
   
ensure_dir_render_contentpopr   r   )r/   r   r   targetnetwork_dirrd   r   r   r   r8   rA   r   r   r   render_network_stateT  s"   

zRenderer.render_network_statec                 C   sD   d}d}|D ]}|  D ]\}}|||| | q|d7 }qd S )Nr   r-   ru   )r   r;   
capitalize)r/   policyrM   r:   r   r7   r8   rA   r   r   r   parseRoutingPolicyq  s   
zRenderer.parseRoutingPolicynsCfgc                 C   sJ   i }d}dD ]}||vrq||   D ]\}}||v r!|| ||< qq|S )Nzrouting-policy)	ethernetsbondsvlansbridges)r   )r/   r   routingPoliciesr   r   rV   settingsr   r   r   extractRoutingPoliciesy  s   zRenderer.extractRoutingPoliciesc                  C   s  i }i }i }i }d|j v r| |}|d }|d }||d< d|j v r4| |}|d }	|d }|	|d< d|j v rJ| |}
|
d }|
d	 }||d< | |j }| D ]}t }|d
 }||g }|D ]	}|dd| qf||}|r}| 	|| ||}|r|dd| ||}|r|d |i |}|r|dd| |d |i |}|r|dd| |dd| | 
||}| || | ||}| ||| d}| D ]}| d| || |d }q|jdkra|d
 }|j d  D ]\}}d|v r|d|kr|} nq||j d v ra|j d | }| || dD ]0}d| d|v rWd|d| di v rW| d| d| d }t|| |||| q0||| i qT|S )!Nr   r   	vlan_linkr   r   	bond_linkr   r   bridge_linkrP   r$   r*   r+   	path-costr,   Costport-priorityPriorityr   cru   r   r   zset-name)r   6rm   domainr   r   z has both dhcpzdomain and dhcpz*-overrides.use-domains configured. Use one)rL   render_vlansrender_bondsrender_bridgesr   iter_interfacesr!   rK   r9   r   rX   r^   r   r   iter_routesrk   r   r   r   RuntimeErrorr   r   rD   ) r/   r   ret_dictr   r   r   	vlan_dictr   	bond_dictr   bridge_dictr   r   rV   rM   
iface_namevlan_link_namer   rPolicybond_link_namebridge_link_namer7   r   rm   r:   r   rP   dev_namedev_cfgr   r   	exceptionr   r   r   r     s   











zRenderer._render_contentc                 C   s   t t}i }|jdi }| D ]`\}}|d}|d}|d u s'|d u r.td| q|| | t }	|		dd| |		ddd |d	}
|
rT|		dd
|
 |d}
|
rd|		dd|

  |		dd| |	 ||< q||dS )Nr   idr   z)Skipping VLAN %s - missing 'id' or 'link'r)   rN   KindvlanrY   rZ   
macaddressrT   r*   Id)r   r   )r   r   rL   rK   r   r   r   r   r!   r9   lowerrD   )r/   r   vlan_link_infovlan_ndev_configsr   	vlan_namevlan_cfgvlan_idparentrM   r7   r   r   r   r     s4   



zRenderer.render_vlansc              	      s*  i }i }d}|j di }| D ]\ }|d}|s#td  q| fdd|D  t }|dd  |dd	d
 |d}	|	rN|dd|	 |d}	|	r^|dd|	  |di }
t	t
tt
ttgt
f f f }i ddt
fdddd fddt
fdddd fddt
fdddd fd d!t
fd"d#t
fd$d%t
fd&d't
fd(d)d*d fd+d,t
fd-d.t
fd/d0t
fd1d2t
fd3d4t
fd5d6d7d f}| D ]\}\}}||
v r|||||
|  qd8|
v r	|
d8 }t|t
r|g}||d9d:| | | < q||d;S )<Nr+   r   
interfacesz'Skipping bond %s - missing 'interfaces'c                    s   i | ]}| qS r   r   ).0rV   	bond_namer   r   
<dictcomp>.  s    z)Renderer.render_bonds.<locals>.<dictcomp>r)   rN   r   bondrY   rZ   r   rT   
parametersz	ad-selectAdSelectzall-slaves-activeAllSlavesActivec                 S   s   t |  S N)r   r   rA   r   r   r   <lambda>F  s    z'Renderer.render_bonds.<locals>.<lambda>zarp-all-targetsARPAllTargetszarp-intervalARPIntervalSecc                 S   
   |  dS Nmsr   r  r   r   r   r  I     
 zarp-validateARPValidatez
down-delayDownDelaySecc                 S   r	  r
  r   r  r   r   r   r  K  r  zfail-over-mac-policyFailOverMACPolicyzgratuitous-arpGratuitousARPz	lacp-rateLACPTransmitRatezlearn-packet-intervalLearnPacketIntervalSeczmii-monitor-intervalMIIMonitorSecc                 S   r	  r
  r   r  r   r   r   r  P  r  z	min-linksMinLinksmodeModezpackets-per-slavePacketsPerSlavezprimary-reselect-policyPrimaryReselectPolicyztransmit-hash-policyTransmitHashPolicyzup-delay
UpDelaySecc                 S   r	  r
  r   r  r   r   r   r  V  r  zarp-ip-targetsARPIPTargetsr}   )r   r   )rL   rK   r   r   r   r   r!   r9   r   r   r   r   r   objectr   r   rD   )r/   r   bond_link_infobond_ndev_configsr   r   bond_cfgr   rM   r7   paramsParamMapType	param_mapr   option	formattertargetsr   r   r   r      s   


	


zRenderer.render_bondsc                 C   sj  i i i d}i }|j di }| D ]\}}|dg }|s&td| q|D ]}|||< q(t }	|	dd| |	ddd |d	}
|
rN|	dd
|
 |d}
|
r^|	dd|
  |di }ddddddd}| D ]\}}||}
|
rt|
t	r|
rdnd}
|	d||
 qq|d}
|
r|
|d |< |d}
|
r|
|d |< |	
 ||< q||dS )N)r   r   r   r   r   z)Skipping bridge %s - missing 'interfaces'r)   rN   r   bridgerY   rZ   r   rT   r  AgeingTimeSecForwardDelaySecHelloTimeSec	MaxAgeSecr   STP)zageing-timezforward-delayz
hello-timezmax-ageprioritystprq   r]   r,   r   r   )r   r   )rL   rK   r   r   r   r!   r9   r   r   r   rD   )r/   r   bridge_link_infobridge_ndev_configsr   bridge_name
bridge_cfgr   rV   rM   r7   r   r"  r   sysd_keyr   r   r   r   j  sb   






zRenderer.render_bridgesr  )r   )NN)rE   rF   rG   __doc__r0   r!   rX   r^   rk   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rH   {   s4    

B

u&JrH   c                 C   s2   ddg}ddg}|D ]}t j||ds dS q
dS )Nip	systemctlz	/usr/sbinz/bin)r   FT)r	   which)r   expectedr   pr   r   r   	available  s   r9  r  )loggingcollectionsr   typingr   r   r   r   r   r   	cloudinitr	   r
   cloudinit.netr   r   cloudinit.net.network_stater   	getLoggerrE   r   r   r   r   r!   rH   r9  r   r   r   r   <module>   s     
*B    7