
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
3
\me                 @   s  U d dl Z d dlZd dlZd dlmZmZmZmZ d dlm	Z	m
Z
 d dlmZmZmZmZmZmZmZmZmZ er~d dlmZ ejeZdZdddd	giZd
ddddddddddddddgZdddddddd d!d"d#d$d%d&d'd(d)d*d+dd,d-dd.d/d0dd1d2Zeeeeef f edd3d4d5Z d6d7 Z!G d8d9 d9e"Z#d:d; Z$G d<d= d=Z%G d>d? d?Z&d@dA Z'f fdBdCZ(dDdE Z)dFdG Z*dLee+e%dIdJdKZ,dS )M    N)TYPE_CHECKINGAnyDictOptional)safeyamlutil)	find_interface_name_from_macget_interfaces_by_macipv4_mask_to_net_prefixipv6_mask_to_net_prefixis_ip_networkis_ipv4_networkis_ipv6_addressis_ipv6_networknet_prefix_to_ipv4_mask)Renderer   versionconfignetwork_state	addressesdhcp4zdhcp4-overridesdhcp6zdhcp6-overridesgateway4gateway6
interfacesmatchmtunameserversrendererzset-name	wakeonlanz	accept-raz	ad-selectzarp-intervalzarp-ip-targetzarp-validatez
down-delayzfail-over-mac-policyz	lacp-ratezmii-monitor-intervalz	min-linksmodezgratuitous-arpZprimaryzprimary-reselect-policyzup-delayztransmit-hash-policy)zbond-ad-selectzbond-arp-intervalzbond-arp-ip-targetzbond-arp-validatezbond-downdelayzbond-fail-over-maczbond-lacp-ratezbond-miimonzbond-min-linksz	bond-modezbond-num-grat-arpzbond-primaryzbond-primary-reselectzbond-updelayzbond-xmit-hash-policyzageing-timeZpriorityzforward-delayz
hello-timezmax-agez	path-costzport-prioritystp)Zbridge_ageingZbridge_bridgeprioZ	bridge_fdZbridge_gcintZbridge_helloZbridge_maxageZbridge_maxwaitZbridge_pathcostZbridge_portprio
bridge_stpZbridge_waitport)bondbridge)diktreturnc             C   s$   d| ksd| kr t jdddd dS )z8Warn about deprecations of v2 properties for all devicesr   r   z$The use of `gateway4` and `gateway6`z22.4zhFor more info check out: https://cloudinit.readthedocs.io/en/latest/topics/network-config-format-v2.html)Z
deprecatedZdeprecated_versionZextra_messageN)r   Z	deprecate)r&    r(   #/usr/lib/python3.6/network_state.pywarn_deprecated_all_devicesV   s
    r*   c             C   s$   t | }x|D ]}|j| qW |S )N)setdiscard)ZexpectedactualZmissingkeyr(   r(   r)   	diff_keysa   s    
r/   c               @   s   e Zd ZdS )InvalidCommandN)__name__
__module____qualname__r(   r(   r(   r)   r0   h   s   r0   c                s    fdd}|S )Nc                s   t j  fdd}|S )Nc                s4   r"t |}|r"td|f  | |f||S )Nz&Command missing %s of required keys %s)r/   r0   )selfcommandargskwargsmissing_keys)funcrequired_keysr(   r)   	decoratorn   s    
z7ensure_command_keys.<locals>.wrapper.<locals>.decorator)	functoolswraps)r9   r;   )r:   )r9   r)   wrapperm   s    z$ensure_command_keys.<locals>.wrapperr(   )r:   r>   r(   )r:   r)   ensure_command_keysl   s    r?   c               @   s   e Zd ZefeedddZeedddZedd Z	ed	d
 Z
