a 'Dgb@sUddlZddlZddlZddlmZmZmZmZddlm Z m Z m Z ddl m Z mZmZmZmZmZmZmZmZerddlmZeeZdZdgdiZgdZd d d d d ddddddddddddddddddddd dd! d"Zeeeeeffe d#<e!dd$d%d&Z"d'd(Z#Gd)d*d*e$Z%d+d,Z&Gd-d.d.Z'Gd/d0d0Z(d1d2Z)d>d4d5Z*d6d7Z+d8d9Z,d?e!e-e'd;d.wrapper..decorator) functoolswraps)rFrHrG)rFr4wrapperns z$ensure_command_keys..wrapperr3)rGrLr3rKr4ensure_command_keysms rMc@seZdZefeedddZeedddZeddZ ed d Z ed d Z ed dZ dddZ dddZddZddZeeddddZdS) NetworkState)rrcCs*t||_||_|dd|_d|_dS)Nuse_ipv6F)copydeepcopy_network_state_versiongetrO_has_default_route)rArrr3r3r4__init__s zNetworkState.__init__r2cCs |jdS)Nr)rRrAr3r3r4rszNetworkState.configcCs|jSr6)rSrXr3r3r4rszNetworkState.versioncCs,z|jddWSty&gYS0dS)Ndnsr#rRKeyErrorrXr3r3r4dns_nameserverss zNetworkState.dns_nameserverscCs,z|jddWSty&gYS0dS)NrYsearchrZrXr3r3r4dns_searchdomainss zNetworkState.dns_searchdomainscCs|jdur||_|jSr6)rU_maybe_has_default_routerXr3r3r4has_default_routes  zNetworkState.has_default_routeNccs>|jdi}|D]"}|dur*|Vq||r|VqdS)Nr )rRrTvalues)rA filter_funcZifacesifacer3r3r4iter_interfacess  zNetworkState.iter_interfacesccs6|jdgD]"}|dur*||r0|Vq|VqdSNroutesrRrT)rArbrouter3r3r4 iter_routess zNetworkState.iter_routescCsh|D]}||rdSq|D]<}|dgD]*}|dgD]}||rFdSqFq6q&dS)NTsubnetsrfF)ri_is_default_routerdrT)rArhrcsubnetr3r3r4r_s    z%NetworkState._maybe_has_default_routecCs d}|ddko|d|vS)N)z::z0.0.0.0prefixrnetwork)rT)rArhZ default_netsr3r3r4rkszNetworkState._is_default_route)rr2cCs,i}d|vr|d|d<|d|ifi|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`. rrr3)clsrrDr3r3r4to_passthroughs  zNetworkState.to_passthrough)N)N)r>r?r@NETWORK_STATE_VERSIONdictintrVpropertyrrr\r^r`rdrir_rk classmethodrpr3r3r3r4rNs(       rNc@seZdZigggddddZeddfddddZeed d d Zed d Z e j dd Z ddZ ddZ ddZ ddZdHddZdIddZdJddZedgdd Zedgd!d"Zegd#d$d%Zegd&d'd(Zedd)gd*d+Zedgd,d-Zd.d/Zed0gd1d2Zed0gd3d4Zed5gd6d7Zd8d9Zd:d;Zdd?Z d@dAZ!dd dBdCZ"dKdDdEZ#dFdGZ$dS)LNetworkStateInterpreterr#r]FN)r rfrYrOrzOptional[Renderer])r$cCsv||_||_t|j|_||jd<d|_i|_||_|j |j |j |j |j |j|j|j|j|j|j|j|jd |_dS)NrF) r.Zbondsr/ZbridgesZ ethernetsZ infinibandZloopback nameserverphysicalrhvlanZvlansZwifis)rS_configrPrQinitial_network_staterR_parsed_interface_dns_map _renderer handle_bond handle_bonds handle_bridgehandle_bridgeshandle_ethernetshandle_infinibandhandle_loopbackhandle_nameserverhandle_physical handle_route handle_vlan handle_vlans handle_wifiscommand_handlers)rArrr$r3r3r4rVs* z NetworkStateInterpreter.__init__rWcCsHddlm}|jdkr8t|j|r8tdt|j St|j |jdS)NrrzPassthrough netplan v2 configr) cloudinit.net.netplanrrS isinstancerLOGdebugrNrpr{rR)rANetplanRendererr3r3r4rs    z%NetworkStateInterpreter.network_statecCs |jdSNrOrgrXr3r3r4rOsz NetworkStateInterpreter.use_ipv6cCs|jd|idSr)rRupdate)rAvalr3r3r4rO scCs|j|j|jd}t|S)Nr)rSr{rRrdumps)rAstater3r3r4dumps zNetworkStateInterpreter.dumpcCsvd|vrtdtdt|d}t||}|rNd|}t|t|dd|DD]}t||||q\dS)Nrz$Invalid state, missing version fieldzInvalid state, missing keys: %scSsg|]}|dvr|qS)rr3).0kr3r3r4 $z0NetworkStateInterpreter.load..)rerror ValueErrorNETWORK_STATE_REQUIRED_KEYSr<setattr)rArrGrEmsgr;r3r3r4loads    zNetworkStateInterpreter.loadcCs t|jSr6)rrrRrXr3r3r4dump_network_state'sz*NetworkStateInterpreter.dump_network_statecCs|j|jdS)N)rr)rSr{rXr3r3r4as_dict*szNetworkStateInterpreter.as_dictTcCs>|jdkr|j|dd|_n|jdkr:|j|dd|_dS)Nr skip_brokenTr)rSparse_config_v1r}parse_config_v2)rArr3r3r4 parse_config-s     z$NetworkStateInterpreter.parse_configc Cs|jD]}|d}z|j|}Wn2tyR}ztd||WYd}~n d}~00z ||Wqty|svntjd|ddt|Yq0q|j D]n\}}d}z|j d|}Wn4ty}zt d ||WYd}~n d}~00|r|\} } | | d|d <qdS) Ntypez"No handler found for command '%s'Skipping invalid command: %sTexc_infor zINameserver specified for interface {0}, but interface {0} does not exist!rwrY)r{rr[ RuntimeErrorr=rwarningrrr~itemsrRrformat) rArrB command_typehandlere interfacerYrcr#r]r3r3r4r5sH   z'NetworkStateInterpreter.parse_config_v1c Csddlm}t|j|rdS|jD]\}}|dvr8q&z|j|}Wn2tyx}ztd||WYd}~n d}~00z||| |Wq&t y|snt j d|ddt |Yq&0q&dS)Nrr)rr$z!No handler found for command '%s'rTr)rrrrr{rrr[r _v2_commonr=rrrr)rArrrrBrrr3r3r4rXs0   z'NetworkStateInterpreter.parse_config_v2namecCs ||Sr6rrArBr3r3r4rtsz'NetworkStateInterpreter.handle_loopbackc Cs\|jdi}||di}|diD]\}}|||iq.t|d}|js|D],}|ddst|dr^d|_qq^|d d }|d urt |}|d d } | d urt | } |d d } | d urt | } ||d |d|d|ddd|dd d ||| | d |d |d} |jd| |i| d S)z command = { 'type': 'physical', 'mac_address': 'c0:d6:9f:2c:e8:80', 'name': 'eth0', 'subnets': [ {'type': 'dhcp4'} ], 'accept-ra': 'true' } r rparamsrjr6addressTr'Nr&r( config_id mac_addressinetZmanualr") rrrrrr)r"rgatewayrjr'r&r() rRrTrr_normalize_subnetsrOendswithrrZis_truer) rArBr rcparamrrjrlZ accept_rar&r(Z iface_keyr3r3r4rxsP      z'NetworkStateInterpreter.handle_physical)rvlan_id vlan_linkcCs\|jdi}||||di}|d|d<|d|d<||d|idS)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 rrzvlan-raw-devicerN)rRrTrr)rArBr rcr3r3r4rs  z#NetworkStateInterpreter.handle_vlan)rbond_interfacesrc Cs|||jd}||di}|dD]\}}|||iq6|ddi|jd|d|i|dD]}||vr|dd}|||jdi}||}|d|d <|dD]\}}|||iq|jd||iq~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 rrz bond-slavesZnonerr.)rrz bond-masterN)rrRrTrr) rArBr rcrrifnamecmdZbond_ifr3r3r4rs&    z#NetworkStateInterpreter.handle_bondbridge_interfacesc Cs|jdi}|dD] }||vr&qd|i}||q|jdi}||||di}|d|d<|diD]\}}|||iq|d}|durt|ts|dvrd }n|d vrd }ntd j|d |d|i||d|idS)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 rrZ bridge_portsrr-N)Zon1rT)Zoff0rFz2Cannot convert bridge_stp value ({stp}) to boolean)r,) rRrTrrrrboolrr) rArBr rrrcrrr-r3r3r4rs4    z%NetworkStateInterpreter.handle_bridgecCs||dSr6rrr3r3r4r<sz)NetworkStateInterpreter.handle_infinibandcCsxg}g}d|vr<|d}t|ts(|g}|D]}||q,d|vrp|d}t|ts\|g}|D]}||q`||fS)Nrr])rlistappend)rArBr#r]addrsaddrpathspathr3r3r4 _parse_dns@s    z"NetworkStateInterpreter._parse_dnsrcCsV|jd}||\}}d|vr6||f|j|d<n|d||d|dS)NrYrr#r])rRrTrr~extend)rArBrYr#r]r3r3r4rQs z)NetworkStateInterpreter.handle_nameservercCs0|jd}||\}}||d||d<dS)Nr rwrY)rRrTr)rArBrcZ_ifacer#r]r3r3r4_handle_individual_nameserver^s z5NetworkStateInterpreter._handle_individual_nameserver destinationcCs|jdt|dSre)rRr_normalize_routerr3r3r4rdsz$NetworkStateInterpreter.handle_routecCs|j|dddS)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_bridgerr3r3r4risz$NetworkStateInterpreter.handle_bondscCs|j|dddS)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/rNrrr3r3r4rsz&NetworkStateInterpreter.handle_bridgescCst}|D]\}}|dd}|di}|dd}|sPtd|t|||d<|}|d} | rp| }n |r|r|} t| } | r| }||d <|d d} | rd | i|d <d D]} | |vr|| || <qt|| |}t |d kr| d|itd|| |qdS)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'} ] } ry)rrr!Z macaddressNzHNetworkState Version2: missing "macaddress" info in config entry: %s: %srr%rdriverr)r"r!r&r'r(rrjz!v2(ethernets) -> v1(physical): %s) r rrTrrstrlowerr r5_v2_to_v1_ipcfglenrr)rArBZ ifaces_by_macZethcfgZphy_cmdr!rrZset_nameZlcase_mac_addressZmacrr;rjr3r3r4rsH-        z(NetworkStateInterpreter.handle_ethernetscCs|D]x\}}d||d|dd}d|vr>|d|d<t|||}t|dkrj|d|itd|||qd 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'}], } rzidlink)rrrrr"rrjzv2(vlans) -> v1(vlan): %sN) rrTr5rrrrrr)rArBrzrZvlan_cmdrjr3r3r4rs    z$NetworkStateInterpreter.handle_vlanscCstddS)NzOWifi configuration is only available to distros with netplan rendering support.)rrrr3r3r4r"sz$NetworkStateInterpreter.handle_wifiscCsvtd||D]\\}}d|vr|dd}|dd}ddi}|rX||d<|rd||d<|||qdS)Nzv2_common: handling config: %sr#r]rrrxr)rrrrTr)rArrcZdev_cfgr]rYZname_cmdr3r3r4r(s z"NetworkStateInterpreter._v2_commonc s.tddt|D|D]\}}tdd|D}|di}|dd}|rh||d<d|d ||d |d d tfd d|Di}d|vr|d|d<t|||} t| dkr|d| it d||||dkr| |q$|dkr| |q$t dj|dq$dS)z(Common handler for bond and bridge typescss|]\}}||fVqdSr6r3rrvr3r3r4 :sz>NetworkStateInterpreter._handle_bond_bridge..css"|]\}}|tvr||fVqdSr6)NETWORK_V2_KEY_FILTER)rr;valuer3r3r4r?s parameterszgratuitious-arpNr*rrZ _interfacesr rc3s|]\}}||fVqdSr6r3rZ v2key_to_v1r3r4rOrr"rrjzv2(%s) -> v1(%s): %sr/r.z Unknown command type: {cmd_type}r)rrr0rTrpopr5rrrrrrrrr) rArBrZ item_nameZitem_cfgZ item_paramsrZ grat_valueZv1_cmdrjr3rr4r6s@          z+NetworkStateInterpreter._handle_bond_bridgec Csdd}g}|dr:ddi}||di||||drnddi}d|_||di|||d }d }i}|d gD]}d |d }d |vrd|vr|d ur|d}|d|in(d|vr|d ur|d}|d|id|vrD|sD|dd } | r| |d<|dd} | r:| |d<||||qg} |dgD]6} | t| d| d| d| ddq`t|rt| r| |dd<|S)z7Common ipconfig extraction from v2 to v1 subnets array.cSsd|vr|d|d<dS)Nz route-metricmetricr3)Z overridesrlr3r3r4_add_dhcp_overrideshszDNetworkStateInterpreter._v2_to_v1_ipcfg.._add_dhcp_overridesrrrrTrNrstatic)rr:rrrr#r\r] dns_searchrftoZviarr")rrrr"r)rTrrOrrr) rArrrjrlrrr#rrr]rfrhr3r3r4res`          z'NetworkStateInterpreter._v2_to_v1_ipcfg)T)T)T)N)%r>r?r@r|rqrVrtrNrrOsetterrrrrrrrrMrrrrrrrrrrrrrrrrrrr3r3r3r4rvsl      #   <    4  @    _" /rvcCszt|}tdd|D}|ddvr@|t|dddd|d gD|d <d d }d D]}|||qf|S) Ncss|]\}}|r||fVqdSr6r3rr3r3r4rrz$_normalize_subnet..r)rZstatic6)r ip_address address_keyscSsg|] }t|qSr3)r)rrr3r3r4rsz%_normalize_subnet..rfcSs*||vr&t||ts&||||<dSr6)rrsplit)Zsnetrr3r3r4listifysz"_normalize_subnet..listify)rr\)rPrQrrrrTr_normalize_net_keys)rlZ normal_subnetrrr3r3r4_normalize_subnets     rr3cCsdd|D}d}|D]}||r|}q2q|sZdd||f}t|t|t||}t|std|td|dt|}t |}|d } d |vr| d \} } } | ||<|rt | } n*|rt | } ntd|td|dnRd |vrt |d } n:| r0|r0t | } n$| rF|rFt | } n|rPd nd } d |vrt|d t| krtd| || |d <|rd |vr|d =n|rt|d |d <|S)aNormalize 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. cSs"i|]\}}|s|dkr||qS)rr3rr3r3r4 rz'_normalize_net_keys..Nz/No config network address keys [%s] found in %s,z$Address %s is not a valid ip networkzAddress z is not a valid ip addressnetmask/rm@z;Overwriting existing 'prefix' with '%s' in network info: %s)rrTjoinrrrrr rr partitionr r rsrr)rnrnetZaddr_keyr;messagerZipv6Zipv4rZ addr_part_Z maybe_prefixrmr3r3r4rsb                rc Cstdd|D}d|vr0|d|d<|d=|t|dd|d}|rzt||d<Wn4ty}ztd||WYd }~n d }~00|S) anormalize 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. css"|]\}}|dvr||fVqdS))NNr3rr3r3r4rsz#_normalize_route..rrn)rnrrrz(Route config metric {} is not an integerN) rrrrrrTrsr TypeErrorr)rhZ normal_routerrr3r3r4rs,   rcCs|sg}dd|DS)NcSsg|] }t|qSr3)r)rsr3r3r4r7rz&_normalize_subnets..r3)rjr3r3r4r4srT) net_configrr2cCsfd}|d}|d}|dkr$|}|rP|durPt|||d}|j|d|j}|sbtd||S)zfParses the config, returns NetworkState object :param net_config: curtin network config dict Nrrr)rrr$rzpNo valid network_state object created from network config. Did you specify the correct version? Network config: )rTrvrrr)r rr$rrrZnsir3r3r4parse_net_config_data:s$     r )r3)TN)/rPrIZloggingtypingrrrrZ cloudinitrrrZ cloudinit.netr r r r r rrrrZcloudinit.net.rendererrZ getLoggerr>rrqrrr0r__annotations__rrr5r< Exceptionr=rMrNrvrrrrrr r3r3r3r4s~ ,   " VY L"