o
    th͑                     @   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
mZ d dlmZmZmZmZmZmZmZmZmZmZ erCd dlmZ eeZdZdg diZg d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d dd!d"Zee ee ef f e!d#< d$e"d%dfd&d'Z#d(d) Z$G d*d+ d+e%Z&d,d- Z'G d.d/ d/Z(G d0d1 d1Z)d2d3 Z*d@d5d6Z+d7d8 Z,d9d: Z-	;	dAd<e"d=e.d%e(fd>d?Z/dS )B    N)TYPE_CHECKINGAnyDictOptional)	lifecycle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_address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-raoptionalz	ad-selectzarp-intervalzarp-ip-targetzarp-validatez
down-delayzfail-over-mac-policyz	lacp-ratezmii-monitor-intervalz	min-linksmodegratuitous-arp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-timepriorityzforward-delayz
hello-timezmax-agez	path-costzport-prioritystp)bridge_ageingbridge_bridgeprio	bridge_fdbridge_gcintbridge_hellobridge_maxagebridge_maxwaitbridge_pathcostbridge_portprio
bridge_stpbridge_waitport)bondbridgeNET_CONFIG_TO_V2diktreturnc                 C   s(   d| v sd| v rt jdddd dS dS )z8Warn about deprecations of v2 properties for all devicesr   r    z$The use of `gateway4` and `gateway6`z22.4zbFor more info check out: https://docs.cloud-init.io/en/latest/topics/network-config-format-v2.html)
deprecateddeprecated_versionextra_messageN)r   	deprecate)r=    rC   =/usr/lib/python3/dist-packages/cloudinit/net/network_state.pywarn_deprecated_all_devicesX   s   
rE   c                 C   s    t | }|D ]}|| q|S N)setdiscard)expectedactualmissingkeyrC   rC   rD   	diff_keysc   s   rM   c                   @   s   e Zd ZdS )InvalidCommandN)__name__
__module____qualname__rC   rC   rC   rD   rN   j   s    rN   c                    s    fdd}|S )Nc                    s   t   fdd}|S )Nc                    s:   rt |}|rtd|f  | |g|R i |S )Nz&Command missing %s of required keys %s)rM   rN   )selfcommandargskwargsmissing_keys)funcrequired_keysrC   rD   	decoratorp   s   
z7ensure_command_keys.<locals>.wrapper.<locals>.decorator)	functoolswraps)rW   rY   rX   )rW   rD   wrappero   s   
z$ensure_command_keys.<locals>.wrapperrC   )rX   r]   rC   r\   rD   ensure_command_keysn   s   r^   c                   @   s   e Zd ZefdedefddZedef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dedd fddZdS )NetworkStater   r   c                 C   s*   t || _|| _|dd| _d | _d S )Nuse_ipv6F)copydeepcopy_network_state_versiongetr`   _has_default_route)rR   r   r   rC   rC   rD   __init__   s   
zNetworkState.__init__r>   c                 C   s
   | j d S )Nr   )rc   rR   rC   rC   rD   r         
zNetworkState.configc                 C   s   | j S rF   )rd   rh   rC   rC   rD   r      s   zNetworkState.versionc                 C   (   z| j d d W S  ty   g  Y S w )Ndnsr$   rc   KeyErrorrh   rC   rC   rD   dns_nameservers   
   zNetworkState.dns_nameserversc                 C   rj   )Nrk   searchrl   rh   rC   rC   rD   dns_searchdomains   ro   zNetworkState.dns_searchdomainsc                 C   s   | j d u r
|  | _ | j S rF   )rf   _maybe_has_default_routerh   rC   rC   rD   has_default_route   s   

zNetworkState.has_default_routeNc                 c   s@    | j di }| D ]}|d u r|V  q||r|V  qd S )Nr!   )rc   re   values)rR   filter_funcifacesifacerC   rC   rD   iter_interfaces   s   zNetworkState.iter_interfacesc                 c   s8    | j dg D ]}|d ur||r|V  q|V  qd S Nroutesrc   re   )rR   ru   routerC   rC   rD   iter_routes   s   zNetworkState.iter_routesc                 C   sh   |   D ]
}| |r dS q|  D ]}|dg D ]}|dg D ]}| |r/   dS q#qqdS )NTsubnetsrz   F)r}   _is_default_routerx   re   )rR   r|   rw   subnetrC   rC   rD   rr      s   


z%NetworkState._maybe_has_default_routec                 C   s    d}| ddko| d|v S )N)z::z0.0.0.0prefixr   network)re   )rR   r|   default_netsrC   rC   rD   r      s   zNetworkState._is_default_routec                 C   s,   i }d|v r|d |d< | d|ifi |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   rC   )clsr   rU   rC   rC   rD   to_passthrough   s   	zNetworkState.to_passthroughrF   )rO   rP   rQ   NETWORK_STATE_VERSIONdictintrg   propertyr   r   rn   rq   rs   rx   r}   rr   r   classmethodr   rC   rC   rC   rD   r_      s.    






	r_   c                   @   s  e Zd Zi g g g ddddZeddf	dHddZed	efd
dZedd Z	e	j
dd Z	dd Zdd Zdd Zdd ZdIddZdIddZdIddZedgdd  Zedgd!d" Zeg d#d$d% Zeg d&d'd( Zedd)gd*d+ Zedgd,d- Zd.d/ Zed0gd1d2 Zed0gd3d4 Zed5gd6d7 Zd8d9 Zd:d; Zd<d= Zd>d? Z d@dA Z!dJdBdCZ"dKdDdEZ#dFdG Z$dS )LNetworkStateInterpreterr$   rp   FN)r!   rz   rk   r`   r   r%   Optional[Renderer]c                 C   sv   || _ || _t| j| _|| jd< d| _i | _|| _| j	| j
| j| j| j| j| j| j| j| j| j| j| jd| _d S )Nr   F)r:   bondsr;   bridges	ethernets
infinibandloopback
nameserverphysicalr|   vlanvlanswifis)rd   _configra   rb   initial_network_staterc   _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)rR   r   r   r%   rC   rC   rD   rg      s*   
z NetworkStateInterpreter.__init__r>   c                 C   sH   ddl m} | jdkrt| j|rtd t| j	S t| j
| jdS )Nr   r      zPassthrough netplan v2 configr   )cloudinit.net.netplanr   rd   
isinstancer   LOGdebugr_   r   r   rc   )rR   NetplanRendererrC   rC   rD   r      s
   
