U
    n¸gdíJ  ã                   @   sì   d dl Z d dlZd dlZd dlZd dlmZm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mZmZmZ d dlmZmZ dZe
 e¡Zd	d
„ Zdeedœdd„Zdd„ Zddd„ZG dd„ dej ƒZ ddd„Z!ddd„Z"dS )é    N)ÚOptionalÚcast)Úfeatures)Úlog)ÚsafeyamlÚsubpÚutil)ÚIPV6_DYNAMIC_TYPESÚSYS_CLASS_NETÚget_devicelistÚrendererÚsubnet_is_ipv6)ÚNET_CONFIG_TO_V2ÚNetworkStates4  # This is the initial network config.
# It can be overwritten by cloud-init or console-conf.
network:
    version: 2
    ethernets:
        all-en:
            match:
                name: "en*"
            dhcp4: true
        all-eth:
            match:
                name: "eth*"
            dhcp4: true
c                    s   t ‡ fdd„|  ¡ D ƒƒS )Nc                 3   s$   | ]\}}|  ˆ ¡r||fV  qd S )N)Ú
startswith)Ú.0ÚkeyÚvalue©Úmatch© ú7/usr/lib/python3/dist-packages/cloudinit/net/netplan.pyÚ	<genexpr>)   s   
þz,_get_params_dict_by_match.<locals>.<genexpr>)ÚdictÚitems)Úconfigr   r   r   r   Ú_get_params_dict_by_match(   s    þr   )r   Úentryc                 C   sr  d)dd„}|dkrg }g }g }g }g }|   dg ¡}	|	dkr>g }	|	D ]}
|
  d¡}| d¡r||dkrl|d7 }| |d	i¡ qB|tkr”| d
d	i¡ qB|dkrBd|
  d¡ }d|
krÄ|d|
  d¡ 7 }|
  d¡rx|
  d¡d|
d krèdnddœ}zDt |
d ¡}tj|dd}||kr2t d|
d |¡ d	|d< W n8 t	k
rl } zt 
d|
d ||¡ W 5 d}~X Y nX | |¡ d|
kr–|||
  dg ¡ƒ7 }d|
kr´|||
  dg ¡ƒ7 }d|
krîd}t|
ƒrÚd|krÚd}| ||
  d¡i¡ |
  dg ¡D ]X}d|  d ¡|  d¡f }|  d¡|dœ}d!|krF| d!|  d!d"¡i¡ | |¡ qú| |¡ qBd| krª|  d¡}|rž| d |kržt 
d#|| d |¡ n| d |d< t|ƒd$krÆ| d%|i¡ t|ƒd$krâ| d|i¡ t|ƒd$krd%|i}| d&|i¡ t|ƒd$kr<|  d&i ¡}| d'|i¡ | d&|i¡ d(| krn| d( dk	rn| d(t |   d(¡¡i¡ dS )*aÖ  This method parse a cloudinit.net.network_state dictionary (config) and
       maps netstate keys/values into a dictionary (entry) to represent
       netplan yaml. (config v1 -> netplan)

    An example config dictionary might look like:

    {'mac_address': '52:54:00:12:34:00',
     'name': 'interface0',
     'subnets': [
        {'address': '192.168.1.2/24',
         'mtu': 1501,
         'type': 'static'},
        {'address': '2001:4800:78ff:1b:be76:4eff:fe06:1000",
         'mtu': 1480,
         'netmask': 64,
         'type': 'static'}],
      'type: physical',
      'accept-ra': 'true'
    }

    An entry dictionary looks like:

    {'set-name': 'interface0',
     'match': {'macaddress': '52:54:00:12:34:00'},
     'mtu': 1501}

    After modification returns

    {'set-name': 'interface0',
     'match': {'macaddress': '52:54:00:12:34:00'},
     'mtu': 1501,
     'address': ['192.168.1.2/24', '2001:4800:78ff:1b:be76:4eff:fe06:1000"],
     'ipv6-mtu': 1480}

    ú c                 S   s.   | rt | tƒs| S || kr$|  |¡S | gS dS )zT
        Helper to convert strings to list of strings, handle single string
        N)Ú
