o
    fU                     @   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 d dlmZm	Z	 d dl
mZmZmZ d dlmZ eeZg dZg dZg dZd	d
 Zdd ZdddZdd Zdd Zdd ZG dd dejZdddZdddZdS )    N)Optional)subputil)ParserErrorrenderersubnet_is_ipv6)NetworkState)zpre-upupzpost-updownzpre-downz	post-down)bridge_ageingbridge_bridgeprio	bridge_fdbridge_gcinitbridge_hellobridge_maxagebridge_maxwait
bridge_stp)addressnetmask	broadcastnetworkmetricgatewaypointtopointmediamtuhostname
leasehours	leasetimevendorclientbootfileserverhwaddrproviderframenetnumendpointlocalttlc                 C   s   g }g d}|  D ]:\}}|dkrq
|dkr!d|d |d f }|rD||v rDt|tr1d|}d|v r;|dd}|d	|| q
t|S )
N)
r   r   r   r   r   pointopointr   scope
dns_searchdns_nameserversr   r   z%s/%sprefix _-    {0} {1})items
isinstancelistjoinreplaceappendformatsorted)ifacesubnetcontent	valid_mapkeyvalue rA   3/usr/lib/python3/dist-packages/cloudinit/net/eni.py_iface_add_subnet@   s   

rC   c           
   
   C   s  |dkrg S g }g d}g d}ddi}| d dvr| d |  D ][\}}t|tr4| | r2dnd	}|r:||v r;q#|d
krP|rP||krOtd| d || q#||v rg|D ]}	| d||||	 qVq#t|trqd	|}| d|||| q#t
|S )Nr   )	control	device_iddriverindexinetmodenamesubnetstype)bridge_pathcostbridge_portpriobridge_waitportmac_address	hwaddressrL   )bondbridge
infinibandvlanonoffr   zZNetwork config: ignoring %s device-level mtu:%s because ipv4 subnet-level mtu:%s provided.rJ   r2   r/   )r8   r3   r4   boolLOGwarningr9   getr5   r6   r:   )
r;   rG   ipv4_subnet_mtur=   
ignore_mapmultiline_keysrenamesr?   r@   vrA   rA   rB   _iface_add_attrs^   s<   



ra   Fc                 C   s   | d }| d }|dkrd}n|dv rd| }nd| }|   }|||d djdi |d	jdi |g}|rJ| d
rJ|djdi | |S )NrJ   rD   auto)hotplugzallow-z
# control-)fullnamecverbz{cverb} {fullname}ziface {fullname} {inet} {mode}rP   z    hwaddress {mac_address}rA   )copyupdater9   r[   r8   )r;   rG   render_hwaddressrd   rD   re   substlinesrA   rA   rB   _iface_start_entry   s   
rk   c                    sf  d}|  D ]}| }|drq|d}|d }|dkrx|d }|ds0tj||}t|D ]A t }	 fdd	|	D }	|	D ].}
t	|
d
}|
  }W d   n1 s_w   Y  tj|
}t| |tj|| qGq5q|dkr|d }|dstj||}t|D ]. t	 d
}|
  }W d   n1 sw   Y  tj }t| |tj|| qq|dkr|dd D ]}|| vrd|i| |< d| | d< qq|dkr|dd \}}}|| vrd|i| |< nd| | v rtd||f || | d< || | d< |}q|dkr2|d dkr'|d }n|d }|| | d< q|tv r@|d | | |< q|tv rc|| | vrRg | | |< | | | d|dd  q|drd| | vrvi | | d< |dkrg | | d d< |dd D ]}| | d d | qq|dkrg | | d d< |dd D ]}| | d d | qq|drwd| | vri | | d< |tv r|ddd}|d | | d |< q|d kr	g | | d d!< |dd D ]}| | d d! | qq|d"kr-|d  d#kr"|d | | d d#< q|d | | d d#< q|d$krRd%| | d vrCi | | d d%< |d | | d d% |d < q|d&krvd'| | d vrhi | | d d'< |d | | d d' |d < q|d(rd)| | vri | | d)< |d(dd}|d | | d) |< q|  D ]}d| | vrd*| | d< qdS )+a~  Parses the file contents, placing result into ifaces.

    '_source_path' is added to every dictionary entry to define which file
    the configuration information came from.

    :param ifaces: interface dictionary
    :param contents: contents of interfaces file
    :param src_dir: directory interfaces file was located
    :param src_path: file path the `contents` was read
    N#r/   r   zsource-directory   /c                    s@   g | ]}t jt j |rtd |durt j |qS )z^[a-zA-Z0-9_-]+$N)ospathisfiler6   rematch).0rp   expanded_pathrA   rB   