z%NetworkStateInterpreter.network_statec                 C   s   | j dS Nr`   r{   rh   rC   rC   rD   r`     s   z NetworkStateInterpreter.use_ipv6c                 C   s   | j d|i d S r   )rc   update)rR   valrC   rC   rD   r`     s   c                 C   s   | j | j| jd}t|S )Nr   )rd   r   rc   r   dumps)rR   staterC   rC   rD   dump  s
   
zNetworkStateInterpreter.dumpc                 C   sv   d|vrt d tdt|d  }t||}|r'd| }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 vr|qS )r   rC   ).0krC   rC   rD   
<listcomp>%  s    z0NetworkStateInterpreter.load.<locals>.<listcomp>)r   error
ValueErrorNETWORK_STATE_REQUIRED_KEYSrM   setattr)rR   r   rX   rV   msgrL   rC   rC   rD   load  s   


zNetworkStateInterpreter.loadc                 C   s   t | jS rF   )r   r   rc   rh   rC   rC   rD   dump_network_state(  s   z*NetworkStateInterpreter.dump_network_statec                 C   s   | j | jdS )N)r   r   )rd   r   rh   rC   rC   rD   as_dict+  s   zNetworkStateInterpreter.as_dictTc                 C   sD   | j dkr| j|d d| _d S | j dkr | j|d d| _d S d S )Nr   skip_brokenTr   )rd   parse_config_v1r   parse_config_v2)rR   r   rC   rC   rD   parse_config.  s   



z$NetworkStateInterpreter.parse_configc                 C   s   | j D ]B}|d }z| j| }W n ty# } ztd| |d }~ww z|| W q tyE   |s4 tjd|dd t|   Y qw | j	
 D ]1\}}d }z	| jd | }W n tyn } ztd||d }~ww |r||\}	}
|	|
d|d	< qKd 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   rk   )r   r   rm   RuntimeErrorrN   r   warningr   r   r   itemsrc   r   format)rR   r   rS   command_typehandlere	interfacerk   rw   r$   rp   rC   rC   rD   r   6  sT   

z'NetworkStateInterpreter.parse_config_v1c                 C   s   ddl m} t| j|rd S | j D ]J\}}|dv rqz| j| }W n ty6 } ztd| |d }~ww z|| | 	| W q t
y]   |sL tjd|dd t|   Y qw d S )Nr   r   )r   r%   z!No handler found for command '%s'r   Tr   )r   r   r   r   r   r   r   rm   r   
_v2_commonrN   r   r   r   r   )rR   r   r   r   rS   r   r   rC   rC   rD   r   Y  s8   z'NetworkStateInterpreter.parse_config_v2namec                 C   s
   |  |S rF   r   rR   rS   rC   rC   rD   r   u  ri   z'NetworkStateInterpreter.handle_loopbackc                 C   s|  | j di }||d i }|di  D ]\}}|||i qt|d}| jsF|D ]}|dds@t|drEd| _ nq/|d	d
}|d
urUt	|}|dd
}	|	d
urdt	|	}	|dd
}
|
d
urst	|
}
||d|d|d|ddd|dd
d
|||	|
|dd |d r|d 
 |d< |d|d}| j 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!   r   paramsr~   r   6addressTr(   Nr'   r)   	config_idmac_addressinetmanualr#   keep_configuration)r   r   r   r   r   r*   r#   r   gatewayr~   r(   r'   r)   r   )rc   re   r   r   _normalize_subnetsr`   endswithr   r   is_truelowerr   )rR   rS   r!   rw   paramr   r~   r   	accept_rar'   r)   	iface_keyrC   rC   rD   r   y  sX   