edd Zedd ZdddZdddZdd Zdd Zeed dddZdS )NetworkState)r   r   c             C   s*   t j|| _|| _|jdd| _d | _d S )Nuse_ipv6F)copydeepcopy_network_state_versiongetrA   _has_default_route)r4   r   r   r(   r(   r)   __init__   s    zNetworkState.__init__)r'   c             C   s
   | j d S )Nr   )rD   )r4   r(   r(   r)   r      s    zNetworkState.configc             C   s   | j S )N)rE   )r4   r(   r(   r)   r      s    zNetworkState.versionc             C   s(   y| j d d S  tk
r"   g S X d S )Ndnsr   )rD   KeyError)r4   r(   r(   r)   dns_nameservers   s    zNetworkState.dns_nameserversc             C   s(   y| j d d S  tk
r"   g S X d S )NrI   search)rD   rJ   )r4   r(   r(   r)   dns_searchdomains   s    zNetworkState.dns_searchdomainsc             C   s   | j d kr| j | _ | j S )N)rG   _maybe_has_default_route)r4   r(   r(   r)   has_default_route   s    

zNetworkState.has_default_routeNc             c   sB   | j jdi }x.|j D ]"}|d kr,|V  q||r|V  qW d S )Nr   )rD   rF   values)r4   filter_funcZifacesifacer(   r(   r)   iter_interfaces   s    zNetworkState.iter_interfacesc             c   s:   x4| j jdg D ]"}|d k	r,||r2|V  q|V  qW d S )Nroutes)rD   rF   )r4   rQ   router(   r(   r)   iter_routes   s
    zNetworkState.iter_routesc             C   sp   x| j  D ]}| j|r
dS q
W xJ| j D ]>}x8|jdg D ](}x"|jdg D ]}| j|rNdS qNW q<W q*W dS )NTsubnetsrT   F)rV   _is_default_routerS   rF   )r4   rU   rR   subnetr(   r(   r)   rN      s    

z%NetworkState._maybe_has_default_routec             C   s    d}|j ddko|j d|kS )N::0.0.0.0prefixr   network)rZ   r[   )rF   )r4   rU   Zdefault_netsr(   r(   r)   rX      s    zNetworkState._is_default_route)r   r'   c             C   s(   i }d|kr|d |d< | d|if|S )zInstantiates a `NetworkState` without interpreting its data.

        That means only `config` and `version` are copied.

        :param network_state: Network state data.
        :return: Instance of `NetworkState`.
        r   r   r(   )clsr   r7   r(   r(   r)   to_passthrough   s    	zNetworkState.to_passthrough)N)N)r1   r2   r3   NETWORK_STATE_VERSIONdictintrH   propertyr   r   rK   rM   rO   rS   rV   rN   rX   classmethodr_   r(   r(   r(   r)   r@   ~   s   
	
r@   c               @   s  e Zd Zi g g g ddddZeddfddddZeed	d
dZedd Z	e	j
dd Z	dd Zdd Zdd Zdd ZdJddZdKddZdLddZedgdd  Zedgd!d" Zedd#d$gd%d& Zedd'd(gd)d* Zedd+gd,d- Zedgd.d/ Zd0d1 Zed2gd3d4 Zed2gd5d6 Zed7gd8d9 Zd:d; Zd<d= Zd>d? Zd@dA Z dBdC Z!dd	dDdEZ"dMdFdGZ#dHdI Z$dS )NNetworkStateInterpreter)r   rL   FN)r   rT   rI   rA   r   zOptional[Renderer])r   c             C   sv   || _ || _tj| j| _|| jd< d| _i | _|| _| j	| j
| j| j| j| j| j| j| j| j| j| j| jd| _d S )Nr   F)r$   Zbondsr%   ZbridgesZ	ethernetsZ
infinibandZloopback
nameserverphysicalrU   vlanZvlansZwifis)rE   _configrB   rC   initial_network_staterD   _parsed_interface_dns_map	_rendererhandle_bondhandle_bondshandle_bridgehandle_bridgeshandle_ethernetshandle_infinibandhandle_loopbackhandle_nameserverhandle_physicalhandle_routehandle_vlanhandle_vlanshandle_wifiscommand_handlers)r4   r   r   r   r(   r(   r)   rH      s(    
z NetworkStateInterpreter.__init__)r'   c             C   sH   ddl m} | jdkr8t| j|r8tjd tj| j	S t| j
| jdS )Nr   )r      zPassthrough netplan v2 config)r   )cloudinit.net.netplanr   rE   
isinstancerm   LOGdebugr@   r_   ri   rD   )r4   NetplanRendererr(   r(   r)   r      s
    
z%NetworkStateInterpreter.network_statec             C   s   | j jdS )NrA   )rD   rF   )r4   r(   r(   r)   rA     s    z NetworkStateInterpreter.use_ipv6c             C   s   | j jd|i d S )NrA   )rD   update)r4   valr(   r(   r)   rA   
  s    c             C   s   | j | j| jd}tj|S )N)r   r   r   )rE   ri   rD   r   dumps)r4   stater(   r(   r)   dump  s    
zNetworkStateInterpreter.dumpc             C   sz   d|krt jd tdt|d  }t||}|rNd| }t j| t|x&dd |D D ]}t| |||  q^W d S )Nr   z$Invalid state, missing version fieldzInvalid state, missing keys: %sc             S   s   g | ]}|dkr|qS )r   )r   r(   ).0kr(   r(   r)   
<listcomp>#  s    z0NetworkStateInterpreter.load.<locals>.<listcomp>)r   error
ValueErrorNETWORK_STATE_REQUIRED_KEYSr/   setattr)r4   r   r:   r8   msgr.   r(   r(   r)   load  s    


zNetworkStateInterpreter.loadc             C   s   t j| jS )N)r   r   rD   )r4   r(   r(   r)   dump_network_state&  s    z*NetworkStateInterpreter.dump_network_statec             C   s   | j | jdS )N)r   r   )rE   ri   )r4   r(   r(   r)   as_dict)  s    zNetworkStateInterpreter.as_dictTc             C   s>   | j dkr| j|d d| _n| j dkr:| j|d d| _d S )Nr   )skip_brokenTr|   )rE   parse_config_v1rk   parse_config_v2)r4   r   r(   r(   r)   parse_config,  s    

z$NetworkStateInterpreter.parse_configc             C   s   x| j D ]}|d }y| j| }W n0 tk
rR } ztd| |W Y d d }~X nX y|| W q tk
r   |sx ntjd|dd tj| j  Y qX qW xz| j	j
 D ]l\}}d }y| jd | }W n2 tk