isinstanceÚstrÚsplit)ÚobjÚtokenr   r   r   Ú_listifyU   s    
ÿz$_extract_addresses.<locals>._listifyNÚsubnetsÚtypeZdhcpÚ4TZdhcp6)ZstaticZstatic6z%sZaddressÚprefixz/%dZgatewayú:z::/0z	0.0.0.0/0)ZviaÚtoF)ÚstrictzAGateway %s is not contained within subnet %s, adding on-link flagzon-linkzDFailed to check whether gateway %s is contained within subnet %s: %sÚdns_nameserversZ
dns_searchZmtuzipv6-mtuÚroutesz%s/%sÚnetworkZmetricéd   zZNetwork config: ignoring %s device-level mtu:%s because ipv4 subnet-level mtu:%s provided.r   Ú	addressesÚnameserversÚsearchz	accept-ra)r   )Úgetr   Úupdater	   Ú	ipaddressZ
ip_addressZ
ip_networkÚLOGÚdebugÚ
ValueErrorZwarningÚappendr   Úlenr   Zis_true)r   r   Úifnamer   r$   r0   r-   r1   Úsearchdomainsr%   ZsubnetZsn_typeZaddrZ	new_routeZsubnet_gatewayZsubnet_networkÚeZmtukeyZrouteZto_netZ	entry_mtuÚnsr   r   r   Ú_extract_addresses0   sª    %



þ
üû



þ


ûr?   c                    s8   t ‡ fdd„|  ¡ D ƒƒ}t|ƒdkr4| d|i¡ d S )Nc                    s$   g | ]\}}|  d d¡ˆ kr|‘qS )zbond-masterN)r3   )r   ÚnameÚcfg©Úbond_masterr   r   Ú
<listcomp>Å   s   þz0_extract_bond_slaves_by_name.<locals>.<listcomp>r   Ú
interfaces)Úsortedr   r:   r4   )rE   r   rC   Zbond_slave_namesr   rB   r   Ú_extract_bond_slaves_by_nameÃ   s    
þÿrG   c                    s‚   t  ˆ d¡}tj |¡sd S tj|dd}|tkr6d S ‡ fdd„dD ƒ}dd„ |D ƒ}t 	d||¡ |g| D ]}t 
|¡ qnd S )	Nz etc/netplan/00-snapd-config.yamlF)Údecodec                    s   g | ]}t  ˆ |¡‘qS r   )r   Útarget_path©r   Úf©Útargetr   r   rD   Ù   s   ÿz"_clean_default.<locals>.<listcomp>)z-run/systemd/network/10-netplan-all-en.networkz.run/systemd/network/10-netplan-all-eth.networkz#run/systemd/generator/netplan.stampc                 S   s   g | ]}t j |¡r|‘qS r   )ÚosÚpathÚisfilerJ   r   r   r   rD   á   s      z9removing known config '%s' and derived existing files: %s)r   rI   rN   rO   rP   r   Z	load_fileÚKNOWN_SNAPD_CONFIGr6   r7   Úunlink)rM   ZtpathÚcontentZderivedÚexistingrK   r   rL   r   Ú_clean_defaultÏ   s"    
þýrU   c                   @   sr   e Zd ZdZddgZddgZddd„Zedd	„ ƒZde	e
e dd
œdd„Zddd„Zddd„Ze	edœdd„ZdS )ÚRendererzBRenders network information in a /etc/netplan/network.yaml format.ÚnetplanZgenerateÚinfoNc                 C   sR   |si }|  dd¡| _|  dd ¡| _|  dd¡| _|  dd¡| _|  dd ¡| _d S )	NÚnetplan_pathzetc/netplan/50-cloud-init.yamlÚnetplan_headerZpostcmdsFÚclean_defaultTr   )r3   rY   rZ   Ú	_postcmdsr[   Ú	_features)Úselfr   r   r   r   Ú__init__ò   s     ÿzRenderer.__init__c              
   C   sˆ   | j d kr‚z0tj| jdd\}}t |¡}|d d | _ W nF tjk