z'NetworkStateInterpreter.handle_physical)r   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!   r   r   zvlan-raw-devicer   N)rc   re   r   r   )rR   rS   r!   rw   rC   rC   rD   r     s   

z#NetworkStateInterpreter.handle_vlan)r   bond_interfacesr   c           	      C   s  |  | | jd}||di }|d D ]\}}|||i q|ddi | jd |d |i |dD ]@}||vrO|dd}|  | | jdi }||}|d|d	< |d D ]\}}|||i qi| 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!   r   r   zbond-slavesnoner   r:   )r   r   zbond-masterN)r   rc   re   r   r   )	rR   rS   r!   rw   r   r   ifnamecmdbond_ifrC   rC   rD   r     s(   


z#NetworkStateInterpreter.handle_bondbridge_interfacesc           	      C   s  | j di }|dD ]}||v rqd|i}| | q| j di }| | ||di }|d |d< |di  D ]\}}|||i q@|d}|durwt|tsw|dv rad	}n|d
v rhd}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   r   bridge_portsr   r8   N)on1r   T)off0r   Fz2Cannot convert bridge_stp value ({stp}) to boolean)r.   )	rc   re   r   r   r   r   boolr   r   )	rR   rS   r!   r   r   rw   r   r   r8   rC   rC   rD   r     s4   

z%NetworkStateInterpreter.handle_bridgec                 C   s   |  | d S rF   r   r   rC   rC   rD   r   B  s   z)NetworkStateInterpreter.handle_infinibandc                 C   sx   g }g }d|v r|d }t |ts|g}|D ]}|| qd|v r8|d }t |ts.|g}|D ]}|| q0||fS )Nr   rp   )r   listappend)rR   rS   r$   rp   addrsaddrpathspathrC   rC   rD   
_parse_dnsF  s   

