o
    w7eK                     @   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dedef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   sZ  d'dd}|du rg }g }g }g }g }|  dg }	|	du rg }	|	D ]}
|
 d}|dr=|dkr5|d7 }||d	i q!|tv rI|d
d	i q!|dv rd|
 d }d|
v rb|d|
 d 7 }|
 dr|
 ddd}z!t|
d }tj|dd}||vrtd|
d | d	|d< W n t	y } zt
d|
d || W Y d}~nd}~ww || d|
v r|||
 dg 7 }d|
v r|||
 dg 7 }d|
v rd}t|
rd|v rd}|||
 di |
 dg D ]+}d| d| df }| d|d}d|v r|d| dd i || q|| q!d| v rE| d}|r?| d |kr?t
d!|| d | n| d |d< t|d"krS|d#|i t|d"kra|d|i t|d"krsd#|i}|d$|i t|d"kr| d$i }|d%|i |d$|i d&| v r| d& dur|d&t|  d&i dS dS 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 || v r| |S | gS )zT
        Helper to convert strings to list of strings, handle single string
        )
isinstancestrsplit)objtokenr   r   r   _listifyV   s   
z$_extract_addresses.<locals>._listifyNsubnetstypedhcp4Tdhcp6)staticstatic6z%saddressprefixz/%dgatewaydefault)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_nameservers
dns_searchmtuzipv6-mturoutesz%s/%snetworkmetricd   zZNetwork config: ignoring %s device-level mtu:%s because ipv4 subnet-level mtu:%s provided.r   	addressesnameserverssearchz	accept-ra)r   )getr   updater	   	ipaddress
ip_address
ip_networkLOGdebug
ValueErrorwarningappendr   lenr   is_true)r   r   ifnamer   r%   r;   r7   r<   searchdomainsr&   subnetsn_typeaddr	new_routesubnet_gatewaysubnet_networkemtukeyrouteto_net	entry_mtunsr   r   r   _extract_addresses1   s   
%








rX   c                    s<   t  fdd|  D }t|dkr|d|i d S d S )Nc                    s$   g | ]\}}| d d kr|qS )zbond-masterN)r>   )r   namecfgbond_masterr   r   
<listcomp>   s
    z0_extract_bond_slaves_by_name.<locals>.<listcomp>r   
interfaces)sortedr   rH   r?   )r^   r   r\   bond_slave_namesr   r[   r   _extract_bond_slaves_by_name   s   
ra   c                    s   t  d}tj|sd S tj|dd}|tkrd S  fdddD }dd |D }t	d|| |g| D ]}t
| q7d S )	Nz etc/netplan/00-snapd-config.yamlF)decodec                    s   g | ]}t  |qS r   )r   target_pathr   ftargetr   r   r]      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isfilerd   r   r   r   r]      s    z9removing known config '%s' and derived existing files: %s)r   rc   rh   ri   rj   r   	load_fileKNOWN_SNAPD_CONFIGrC   rD   unlink)rg   tpathcontentderivedexistingre   r   rf   r   _clean_default   s$   
rr   c                   @   s   e Zd ZdZddgZddgZdddZedd	 Z		dd
e	de
e ddfddZddedefddZdddZd
e	defddZdS )RendererzBRenders network information in a /etc/netplan/network.yaml format.netplan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_headerpostcmdsFclean_defaultTr   )r>   rw   rx   	_postcmdsrz   	_features)selfr   r   r   r   __init__   s   zRenderer.__init__c              
   C   s   | j d u rGztj| jdd\}}t|}|d d | _ W | j S  tjy+   Y | j S  ttfyF } zt	d| W Y d }~| j S d }~ww | j S )NTcapturez
netplan.ior   z-Failed to list features from netplan info: %s)
r|   r   NETPLAN_INFOr   	load_yamlProcessExecutionError	TypeErrorKeyErrorrC   rD   )r}   	info_blob_errrv   rR   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s*|d7 }|| }d}t j|r`tt| }t|d}	t|	}
W d    n1 sUw   Y  ||
kr`d}tjrednd}|s|t j|r|t|}||@ |kr||}tj|||d | jrt|d	 | j| j|d
 | j| jd d S )N 