rP   Y n2 ttfk
r€ } zt 	d|¡ W 5 d }~X Y nX | j S )NT©Zcapturez
netplan.ior   z-Failed to list features from netplan info: %s)
r]   r   ÚNETPLAN_INFOr   Z	load_yamlÚProcessExecutionErrorÚ	TypeErrorÚKeyErrorr6   r7   )r^   Z	info_blobZ_errrX   r=   r   r   r   r   ý   s    

zRenderer.features)Únetwork_stateÚ	templatesÚreturnc           	      C   sÌ   t j t |¡| j¡}t t j |¡¡ | j	r4| j	nd}|  
|¡}| d¡sT|d7 }tjr^dnd}t j |¡rˆt |¡}||@ |krˆ|}tj||| |d | jr¬t|d | j| jd | j| jd d S )NÚ Ú
i€  i¤  )ÚmoderL   )Úrun)rN   rO   Újoinr   rI   rY   r   Z
ensure_dirÚdirnamerZ   Ú_render_contentÚendswithr   ZNETPLAN_CONFIG_ROOT_READ_ONLYÚexistsZget_permissionsZ
write_filer[   rU   Ú_netplan_generater\   Ú_net_setup_link)	r^   re   rf   rM   ZfpnplanÚheaderrS   rj   Zcurrent_moder   r   r   Úrender_network_state  s     	



zRenderer.render_network_stateFc                 C   s&   |st  d¡ d S tj| jdd d S )Nz!netplan generate postcmd disabledTr`   )r6   r7   r   ÚNETPLAN_GENERATE)r^   rk   r   r   r   rq   -  s    
zRenderer._netplan_generatec                 C   s¤   |st  d¡ dS dddg}t}tdƒD ]l}z>tƒ D ],}tj t| ¡r4t	j	|t| g dd q4W  q W q( t	j
k
r’ } z|}W 5 d}~X Y q(X q(td	ƒ|‚dS )
z¤To ensure device link properties are applied, we poke
        udev to re-evaluate networkd .link files and call
        the setup_link udev builtin command
        z'netplan net_setup_link postcmd disabledNZudevadmztest-builtinZnet_setup_linké   Tr`   zQ'udevadm test-builtin net_setup_link' unable to run successfully for all devices.)r6   r7   Ú	ExceptionÚranger   rN   rO   Úislinkr
   r   rb   ÚRuntimeError)r^   rk   Z	setup_lnkZlast_exceptionÚ_Zifacer=   r   r   r   rr   3  s*    


 ÿ
