o
    i_                     @   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 }|  |}|d }|d }||d< | |}|d }|d }||d< | |}	|	d }
|	d }|
|d< | |j}| D ]}t }|d }||g }|D ]	}|dd	| qQ||}|rh| 	|| ||}|rv|dd
| ||}|r|d |i |}|r|dd| |d |i |}|r|dd| |dd| | 
||}| || | ||}| ||| d}| D ]}| d| || |d }q|jdkrK|d }|jd  D ]\}}d|v r|d|kr|} nq||jd v rK|jd | }| || dD ]0}d| d|v rAd|d| di v rA| d| d| d}t|| |||| q||| i q?|S )Nr   	vlan_linkr   	bond_linkr   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)render_vlansrender_bondsrender_bridgesr   rL   iter_interfacesr!   rK   r9   r   rX   r^   r   r   iter_routesrk   r   r   r   RuntimeErrorr   r   rD   ) r/   r   ret_dict	vlan_dictr   r   	bond_dictr   r   bridge_dictr   r   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 }td}||D ]b}|d }|d}|d}|d u s(|d u r/td| q|| | t	 }	|	
dd| |	
ddd |d	}
|
rU|	
dd
|
 |d}
|
re|	
dd|
  |	
dd| |	 ||< q||dS )NvlanrP   vlan_idzvlan-raw-devicez)Skipping VLAN %s - missing 'id' or 'link'r)   rN   KindrY   rZ   rU   rT   r*   Id)r   r   )r   r   r   filter_by_typer   rK   r   r   r   r!   r9   lowerrD   )r/   r   vlan_link_infovlan_ndev_configsvlan_filterrV   r   r   parentrM   r7   r   r   r   r     s6   




zRenderer.render_vlansc              	      s<  i }i }d}t d}t d}||D ]}|d   fdd||D }|s1td  q| fdd	|D  t }	|	d
d  |	d
dd |	d}
|
r\|	d
d|
 |	d}
|
rl|	d
d|

  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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d0d1d2d fd3d4tfd5d6tfd7d8tf}| D ]\}\}}||v r|	|||||  qd9|v r|d9 }t|tr|g}|	|d:d;| |	 | < q||d<S )=Nr+   bondbond-masterrP   c                    s    g | ]}|d   kr|d qS )r   rP   r   ).0slave_ifacer   r   r   
<listcomp>$  s
    z)Renderer.render_bonds.<locals>.<listcomp>z'Skipping bond %s - missing 'interfaces'c                    s   i | ]}| qS r   r   )r   rV   r   r   r   
<dictcomp>/  s    z)Renderer.render_bonds.<locals>.<dictcomp>r)   rN   r   rY   rZ   rU   rT   zbond-ad-selectAdSelectzbond-arp-intervalARPIntervalSecc                 S   
   |  dS Nmsr   rA   r   r   r   <lambda>C     
 z'Renderer.render_bonds.<locals>.<lambda>zbond-arp-validateARPValidatezbond-downdelayDownDelaySecc                 S   r  r  r   r  r   r   r   r  E  r  zbond-fail-over-macFailOverMACPolicyzbond-lacp-rateLACPTransmitRatezbond-miimonMIIMonitorSecc                 S   r  r  r   r  r   r   r   r  H  r  zbond-min-linksMinLinksz	bond-modeModezbond-num-grat-arpGratuitousARPzbond-primary-reselectPrimaryReselectPolicyzbond-updelay
UpDelaySecc                 S   r  r  r   r  r   r   r   r  M  r  zbond-xmit-hash-policyTransmitHashPolicyzbond-all-slaves-activeAllSlavesActivec                 S   s   t |  S N)r   r   r  r   r   r   r  Q  s    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!   r9   rK   r   r   r   r   r   objectr   r   r   rD   )r/   r   bond_link_infobond_ndev_configsr   bond_filterslave_filterrV   bond_slavesrM   r7   ParamMapType	param_mapr   option	formattertargetsr   r   r   r     s   




	

zRenderer.render_bondsc                 C   s`  i i i d}i }t d}||D ]}|d }|dg }|s'td| q|D ]}|||< q)t }	|	dd| |	ddd |d	}
|
rO|	dd
|
 |d}
|
r_|	dd|
  ddddddd}|	 D ]\}}||}
|
rt
|
tr|
rdnd}
|	d||
 ql|d}
|
r|
|d |< |d}
|
r|
|d |< |	 ||< q||dS )N)
macaddressr   r   bridgerP   bridge_portsz)Skipping bridge %s - missing 'interfaces'r)   rN   r   rY   rZ   rU   rT   AgeingTimeSecr   ForwardDelaySecHelloTimeSec	MaxAgeSecSTP)bridge_ageingbridge_bridgeprio	bridge_fdbridge_hellobridge_maxage
bridge_stprq   r]   r,   bridge_pathcostr   bridge_portprior   )r   r   )r   r   r   rK   r   r   r!   r9   r   r   r   r   rD   )r/   r   bridge_link_infobridge_ndev_configsbridge_filterrV   r   r'  bridge_portrM   r7   r!  r   sysd_keyr   r   r   r   i  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

o'NrH   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   r@  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   r@  r   r   r   r   <module>   s     
*B    6