r } ztdj||W Y d d }~X nX |r|\}	}
|	|
d|d	< qW d S )
Ntypez"No handler found for  command '%s'zSkipping invalid command: %sT)exc_infor   zINameserver specified for interface {0}, but interface {0} does not exist!)r   rL   rI   )ri   r{   rJ   RuntimeErrorr0   r   warningr   r   rl   itemsrD   r   format)r4   r   r5   command_typehandlere	interfacerI   rR   r   rL   r(   r(   r)   r   4  s:    z'NetworkStateInterpreter.parse_config_v1c             C   s   ddl m} t| j|rd S x| jj D ]\}}|d	kr:q(y| j| }W n0 tk
rx } ztd| |W Y d d }~X nX y|| | j	| W q( t
k
r   |s ntjd|dd tj| j  Y q(X q(W d S )
Nr   )r   r   r   z!No handler found for command '%s'zSkipping invalid command: %sT)r   )r   r   )r}   r   r~   rm   ri   r   r{   rJ   r   
_v2_commonr0   r   r   r   r   )r4   r   r   r   r5   r   r   r(   r(   r)   r   W  s*    z'NetworkStateInterpreter.parse_config_v2namec             C   s
   | j |S )N)rv   )r4   r5   r(   r(   r)   rt   s  s    z'NetworkStateInterpreter.handle_loopbackc       
      C   s.  | j jdi }|j|d i }x*|jdi j D ]\}}|j||i q0W t|jd}| jsx2|D ]*}|jdjdst|jdrdd| _P qdW |jd	d
}|d
k	rtj	|}|jdd
}	|	d
k	rtj	|	}	|j|jd|jd|jddd|jdd
d
|||	d | j d j|jd|i | j
  d
S )z
        command = {
            'type': 'physical',
            'mac_address': 'c0:d6:9f:2c:e8:80',
            'name': 'eth0',
            'subnets': [
                {'type': 'dhcp4'}
             ],
            'accept-ra': 'true'
        }
        r   r   paramsrW   r   6addressTz	accept-raNr    mac_addressinetZmanualr   )r   r   r   r   r!   r   r   gatewayrW   z	accept-rar    )rD   rF   r   r   _normalize_subnetsrA   endswithr   r   Zis_truer   )
