U
    Ad6                     @   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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d3< e dd4d5d6Z!d7d8 Z"d9d: Z#G d;d< d<e$Z%d=d> Z&G d?d@ d@e'Z(G dAdB dBZ)G dCdD dDe(dEZ*dFdG Z+dSdIdJZ,dKdL Z-dMdN Z.dTe e/e)dPdQdRZ0dS )U    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dhcp4dhcp4-overridesdhcp6dhcp6-overridesgateway4gateway6
interfacesmatchmtunameserversrendererset-name	wakeonlan	accept-raz	ad-selectzarp-intervalzarp-ip-targetzarp-validatez
down-delayzfail-over-mac-policyz	lacp-ratezmii-monitor-intervalz	min-linksmode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NET_CONFIG_TO_V2)diktreturnc                 C   s   d| ksd| krt d dS )z8Warn about deprecations of v2 properties for all devicesr   r   zDEPRECATED: The use of `gateway4` and `gateway6` is deprecated. For more info check out: https://cloudinit.readthedocs.io/en/latest/topics/network-config-format-v2.htmlNLOGwarning)r-    r2   =/usr/lib/python3/dist-packages/cloudinit/net/network_state.pywarn_deprecated_all_devicesV   s    r4   c                 C   s   t | }t }|| |S N)r   Z	read_confNetworkStateInterpreterload)Z
state_filestatensir2   r2   r3   from_state_file`   s    

r:   c                 C   s    t | }|D ]}|| q|S r5   )setdiscard)ZexpectedZactualZmissingkeyr2   r2   r3   	diff_keysg   s    r>   c                   @   s   e Zd ZdS )InvalidCommandN)__name__
__module____qualname__r2   r2   r2   r3   r?   n   s   r?   c                    s    fdd}|S )Nc                    s   t   fdd}|S )Nc                    s4   r"t |}|r"td|f  | |f||S )Nz&Command missing %s of required keys %s)r>   r?   )selfcommandargskwargsmissing_keys)funcrequired_keysr2   r3   	decoratort   s    
z7ensure_command_keys.<locals>.wrapper.<locals>.decorator)	functoolswraps)rH   rJ   rI   )rH   r3   wrappers   s    
z$ensure_command_keys.<locals>.wrapperr2   )rI   rN   r2   rM   r3   ensure_command_keysr   s    rO   c                       s    e Zd ZdZ fddZ  ZS )CommandHandlerMetaa  Metaclass that dynamically creates a 'command_handlers' attribute.

    This will scan the to-be-created class for methods that start with
    'handle_' and on finding those will populate a class attribute mapping
    so that those methods can be quickly located and called.
    c                    sb   i }|  D ]6\}}t|r|dr|tdd  }|r|||< q||d< tt| | |||S )NZhandle_command_handlers)itemscallable
startswithlensuperrP   __new__)clsnameparentsZdctrQ   Z	attr_nameattrZhandles_what	__class__r2   r3   rW      s    
zCommandHandlerMeta.__new__)r@   rA   rB   __doc__rW   __classcell__r2   r2   r\   r3   rP      s   rP   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 || _|| _|dd| _d | _d S )Nuse_ipv6F)copydeepcopy_network_state_versiongetra   _has_default_route)rC   r   r   r2   r2   r3   __init__   s    zNetworkState.__init__r.   c                 C   s
   | j d S )Nr   )rd   rC   r2   r2   r3   r      s    zNetworkState.configc                 C   s   | j S r5   )re   rj   r2   r2   r3   r      s    zNetworkState.versionc                 C   s.   z| j d d W S  tk
r(   g  Y S X d S )Ndnsr!   rd   KeyErrorrj   r2   r2   r3   dns_nameservers   s    zNetworkState.dns_nameserversc                 C   s.   z| j d d W S  tk
r(   g  Y S X d S )Nrk   searchrl   rj   r2   r2   r3   dns_searchdomains   s    zNetworkState.dns_searchdomainsc                 C   s   | j d kr|  | _ | j S r5   )rg   _maybe_has_default_routerj   r2   r2   r3   has_default_route   s    

zNetworkState.has_default_routeNc                 c   s>   | j di }| D ]"}|d kr*|V  q||r|V  qd S )Nr   )rd   rf   values)rC   filter_funcZifacesifacer2   r2   r3   iter_interfaces   s    zNetworkState.iter_interfacesc                 c   s6   | j dg D ]"}|d k	r*||r0|V  q|V  qd S Nroutesrd   rf   )rC   rt   router2   r2   r3   iter_routes   s
    zNetworkState.iter_routesc                 C   sh   |   D ]}| |r dS q|  D ]<}|dg D ]*}|dg D ]}| |rF   dS qFq6q&dS )NTsubnetsrx   F)r{   _is_default_routerv   rf   )rC   rz   ru   subnetr2   r2   r3   rq      s    

z%NetworkState._maybe_has_default_routec                 C   s    d}| ddko| d|kS )N)z::z0.0.0.0prefixr   network)rf   )rC   rz   Zdefault_netsr2   r2   r3   r}      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   r2   )rX   r   rF   r2   r2   r3   to_passthrough   s    	zNetworkState.to_passthrough)N)N)r@   rA   rB   NETWORK_STATE_VERSIONdictintrh   propertyr   r   rn   rp   rr   rv   r{   rq   r}   classmethodr   r2   r2   r2   r3   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 )Nr6   r!   ro   FN)r   rx   rk   ra   r   zOptional[Renderer])r"   c                 C   s:   || _ || _t| j| _|| jd< d| _i | _|| _d S )Nr   F)	re   _configrb   rc   initial_network_staterd   _parsed_interface_dns_map	_renderer)rC   r   r   r"   r2   r2   r3   rh      s    
z NetworkStateInterpreter.__init__ri   c                 C   sH   ddl m} | jdkr8t| j|r8td t| j	S t| j
| jdS )Nr   r      zPassthrough netplan v2 configr   )cloudinit.net.netplanr   re   
isinstancer   r0   debugr`   r   r   rd   )rC   NetplanRendererr2   r2   r3   r     s
    