FrbTi  i  )moderf   )runsame_content)r   )rh   ri   joinr   rc   rw   r   
ensure_dirdirname_render_contentrx   endswithexistshash_bufferioBytesIOencodeopenr   NETPLAN_CONFIG_ROOT_READ_ONLYget_permissions
write_filerz   rr   _netplan_generater{   _net_setup_link)r}   r   r   rg   fpnplanro   headerr   hashed_contentre   hashed_original_contentr   current_moder   r   r   render_network_state  s2   	



zRenderer.render_network_stateFr   r   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   )rC   rD   r   NETPLAN_GENERATE)r}   r   r   r   r   r   r   9  s   
zRenderer._netplan_generatec                 C   s   |s	t d dS g d}t}tdD ]5}zt D ]}tjt| r/t	j	|t| g dd qW  dS  t	j
yH } z|}W Y d}~qd}~ww td|)zTo 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 disabledN)udevadmztest-builtinnet_setup_link   Tr   zQ'udevadm test-builtin net_setup_link' unable to run successfully for all devices.)rC   rD   	Exceptionranger   rh   ri   islinkr
   r   r   RuntimeError)r}   r   	setup_lnklast_exception_ifacerR   r   r   r   r   E  s.   

zRenderer._net_setup_linkc           +   	   C   s6  |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 u rv|dd }|d urpd| i|d< n|d= |d= t|||| j |||i q2|dkri }i }tttd}dD ]%}t||}| D ]\}}||dd}|d u rq|||i qqt|dkr|d|i |dr|d  |d< |d}|dkrt||| t|||| j |||i q2|dkr|d}tt|}d|i}d}t||}i }tttd} | D ]8\}}| |}|d u r1q!|||i |dv rXi }!|D ]}"|" \}#}$t|$|!|#< qA|||!i q!t|dkrh|d|i |drv|d  |d< t|||| j |||i q2|dkr|d|dd }%|dd }|d ur| |%d< t||%|| j |||%i q2|	s|
r|	|
d!}&|||||fD ] }'|' D ]\}(})d"|)v sd#|)vrߐq|)d"|&i qϐqd$d% }*|d& ||*d'|7 }||*d(|7 }||*d)|7 }||*d*|7 }||*d+|7 }d,|S )-N   zV2 to V2 passthroughr8   F)explicit_startexplicit_endr^   rY   c                 S   s   | d d uS )N   r   )itr   r   r   <lambda>~  s    z*Renderer._render_content.<locals>.<lambda>r'   physicalr   )set-namer   mac_address
macaddressr   bond)bond_zbond-r   -r   
parameterszbond-slavesnonebridgebridge_portsbridge_)z	path-costzport-priorityvlanvlan_idzvlan-raw-device)idlink)r;   r=   r<   r;   c                 S   s0   |rt j| |idddd}t|d}|gS g S )NFT)r   r   noaliasz    )r   dumpstextwrapindent)rY   sectiondumptxtr   r   r   _render_section  s   z1Renderer._render_content.<locals>._render_sectionznetwork:
    version: 2
	ethernetswifisbondsbridgesvlansr   )versionrC   rD   r   r   r   _network_stater>   r4   dns_searchdomainsiter_interfacesr   filterr   lowerrX   r   r?   r   r   r   replacerH   ra   r_   copyr"   intrG   r   )+r}   r   r   r   r   r   r   ro   r^   r<   rK   r   rJ   ifcfgif_typeethmacaddrr   bond_configv2_bond_mapr   bond_paramsparamr   newnameslave_interfacesr   portsr   match_prefixparams	br_configv2_bridge_mapnewvaluevalportportvalr   nscfgr   _namerZ   r   r   r   r   r   d  s   


















zRenderer._render_contentr   )NN)FF)F)__name__
__module____qualname____doc__r   r   r~   propertyr   r   r   r   r   boolr   r   r!   r   r   r   r   r   rs      s&    


,
rs   c                 C   s2   dg}ddg}|D ]}t j||| ds dS q	dS )Nrt   z	/usr/sbinz/sbin)r=   rg   FT)r   which)rg   expectedr=   pr   r   r   	available  s   r   r   )#r   r   r@   rh   r   typingr   r   	cloudinitr   r   loggingr   r   r   cloudinit.netr	   r
   r   r   r   cloudinit.net.network_stater   r   rl   	getLoggerr   rC   r   r   rX   ra   rr   rs   r   r   r   r   r   <module>   s,   
 
  