r4   r5   r   rR   paramr   rW   rY   Z	accept_rar    r(   r(   r)   rv   w  s>    



z'NetworkStateInterpreter.handle_physicalvlan_id	vlan_linkc             C   s\   | j jdi }| j| |j|jdi }|jd|d< |jd|d< |j|d |i dS )z
        auto eth0.222
        iface eth0.222 inet static
                address 10.10.10.1
                netmask 255.255.255.0
                hwaddress ether BC:76:4E:06:96:B3
                vlan-raw-device eth0
        r   r   r   zvlan-raw-devicer   N)rD   rF   rv   r   )r4   r5   r   rR   r(   r(   r)   rx     s    

z#NetworkStateInterpreter.handle_vlanbond_interfacesr   c       	      C   s  | j | | jjd}|j|jdi }x(|jdj D ]\}}|j||i q8W |jddi | jd j|d |i x|jdD ]}||kr|dd}| j | | jjdi }|j|}|jd|d	< x(|jdj D ]\}}|j||i qW | jd j||i qW d
S )aU  
        #/etc/network/interfaces
        auto eth0
        iface eth0 inet manual
            bond-master bond0
            bond-mode 802.3ad

        auto eth1
        iface eth1 inet manual
            bond-master bond0
            bond-mode 802.3ad

        auto bond0
        iface bond0 inet static
             address 192.168.0.10
             gateway 192.168.0.1
             netmask 255.255.255.0
             bond-slaves none
             bond-mode 802.3ad
             bond-miimon 100
             bond-downdelay 200
             bond-updelay 200
             bond-lacp-rate 4
        r   r   r   zbond-slavesZnoner   r$   )r   r   zbond-masterN)rv   rD   rF   r   r   )	r4   r5   r   rR   r   r   ifnamecmdZbond_ifr(   r(   r)   rn     s$    


z#NetworkStateInterpreter.handle_bondbridge_interfacesc       	      C   s  | j jdi }x.|jdD ] }||kr(qd|i}| j| qW | j jdi }| j| |j|jdi }|d |d< x*|jdi j D ]\}}|j||i qW |jd}|dk	ot|t  r|dkrd}n|dkrd}ntdj|d|jd|i |j|d |i dS )a  
            auto br0
            iface br0 inet static
                    address 10.10.10.1
                    netmask 255.255.255.0
                    bridge_ports eth0 eth1
                    bridge_stp off
                    bridge_fd 0
                    bridge_maxwait 0

        bridge_params = [
            "bridge_ports",
            "bridge_ageing",
            "bridge_bridgeprio",
            "bridge_fd",
            "bridge_gcint",
            "bridge_hello",
            "bridge_hw",
            "bridge_maxage",
            "bridge_maxwait",
            "bridge_pathcost",
            "bridge_portprio",
            "bridge_stp",
            "bridge_waitport",
        ]
        r   r   r   Zbridge_portsr   r#   Non1r   Toff0r   Fz2Cannot convert bridge_stp value ({stp}) to boolean)r"   )r   r   r   )r   r   r   )	rD   rF   rv   r   r   r~   boolr   r   )	r4   r5   r   r   r   rR   r   r   r#   r(   r(   r)   rp     s.    


z%NetworkStateInterpreter.handle_bridgec             C   s   | j | d S )N)rv   )r4   r5   r(   r(   r)   rs   5  s    z)NetworkStateInterpreter.handle_infinibandc             C   s   g }g }d|kr@|d }t |ts(|g}x|D ]}|j| q.W d|krx|d }t |ts`|g}x|D ]}|j| qfW ||fS )Nr   rL   )r~   listappend)r4   r5   r   rL   Zaddrsaddrpathspathr(   r(   r)   
_parse_dns9  s    



z"NetworkStateInterpreter._parse_dnsr   c             C   sV   | j jd}| j|\}}d|kr6||f| j|d < n|d j| |d j| d S )NrI   r   r   rL   )rD   rF   r   rl   extend)r4   r5   rI   r   rL   r(   r(   r)   ru   J  s    z)NetworkStateInterpreter.handle_nameserverc             C   s0   | j jd}| j|\}}||d|| d< d S )Nr   )r   rL   rI   )rD   rF   r   )r4   r5   rR   Z_ifacer   rL   r(   r(   r)   _handle_individual_nameserverW  s    z5NetworkStateInterpreter._handle_individual_nameserverdestinationc             C   s   | j d jt| d S )NrT   )rD   r   _normalize_route)r4   r5   r(   r(   r)   rw   ]  s    z$NetworkStateInterpreter.handle_routec             C   s   | j |dd dS )a  
        v2_command = {
          bond0: {
            'interfaces': ['interface0', 'interface1'],
            'parameters': {
               'mii-monitor-interval': 100,
               'mode': '802.3ad',
               'xmit_hash_policy': 'layer3+4'}},
          bond1: {
            'bond-slaves': ['interface2', 'interface7'],
            'parameters': {
                'mode': 1,
            }
          }
        }

        v1_command = {
            'type': 'bond'
            'name': 'bond0',
            'bond_interfaces': [interface0, interface1],
            'params': {
                'bond-mode': '802.3ad',
                'bond_miimon: 100,
                'bond_xmit_hash_policy': 'layer3+4',
            }
        }

        r$   )cmd_typeN)_handle_bond_bridge)r4   r5   r(   r(   r)   ro   b  s    z$NetworkStateInterpreter.handle_bondsc             C   s   | j |dd dS )a  
        v2_command = {
          br0: {
            'interfaces': ['interface0', 'interface1'],
            'forward-delay': 0,
            'stp': False,
            'maxwait': 0,
          }
        }

        v1_command = {
            'type': 'bridge'
            'name': 'br0',
            'bridge_interfaces': [interface0, interface1],
            'params': {
                'bridge_stp': 'off',
                'bridge_fd: 0,
                'bridge_maxwait': 0
            }
        }

        r%   )r   N)r   )r4   r5   r(   r(   r)   rq     s    z&NetworkStateInterpreter.handle_bridgesc             C   s$  t  }x|j D ]\}}ddi}|jdi }|jdd}|sRtjd|t| ||d< |}|jd}	|	rr|	}n |r|r|j }
t|
}|r|}||d	< |jd
d}|rd
|i|d< x dD ]}||kr|| ||< qW t| | j	|}t
|dkr|jd|i tjd| | j| qW dS )a  
        ethernets:
          eno1:
            match:
              macaddress: 00:11:22:33:44:55
              driver: hv_netvsc
            wakeonlan: true
            dhcp4: true
            dhcp6: false
            addresses:
              - 192.168.14.2/24
              - 2001:1::1/64
            gateway4: 192.168.14.1
            gateway6: 2001:1::2
            nameservers:
              search: [foo.local, bar.local]
              addresses: [8.8.8.8, 8.8.4.4]
          lom:
            match:
              driver: ixgbe
            set-name: lom1
            dhcp6: true
            accept-ra: true
          switchports:
            match:
              name: enp2*
            mtu: 1280

        command = {
            'type': 'physical',
            'mac_address': 'c0:d6:9f:2c:e8:80',
            'name': 'eth0',
            'subnets': [
                {'type': 'dhcp4'}
             ]
        }
        r   rg   r   
macaddressNzHNetworkState Version2: missing "macaddress" info in config entry: %s: %sr   zset-namer   driverr   r   r    	accept-rar   rW   z!v2(ethernets) -> v1(physical):
%s)r   r   r    r   )r	   r   rF   r   r   strlowerr   r*   _v2_to_v1_ipcfglenr   rv   )r4   r5   Zifaces_by_macZethcfgZphy_cmdr   r   r   Zset_nameZlcase_mac_addressZmacr   r.   rW   r(   r(   r)   rr     sB    -



z(NetworkStateInterpreter.handle_ethernetsc             C   s   x|j  D ]x\}}d||jd|jdd}d|kr@|d |d< t| | j|}t|dkrl|jd|i tjd| | j| q
W d	S )
aq  
        v2_vlans = {
            'eth0.123': {
                'id': 123,
                'link': 'eth0',
                'dhcp4': True,
            }
        }

        v1_command = {
            'type': 'vlan',
            'name': 'eth0.123',
            'vlan_link': 'eth0',
            'vlan_id': 123,
            'subnets': [{'type': 'dhcp4'}],
        }
        rh   idlink)r   r   r   r   r   r   rW   zv2(vlans) -> v1(vlan):
%sN)	r   rF   r*   r   r   r   r   r   rx   )r4   r5   rh   r   Zvlan_cmdrW   r(   r(   r)   ry     s    
z$NetworkStateInterpreter.handle_vlansc             C   s   t jd d S )NzOWifi configuration is only available to distros with netplan rendering support.)r   r   )r4   r5   r(   r(   r)   rz     s    z$NetworkStateInterpreter.handle_wifisc       
      C   s   t jd| x|j D ]\}}d|kr8|jd}|r8|}d|kr|jdjdg }|jdjdg }ddi}t|dkr|jd|i t|dkr|jd	|i | j| |jd
i jd}|rt|}	|	r|	}| j|| qW d S )Nzv2_common: handling config:
%szset-namer   rL   r   r   rf   r   r   r   r   )	r   r   r   rF   r   r   ru   r   r   )
r4   r   rR   Zdev_cfgZset_name_ifacerL   rI   Zname_cmdr   Zreal_if_namer(   r(   r)   r      s,    

z"NetworkStateInterpreter._v2_commonc       
         s4  t dd tj|j D  x|j D ]\}}t dd |j D }|jdi }|jdd}|rl||d< d|d	||d
 |jddt  fdd|j D i}d|kr|d |d< t| | j|}	t|	dkr|jd|	i t	j
d||| |dkr| j| q(|dkr| j| q(tdj|dq(W dS )z(Common handler for bond and bridge typesc             s   s   | ]\}}||fV  qd S )Nr(   )r   r   vr(   r(   r)   	<genexpr>@  s    z>NetworkStateInterpreter._handle_bond_bridge.<locals>.<genexpr>c             s   s"   | ]\}}|t kr||fV  qd S )N)NETWORK_V2_KEY_FILTER)r   r.   valuer(   r(   r)   r   E  s   Z
parameterszgratuitious-arpNzgratuitous-arpr   r   Z_interfacesr   r   c             3   s   | ]\}} | |fV  qd S )Nr(   )r   r   r   )v2key_to_v1r(   r)   r   T  s    r   r   rW   zv2(%s) -> v1(%s):
%sr%   r$   z Unknown command type: {cmd_type})r   )ra   NET_CONFIG_TO_V2rF   r   popr*   r   r   r   r   r   rp   rn   r   r   )
r4   r5   r   Z	item_nameZitem_cfgZitem_paramsr   Z
grat_valueZv1_cmdrW   r(   )r   r)   r   ;  s8    


z+NetworkStateInterpreter._handle_bond_bridgec             C   s  dd }g }|j dr:ddi}||j di | |j| |j drnddi}d| _||j di | |j| d	}d	}i }x|j d
g D ]}d|d}d|krd|kr|d	kr|j d}|jd|i n(d|kr|d	kr|j d}|jd|i d|ko| rF|j dj d
}	|	r|	|d< |j dj d}
|
r<|
|d< |j| |j| qW g }x>|j dg D ].}|jt|j d|j d|j dd qfW t|rt|r||d d< |S )z7Common ipconfig extraction from v2 to v1 subnets array.c             S   s   d| kr| d |d< d S )Nzroute-metricmetricr(   )Z	overridesrY   r(   r(   r)   _add_dhcp_overridesm  s    zDNetworkStateInterpreter._v2_to_v1_ipcfg.<locals>._add_dhcp_overridesr   r   zdhcp4-overridesr   Tzdhcp6-overridesNr   static)r   r   :r   r   r   r   rK   rL   
dns_searchrT   ZtoZviar   )r   r   r   r   )rF   r   rA   r   r   r   )r4   r   r   rW   rY   r   r   r   r   r   rL   rT   rU   r(   r(   r)   r   j  sV    






z'NetworkStateInterpreter._v2_to_v1_ipcfg)T)T)T)N)%r1   r2   r3   rj   r`   rH   rc   r@   r   rA   setterr   r   r   r   r   r   r   r?   rt   rv   rx   rn   rp   rs   r   ru   r   rw   ro   rq   rr   ry   rz   r   r   r   r(   r(   r(   r)   re      sL   

#
75A^"
/re   c             C   s~   t j| } tdd | j D }| jddkr@|jt|dd d	d
 | jdg D |d< dd }xdD ]}||| qhW |S )Nc             s   s   | ]\}}|r||fV  qd S )Nr(   )r   r   r   r(   r(   r)   r     s    z$_normalize_subnet.<locals>.<genexpr>r   r   static6r   
ip_address)address_keysc             S   s   g | ]}t |qS r(   )r   )r   rr(   r(   r)   r     s    z%_normalize_subnet.<locals>.<listcomp>rT   c             S   s,   || kr(t | | t r(| | j | |< d S )N)r~   r   split)Zsnetr   r(   r(   r)   listify  s    z"_normalize_subnet.<locals>.listifyr   rK   )r   r   )r   r   )r   rK   )rB   rC   ra   r   rF   r   _normalize_net_keys)rY   Znormal_subnetr   r   r(   r(   r)   _normalize_subnet  s    
 

r   c             C   s  dd | j  D }d}x|D ]}|j|r|}P qW |s\ddj|| f }tj| t|t|j|}t|stjd| td| dt|}t	|}|jd	}	d
|kr|j
d
\}
}}|
||< |rt|}n*|rt|}ntjd| td| dnRd|krt|d }n:|	r2|r2t|	}n$|	rH|rHt|	}n|rRdnd}d|krt|d t|krtjd|| ||d< |rd	|kr|d	= n|rt|d |d	< |S )a  Normalize dictionary network keys returning prefix and address keys.

    @param network: A dict of network-related definition containing prefix,
        netmask and address_keys.
    @param address_keys: A tuple of keys to search for representing the address
        or cidr. The first address_key discovered will be used for
        normalization.

    @returns: A dict containing normalized prefix and matching addr_key.
    c             S   s"   i | ]\}}|s|d kr||qS )r   r(   )r   r   r   r(   r(   r)   