z%NetworkStateInterpreter.network_statec                 C   s   | j dS Nra   ry   rj   r2   r2   r3   ra     s    z NetworkStateInterpreter.use_ipv6c                 C   s   | j d|i d S r   )rd   update)rC   valr2   r2   r3   ra     s    c                 C   s   | j | j| jd}t|S )N)r   r   r   )re   r   rd   r   dumps)rC   r8   r2   r2   r3   dump  s
    zNetworkStateInterpreter.dumpc                 C   sv   d|krt d tdt|d  }t||}|rNd| }t | t|dd |D D ]}t| |||  q\d S )Nr   z$Invalid state, missing version fieldzInvalid state, missing keys: %sc                 S   s   g | ]}|d kr|qS )r   r2   ).0kr2   r2   r3   
<listcomp>.  s      z0NetworkStateInterpreter.load.<locals>.<listcomp>)r0   error
ValueErrorNETWORK_STATE_REQUIRED_KEYSr>   setattr)rC   r8   rI   rG   msgr=   r2   r2   r3   r7   !  s    


zNetworkStateInterpreter.loadc                 C   s   t | jS r5   )r   r   rd   rj   r2   r2   r3   dump_network_state1  s    z*NetworkStateInterpreter.dump_network_statec                 C   s   | j | jdS )N)r   r   )re   r   rj   r2   r2   r3   as_dict4  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_v1r   parse_config_v2)rC   r   r2   r2   r3   parse_config7  s    

z$NetworkStateInterpreter.parse_configc                 C   s  | j D ]}|d }z| j| }W n0 tk
rP } ztd| |W 5 d }~X Y nX z|| | W q tk
r   |sx ntjd|dd t|   Y qX q| j	
 D ]l\}}d }z| jd | }W n2 tk
r } ztd||W 5 d }~X Y nX |r|\}	}
|	|
d|d	< qd S )
Ntypez"No handler found for  command '%s'Skipping invalid command: %sTexc_infor   zINameserver specified for interface {0}, but interface {0} does not exist!)r   ro   rk   )r   rQ   rm   RuntimeErrorr?   r0   r1   r   r   r   rR   rd   r   format)rC   r   rD   command_typehandlere	interfacerk   ru   r!   ro   r2   r2   r3   r   ?  sL    
  z'NetworkStateInterpreter.parse_config_v1c                 C   s   ddl m} t| j|rd S | j D ]\}}|dkr8q&z| j| }W n0 tk