ÿýzRenderer._net_setup_link)re   rg   c           +   	   C   sF  |j dkr*t d¡ tjd|jidddS i }i }i }i }i }g }|j dg ¡}|j}	|j	}
| 
¡ D ]}| d¡}ttdd	„ | ¡ ƒƒ}| d
¡}|dkr|| dd ¡dœ}|d d krî| dd ¡}|d k	râd| ¡ i|d< n|d= |d= t|||| jƒ | ||i¡ qd|dkr i }i }ttt d¡ƒ}dD ]R}t||ƒ}| ¡ D ]8\}}| | dd¡¡}|d krrqJ| ||i¡ qJq4t|ƒdkr¤| d|i¡ | d¡rÀ|d  ¡ |d< | d¡}|dkràt|||ƒ t|||| jƒ | ||i¡ qd|dkr| d¡}tt |¡ƒ}d|i}d}t||ƒ}i }ttt d¡ƒ} | ¡ D ]p\}}|  |¡}|d krtqT| ||i¡ |dkrTi }!|D ]}"|" ¡ \}#}$t|$ƒ|!|#< q”| ||!i¡ qTt|ƒdkrâ| d|i¡ | d¡rþ|d  ¡ |d< t|||| jƒ | ||i¡ qd|dkrd| d¡| d¡d œ}%| dd ¡}|d k	r^| ¡ |%d< t||%|| jƒ | ||%i¡ qd|	sŠ|
rä|	|
d!œ}&|||||fD ]@}'|' ¡ D ]0\}(})d"|)ks®d#|)krÎq®|) d"|&i¡ q®q¢d$d%„ }*| d&¡ ||*d'|ƒ7 }||*d(|ƒ7 }||*d)|ƒ7 }||*d*|ƒ7 }||*d+|ƒ7 }d, |¡S )-Né   zV2 to V2 passthroughr.   F)Úexplicit_startÚexplicit_endrE   r@   c                 S   s   | d d k	S )Né   r   )Úitr   r   r   Ú<lambda>l  ó    z*Renderer._render_content.<locals>.<lambda>r&   Zphysicalr   )úset-namer   Zmac_addressZ
macaddressrƒ   Úbond)Zbond_zbond-r{   ú-r   Z
parameterszbond-slavesZnoneÚbridgeÚbridge_portsZbridge_)z	path-costzport-priorityÚvlanZvlan_idzvlan-raw-device)ÚidÚlink)r0   r2   r1   r0   c                 S   s0   |r,t j| |idddd}t |d¡}|gS g S )NFT)r}   r~   Znoaliasz    )r   ÚdumpsÚtextwrapÚindent)r@   ÚsectionÚdumpZtxtr   r   r   Ú_render_sectionÚ  s    üz1Renderer._render_content.<locals>._render_sectionznetwork:
    version: 2
Ú	ethernetsÚwifisÚbondsÚbridgesÚvlansrh   )Úversionr6   r7   r   r‹   r   Z_network_stater3   r,   Zdns_searchdomainsZiter_interfacesr   Úfilterr   Úlowerr?   r   r4   r   r   r   Úreplacer:   rG   rF   Úcopyr!   Úintr9   rl   )+r^   re   r‘   r’   r”   r“   r•   rS   rE   r1   r<   r   r;   ZifcfgZif_typeZethZmacaddrr„   Zbond_configZv2_bond_mapr   Zbond_paramsZparamr   ZnewnameZslave_interfacesr‡   Zportsr†   Zmatch_prefixZparamsZ	br_configZv2_bridge_mapZnewvalueÚvalZportZportvalrˆ   ZnscfgrŽ   Ú_namerA   r   r   r   r   rn   R  sÎ    

ý



þ






 ÿ



þ


zRenderer._render_content)N)NN)F)F)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ru   ra   r_   Úpropertyr   r   r   r   rt   rq   rr   r    rn   r   r   r   r   rV   ì   s    

  üû!

rV   c                 C   s2   dg}ddg}|D ]}t j||| ds dS qdS )NrW   z	/usr/sbinz/sbin)r2   rM   FT)r   Zwhich)rM   Zexpectedr2   Úpr   r   r   Ú	availableð  s    r¤   c                 C   s>   d}t ||dœƒ}|sd}| d¡s,|d7 }| | ¡}|| S )Nzetc/network/50-cloud-init.yaml)rY   rZ   rh   ri   )rV   ro   rn   )re   rs   rY   r   Úcontentsr   r   r   Únetwork_state_to_netplanù  s    þÿ

r¦   )N)N)N)N)#rš   r5   rN   rŒ   Útypingr   r   Z	cloudinitr   r   Zloggingr   r   r   Zcloudinit.netr	   r
   r   r   r   Zcloudinit.net.network_stater   r   rQ   Z	getLoggerrž   r6   r   r   r?   rG   rU   rV   r¤   r¦   r   r   r   r   Ú<module>   s*   
 
  
	