U
    µ²ødËK  ã                   @   sê   d dl Z 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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   Ú_listifyV   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_addresses1   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                   @   sz   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ee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
r>| j
nd}| d¡sT|d7 }|| }d}t j |¡r¬t t | ¡ ¡¡}t|dƒ}	t |	¡}
W 5 Q R X ||
kr¬d}tjr¶dnd}|sät j |¡rät |¡}||@ |krä|}tj|||d | jrt|d	 | j| j|d
 | j| jd d S )NÚ Ú
FÚrbTi€  i¤  )ÚmoderL   ©ÚrunÚsame_content)rm   )rN   rO   Újoinr   rI   rY   r   Z
ensure_dirÚdirnameÚ_render_contentrZ   ÚendswithÚexistsZhash_bufferÚioÚBytesIOÚencodeÚopenr   ZNETPLAN_CONFIG_ROOT_READ_ONLYZget_permissionsZ
write_filer[   rU   Ú_netplan_generater\   Ú_net_setup_link)r^   re   rf   rM   ZfpnplanrS   Úheaderrn   Zhashed_contentrK   Zhashed_original_contentrk   Zcurrent_moder   r   r   Úrender_network_state  s0    	



zRenderer.render_network_stateFrl   c                 C   s8   |st  d¡ d S |r$t  d¡ d S tj| jdd d S )Nz!netplan generate postcmd disabledzEskipping call to `netplan generate`. reason: identical netplan configTr`   )r6   r7   r   ÚNETPLAN_GENERATE)r^   rm   rn   r   r   r   rx   9  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^   rm   Z	setup_lnkZlast_exceptionÚ_Zifacer=   r   r   r   ry   E  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>~  ó    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   ro   )+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   rq   d  sÎ    

ý



þ






 ÿ



þ


zRenderer._render_content)N)NN)FF)F)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r|   ra   r_   Úpropertyr   r   r   r   r{   Úboolrx   ry   r    rq   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¬   )N)N)N)#r¡   rt   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   Ú<module>   s*   
 
  