rv } ztd| |W 5 d }~X Y nX z|| | | 	| W q& t
k
r   |s ntjd|dd t|   Y q&X q&d S )Nr   r   )r   r"   z!No handler found for command '%s'r   Tr   )r   r   r   r   r   rR   rQ   rm   r   
_v2_commonr?   r0   r1   r   r   )rC   r   r   r   rD   r   r   r2   r2   r3   r   b  s4    
  z'NetworkStateInterpreter.parse_config_v2rY   c                 C   s
   |  |S r5   handle_physicalrC   rD   r2   r2   r3   handle_loopback~  s    z'NetworkStateInterpreter.handle_loopbackc           
      C   s(  | j di }||d i }|di  D ]\}}|||i q.t|d}| js|D ],}|ddst|dr^d| _ qq^|d	d
}|d
k	rt	|}|dd
}	|	d
k	rt	|	}	||d|d|ddd|dd
d
|||	d | j d |d|i | 
  d
S )z
        command = {
            'type': 'physical',
            'mac_address': 'c0:d6:9f:2c:e8:80',
            'name': 'eth0',
            'subnets': [
                {'type': 'dhcp4'}
             ],
            'accept-ra': 'true'
        }
        r   rY   paramsr|   r   6addressTr%   Nr$   mac_addressinetZmanualr    )rY   r   r   r   r&   r    r   gatewayr|   r%   r$   )rd   rf   rR   r   _normalize_subnetsra   endswithr   r   Zis_truer   )
rC   rD   r   ru   paramr   r|   r~   Z	accept_rar$   r2   r2   r3   r     sD    

z'NetworkStateInterpreter.handle_physicalvlan_id	vlan_linkc                 C   s\   | j di }| | ||di }|d|d< |d|d< ||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   rY   r   zvlan-raw-devicer   N)rd   rf   r   r   )rC   rD   r   ru   r2   r2   r3   handle_vlan  s    

z#NetworkStateInterpreter.handle_vlanbond_interfacesr   c           	      C   s  |  | | jd}||di }|d D ]\}}|||i q6|ddi | jd |d |i |dD ]}||kr|dd}|  | | jdi }||}|d|d	< |d D ]\}}|||i q| jd ||i q~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   rY   r   zbond-slavesZnoner   r*   )rY   r   zbond-masterN)r   rd   rf   rR   r   )	rC   rD   r   ru   r   r   ifnamecmdZbond_ifr2   r2   r3   handle_bond  s&    


z#NetworkStateInterpreter.handle_bondbridge_interfacesc           	      C   s  | j di }|dD ] }||kr&qd|i}| | q| j di }| | ||di }|d |d< |di  D ]\}}|||i q|d}|dk	rt|tkr|dkrd	}n|d
krd}ntdj|d|d|i ||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   rY   Zbridge_portsr   r)   N)Zon1r   T)Zoff0r   Fz2Cannot convert bridge_stp value ({stp}) to boolean)r(   )	rd   rf   r   rR   r   r   boolr   r   )	rC   rD   r   r   r   ru   r   r   r)   r2   r2   r3   handle_bridge  s6     

z%NetworkStateInterpreter.handle_bridgec                 C   s   |  | d S r5   r   r   r2   r2   r3   handle_infiniband@  s    z)NetworkStateInterpreter.handle_infinibandc                 C   sz   g }g }d|kr>|d }t |tks*|g}|D ]}|| q.d|krr|d }t|ts^|g}|D ]}|| qb||fS )Nr   ro   )r   listappendr   )rC   rD   r!   ro   Zaddrsaddrpathspathr2   r2   r3   
_parse_dnsD  s    
z"NetworkStateInterpreter._parse_dnsr   c                 C   sV   | j d}| |\}}d|kr6||f| j|d < n|d | |d | d S )Nrk   r   r!   ro   )rd   rf   r   r   extend)rC   rD   rk   r!   ro   r2   r2   r3   handle_nameserverU  s    z)NetworkStateInterpreter.handle_nameserverc                 C   s0   | j d}| |\}}||d|| d< d S )Nr   r   rk   )rd   rf   r   )rC   rD   ru   Z_ifacer!   ro   r2   r2   r3   _handle_individual_nameserverb  s    z5NetworkStateInterpreter._handle_individual_nameserverdestinationc                 C   s   | j d t| d S rw   )rd   r   _normalize_router   r2   r2   r3   handle_routeh  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_bridger   r2   r2   r3   handle_bondsm  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   Nr   r   r2   r2   r3   handle_bridges  s    z&NetworkStateInterpreter.handle_bridgesc                 C   s  t  }| D ]\}}ddi}|di }|dd}|sNtd|t| ||d< |}|d}	|	rn|	}n |r|r| }
t|
}|r|}||d	< |d
d}|rd
|i|d< dD ]}||kr|| ||< qt| | 	|}t
|dkr|d|i td| | | qdS )a  
        ethernets:
          eno1:
            match:
              macaddress: 00:11:22:33:44:55
              driver: hv_netsvc
            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   Zphysicalr   