z"NetworkStateInterpreter._parse_dnsr   c                 C   sX   | j d}| |\}}d|v r||f| j|d < d S |d | |d | d S )Nrk   r   r$   rp   )rc   re   r   r   extend)rR   rS   rk   r$   rp   rC   rC   rD   r   W  s   z)NetworkStateInterpreter.handle_nameserverc                 C   s0   | j d}| |\}}||d|| d< d S )Nr!   r   rk   )rc   re   r   )rR   rS   rw   _ifacer$   rp   rC   rC   rD   _handle_individual_nameserverd  s   z5NetworkStateInterpreter._handle_individual_nameserverdestinationc                 C   s   | j d t| d S ry   )rc   r   _normalize_router   rC   rC   rD   r   j  s   z$NetworkStateInterpreter.handle_routec                 C      | 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   rC   rC   rD   r   o  s   z$NetworkStateInterpreter.handle_bondsc                 C   r  )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   rC   rC   rD   r     s   z&NetworkStateInterpreter.handle_bridgesc                 C   s  t  }| D ]\}}|dd}|di }|dd}|s'td|t| ||d< |}|d}	|	r7|	}n|rG|rG| }
t|
}|rG|}||d	< |d
d}|rYd
|i|d< dD ]}||v rg|| ||< q[t| | 	|}t
|dkr~|d|i td| | | q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   )r   r   r"   
macaddressNzHNetworkState Version2: missing "macaddress" info in config entry: %s: %sr   r&   r   driverr   )r#   r"   r'   r(   r)   r   r~   z!v2(ethernets) -> v1(physical):
%s)r
   r   re   r   r   strr   r	   rE   _v2_to_v1_ipcfglenr   r   )rR   rS   ifaces_by_macethcfgphy_cmdr"   r   r   set_namelcase_mac_addressmacr  rL   r~   rC   rC   rD   r     sL   -

z(NetworkStateInterpreter.handle_ethernetsc                 C   s   |  D ]@\}}d||d|d|dd}d|v r#|d |d< t| | |}t|dkr9|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'}],
        }
        r   idlinkr  )r   r   r   r   r   r#   r   r~   zv2(vlans) -> v1(vlan):
%sN)	r   re   rE   r
  r  r   r   r   r   )rR   rS   r   r  vlan_cmdr~   rC   rC   rD   r     s    
z$NetworkStateInterpreter.handle_vlansc                 C   s   t d d S )NzOWifi configuration is only available to distros with netplan rendering support.)r   r   r   rC   rC   rD   r   )  s   z$NetworkStateInterpreter.handle_wifisc                 C   sv   t d| | D ].\}}d|v r8|dd}|dd}ddi}|r,||d< |r2||d< | || q
d S )Nzv2_common: handling config:
%sr$   rp   r   r   r   r   )r   r   r   re   r   )rR   r  rw   dev_cfgrp   rk   name_cmdrC   rC   rD   r   /  s   z"NetworkStateInterpreter._v2_commonc           
         s:  t dd t| D  | D ]\}}t dd | D }|di }|dd}|r3||d< d|d	||d
 |ddt  fdd| D i}d|v rW|d |d< d|v ra|d |d< t| | |}	t|	dkrw|d|	i t	
d||| |dkr| | q|dkr| | qtdj|ddS )z(Common handler for bond and bridge typesc                 s   s    | ]	\}}||fV  qd S rF   rC   r   r   vrC   rC   rD   	<genexpr>A  s    
z>NetworkStateInterpreter._handle_bond_bridge.<locals>.<genexpr>c                 s   s$    | ]\}}|t vr||fV  qd S rF   )NETWORK_V2_KEY_FILTER)r   rL   valuerC   rC   rD   r  F  s    
parameterszgratuitious-arpNr+   r   r   _interfacesr!   r   c                 3   s     | ]\}} | |fV  qd S rF   rC   r  v2key_to_v1rC   rD   r  V      r#   r  r   r   r~   zv2(%s) -> v1(%s):
%sr;   r:   z Unknown command type: {cmd_type}r  )r   r<   re   r   poprE   r
  r  r   r   r   r   r   r   r   )
rR   rS   r  	item_nameitem_cfgitem_paramsr   
grat_valuev1_cmdr~   rC   r  rD   r  =  sF   
z+NetworkStateInterpreter._handle_bond_bridgec                 C   s  dd }g }| drddi}|| di | || | dr7ddi}d| _|| di | || d	}d	}i }| d
g D ]`}d|d}d|v rcd|v rb|d	u rb| d}|d|i nd|v rw|d	u rw| d}|d|i d|v r|s| d d
}	|	r|	|d< | d d}
|
r|
|d< || || qCg }| dg D ]}|t| d| d| d| d| dd qt|rt|r||d d< |S )z7Common ipconfig extraction from v2 to v1 subnets array.c                 S   s   d| v r| d |d< d S d S )Nzroute-metricmetricrC   )	overridesr   rC   rC   rD   _add_dhcp_overridesr  s   zDNetworkStateInterpreter._v2_to_v1_ipcfg.<locals>._add_dhcp_overridesr   r   r   r   Tr   Nr   static)r   r   :r    r   r   r$   rn   rp   
dns_searchrz   toviar(  r#   table)r   r   r(  r#   r0  r   )re   r   r`   r   r  r  )rR   r  r*  r~   r   r   r    r$   r   r   rp   rz   r|   rC   rC   rD   r
  o  sd   