<listcomp>   s    z*_parse_deb_config_data.<locals>.<listcomp>rsourcerb   _source_pathTr;      familyz:Interface %s can only be defined once. Re-defined in '%s'.methodrQ   ether   zdns-dnsz
dns-searchsearchzdns-nameserversnameserversbridge_rS    bridge_portsports	bridge_hwmacrM   pathcostrN   portpriozbond-rR   F)
splitlinesstrip
startswithsplitro   rp   r6   globlistdiropenreadabspath_parse_deb_config_datadirnamer   NET_CONFIG_OPTIONSNET_CONFIG_COMMANDSr8   NET_CONFIG_BRIDGE_OPTIONSr7   lowerkeys)ifacescontentssrc_dirsrc_pathcurrifliner   optionparsed_src_dirdir_contentsentryfpsrc_data	abs_entrynew_src_pathabs_pathr;   r|   r}   valdomainr"   bridge_optionbond_optionrA   ru   rB   r      s   











"






r   c                 C   s   i }t || d d d t|S )N)r   r   )r   _ifaces_to_net_config_data)eni_datar   rA   rA   rB   convert_eni_data7  s   r   c                    s4  i  |   D ]\}}|dd }| vr2|dkrd}nd}||g d |< d|v r2|d  | d< ||d	 d
}|drCd|d< nd|d< |d	dkrT|d |d< dD ]}||v rb|| ||< qVd|v rdD ]}||d v r|d | r|d | |d| < qi | d | qd fddt D dS )zReturn network config that represents the ifaces data provided.
    ifaces = _parse_deb_config_data(...)
    config = ifaces_to_net_config_data(ifaces)
    state = parse_net_config_data(config).:r   loloopbackphysical)rL   rJ   rK   rQ   rP   r}   )_orig_eni_namerL   rb   rD   manualstaticr   )r   r   r   r   )r   r   dns_rK   rm   c                    s   g | ]} | qS rA   rA   )rt   ddevsrA   rB   rw   d      z._ifaces_to_net_config_data.<locals>.<listcomp>)versionconfig)r3   	partitionr[   r8   r:   )r   rJ   datadevnamedtyper<   copy_keynrA   r   rB   r   >  s6   

r   c                   @   sX   e Zd ZdZdddZdddZdd	d
ZdddZ		ddede	e
 ddfddZdS )Rendererz@Renders network information in a /etc/network/interfaces format.Nc                 C   s6   |si }| dd| _| dd | _| dd| _d S )Neni_pathetc/network/interfaces
eni_headernetrules_pathz(etc/udev/rules.d/70-persistent-net.rules)r[   r   r   r   )selfr   rA   rA   rB   __init__j  s   
zRenderer.__init__r   c                 C   sH  g }|d }|d }d}ddd}d}|d d	kr"|d
 d	kr"d}n|d dkr0|d dkr0d}d}	dD ][}
|r=|
dkr=q4|
dkrO|	d|||
 ||
 f 7 }	q4|
|v r|
dkrd||
 v rb|	d7 }	n| ddkrn|	d7 }	n|	d7 }	d|v r|	d||
 |d f 7 }	q4|	d||
 ||
 f 7 }	q4|||	 |  |||	 |  |S )a  When rendering routes for an iface, in some cases applying a route
        may result in the route command returning non-zero which produces
        some confusing output for users manually using ifup/ifdown[1].  To
        that end, we will optionally include an '|| true' postfix to each
        route line allowing users to work with ifup/ifdown without using
        --force option.

        We may at somepoint not want to emit this additional postfix, and
        add a 'strict' flag to this function.  When called with strict=True,
        then we will not append the postfix.

        1. http://askubuntu.com/questions/168033/
                 how-to-set-static-routes-in-ubuntu-server
        zpost-up route addzpre-down route delz || truegwr   )r   r   r   r   z0.0.0.0r   z defaultz::r.   r   z -A inet6 default)r   r   r   r   z%s %s %sr   z	 -A inet6    z -hostz -netz %s/%sz %s %s)r[   r8   )r   routeindentr=   r	   r
   or_truemapping