macaddressNzHNetworkState Version2: missing "macaddress" info in config entry: %s: %sr   r#   rY   driverr   )r    r   r$   r%   r   r|   z!v2(ethernets) -> v1(physical):
%s)r	   rR   rf   r0   r   strlowerr   r4   _v2_to_v1_ipcfgrU   r   r   )rC   rD   Zifaces_by_macZethcfgZphy_cmdr   r   rY   Zset_nameZlcase_mac_addressZmacr   r=   r|   r2   r2   r3   handle_ethernets  sH    - 

z(NetworkStateInterpreter.handle_ethernetsc                 C   s   |  D ]x\}}d||d|dd}d|kr>|d |d< t| | |}t|dkrj|d|i td| | | q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'}],
        }
        vlanidlink)r   rY   r   r   r    r   r|   zv2(vlans) -> v1(vlan):
%sN)	rR   rf   r4   r   rU   r   r0   r   r   )rC   rD   r   r   Zvlan_cmdr|   r2   r2   r3   handle_vlans  s    
z$NetworkStateInterpreter.handle_vlansc                 C   s   t d d S )NzOWifi configuration is only available to distros with netplan rendering support.r/   r   r2   r2   r3   handle_wifis&  s    z$NetworkStateInterpreter.handle_wifisc           
      C   s   t d| | D ]\}}d|kr6|d}|r6|}d|kr|ddg }|ddg }ddi}t|dkr|d|i t|dkr|d	|i | | |d
i d}|rt|}	|	r|	}| || qd S )Nzv2_common: handling config:
%sr#   r!   ro   r   r   Z
nameserverr   r   r   r   )	r0   r   rR   rf   rU   r   r   r   r   )
rC   r   ru   Zdev_cfgZset_name_ifacero   rk   Zname_cmdr   Zreal_if_namer2   r2   r3   r   ,  s.    

z"NetworkStateInterpreter._v2_commonc           
         s.  t dd t| D  | D ]\}}t dd | D }|di }|dd}|rh||d< d|d	||d
 |ddt  fdd| D i}d|kr|d |d< t| | |}	t|	dkr|d|	i t	
d||| |dkr| | q$|dkr| | q$tdj|dq$dS )z(Common handler for bond and bridge typesc                 s   s   | ]\}}||fV  qd S r5   r2   r   r   vr2   r2   r3   	<genexpr>K  s    z>NetworkStateInterpreter._handle_bond_bridge.<locals>.<genexpr>c                 s   s"   | ]\}}|t kr||fV  qd S r5   )NETWORK_V2_KEY_FILTER)r   r=   valuer2   r2   r3   r   P  s   Z
parameterszgratuitious-arpNr'   r   rY   Z_interfacesr   r   c                 3   s   | ]\}} | |fV  qd S r5   r2   r   Zv2key_to_v1r2   r3   r   `  s     r    r   r|   zv2(%s) -> v1(%s):
%sr+   r*   z Unknown command type: {cmd_type}r   )r   r,   rf   rR   popr4   r   rU   r   r0   r   r   r   r   r   )
rC   rD   r   Z	item_nameZitem_cfgZitem_paramsr   Z
grat_valueZv1_cmdr|   r2   r   r3   r   G  sH        