<dictcomp>  s    z'_normalize_net_keys.<locals>.<dictcomp>Nz/No config network address keys [%s] found in %s,z$Address %s is not a valid ip networkzAddress z is not a valid ip addressnetmask/r\   @      z;Overwriting existing 'prefix' with '%s' in network info: %s)r   rF   joinr   r   r   r   r   r   r   	partitionr   r
   rb   r   r   )r]   r   ZnetZaddr_keyr.   messager   Zipv6Zipv4r   Z	addr_part_Zmaybe_prefixr\   r(   r(   r)   r     s^    









 
r   c             C   s   t dd | j D }d|kr0|d |d< |d= |jt|d	d |jd}|ryt||d< W n2 tk
r } ztdj||W Y dd}~X nX |S )
a  normalize a route.
    return a dictionary with only:
       'type': 'route' (only present if it was present in input)
       'network': the network portion of the route as a string.
       'prefix': the network prefix for address as an integer.
       'metric': integer metric (only if present in input).
       'netmask': netmask (string) equivalent to prefix iff network is ipv4.
    c             s   s"   | ]\}}|dkr||fV  qdS ) N)r   Nr(   )r   r   r   r(   r(   r)   r   !  s    z#_normalize_route.<locals>.<genexpr>r   r]   )r   r   z(Route config metric {} is not an integerN)r]   r   )	ra   r   r   r   rF   rb   r   	TypeErrorr   )rU   Znormal_router   r   r(   r(   r)   r     s"    


r   c             C   s   | sg } dd | D S )Nc             S   s   g | ]}t |qS r(   )r   )r   sr(   r(   r)   r   ;  s    z&_normalize_subnets.<locals>.<listcomp>r(   )rW   r(   r(   r)   r   8  s    r   T)
net_configr   r'   c             C   sf   d}| j d}| j d}|dkr$| }|rP|dk	rPt|||d}|j|d |j}|sbtd|  |S )zfParses the config, returns NetworkState object

    :param net_config: curtin network config dict
    Nr   r   r|   )r   r   r   )r   zpNo valid network_state object created from network config. Did you specify the correct version? Network config:
)rF   re   r   r   r   )r   r   r   r   r   r   Znsir(   r(   r)   parse_net_config_data>  s    	

r   )TN)-rB   r<   ZloggingZtypingr   r   r   r   Z	cloudinitr   r   Zcloudinit.netr   r	   r
   r   r   r   r   r   r   Zcloudinit.net.rendererr   Z	getLoggerr1   r   r`   r   r   r   r   ra   r*   r/   	Exceptionr0   r?   r@   re   r   r   r   r   r   r   r(   r(   r(   r)   <module>   s    ,
 V     ^L" 