default_gw
route_linekrA   rA   rB   _render_routes  sB   

zRenderer._render_routeFc                    s   g }  di } dd } dd }|rd d< |rt|D ]\}}d }	| d< |d  d< | d	d
 d	< d}
t|rC|
d7 }
n| d}	|
 d< |d dks^|d dks^|d dkrod d< |d urn|rjdnd d< n2|d dkr~d
 d< d d< n#|d dkrd
 d< d d< nt|rd d< |d ur|rdnd d< d fdd|D v rd d	< tt ||dt | t ||	 }| dg D ]}|| j	|dd q|
| q |S g }d  v sd! v r|
d"jd&i   |
d#jd&i   |t d$d d% |
| |S )'NrK   z	accept-ra	wakeonlangzethernet-wolrG   rL   rI   rD   rb   rH   6r   dhcp4dhcp6zipv6_dhcpv6-statefuldhcp10	accept_razipv6_dhcpv6-stateless
ipv6_slaacr   Tc                    s   g | ]
}d  d  |v qS )zauto %srJ   rA   )rt   r   r;   rA   rB   rw     s    z*Renderer._render_iface.<locals>.<listcomp>aliasrh   routesz    )r   zbond-masterzbond-slaveszauto {name}ziface {name} {inet} {mode}r   )rG   r\   rA   )r[   pop	enumerater   r5   rk   rC   ra   extendr   r8   r9   )r   r;   rh   sectionsrK   r   ethernet_wolrG   r<   r\   subnet_inetrj   r   rA   r   rB   _render_iface  sx   





zRenderer._render_ifacec           	         s  ddddddgd}|  D ]}|ddkrt|}q|j}|r.d	||d
 d d< |j}|r>d	||d
 d d< ddddddd g }|| | t	|   fdddD ]}|ddkrgq]|| j||d q]|
 D ]
}|| | qvddd |D d S )z1Given state, emit etc/network/interfaces content.r   r   rH   r   rb   )rL   rD   )rJ   rL   rH   rK   rJ   r/   rK   r   r-   r,   rm   r      r{      )r   r   rT   rR   rS   rU   c                    s    | d  | d fS )NrL   rJ   rA   )r   orderrA   rB   <lambda>  r   z-Renderer._render_interfaces.<locals>.<lambda>)r?   r   z

c                 S   s   g | ]}d  |qS )
)r6   )rt   srA   rA   rB   rw   &  s    z/Renderer._render_interfaces.<locals>.<listcomp>r   )iter_interfacesr[   rf   deepcopyr-   r6   dns_searchdomainsr   r   r:   iter_routesr8   r   )	r   network_staterh   r   r;   r   searchdomainsr   r   rA   r   rB   _render_interfaces  sH   

	

zRenderer._render_interfacesr   	templatesreturnc                 C   s   t || j}ttj| | jr| jnd}t	||| 
|  | jrCt || j}ttj| tj	|| |dd d S d S )Nr   T)r=   preserve_mode)r   target_pathr   r   
ensure_dirro   rp   r   r   
write_filer   r   _render_persistent_net)r   r   r   targetfpeniheadernetrulesrA   rA   rB   render_network_state(  s   
zRenderer.render_network_stateN)r   F)NN)__name__
__module____qualname____doc__r   r   r   r   r   r   dictr  rA   rA   rA   rB   r   g  s    

	
4
M7r   c                 C   sF   d}t ||d dd}|sd}|ds|d7 }|j| |d}|| S )Nr   )r   r   r   )r   r   r   r   )r   endswithr   )r   r  rh   r   r   r   rA   rA   rB   network_state_to_eni=  s   
r  c                 C   sP   g d}ddg}|D ]}t j||| ds dS q
t | d}tj|s&dS dS )N)ifqueryifupifdownz/sbinz	/usr/sbin)r   r   Fr   T)r   whichr   ro   rp   rq   )r   expectedr   penirA   rA   rB   	availableQ  s   r  r  )NFr  )rf   r   loggingro   rr   typingr   	cloudinitr   r   cloudinit.netr   r   r   cloudinit.net.network_stater   	getLoggerr  rY   r   r   r   rC   ra   rk   r   r   r   r   r  r  rA   rA   rA   rB   <module>   s0   
	
< ) 
W