z+NetworkStateInterpreter._handle_bond_bridgec                 C   s  dd }g }| dr:ddi}|| di | || | drnddi}d| _|| di | || d	}d	}i }| d
g D ]}d|d}d|krd|kr|d	kr| d}|d|i n(d|kr|d	kr| d}|d|i d|krD|sD| d d
}	|	r|	|d< | d d}
|
r:|
|d< || || qg }| dg D ]&}|t| d| dd q`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metricr2   )Z	overridesr~   r2   r2   r3   _add_dhcp_overridesy  s    zDNetworkStateInterpreter._v2_to_v1_ipcfg.<locals>._add_dhcp_overridesr   r   r   r   Tr   Nr   static)r   r   :r   r   r   r!   rn   ro   
dns_searchrx   toZvia)r   r   r   )rf   r   ra   r   r   rU   )rC   r   r   r|   r~   r   r   r!   r   r   ro   rx   rz   r2   r2   r3   r   v  s\    






z'NetworkStateInterpreter._v2_to_v1_ipcfg)T)T)T)N)%r@   rA   rB   r   r   rh   r   r`   r   ra   setterr   r7   r   r   r   r   r   rO   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r2   r2   r2   r3   r6      sl   



#


6

4

@



^"
/r6   )	metaclassc                 C   sz   t | } tdd |  D }| ddkr@|t|dd dd | d	g D |d	< d
d }dD ]}||| qf|S )Nc                 s   s   | ]\}}|r||fV  qd S r5   r2   r   r2   r2   r3   r     s      z$_normalize_subnet.<locals>.<genexpr>r   )r   Zstatic6)r   Z
ip_addressaddress_keysc                 S   s   g | ]}t |qS r2   )r   )r   rr2   r2   r3   r     s    z%_normalize_subnet.<locals>.<listcomp>rx   c                 S   s*   || kr&t | | ts&| |  | |< d S r5   )r   r   split)ZsnetrY   r2   r2   r3   listify  s    z"_normalize_subnet.<locals>.listify)r   rn   )rb   rc   r   rR   rf   r   _normalize_net_keys)r~   Znormal_subnetr   r   r2   r2   r3   _normalize_subnet  s     
	

r   r2   c                 C   s  dd |   D }d}|D ]}||r|} q2q|sZdd|| f }t| t|t||}t|std| td| dt|}t	|}|d	}	d
|kr|
d
\}
}}|
||< |rt|}n*|rt|}ntd| td| dnRd|krt|d }n:|	r0|r0t|	}n$|	rF|rFt|	}n|rPdnd}d|krt|d t|krt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   r2   r   r2   r2   r3   
<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)rR   rf   joinr0   r   r   r   r   r   r   	partitionr   r
   r   r1   r   )r   r   ZnetZaddr_keyr=   messager   Zipv6Zipv4r  Z	addr_part_Zmaybe_prefixr   r2   r2   r3   r     sb    








 
r   c              
   C   s   t dd |  D }d|kr0|d |d< |d= |t|dd |d}|rzt||d< W n2 tk
r } ztd||W 5 d	}~X Y 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 )) NNr2   r   r2   r2   r3   r   +  s     z#_normalize_route.<locals>.<genexpr>r   r   )r   r   r   r   z(Route config metric {} is not an integerN)	r   rR   r   r   rf   r   r   	TypeErrorr   )rz   Znormal_router   r   r2   r2   r3   r   !  s.    
 
r   c                 C   s   | sg } dd | D S )Nc                 S   s   g | ]}t |qS r2   )r   )r   sr2   r2   r3   r   F  s     z&_normalize_subnets.<locals>.<listcomp>r2   )r|   r2   r2   r3   r   C  s    r   T)
net_configr   r.   c                 C   sf   d}|  d}|  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   r6   r   r   r   )r  r   r"   r8   r   r   r9   r2   r2   r3   parse_net_config_dataI  s$    	

  r  )r2   )TN)1rb   rK   Zloggingtypingr   r   r   r   Z	cloudinitr   r   Zcloudinit.netr   r	   r
   r   r   r   r   r   r   Zcloudinit.net.rendererr   Z	getLoggerr@   r0   r   r   r   r,   r   __annotations__r   r4   r:   r>   	Exceptionr?   rO   r   rP   r`   r6   r   r   r   r   r   r  r2   r2   r2   r3   <module>   s    ,
 "
V     P
L"  