z'NetworkStateInterpreter._v2_to_v1_ipcfg)r%   r   )T)r>   NrF   )%rO   rP   rQ   r   r   rg   r   r_   r   r`   setterr   r   r   r   r   r   r   r^   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r
  rC   rC   rC   rD   r      sn    





#


A



4
@



_#

2r   c                 C   sz   t | } tdd |  D }| ddv r |t|dd dd | d	g D |d	< d
d }dD ]}||| q3|S )Nc                 s   s     | ]\}}|r||fV  qd S rF   rC   r  rC   rC   rD   r    r!  z$_normalize_subnet.<locals>.<genexpr>r   )r+  static6)r   
ip_addressaddress_keysc                 S      g | ]}t |qS rC   )r  )r   rrC   rC   rD   r     s    z%_normalize_subnet.<locals>.<listcomp>rz   c                 S   s2   || v rt | | ts| |  | |< d S d S d S rF   )r   r   split)snetr   rC   rC   rD   listify  s   z"_normalize_subnet.<locals>.listify)r-  rn   )ra   rb   r   r   re   r   _normalize_net_keys)r   normal_subnetr:  r   rC   rC   rD   _normalize_subnet  s    
	

r=  rC   c                 C   s  dd |   D }d}|D ]}||r|} nq|s-dd|| f }t| t|t||}|dkrit|d}|sLd}t| t|t|rSd	}nt|rZd
}nd| d}t| t|t	|s{td| td| dt
|}t|}	|d}
d|v r|d\}}}|||< |rt|}n8|	rt|}n1td| td| dd|v rt|d }n|
r|	rt|
}n|
r|rt|
}n|rdnd}d|v rt|d t|krtd|| ||d< |rd|v r|d= |S |	rt|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   rC   r  rC   rC   rD   
<dictcomp>  s   " z'_normalize_net_keys.<locals>.<dictcomp>Nz/No config network address keys [%s] found in %s,defaultr   zGateway IP is emptyz	0.0.0.0/0z::/0zInvalid Gateway IP: ''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   re   joinr   r   r   r	  r   r   r   r   r   	partitionr   r   r   r   r   )r   r5  netaddr_keyrL   messager   gw_ipipv6ipv4rB  	addr_part_maybe_prefixr   rC   rC   rD   r;    s   








r;  c              
   C   s   t dd |  D }d|v r|d |d< |d= |t|dd |d}|rFz	t||d< W |S  tyE } ztd||d	}~ww |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 vr||fV  qdS )) NNrC   r  rC   rC   rD   r  7  s    z#_normalize_route.<locals>.<genexpr>r   r   )r   r   r4  r(  z(Route config metric {} is not an integerN)	r   r   r   r;  re   r   r   	TypeErrorr   )r|   normal_router(  r   rC   rC   rD   r  -  s2   

r  c                 C   s   | sg } dd | D S )Nc                 S   r6  rC   )r=  )r   srC   rC   rD   r   R  s    z&_normalize_subnets.<locals>.<listcomp>rC   )r~   rC   rC   rD   r   O  s   r   T
net_configr   c                 C   sf   d}|  d}|  d}|dkr| }|r(|dur(t|||d}|j|d |j}|s1t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:
)re   r   r   r   r   )rU  r   r%   r   r   r   nsirC   rC   rD   parse_net_config_dataU  s$   	

rW  )rC   )TN)0ra   rZ   loggingtypingr   r   r   r   	cloudinitr   r   r   cloudinit.netr	   r
   r   r   r   r   r   r   r   r   cloudinit.net.rendererr   	getLoggerrO   r   r   r   r  r<   r	  __annotations__r   rE   rM   	ExceptionrN   r^   r_   r   r=  r;  r  r   r   rW  rC   rC   rC   rD   <module>   s   
0
"V     c
\"