summaryrefslogtreecommitdiff
path: root/tests/unittests/test_net.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unittests/test_net.py')
-rw-r--r--tests/unittests/test_net.py5107
1 files changed, 3274 insertions, 1833 deletions
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 70453683..47e4ba00 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -1,20 +1,5 @@
# This file is part of cloud-init. See LICENSE file for license information.
-from cloudinit import net
-from cloudinit import distros
-from cloudinit.net import cmdline
-from cloudinit.net import (
- eni, interface_has_own_mac, natural_sort_key, netplan, network_state,
- renderers, sysconfig)
-from cloudinit.sources.helpers import openstack
-from cloudinit import temp_utils
-from cloudinit import subp
-from cloudinit import util
-from cloudinit import safeyaml as yaml
-
-from cloudinit.tests.helpers import (
- CiTestCase, FilesystemMockingTestCase, dir2dict, mock, populate_dir)
-
import base64
import copy
import gzip
@@ -23,9 +8,32 @@ import json
import os
import re
import textwrap
-from yaml.serializer import Serializer
import pytest
+from yaml.serializer import Serializer
+
+from cloudinit import distros, net
+from cloudinit import safeyaml as yaml
+from cloudinit import subp, temp_utils, util
+from cloudinit.net import (
+ cmdline,
+ eni,
+ interface_has_own_mac,
+ natural_sort_key,
+ netplan,
+ network_state,
+ networkd,
+ renderers,
+ sysconfig,
+)
+from cloudinit.sources.helpers import openstack
+from tests.unittests.helpers import (
+ CiTestCase,
+ FilesystemMockingTestCase,
+ dir2dict,
+ mock,
+ populate_dir,
+)
DHCP_CONTENT_1 = """
DEVICE='eth0'
@@ -48,15 +56,19 @@ DOMAINSEARCH='foo.com'
"""
DHCP_EXPECTED_1 = {
- 'name': 'eth0',
- 'type': 'physical',
- 'subnets': [{'broadcast': '192.168.122.255',
- 'control': 'manual',
- 'gateway': '192.168.122.1',
- 'dns_search': ['foo.com'],
- 'type': 'dhcp',
- 'netmask': '255.255.255.0',
- 'dns_nameservers': ['192.168.122.1']}],
+ "name": "eth0",
+ "type": "physical",
+ "subnets": [
+ {
+ "broadcast": "192.168.122.255",
+ "control": "manual",
+ "gateway": "192.168.122.1",
+ "dns_search": ["foo.com"],
+ "type": "dhcp",
+ "netmask": "255.255.255.0",
+ "dns_nameservers": ["192.168.122.1"],
+ }
+ ],
}
DHCP6_CONTENT_1 = """
@@ -73,12 +85,17 @@ DNSDOMAIN=
"""
DHCP6_EXPECTED_1 = {
- 'name': 'eno1',
- 'type': 'physical',
- 'subnets': [{'control': 'manual',
- 'dns_nameservers': ['2001:67c:1562:8010::2:1'],
- 'netmask': '64',
- 'type': 'dhcp6'}]}
+ "name": "eno1",
+ "type": "physical",
+ "subnets": [
+ {
+ "control": "manual",
+ "dns_nameservers": ["2001:67c:1562:8010::2:1"],
+ "netmask": "64",
+ "type": "dhcp6",
+ }
+ ],
+}
STATIC_CONTENT_1 = """
@@ -97,14 +114,20 @@ DOMAINSEARCH='foo.com'
"""
STATIC_EXPECTED_1 = {
- 'name': 'eth1',
- 'type': 'physical',
- 'subnets': [{'broadcast': '10.0.0.255', 'control': 'manual',
- 'gateway': '10.0.0.1',
- 'dns_search': ['foo.com'], 'type': 'static',
- 'netmask': '255.255.255.0',
- 'dns_nameservers': ['10.0.1.1'],
- 'address': '10.0.0.2'}],
+ "name": "eth1",
+ "type": "physical",
+ "subnets": [
+ {
+ "broadcast": "10.0.0.255",
+ "control": "manual",
+ "gateway": "10.0.0.1",
+ "dns_search": ["foo.com"],
+ "type": "static",
+ "netmask": "255.255.255.0",
+ "dns_nameservers": ["10.0.1.1"],
+ "address": "10.0.0.2",
+ }
+ ],
}
V1_NAMESERVER_ALIAS = """
@@ -471,34 +494,42 @@ ethernets:
# Examples (and expected outputs for various renderers).
OS_SAMPLES = [
{
- 'in_data': {
+ "in_data": {
"services": [{"type": "dns", "address": "172.19.0.12"}],
- "networks": [{
- "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
- "type": "ipv4", "netmask": "255.255.252.0",
- "link": "tap1a81968a-79",
- "routes": [{
- "netmask": "0.0.0.0",
- "network": "0.0.0.0",
- "gateway": "172.19.3.254",
- }],
- "ip_address": "172.19.1.34", "id": "network0"
- }],
+ "networks": [
+ {
+ "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
+ "type": "ipv4",
+ "netmask": "255.255.252.0",
+ "link": "tap1a81968a-79",
+ "routes": [
+ {
+ "netmask": "0.0.0.0",
+ "network": "0.0.0.0",
+ "gateway": "172.19.3.254",
+ }
+ ],
+ "ip_address": "172.19.1.34",
+ "id": "network0",
+ }
+ ],
"links": [
{
"ethernet_mac_address": "fa:16:3e:ed:9a:59",
- "mtu": None, "type": "bridge", "id":
- "tap1a81968a-79",
- "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+ "mtu": None,
+ "type": "bridge",
+ "id": "tap1a81968a-79",
+ "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f",
},
],
},
- 'in_macs': {
- 'fa:16:3e:ed:9a:59': 'eth0',
+ "in_macs": {
+ "fa:16:3e:ed:9a:59": "eth0",
},
- 'out_sysconfig_opensuse': [
- ('etc/sysconfig/network/ifcfg-eth0',
- """
+ "out_sysconfig_opensuse": [
+ (
+ "etc/sysconfig/network/ifcfg-eth0",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
BOOTPROTO=static
@@ -506,26 +537,39 @@ IPADDR=172.19.1.34
LLADDR=fa:16:3e:ed:9a:59
NETMASK=255.255.252.0
STARTMODE=auto
-""".lstrip()),
- ('etc/resolv.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/resolv.conf",
+ """
; Created by cloud-init on instance boot automatically, do not edit.
;
nameserver 172.19.0.12
-""".lstrip()),
- ('etc/NetworkManager/conf.d/99-cloud-init.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/NetworkManager/conf.d/99-cloud-init.conf",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
[main]
dns = none
-""".lstrip()),
- ('etc/udev/rules.d/85-persistent-net-cloud-init.rules',
- "".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
- 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))],
- 'out_sysconfig_rhel': [
- ('etc/sysconfig/network-scripts/ifcfg-eth0',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/udev/rules.d/85-persistent-net-cloud-init.rules",
+ "".join(
+ [
+ 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
+ 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n',
+ ]
+ ),
+ ),
+ ],
+ "out_sysconfig_rhel": [
+ (
+ "etc/sysconfig/network-scripts/ifcfg-eth0",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
BOOTPROTO=none
@@ -539,60 +583,82 @@ NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
-""".lstrip()),
- ('etc/resolv.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/resolv.conf",
+ """
; Created by cloud-init on instance boot automatically, do not edit.
;
nameserver 172.19.0.12
-""".lstrip()),
- ('etc/NetworkManager/conf.d/99-cloud-init.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/NetworkManager/conf.d/99-cloud-init.conf",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
[main]
dns = none
-""".lstrip()),
- ('etc/udev/rules.d/70-persistent-net.rules',
- "".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
- 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))]
-
+""".lstrip(),
+ ),
+ (
+ "etc/udev/rules.d/70-persistent-net.rules",
+ "".join(
+ [
+ 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
+ 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n',
+ ]
+ ),
+ ),
+ ],
},
{
- 'in_data': {
+ "in_data": {
"services": [{"type": "dns", "address": "172.19.0.12"}],
- "networks": [{
- "network_id": "public-ipv4",
- "type": "ipv4", "netmask": "255.255.252.0",
- "link": "tap1a81968a-79",
- "routes": [{
- "netmask": "0.0.0.0",
- "network": "0.0.0.0",
- "gateway": "172.19.3.254",
- }],
- "ip_address": "172.19.1.34", "id": "network0"
- }, {
- "network_id": "private-ipv4",
- "type": "ipv4", "netmask": "255.255.255.0",
- "link": "tap1a81968a-79",
- "routes": [],
- "ip_address": "10.0.0.10", "id": "network1"
- }],
+ "networks": [
+ {
+ "network_id": "public-ipv4",
+ "type": "ipv4",
+ "netmask": "255.255.252.0",
+ "link": "tap1a81968a-79",
+ "routes": [
+ {
+ "netmask": "0.0.0.0",
+ "network": "0.0.0.0",
+ "gateway": "172.19.3.254",
+ }
+ ],
+ "ip_address": "172.19.1.34",
+ "id": "network0",
+ },
+ {
+ "network_id": "private-ipv4",
+ "type": "ipv4",
+ "netmask": "255.255.255.0",
+ "link": "tap1a81968a-79",
+ "routes": [],
+ "ip_address": "10.0.0.10",
+ "id": "network1",
+ },
+ ],
"links": [
{
"ethernet_mac_address": "fa:16:3e:ed:9a:59",
- "mtu": None, "type": "bridge", "id":
- "tap1a81968a-79",
- "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+ "mtu": None,
+ "type": "bridge",
+ "id": "tap1a81968a-79",
+ "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f",
},
],
},
- 'in_macs': {
- 'fa:16:3e:ed:9a:59': 'eth0',
+ "in_macs": {
+ "fa:16:3e:ed:9a:59": "eth0",
},
- 'out_sysconfig_opensuse': [
- ('etc/sysconfig/network/ifcfg-eth0',
- """
+ "out_sysconfig_opensuse": [
+ (
+ "etc/sysconfig/network/ifcfg-eth0",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
BOOTPROTO=static
@@ -602,26 +668,39 @@ LLADDR=fa:16:3e:ed:9a:59
NETMASK=255.255.252.0
NETMASK1=255.255.255.0
STARTMODE=auto
-""".lstrip()),
- ('etc/resolv.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/resolv.conf",
+ """
; Created by cloud-init on instance boot automatically, do not edit.
;
nameserver 172.19.0.12
-""".lstrip()),
- ('etc/NetworkManager/conf.d/99-cloud-init.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/NetworkManager/conf.d/99-cloud-init.conf",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
[main]
dns = none
-""".lstrip()),
- ('etc/udev/rules.d/85-persistent-net-cloud-init.rules',
- "".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
- 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))],
- 'out_sysconfig_rhel': [
- ('etc/sysconfig/network-scripts/ifcfg-eth0',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/udev/rules.d/85-persistent-net-cloud-init.rules",
+ "".join(
+ [
+ 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
+ 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n',
+ ]
+ ),
+ ),
+ ],
+ "out_sysconfig_rhel": [
+ (
+ "etc/sysconfig/network-scripts/ifcfg-eth0",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
BOOTPROTO=none
@@ -637,80 +716,106 @@ NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
-""".lstrip()),
- ('etc/resolv.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/resolv.conf",
+ """
; Created by cloud-init on instance boot automatically, do not edit.
;
nameserver 172.19.0.12
-""".lstrip()),
- ('etc/NetworkManager/conf.d/99-cloud-init.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/NetworkManager/conf.d/99-cloud-init.conf",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
[main]
dns = none
-""".lstrip()),
- ('etc/udev/rules.d/70-persistent-net.rules',
- "".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
- 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))]
-
+""".lstrip(),
+ ),
+ (
+ "etc/udev/rules.d/70-persistent-net.rules",
+ "".join(
+ [
+ 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
+ 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n',
+ ]
+ ),
+ ),
+ ],
},
{
- 'in_data': {
+ "in_data": {
"services": [{"type": "dns", "address": "172.19.0.12"}],
- "networks": [{
- "network_id": "public-ipv4",
- "type": "ipv4", "netmask": "255.255.252.0",
- "link": "tap1a81968a-79",
- "routes": [{
- "netmask": "0.0.0.0",
- "network": "0.0.0.0",
- "gateway": "172.19.3.254",
- }],
- "ip_address": "172.19.1.34", "id": "network0"
- }, {
- "network_id": "public-ipv6-a",
- "type": "ipv6", "netmask": "",
- "link": "tap1a81968a-79",
- "routes": [
- {
- "gateway": "2001:DB8::1",
- "netmask": "::",
- "network": "::"
- }
- ],
- "ip_address": "2001:DB8::10", "id": "network1"
- }, {
- "network_id": "public-ipv6-b",
- "type": "ipv6", "netmask": "64",
- "link": "tap1a81968a-79",
- "routes": [
- ],
- "ip_address": "2001:DB9::10", "id": "network2"
- }, {
- "network_id": "public-ipv6-c",
- "type": "ipv6", "netmask": "64",
- "link": "tap1a81968a-79",
- "routes": [
- ],
- "ip_address": "2001:DB10::10", "id": "network3"
- }],
+ "networks": [
+ {
+ "network_id": "public-ipv4",
+ "type": "ipv4",
+ "netmask": "255.255.252.0",
+ "link": "tap1a81968a-79",
+ "routes": [
+ {
+ "netmask": "0.0.0.0",
+ "network": "0.0.0.0",
+ "gateway": "172.19.3.254",
+ }
+ ],
+ "ip_address": "172.19.1.34",
+ "id": "network0",
+ },
+ {
+ "network_id": "public-ipv6-a",
+ "type": "ipv6",
+ "netmask": "",
+ "link": "tap1a81968a-79",
+ "routes": [
+ {
+ "gateway": "2001:DB8::1",
+ "netmask": "::",
+ "network": "::",
+ }
+ ],
+ "ip_address": "2001:DB8::10",
+ "id": "network1",
+ },
+ {
+ "network_id": "public-ipv6-b",
+ "type": "ipv6",
+ "netmask": "64",
+ "link": "tap1a81968a-79",
+ "routes": [],
+ "ip_address": "2001:DB9::10",
+ "id": "network2",
+ },
+ {
+ "network_id": "public-ipv6-c",
+ "type": "ipv6",
+ "netmask": "64",
+ "link": "tap1a81968a-79",
+ "routes": [],
+ "ip_address": "2001:DB10::10",
+ "id": "network3",
+ },
+ ],
"links": [
{
"ethernet_mac_address": "fa:16:3e:ed:9a:59",
- "mtu": None, "type": "bridge", "id":
- "tap1a81968a-79",
- "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+ "mtu": None,
+ "type": "bridge",
+ "id": "tap1a81968a-79",
+ "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f",
},
],
},
- 'in_macs': {
- 'fa:16:3e:ed:9a:59': 'eth0',
+ "in_macs": {
+ "fa:16:3e:ed:9a:59": "eth0",
},
- 'out_sysconfig_opensuse': [
- ('etc/sysconfig/network/ifcfg-eth0',
- """
+ "out_sysconfig_opensuse": [
+ (
+ "etc/sysconfig/network/ifcfg-eth0",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
BOOTPROTO=static
@@ -721,26 +826,39 @@ IPADDR6_2=2001:DB10::10/64
LLADDR=fa:16:3e:ed:9a:59
NETMASK=255.255.252.0
STARTMODE=auto
-""".lstrip()),
- ('etc/resolv.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/resolv.conf",
+ """
; Created by cloud-init on instance boot automatically, do not edit.
;
nameserver 172.19.0.12
-""".lstrip()),
- ('etc/NetworkManager/conf.d/99-cloud-init.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/NetworkManager/conf.d/99-cloud-init.conf",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
[main]
dns = none
-""".lstrip()),
- ('etc/udev/rules.d/85-persistent-net-cloud-init.rules',
- "".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
- 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))],
- 'out_sysconfig_rhel': [
- ('etc/sysconfig/network-scripts/ifcfg-eth0',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/udev/rules.d/85-persistent-net-cloud-init.rules",
+ "".join(
+ [
+ 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
+ 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n',
+ ]
+ ),
+ ),
+ ],
+ "out_sysconfig_rhel": [
+ (
+ "etc/sysconfig/network-scripts/ifcfg-eth0",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
BOOTPROTO=none
@@ -760,24 +878,36 @@ NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
-""".lstrip()),
- ('etc/resolv.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/resolv.conf",
+ """
; Created by cloud-init on instance boot automatically, do not edit.
;
nameserver 172.19.0.12
-""".lstrip()),
- ('etc/NetworkManager/conf.d/99-cloud-init.conf',
- """
+""".lstrip(),
+ ),
+ (
+ "etc/NetworkManager/conf.d/99-cloud-init.conf",
+ """
# Created by cloud-init on instance boot automatically, do not edit.
#
[main]
dns = none
-""".lstrip()),
- ('etc/udev/rules.d/70-persistent-net.rules',
- "".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
- 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))]
- }
+""".lstrip(),
+ ),
+ (
+ "etc/udev/rules.d/70-persistent-net.rules",
+ "".join(
+ [
+ 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
+ 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n',
+ ]
+ ),
+ ),
+ ],
+ },
]
EXAMPLE_ENI = """
@@ -820,8 +950,39 @@ iface eth1 inet static
""".lstrip()
NETWORK_CONFIGS = {
- 'small': {
- 'expected_eni': textwrap.dedent("""\
+ "small": {
+ "expected_networkd_eth99": textwrap.dedent(
+ """\
+ [Match]
+ Name=eth99
+ MACAddress=c0:d6:9f:2c:e8:80
+ [Address]
+ Address=192.168.21.3/24
+ [Network]
+ DHCP=ipv4
+ Domains=barley.maas sach.maas
+ Domains=wark.maas
+ DNS=1.2.3.4 5.6.7.8
+ DNS=8.8.8.8 8.8.4.4
+ [Route]
+ Gateway=65.61.151.37
+ Destination=0.0.0.0/0
+ Metric=10000
+ """
+ ).rstrip(" "),
+ "expected_networkd_eth1": textwrap.dedent(
+ """\
+ [Match]
+ Name=eth1
+ MACAddress=cf:d6:af:48:e8:80
+ [Network]
+ DHCP=no
+ Domains=wark.maas
+ DNS=1.2.3.4 5.6.7.8
+ """
+ ).rstrip(" "),
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
dns-nameservers 1.2.3.4 5.6.7.8
@@ -839,8 +1000,10 @@ NETWORK_CONFIGS = {
dns-search barley.maas sach.maas
post-up route add default gw 65.61.151.37 metric 10000 || true
pre-down route del default gw 65.61.151.37 metric 10000 || true
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
@@ -866,29 +1029,37 @@ NETWORK_CONFIGS = {
to: 0.0.0.0/0
via: 65.61.151.37
set-name: eth99
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-eth1': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-eth1": textwrap.dedent(
+ """\
BOOTPROTO=static
LLADDR=cf:d6:af:48:e8:80
- STARTMODE=auto"""),
- 'ifcfg-eth99': textwrap.dedent("""\
+ STARTMODE=auto"""
+ ),
+ "ifcfg-eth99": textwrap.dedent(
+ """\
BOOTPROTO=dhcp4
LLADDR=c0:d6:9f:2c:e8:80
IPADDR=192.168.21.3
NETMASK=255.255.255.0
- STARTMODE=auto"""),
+ STARTMODE=auto"""
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-eth1': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-eth1": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=eth1
HWADDR=cf:d6:af:48:e8:80
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
- USERCTL=no"""),
- 'ifcfg-eth99': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-eth99": textwrap.dedent(
+ """\
BOOTPROTO=dhcp
DEFROUTE=yes
DEVICE=eth99
@@ -904,9 +1075,11 @@ NETWORK_CONFIGS = {
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
- USERCTL=no"""),
+ USERCTL=no"""
+ ),
},
- 'yaml': textwrap.dedent("""
+ "yaml": textwrap.dedent(
+ """
version: 1
config:
# Physical interfaces.
@@ -935,10 +1108,20 @@ NETWORK_CONFIGS = {
- 5.6.7.8
search:
- wark.maas
- """),
+ """
+ ),
},
- 'v4_and_v6': {
- 'expected_eni': textwrap.dedent("""\
+ "v4_and_v6": {
+ "expected_networkd": textwrap.dedent(
+ """\
+ [Match]
+ Name=iface0
+ [Network]
+ DHCP=yes
+ """
+ ).rstrip(" "),
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
@@ -947,22 +1130,28 @@ NETWORK_CONFIGS = {
# control-alias iface0
iface iface0 inet6 dhcp
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
iface0:
dhcp4: true
dhcp6: true
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp
DHCLIENT6_MODE=managed
- STARTMODE=auto""")
+ STARTMODE=auto"""
+ )
},
- 'yaml': textwrap.dedent("""\
+ "yaml": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
@@ -970,10 +1159,25 @@ NETWORK_CONFIGS = {
subnets:
- {'type': 'dhcp4'}
- {'type': 'dhcp6'}
- """).rstrip(' '),
+ """
+ ).rstrip(" "),
},
- 'v4_and_v6_static': {
- 'expected_eni': textwrap.dedent("""\
+ "v4_and_v6_static": {
+ "expected_networkd": textwrap.dedent(
+ """\
+ [Match]
+ Name=iface0
+ [Link]
+ MTUBytes=8999
+ [Network]
+ DHCP=no
+ [Address]
+ Address=192.168.14.2/24
+ Address=2001:1::1/64
+ """
+ ).rstrip(" "),
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
@@ -986,8 +1190,10 @@ NETWORK_CONFIGS = {
iface iface0 inet6 static
address 2001:1::1/64
mtu 1500
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
@@ -997,8 +1203,10 @@ NETWORK_CONFIGS = {
- 2001:1::1/64
ipv6-mtu: 1500
mtu: 9000
- """).rstrip(' '),
- 'yaml': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "yaml": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
@@ -1011,19 +1219,23 @@ NETWORK_CONFIGS = {
- type: static
address: 2001:1::1/64
mtu: 1500
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=static
IPADDR=192.168.14.2
IPADDR6=2001:1::1/64
NETMASK=255.255.255.0
STARTMODE=auto
MTU=9000
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=iface0
IPADDR=192.168.14.2
@@ -1038,17 +1250,21 @@ NETWORK_CONFIGS = {
USERCTL=no
MTU=9000
IPV6_MTU=1500
- """),
+ """
+ ),
},
},
- 'v6_and_v4': {
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ "v6_and_v4": {
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp
DHCLIENT6_MODE=managed
- STARTMODE=auto""")
+ STARTMODE=auto"""
+ )
},
- 'yaml': textwrap.dedent("""\
+ "yaml": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
@@ -1056,40 +1272,58 @@ NETWORK_CONFIGS = {
subnets:
- type: dhcp6
- type: dhcp4
- """).rstrip(' '),
+ """
+ ).rstrip(" "),
},
- 'dhcpv6_only': {
- 'expected_eni': textwrap.dedent("""\
+ "dhcpv6_only": {
+ "expected_networkd": textwrap.dedent(
+ """\
+ [Match]
+ Name=iface0
+ [Network]
+ DHCP=ipv6
+ """
+ ).rstrip(" "),
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
auto iface0
iface iface0 inet6 dhcp
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
iface0:
dhcp6: true
- """).rstrip(' '),
- 'yaml': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "yaml": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
name: 'iface0'
subnets:
- {'type': 'dhcp6'}
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp6
DHCLIENT6_MODE=managed
STARTMODE=auto
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=iface0
DHCPV6C=yes
@@ -1099,27 +1333,33 @@ NETWORK_CONFIGS = {
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
},
- 'dhcpv6_accept_ra': {
- 'expected_eni': textwrap.dedent("""\
+ "dhcpv6_accept_ra": {
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
auto iface0
iface iface0 inet6 dhcp
accept_ra 1
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
iface0:
accept-ra: true
dhcp6: true
- """).rstrip(' '),
- 'yaml_v1': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "yaml_v1": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
@@ -1127,23 +1367,29 @@ NETWORK_CONFIGS = {
subnets:
- {'type': 'dhcp6'}
accept-ra: true
- """).rstrip(' '),
- 'yaml_v2': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "yaml_v2": textwrap.dedent(
+ """\
version: 2
ethernets:
iface0:
dhcp6: true
accept-ra: true
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp6
DHCLIENT6_MODE=managed
STARTMODE=auto
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=iface0
DHCPV6C=yes
@@ -1154,27 +1400,42 @@ NETWORK_CONFIGS = {
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
+ "expected_networkd": textwrap.dedent(
+ """\
+ [Match]
+ Name=iface0
+ [Network]
+ DHCP=ipv6
+ IPv6AcceptRA=True
+ """
+ ).rstrip(" "),
},
- 'dhcpv6_reject_ra': {
- 'expected_eni': textwrap.dedent("""\
+ "dhcpv6_reject_ra": {
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
auto iface0
iface iface0 inet6 dhcp
accept_ra 0
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
iface0:
accept-ra: false
dhcp6: true
- """).rstrip(' '),
- 'yaml_v1': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "yaml_v1": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
@@ -1182,23 +1443,29 @@ NETWORK_CONFIGS = {
subnets:
- {'type': 'dhcp6'}
accept-ra: false
- """).rstrip(' '),
- 'yaml_v2': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "yaml_v2": textwrap.dedent(
+ """\
version: 2
ethernets:
iface0:
dhcp6: true
accept-ra: false
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp6
DHCLIENT6_MODE=managed
STARTMODE=auto
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=iface0
DHCPV6C=yes
@@ -1209,42 +1476,61 @@ NETWORK_CONFIGS = {
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
+ "expected_networkd": textwrap.dedent(
+ """\
+ [Match]
+ Name=iface0
+ [Network]
+ DHCP=ipv6
+ IPv6AcceptRA=False
+ """
+ ).rstrip(" "),
},
- 'ipv6_slaac': {
- 'expected_eni': textwrap.dedent("""\
+ "ipv6_slaac": {
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
auto iface0
iface iface0 inet6 auto
dhcp 0
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
iface0:
dhcp6: true
- """).rstrip(' '),
- 'yaml': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "yaml": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
name: 'iface0'
subnets:
- {'type': 'ipv6_slaac'}
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp6
DHCLIENT6_MODE=info
STARTMODE=auto
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=iface0
IPV6_AUTOCONF=yes
@@ -1254,11 +1540,13 @@ NETWORK_CONFIGS = {
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
},
- 'static6': {
- 'yaml': textwrap.dedent("""\
+ "static6": {
+ "yaml": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
@@ -1267,9 +1555,11 @@ NETWORK_CONFIGS = {
subnets:
- type: 'static6'
address: 2001:1::1/64
- """).rstrip(' '),
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=iface0
IPV6ADDR=2001:1::1/64
@@ -1281,42 +1571,52 @@ NETWORK_CONFIGS = {
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
},
- 'dhcpv6_stateless': {
- 'expected_eni': textwrap.dedent("""\
+ "dhcpv6_stateless": {
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
auto iface0
iface iface0 inet6 auto
dhcp 1
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
iface0:
dhcp6: true
- """).rstrip(' '),
- 'yaml': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "yaml": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
name: 'iface0'
subnets:
- {'type': 'ipv6_dhcpv6-stateless'}
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp6
DHCLIENT6_MODE=info
STARTMODE=auto
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=iface0
DHCPV6C=yes
@@ -1328,26 +1628,32 @@ NETWORK_CONFIGS = {
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
},
- 'dhcpv6_stateful': {
- 'expected_eni': textwrap.dedent("""\
+ "dhcpv6_stateful": {
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
auto iface0
iface iface0 inet6 dhcp
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
iface0:
accept-ra: true
dhcp6: true
- """).rstrip(' '),
- 'yaml': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "yaml": textwrap.dedent(
+ """\
version: 1
config:
- type: 'physical'
@@ -1355,95 +1661,118 @@ NETWORK_CONFIGS = {
subnets:
- {'type': 'ipv6_dhcpv6-stateful'}
accept-ra: true
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp6
DHCLIENT6_MODE=managed
STARTMODE=auto
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
- BOOTPROTO=none
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
+ BOOTPROTO=dhcp
DEVICE=iface0
DHCPV6C=yes
IPV6INIT=yes
+ IPV6_AUTOCONF=no
IPV6_FORCE_ACCEPT_RA=yes
DEVICE=iface0
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
},
- 'wakeonlan_disabled': {
- 'expected_eni': textwrap.dedent("""\
+ "wakeonlan_disabled": {
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
auto iface0
iface iface0 inet dhcp
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
ethernets:
iface0:
dhcp4: true
wakeonlan: false
version: 2
- """),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp4
STARTMODE=auto
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp
DEVICE=iface0
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
- 'yaml_v2': textwrap.dedent("""\
+ "yaml_v2": textwrap.dedent(
+ """\
version: 2
ethernets:
iface0:
dhcp4: true
wakeonlan: false
- """).rstrip(' '),
+ """
+ ).rstrip(" "),
},
- 'wakeonlan_enabled': {
- 'expected_eni': textwrap.dedent("""\
+ "wakeonlan_enabled": {
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
auto iface0
iface iface0 inet dhcp
ethernet-wol g
- """).rstrip(' '),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ).rstrip(" "),
+ "expected_netplan": textwrap.dedent(
+ """
network:
ethernets:
iface0:
dhcp4: true
wakeonlan: true
version: 2
- """),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ """
+ ),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp4
ETHTOOL_OPTS="wol g"
STARTMODE=auto
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-iface0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-iface0": textwrap.dedent(
+ """\
BOOTPROTO=dhcp
DEVICE=iface0
ETHTOOL_OPTS="wol g"
@@ -1451,18 +1780,21 @@ NETWORK_CONFIGS = {
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
- 'yaml_v2': textwrap.dedent("""\
+ "yaml_v2": textwrap.dedent(
+ """\
version: 2
ethernets:
iface0:
dhcp4: true
wakeonlan: true
- """).rstrip(' '),
+ """
+ ).rstrip(" "),
},
- 'all': {
- 'expected_eni': ("""\
+ "all": {
+ "expected_eni": """\
auto lo
iface lo inet loopback
dns-nameservers 8.8.8.8 4.4.4.4 8.8.4.4
@@ -1552,8 +1884,9 @@ iface eth0.101 inet static
post-up route add -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
-"""),
- 'expected_netplan': textwrap.dedent("""
+""",
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
@@ -1649,25 +1982,31 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
- barley.maas
- sacchromyces.maas
- brettanomyces.maas
- """).rstrip(' '),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-bond0': textwrap.dedent("""\
+ """
+ ).rstrip(" "),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-bond0": textwrap.dedent(
+ """\
BONDING_MASTER=yes
- BONDING_OPTS="mode=active-backup """
- """xmit_hash_policy=layer3+4 """
- """miimon=100"
+ BONDING_MODULE_OPTS="mode=active-backup """
+ """xmit_hash_policy=layer3+4 """
+ """miimon=100"
BONDING_SLAVE_0=eth1
BONDING_SLAVE_1=eth2
BOOTPROTO=dhcp6
DHCLIENT6_MODE=managed
LLADDR=aa:bb:cc:dd:ee:ff
- STARTMODE=auto"""),
- 'ifcfg-bond0.200': textwrap.dedent("""\
+ STARTMODE=auto"""
+ ),
+ "ifcfg-bond0.200": textwrap.dedent(
+ """\
BOOTPROTO=dhcp4
ETHERDEVICE=bond0
STARTMODE=auto
- VLAN_ID=200"""),
- 'ifcfg-br0': textwrap.dedent("""\
+ VLAN_ID=200"""
+ ),
+ "ifcfg-br0": textwrap.dedent(
+ """\
BRIDGE_AGEINGTIME=250
BOOTPROTO=static
IPADDR=192.168.14.2
@@ -1677,12 +2016,16 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
BRIDGE_PRIORITY=22
BRIDGE_PORTS='eth3 eth4'
STARTMODE=auto
- BRIDGE_STP=off"""),
- 'ifcfg-eth0': textwrap.dedent("""\
+ BRIDGE_STP=off"""
+ ),
+ "ifcfg-eth0": textwrap.dedent(
+ """\
BOOTPROTO=static
LLADDR=c0:d6:9f:2c:e8:80
- STARTMODE=auto"""),
- 'ifcfg-eth0.101': textwrap.dedent("""\
+ STARTMODE=auto"""
+ ),
+ "ifcfg-eth0.101": textwrap.dedent(
+ """\
BOOTPROTO=static
IPADDR=192.168.0.2
IPADDR1=192.168.2.10
@@ -1691,44 +2034,58 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
NETMASK1=255.255.255.0
ETHERDEVICE=eth0
STARTMODE=auto
- VLAN_ID=101"""),
- 'ifcfg-eth1': textwrap.dedent("""\
+ VLAN_ID=101"""
+ ),
+ "ifcfg-eth1": textwrap.dedent(
+ """\
BOOTPROTO=none
LLADDR=aa:d6:9f:2c:e8:80
- STARTMODE=hotplug"""),
- 'ifcfg-eth2': textwrap.dedent("""\
+ STARTMODE=hotplug"""
+ ),
+ "ifcfg-eth2": textwrap.dedent(
+ """\
BOOTPROTO=none
LLADDR=c0:bb:9f:2c:e8:80
- STARTMODE=hotplug"""),
- 'ifcfg-eth3': textwrap.dedent("""\
+ STARTMODE=hotplug"""
+ ),
+ "ifcfg-eth3": textwrap.dedent(
+ """\
BOOTPROTO=static
BRIDGE=yes
LLADDR=66:bb:9f:2c:e8:80
- STARTMODE=auto"""),
- 'ifcfg-eth4': textwrap.dedent("""\
+ STARTMODE=auto"""
+ ),
+ "ifcfg-eth4": textwrap.dedent(
+ """\
BOOTPROTO=static
BRIDGE=yes
LLADDR=98:bb:9f:2c:e8:80
- STARTMODE=auto"""),
- 'ifcfg-eth5': textwrap.dedent("""\
+ STARTMODE=auto"""
+ ),
+ "ifcfg-eth5": textwrap.dedent(
+ """\
BOOTPROTO=dhcp
LLADDR=98:bb:9f:2c:e8:8a
- STARTMODE=manual"""),
- 'ifcfg-ib0': textwrap.dedent("""\
+ STARTMODE=manual"""
+ ),
+ "ifcfg-ib0": textwrap.dedent(
+ """\
BOOTPROTO=static
LLADDR=a0:00:02:20:fe:80:00:00:00:00:00:00:ec:0d:9a:03:00:15:e2:c1
IPADDR=192.168.200.7
MTU=9000
NETMASK=255.255.255.0
STARTMODE=auto
- TYPE=InfiniBand"""),
+ TYPE=InfiniBand"""
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-bond0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-bond0": textwrap.dedent(
+ """\
BONDING_MASTER=yes
BONDING_OPTS="mode=active-backup """
- """xmit_hash_policy=layer3+4 """
- """miimon=100"
+ """xmit_hash_policy=layer3+4 """
+ """miimon=100"
BONDING_SLAVE0=eth1
BONDING_SLAVE1=eth2
BOOTPROTO=none
@@ -1739,8 +2096,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Bond
- USERCTL=no"""),
- 'ifcfg-bond0.200': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-bond0.200": textwrap.dedent(
+ """\
BOOTPROTO=dhcp
DEVICE=bond0.200
DHCLIENT_SET_DEFAULT_ROUTE=no
@@ -1748,8 +2107,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
ONBOOT=yes
PHYSDEV=bond0
USERCTL=no
- VLAN=yes"""),
- 'ifcfg-br0': textwrap.dedent("""\
+ VLAN=yes"""
+ ),
+ "ifcfg-br0": textwrap.dedent(
+ """\
AGEING=250
BOOTPROTO=none
DEFROUTE=yes
@@ -1767,16 +2128,20 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
PRIO=22
STP=no
TYPE=Bridge
- USERCTL=no"""),
- 'ifcfg-eth0': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-eth0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=eth0
HWADDR=c0:d6:9f:2c:e8:80
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
- USERCTL=no"""),
- 'ifcfg-eth0.101': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-eth0.101": textwrap.dedent(
+ """\
BOOTPROTO=none
DEFROUTE=yes
DEVICE=eth0.101
@@ -1793,8 +2158,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
ONBOOT=yes
PHYSDEV=eth0
USERCTL=no
- VLAN=yes"""),
- 'ifcfg-eth1': textwrap.dedent("""\
+ VLAN=yes"""
+ ),
+ "ifcfg-eth1": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=eth1
HWADDR=aa:d6:9f:2c:e8:80
@@ -1803,8 +2170,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
ONBOOT=yes
SLAVE=yes
TYPE=Ethernet
- USERCTL=no"""),
- 'ifcfg-eth2': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-eth2": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=eth2
HWADDR=c0:bb:9f:2c:e8:80
@@ -1813,8 +2182,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
ONBOOT=yes
SLAVE=yes
TYPE=Ethernet
- USERCTL=no"""),
- 'ifcfg-eth3': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-eth3": textwrap.dedent(
+ """\
BOOTPROTO=none
BRIDGE=br0
DEVICE=eth3
@@ -1822,8 +2193,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
- USERCTL=no"""),
- 'ifcfg-eth4': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-eth4": textwrap.dedent(
+ """\
BOOTPROTO=none
BRIDGE=br0
DEVICE=eth4
@@ -1831,8 +2204,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
- USERCTL=no"""),
- 'ifcfg-eth5': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-eth5": textwrap.dedent(
+ """\
BOOTPROTO=dhcp
DEVICE=eth5
DHCLIENT_SET_DEFAULT_ROUTE=no
@@ -1840,8 +2215,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
NM_CONTROLLED=no
ONBOOT=no
TYPE=Ethernet
- USERCTL=no"""),
- 'ifcfg-ib0': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-ib0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=ib0
HWADDR=a0:00:02:20:fe:80:00:00:00:00:00:00:ec:0d:9a:03:00:15:e2:c1
@@ -1851,9 +2228,11 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
NM_CONTROLLED=no
ONBOOT=yes
TYPE=InfiniBand
- USERCTL=no"""),
+ USERCTL=no"""
+ ),
},
- 'yaml': textwrap.dedent("""
+ "yaml": textwrap.dedent(
+ """
version: 1
config:
# Physical interfaces.
@@ -1996,10 +2375,12 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
destination: 10.0.0.0/8
gateway: 11.0.0.1
metric: 3
- """).lstrip(),
+ """
+ ).lstrip(),
},
- 'bond': {
- 'yaml': textwrap.dedent("""
+ "bond": {
+ "yaml": textwrap.dedent(
+ """
version: 1
config:
- type: physical
@@ -2040,13 +2421,15 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
routes:
- gateway: 2001:67c:1562:1
network: 2001:67c:1
- netmask: ffff:ffff:0
+ netmask: "ffff:ffff::"
- gateway: 3001:67c:1562:1
network: 3001:67c:1
- netmask: ffff:ffff:0
+ netmask: "ffff:ffff::"
metric: 10000
- """),
- 'expected_netplan': textwrap.dedent("""
+ """
+ ),
+ "expected_netplan": textwrap.dedent(
+ """
network:
version: 2
ethernets:
@@ -2088,8 +2471,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
- metric: 10000
to: 3001:67c:1/32
via: 3001:67c:1562:1
- """),
- 'expected_eni': textwrap.dedent("""\
+ """
+ ),
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
@@ -2151,8 +2536,10 @@ iface bond0 inet6 static
|| true
pre-down route del -A inet6 3001:67c:1/32 gw 3001:67c:1562:1 metric 10000 \
|| true
- """),
- 'yaml-v2': textwrap.dedent("""
+ """
+ ),
+ "yaml-v2": textwrap.dedent(
+ """
version: 2
ethernets:
eth0:
@@ -2192,8 +2579,10 @@ iface bond0 inet6 static
- metric: 10000
to: 3001:67c:1562:8007::1/64
via: 3001:67c:1562:8007::aac:40b2
- """),
- 'expected_netplan-v2': textwrap.dedent("""
+ """
+ ),
+ "expected_netplan-v2": textwrap.dedent(
+ """
network:
bonds:
bond0:
@@ -2234,17 +2623,18 @@ iface bond0 inet6 static
macaddress: aa:bb:cc:dd:e8:01
set-name: vf0
version: 2
- """),
-
- 'expected_sysconfig_opensuse': {
- 'ifcfg-bond0': textwrap.dedent("""\
+ """
+ ),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-bond0": textwrap.dedent(
+ """\
BONDING_MASTER=yes
- BONDING_OPTS="mode=active-backup xmit_hash_policy=layer3+4 """
- """miimon=100 num_grat_arp=5 """
- """downdelay=10 updelay=20 """
- """fail_over_mac=active """
- """primary=bond0s0 """
- """primary_reselect=always"
+ BONDING_MODULE_OPTS="mode=active-backup xmit_hash_policy=layer3+4 """
+ """miimon=100 num_grat_arp=5 """
+ """downdelay=10 updelay=20 """
+ """fail_over_mac=active """
+ """primary=bond0s0 """
+ """primary_reselect=always"
BONDING_SLAVE_0=bond0s0
BONDING_SLAVE_1=bond0s1
BOOTPROTO=static
@@ -2256,27 +2646,33 @@ iface bond0 inet6 static
NETMASK=255.255.255.0
NETMASK1=255.255.255.0
STARTMODE=auto
- """),
- 'ifcfg-bond0s0': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-bond0s0": textwrap.dedent(
+ """\
BOOTPROTO=none
LLADDR=aa:bb:cc:dd:e8:00
STARTMODE=hotplug
- """),
- 'ifcfg-bond0s1': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-bond0s1": textwrap.dedent(
+ """\
BOOTPROTO=none
LLADDR=aa:bb:cc:dd:e8:01
STARTMODE=hotplug
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-bond0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-bond0": textwrap.dedent(
+ """\
BONDING_MASTER=yes
BONDING_OPTS="mode=active-backup xmit_hash_policy=layer3+4 """
- """miimon=100 num_grat_arp=5 """
- """downdelay=10 updelay=20 """
- """fail_over_mac=active """
- """primary=bond0s0 """
- """primary_reselect=always"
+ """miimon=100 num_grat_arp=5 """
+ """downdelay=10 updelay=20 """
+ """fail_over_mac=active """
+ """primary=bond0s0 """
+ """primary_reselect=always"
BONDING_SLAVE0=bond0s0
BONDING_SLAVE1=bond0s1
BOOTPROTO=none
@@ -2297,8 +2693,10 @@ iface bond0 inet6 static
ONBOOT=yes
TYPE=Bond
USERCTL=no
- """),
- 'ifcfg-bond0s0': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-bond0s0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=bond0s0
HWADDR=aa:bb:cc:dd:e8:00
@@ -2308,19 +2706,25 @@ iface bond0 inet6 static
SLAVE=yes
TYPE=Ethernet
USERCTL=no
- """),
- 'route6-bond0': textwrap.dedent("""\
+ """
+ ),
+ "route6-bond0": textwrap.dedent(
+ """\
# Created by cloud-init on instance boot automatically, do not edit.
#
- 2001:67c:1/ffff:ffff:0 via 2001:67c:1562:1 dev bond0
- 3001:67c:1/ffff:ffff:0 via 3001:67c:1562:1 metric 10000 dev bond0
- """),
- 'route-bond0': textwrap.dedent("""\
+ 2001:67c:1/32 via 2001:67c:1562:1 dev bond0
+ 3001:67c:1/32 via 3001:67c:1562:1 metric 10000 dev bond0
+ """
+ ),
+ "route-bond0": textwrap.dedent(
+ """\
ADDRESS0=10.1.3.0
GATEWAY0=192.168.0.3
NETMASK0=255.255.255.0
- """),
- 'ifcfg-bond0s1': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-bond0s1": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=bond0s1
HWADDR=aa:bb:cc:dd:e8:01
@@ -2330,11 +2734,13 @@ iface bond0 inet6 static
SLAVE=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
},
- 'vlan': {
- 'yaml': textwrap.dedent("""
+ "vlan": {
+ "yaml": textwrap.dedent(
+ """
version: 1
config:
- type: physical
@@ -2357,14 +2763,18 @@ iface bond0 inet6 static
- gateway: 2001:1::1
netmask: '::'
network: '::'
- """),
- 'expected_sysconfig_opensuse': {
+ """
+ ),
+ "expected_sysconfig_opensuse": {
# TODO RJS: unknown proper BOOTPROTO setting ask Marius
- 'ifcfg-en0': textwrap.dedent("""\
+ "ifcfg-en0": textwrap.dedent(
+ """\
BOOTPROTO=static
LLADDR=aa:bb:cc:dd:e8:00
- STARTMODE=auto"""),
- 'ifcfg-en0.99': textwrap.dedent("""\
+ STARTMODE=auto"""
+ ),
+ "ifcfg-en0.99": textwrap.dedent(
+ """\
BOOTPROTO=static
IPADDR=192.168.2.2
IPADDR1=192.168.1.2
@@ -2375,18 +2785,22 @@ iface bond0 inet6 static
STARTMODE=auto
ETHERDEVICE=en0
VLAN_ID=99
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-en0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-en0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=en0
HWADDR=aa:bb:cc:dd:e8:00
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
- USERCTL=no"""),
- 'ifcfg-en0.99': textwrap.dedent("""\
+ USERCTL=no"""
+ ),
+ "ifcfg-en0.99": textwrap.dedent(
+ """\
BOOTPROTO=none
DEFROUTE=yes
DEVICE=en0.99
@@ -2405,11 +2819,13 @@ iface bond0 inet6 static
ONBOOT=yes
PHYSDEV=en0
USERCTL=no
- VLAN=yes"""),
+ VLAN=yes"""
+ ),
},
},
- 'bridge': {
- 'yaml': textwrap.dedent("""
+ "bridge": {
+ "yaml": textwrap.dedent(
+ """
version: 1
config:
- type: physical
@@ -2434,9 +2850,11 @@ iface bond0 inet6 static
bridge_bridgeprio: 22
subnets:
- type: static
- address: 192.168.2.2/24"""),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-br0': textwrap.dedent("""\
+ address: 192.168.2.2/24"""
+ ),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-br0": textwrap.dedent(
+ """\
BOOTPROTO=static
IPADDR=192.168.2.2
NETMASK=255.255.255.0
@@ -2444,24 +2862,30 @@ iface bond0 inet6 static
BRIDGE_STP=off
BRIDGE_PRIORITY=22
BRIDGE_PORTS='eth0 eth1'
- """),
- 'ifcfg-eth0': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-eth0": textwrap.dedent(
+ """\
BOOTPROTO=static
BRIDGE=yes
LLADDR=52:54:00:12:34:00
IPADDR6=2001:1::100/96
STARTMODE=auto
- """),
- 'ifcfg-eth1': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-eth1": textwrap.dedent(
+ """\
BOOTPROTO=static
BRIDGE=yes
LLADDR=52:54:00:12:34:01
IPADDR6=2001:1::101/96
STARTMODE=auto
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-br0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-br0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=br0
IPADDR=192.168.2.2
@@ -2472,8 +2896,10 @@ iface bond0 inet6 static
STP=no
TYPE=Bridge
USERCTL=no
- """),
- 'ifcfg-eth0': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-eth0": textwrap.dedent(
+ """\
BOOTPROTO=none
BRIDGE=br0
DEVICE=eth0
@@ -2486,8 +2912,10 @@ iface bond0 inet6 static
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
- 'ifcfg-eth1': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-eth1": textwrap.dedent(
+ """\
BOOTPROTO=none
BRIDGE=br0
DEVICE=eth1
@@ -2500,11 +2928,13 @@ iface bond0 inet6 static
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
},
- 'manual': {
- 'yaml': textwrap.dedent("""
+ "manual": {
+ "yaml": textwrap.dedent(
+ """
version: 1
config:
- type: physical
@@ -2526,8 +2956,10 @@ iface bond0 inet6 static
subnets:
- type: manual
control: manual
- """),
- 'expected_eni': textwrap.dedent("""\
+ """
+ ),
+ "expected_eni": textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
@@ -2541,8 +2973,10 @@ iface bond0 inet6 static
# control-manual eth2
iface eth2 inet manual
- """),
- 'expected_netplan': textwrap.dedent("""\
+ """
+ ),
+ "expected_netplan": textwrap.dedent(
+ """\
network:
version: 2
@@ -2562,29 +2996,37 @@ iface bond0 inet6 static
match:
macaddress: 52:54:00:12:34:ff
set-name: eth2
- """),
- 'expected_sysconfig_opensuse': {
- 'ifcfg-eth0': textwrap.dedent("""\
+ """
+ ),
+ "expected_sysconfig_opensuse": {
+ "ifcfg-eth0": textwrap.dedent(
+ """\
BOOTPROTO=static
LLADDR=52:54:00:12:34:00
IPADDR=192.168.1.2
NETMASK=255.255.255.0
STARTMODE=manual
- """),
- 'ifcfg-eth1': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-eth1": textwrap.dedent(
+ """\
BOOTPROTO=static
LLADDR=52:54:00:12:34:aa
MTU=1480
STARTMODE=auto
- """),
- 'ifcfg-eth2': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-eth2": textwrap.dedent(
+ """\
BOOTPROTO=static
LLADDR=52:54:00:12:34:ff
STARTMODE=manual
- """),
+ """
+ ),
},
- 'expected_sysconfig_rhel': {
- 'ifcfg-eth0': textwrap.dedent("""\
+ "expected_sysconfig_rhel": {
+ "ifcfg-eth0": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=eth0
HWADDR=52:54:00:12:34:00
@@ -2594,8 +3036,10 @@ iface bond0 inet6 static
ONBOOT=no
TYPE=Ethernet
USERCTL=no
- """),
- 'ifcfg-eth1': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-eth1": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=eth1
HWADDR=52:54:00:12:34:aa
@@ -2604,8 +3048,10 @@ iface bond0 inet6 static
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
- 'ifcfg-eth2': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-eth2": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=eth2
HWADDR=52:54:00:12:34:ff
@@ -2613,51 +3059,85 @@ iface bond0 inet6 static
ONBOOT=no
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
},
},
}
CONFIG_V1_EXPLICIT_LOOPBACK = {
- 'version': 1,
- 'config': [{'name': 'eth0', 'type': 'physical',
- 'subnets': [{'control': 'auto', 'type': 'dhcp'}]},
- {'name': 'lo', 'type': 'loopback',
- 'subnets': [{'control': 'auto', 'type': 'loopback'}]},
- ]}
+ "version": 1,
+ "config": [
+ {
+ "name": "eth0",
+ "type": "physical",
+ "subnets": [{"control": "auto", "type": "dhcp"}],
+ },
+ {
+ "name": "lo",
+ "type": "loopback",
+ "subnets": [{"control": "auto", "type": "loopback"}],
+ },
+ ],
+}
CONFIG_V1_SIMPLE_SUBNET = {
- 'version': 1,
- 'config': [{'mac_address': '52:54:00:12:34:00',
- 'name': 'interface0',
- 'subnets': [{'address': '10.0.2.15',
- 'gateway': '10.0.2.2',
- 'netmask': '255.255.255.0',
- 'type': 'static'}],
- 'type': 'physical'}]}
+ "version": 1,
+ "config": [
+ {
+ "mac_address": "52:54:00:12:34:00",
+ "name": "interface0",
+ "subnets": [
+ {
+ "address": "10.0.2.15",
+ "gateway": "10.0.2.2",
+ "netmask": "255.255.255.0",
+ "type": "static",
+ }
+ ],
+ "type": "physical",
+ }
+ ],
+}
CONFIG_V1_MULTI_IFACE = {
- 'version': 1,
- 'config': [{'type': 'physical',
- 'mtu': 1500,
- 'subnets': [{'type': 'static',
- 'netmask': '255.255.240.0',
- 'routes': [{'netmask': '0.0.0.0',
- 'network': '0.0.0.0',
- 'gateway': '51.68.80.1'}],
- 'address': '51.68.89.122',
- 'ipv4': True}],
- 'mac_address': 'fa:16:3e:25:b4:59',
- 'name': 'eth0'},
- {'type': 'physical',
- 'mtu': 9000,
- 'subnets': [{'type': 'dhcp4'}],
- 'mac_address': 'fa:16:3e:b1:ca:29', 'name': 'eth1'}]}
+ "version": 1,
+ "config": [
+ {
+ "type": "physical",
+ "mtu": 1500,
+ "subnets": [
+ {
+ "type": "static",
+ "netmask": "255.255.240.0",
+ "routes": [
+ {
+ "netmask": "0.0.0.0",
+ "network": "0.0.0.0",
+ "gateway": "51.68.80.1",
+ }
+ ],
+ "address": "51.68.89.122",
+ "ipv4": True,
+ }
+ ],
+ "mac_address": "fa:16:3e:25:b4:59",
+ "name": "eth0",
+ },
+ {
+ "type": "physical",
+ "mtu": 9000,
+ "subnets": [{"type": "dhcp4"}],
+ "mac_address": "fa:16:3e:b1:ca:29",
+ "name": "eth1",
+ },
+ ],
+}
DEFAULT_DEV_ATTRS = {
- 'eth1000': {
+ "eth1000": {
"bridge": False,
"carrier": False,
"dormant": False,
@@ -2670,16 +3150,26 @@ DEFAULT_DEV_ATTRS = {
}
-def _setup_test(tmp_dir, mock_get_devicelist, mock_read_sys_net,
- mock_sys_dev_path, dev_attrs=None):
+def _setup_test(
+ tmp_dir,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ dev_attrs=None,
+):
if not dev_attrs:
dev_attrs = DEFAULT_DEV_ATTRS
mock_get_devicelist.return_value = dev_attrs.keys()
- def fake_read(devname, path, translate=None,
- on_enoent=None, on_keyerror=None,
- on_einval=None):
+ def fake_read(
+ devname,
+ path,
+ translate=None,
+ on_enoent=None,
+ on_keyerror=None,
+ on_einval=None,
+ ):
return dev_attrs[devname][path]
mock_read_sys_net.side_effect = fake_read
@@ -2689,99 +3179,137 @@ def _setup_test(tmp_dir, mock_get_devicelist, mock_read_sys_net,
for dev in dev_attrs:
os.makedirs(os.path.join(tmp_dir, dev))
- with open(os.path.join(tmp_dir, dev, 'operstate'), 'w') as fh:
- fh.write(dev_attrs[dev]['operstate'])
+ with open(os.path.join(tmp_dir, dev, "operstate"), "w") as fh:
+ fh.write(dev_attrs[dev]["operstate"])
os.makedirs(os.path.join(tmp_dir, dev, "device"))
- for key in ['device/driver']:
+ for key in ["device/driver"]:
if key in dev_attrs[dev] and dev_attrs[dev][key]:
target = dev_attrs[dev][key]
link = os.path.join(tmp_dir, dev, key)
- print('symlink %s -> %s' % (link, target))
+ print("symlink %s -> %s" % (link, target))
os.symlink(target, link)
mock_sys_dev_path.side_effect = sys_dev_path
class TestGenerateFallbackConfig(CiTestCase):
-
def setUp(self):
super(TestGenerateFallbackConfig, self).setUp()
self.add_patch(
- "cloudinit.util.get_cmdline", "m_get_cmdline",
- return_value="root=/dev/sda1")
+ "cloudinit.util.get_cmdline",
+ "m_get_cmdline",
+ return_value="root=/dev/sda1",
+ )
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@mock.patch("cloudinit.net.get_devicelist")
- def test_device_driver_v2(self, mock_get_devicelist, mock_read_sys_net,
- mock_sys_dev_path):
+ def test_device_driver_v2(
+ self, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path
+ ):
"""Network configuration for generate_fallback_config is version 2."""
devices = {
- 'eth0': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'hv_netsvc', 'device/device': '0x3',
- 'name_assign_type': '4'},
- 'eth1': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'mlx4_core', 'device/device': '0x7',
- 'name_assign_type': '4'},
-
+ "eth0": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "hv_netsvc",
+ "device/device": "0x3",
+ "name_assign_type": "4",
+ },
+ "eth1": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "mlx4_core",
+ "device/device": "0x7",
+ "name_assign_type": "4",
+ },
}
tmp_dir = self.tmp_dir()
- _setup_test(tmp_dir, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path,
- dev_attrs=devices)
+ _setup_test(
+ tmp_dir,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ dev_attrs=devices,
+ )
network_cfg = net.generate_fallback_config(config_driver=True)
expected = {
- 'ethernets': {'eth0': {'dhcp4': True, 'set-name': 'eth0',
- 'match': {'macaddress': '00:11:22:33:44:55',
- 'driver': 'hv_netsvc'}}},
- 'version': 2}
+ "ethernets": {
+ "eth0": {
+ "dhcp4": True,
+ "set-name": "eth0",
+ "match": {
+ "macaddress": "00:11:22:33:44:55",
+ "driver": "hv_netsvc",
+ },
+ }
+ },
+ "version": 2,
+ }
self.assertEqual(expected, network_cfg)
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@mock.patch("cloudinit.net.get_devicelist")
- def test_device_driver(self, mock_get_devicelist, mock_read_sys_net,
- mock_sys_dev_path):
+ def test_device_driver(
+ self, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path
+ ):
devices = {
- 'eth0': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'hv_netsvc', 'device/device': '0x3',
- 'name_assign_type': '4'},
- 'eth1': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'mlx4_core', 'device/device': '0x7',
- 'name_assign_type': '4'},
-
+ "eth0": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "hv_netsvc",
+ "device/device": "0x3",
+ "name_assign_type": "4",
+ },
+ "eth1": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "mlx4_core",
+ "device/device": "0x7",
+ "name_assign_type": "4",
+ },
}
tmp_dir = self.tmp_dir()
- _setup_test(tmp_dir, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path,
- dev_attrs=devices)
+ _setup_test(
+ tmp_dir,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ dev_attrs=devices,
+ )
network_cfg = net.generate_fallback_config(config_driver=True)
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
render_dir = os.path.join(tmp_dir, "render")
os.makedirs(render_dir)
# don't set rulepath so eni writes them
renderer = eni.Renderer(
- {'eni_path': 'interfaces', 'netrules_path': 'netrules'})
+ {"eni_path": "interfaces", "netrules_path": "netrules"}
+ )
renderer.render_network_state(ns, target=render_dir)
- self.assertTrue(os.path.exists(os.path.join(render_dir,
- 'interfaces')))
- with open(os.path.join(render_dir, 'interfaces')) as fh:
+ self.assertTrue(os.path.exists(os.path.join(render_dir, "interfaces")))
+ with open(os.path.join(render_dir, "interfaces")) as fh:
contents = fh.read()
print(contents)
expected = """
@@ -2793,8 +3321,8 @@ iface eth0 inet dhcp
"""
self.assertEqual(expected.lstrip(), contents.lstrip())
- self.assertTrue(os.path.exists(os.path.join(render_dir, 'netrules')))
- with open(os.path.join(render_dir, 'netrules')) as fh:
+ self.assertTrue(os.path.exists(os.path.join(render_dir, "netrules")))
+ with open(os.path.join(render_dir, "netrules")) as fh:
contents = fh.read()
print(contents)
expected_rule = [
@@ -2804,48 +3332,65 @@ iface eth0 inet dhcp
'ATTR{address}=="00:11:22:33:44:55"',
'NAME="eth0"',
]
- self.assertEqual(", ".join(expected_rule) + '\n', contents.lstrip())
+ self.assertEqual(", ".join(expected_rule) + "\n", contents.lstrip())
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@mock.patch("cloudinit.net.get_devicelist")
- def test_device_driver_blacklist(self, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path):
+ def test_device_driver_blacklist(
+ self, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path
+ ):
devices = {
- 'eth1': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'hv_netsvc', 'device/device': '0x3',
- 'name_assign_type': '4'},
- 'eth0': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'mlx4_core', 'device/device': '0x7',
- 'name_assign_type': '4'},
+ "eth1": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "hv_netsvc",
+ "device/device": "0x3",
+ "name_assign_type": "4",
+ },
+ "eth0": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "mlx4_core",
+ "device/device": "0x7",
+ "name_assign_type": "4",
+ },
}
tmp_dir = self.tmp_dir()
- _setup_test(tmp_dir, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path,
- dev_attrs=devices)
+ _setup_test(
+ tmp_dir,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ dev_attrs=devices,
+ )
- blacklist = ['mlx4_core']
- network_cfg = net.generate_fallback_config(blacklist_drivers=blacklist,
- config_driver=True)
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ blacklist = ["mlx4_core"]
+ network_cfg = net.generate_fallback_config(
+ blacklist_drivers=blacklist, config_driver=True
+ )
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
render_dir = os.path.join(tmp_dir, "render")
os.makedirs(render_dir)
# don't set rulepath so eni writes them
renderer = eni.Renderer(
- {'eni_path': 'interfaces', 'netrules_path': 'netrules'})
+ {"eni_path": "interfaces", "netrules_path": "netrules"}
+ )
renderer.render_network_state(ns, target=render_dir)
- self.assertTrue(os.path.exists(os.path.join(render_dir,
- 'interfaces')))
- with open(os.path.join(render_dir, 'interfaces')) as fh:
+ self.assertTrue(os.path.exists(os.path.join(render_dir, "interfaces")))
+ with open(os.path.join(render_dir, "interfaces")) as fh:
contents = fh.read()
print(contents)
expected = """
@@ -2857,8 +3402,8 @@ iface eth1 inet dhcp
"""
self.assertEqual(expected.lstrip(), contents.lstrip())
- self.assertTrue(os.path.exists(os.path.join(render_dir, 'netrules')))
- with open(os.path.join(render_dir, 'netrules')) as fh:
+ self.assertTrue(os.path.exists(os.path.join(render_dir, "netrules")))
+ with open(os.path.join(render_dir, "netrules")) as fh:
contents = fh.read()
print(contents)
expected_rule = [
@@ -2868,35 +3413,54 @@ iface eth1 inet dhcp
'ATTR{address}=="00:11:22:33:44:55"',
'NAME="eth1"',
]
- self.assertEqual(", ".join(expected_rule) + '\n', contents.lstrip())
+ self.assertEqual(", ".join(expected_rule) + "\n", contents.lstrip())
@mock.patch("cloudinit.util.get_cmdline")
@mock.patch("cloudinit.util.udevadm_settle")
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@mock.patch("cloudinit.net.get_devicelist")
- def test_unstable_names(self, mock_get_devicelist, mock_read_sys_net,
- mock_sys_dev_path, mock_settle, m_get_cmdline):
+ def test_unstable_names(
+ self,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ mock_settle,
+ m_get_cmdline,
+ ):
"""verify that udevadm settle is called when we find unstable names"""
devices = {
- 'eth0': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'hv_netsvc', 'device/device': '0x3',
- 'name_assign_type': False},
- 'ens4': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'mlx4_core', 'device/device': '0x7',
- 'name_assign_type': '4'},
-
+ "eth0": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "hv_netsvc",
+ "device/device": "0x3",
+ "name_assign_type": False,
+ },
+ "ens4": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "mlx4_core",
+ "device/device": "0x7",
+ "name_assign_type": "4",
+ },
}
- m_get_cmdline.return_value = ''
+ m_get_cmdline.return_value = ""
tmp_dir = self.tmp_dir()
- _setup_test(tmp_dir, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path,
- dev_attrs=devices)
+ _setup_test(
+ tmp_dir,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ dev_attrs=devices,
+ )
net.generate_fallback_config(config_driver=True)
self.assertEqual(1, mock_settle.call_count)
@@ -2905,48 +3469,73 @@ iface eth1 inet dhcp
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@mock.patch("cloudinit.net.get_devicelist")
- def test_unstable_names_disabled(self, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path,
- mock_settle, m_get_cmdline):
+ def test_unstable_names_disabled(
+ self,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ mock_settle,
+ m_get_cmdline,
+ ):
"""verify udevadm settle not called when cmdline has net.ifnames=0"""
devices = {
- 'eth0': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'hv_netsvc', 'device/device': '0x3',
- 'name_assign_type': False},
- 'ens4': {
- 'bridge': False, 'carrier': False, 'dormant': False,
- 'operstate': 'down', 'address': '00:11:22:33:44:55',
- 'device/driver': 'mlx4_core', 'device/device': '0x7',
- 'name_assign_type': '4'},
-
+ "eth0": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "hv_netsvc",
+ "device/device": "0x3",
+ "name_assign_type": False,
+ },
+ "ens4": {
+ "bridge": False,
+ "carrier": False,
+ "dormant": False,
+ "operstate": "down",
+ "address": "00:11:22:33:44:55",
+ "device/driver": "mlx4_core",
+ "device/device": "0x7",
+ "name_assign_type": "4",
+ },
}
- m_get_cmdline.return_value = 'net.ifnames=0'
+ m_get_cmdline.return_value = "net.ifnames=0"
tmp_dir = self.tmp_dir()
- _setup_test(tmp_dir, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path,
- dev_attrs=devices)
+ _setup_test(
+ tmp_dir,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ dev_attrs=devices,
+ )
net.generate_fallback_config(config_driver=True)
self.assertEqual(0, mock_settle.call_count)
+@mock.patch(
+ "cloudinit.net.is_openvswitch_internal_interface",
+ mock.Mock(return_value=False),
+)
class TestRhelSysConfigRendering(CiTestCase):
with_logs = True
nm_cfg_file = "/etc/NetworkManager/NetworkManager.conf"
- scripts_dir = '/etc/sysconfig/network-scripts'
- header = ('# Created by cloud-init on instance boot automatically, '
- 'do not edit.\n#\n')
+ scripts_dir = "/etc/sysconfig/network-scripts"
+ header = (
+ "# Created by cloud-init on instance boot automatically, "
+ "do not edit.\n#\n"
+ )
- expected_name = 'expected_sysconfig_rhel'
+ expected_name = "expected_sysconfig_rhel"
def _get_renderer(self):
- distro_cls = distros.fetch('rhel')
+ distro_cls = distros.fetch("rhel")
return sysconfig.Renderer(
- config=distro_cls.renderer_configs.get('sysconfig'))
+ config=distro_cls.renderer_configs.get("sysconfig")
+ )
def _render_and_read(self, network_config=None, state=None, dir=None):
if dir is None:
@@ -2964,9 +3553,8 @@ class TestRhelSysConfigRendering(CiTestCase):
return dir2dict(dir)
def _compare_files_to_expected(self, expected, found):
-
def _try_load(f):
- ''' Attempt to load shell content, otherwise return as-is '''
+ """Attempt to load shell content, otherwise return as-is"""
try:
return util.load_shell_content(f)
except ValueError:
@@ -2977,12 +3565,15 @@ class TestRhelSysConfigRendering(CiTestCase):
orig_maxdiff = self.maxDiff
expected_d = dict(
(os.path.join(self.scripts_dir, k), _try_load(v))
- for k, v in expected.items())
+ for k, v in expected.items()
+ )
# only compare the files in scripts_dir
scripts_found = dict(
- (k, _try_load(v)) for k, v in found.items()
- if k.startswith(self.scripts_dir))
+ (k, _try_load(v))
+ for k, v in found.items()
+ if k.startswith(self.scripts_dir)
+ )
try:
self.maxDiff = None
self.assertEqual(expected_d, scripts_found)
@@ -2990,9 +3581,14 @@ class TestRhelSysConfigRendering(CiTestCase):
self.maxDiff = orig_maxdiff
def _assert_headers(self, found):
- missing = [f for f in found
- if (f.startswith(self.scripts_dir) and
- not found[f].startswith(self.header))]
+ missing = [
+ f
+ for f in found
+ if (
+ f.startswith(self.scripts_dir)
+ and not found[f].startswith(self.header)
+ )
+ ]
if missing:
raise AssertionError("Missing headers in: %s" % missing)
@@ -3000,16 +3596,22 @@ class TestRhelSysConfigRendering(CiTestCase):
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@mock.patch("cloudinit.net.get_devicelist")
- def test_default_generation(self, mock_get_devicelist,
- mock_read_sys_net,
- mock_sys_dev_path, m_get_cmdline):
+ def test_default_generation(
+ self,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ m_get_cmdline,
+ ):
tmp_dir = self.tmp_dir()
- _setup_test(tmp_dir, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path)
+ _setup_test(
+ tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path
+ )
network_cfg = net.generate_fallback_config()
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
render_dir = os.path.join(tmp_dir, "render")
os.makedirs(render_dir)
@@ -3017,7 +3619,7 @@ class TestRhelSysConfigRendering(CiTestCase):
renderer = self._get_renderer()
renderer.render_network_state(ns, target=render_dir)
- render_file = 'etc/sysconfig/network-scripts/ifcfg-eth1000'
+ render_file = "etc/sysconfig/network-scripts/ifcfg-eth1000"
with open(os.path.join(render_dir, render_file)) as fh:
content = fh.read()
expected_content = """
@@ -3037,35 +3639,44 @@ USERCTL=no
"""ValueError is raised when duplicate ipv4 gateways exist."""
net_json = {
"services": [{"type": "dns", "address": "172.19.0.12"}],
- "networks": [{
- "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
- "type": "ipv4", "netmask": "255.255.252.0",
- "link": "tap1a81968a-79",
- "routes": [{
- "netmask": "0.0.0.0",
- "network": "0.0.0.0",
- "gateway": "172.19.3.254",
- }, {
- "netmask": "0.0.0.0", # A second default gateway
- "network": "0.0.0.0",
- "gateway": "172.20.3.254",
- }],
- "ip_address": "172.19.1.34", "id": "network0"
- }],
+ "networks": [
+ {
+ "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
+ "type": "ipv4",
+ "netmask": "255.255.252.0",
+ "link": "tap1a81968a-79",
+ "routes": [
+ {
+ "netmask": "0.0.0.0",
+ "network": "0.0.0.0",
+ "gateway": "172.19.3.254",
+ },
+ {
+ "netmask": "0.0.0.0", # A second default gateway
+ "network": "0.0.0.0",
+ "gateway": "172.20.3.254",
+ },
+ ],
+ "ip_address": "172.19.1.34",
+ "id": "network0",
+ }
+ ],
"links": [
{
"ethernet_mac_address": "fa:16:3e:ed:9a:59",
- "mtu": None, "type": "bridge", "id":
- "tap1a81968a-79",
- "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+ "mtu": None,
+ "type": "bridge",
+ "id": "tap1a81968a-79",
+ "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f",
},
],
}
- macs = {'fa:16:3e:ed:9a:59': 'eth0'}
+ macs = {"fa:16:3e:ed:9a:59": "eth0"}
render_dir = self.tmp_dir()
network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
renderer = self._get_renderer()
with self.assertRaises(ValueError):
renderer.render_network_state(ns, target=render_dir)
@@ -3075,56 +3686,138 @@ USERCTL=no
"""ValueError is raised when duplicate ipv6 gateways exist."""
net_json = {
"services": [{"type": "dns", "address": "172.19.0.12"}],
- "networks": [{
- "network_id": "public-ipv6",
- "type": "ipv6", "netmask": "",
- "link": "tap1a81968a-79",
- "routes": [{
- "gateway": "2001:DB8::1",
- "netmask": "::",
- "network": "::"
- }, {
- "gateway": "2001:DB9::1",
- "netmask": "::",
- "network": "::"
- }],
- "ip_address": "2001:DB8::10", "id": "network1"
- }],
+ "networks": [
+ {
+ "network_id": "public-ipv6",
+ "type": "ipv6",
+ "netmask": "",
+ "link": "tap1a81968a-79",
+ "routes": [
+ {
+ "gateway": "2001:DB8::1",
+ "netmask": "::",
+ "network": "::",
+ },
+ {
+ "gateway": "2001:DB9::1",
+ "netmask": "::",
+ "network": "::",
+ },
+ ],
+ "ip_address": "2001:DB8::10",
+ "id": "network1",
+ }
+ ],
"links": [
{
"ethernet_mac_address": "fa:16:3e:ed:9a:59",
- "mtu": None, "type": "bridge", "id":
- "tap1a81968a-79",
- "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+ "mtu": None,
+ "type": "bridge",
+ "id": "tap1a81968a-79",
+ "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f",
},
],
}
- macs = {'fa:16:3e:ed:9a:59': 'eth0'}
+ macs = {"fa:16:3e:ed:9a:59": "eth0"}
render_dir = self.tmp_dir()
network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
renderer = self._get_renderer()
with self.assertRaises(ValueError):
renderer.render_network_state(ns, target=render_dir)
self.assertEqual([], os.listdir(render_dir))
+ def test_invalid_network_mask_ipv6(self):
+ net_json = {
+ "services": [{"type": "dns", "address": "172.19.0.12"}],
+ "networks": [
+ {
+ "network_id": "public-ipv6",
+ "type": "ipv6",
+ "netmask": "",
+ "link": "tap1a81968a-79",
+ "routes": [
+ {
+ "gateway": "2001:DB8::1",
+ "netmask": "ff:ff:ff:ff::",
+ "network": "2001:DB8:1::1",
+ },
+ ],
+ "ip_address": "2001:DB8::10",
+ "id": "network1",
+ }
+ ],
+ "links": [
+ {
+ "ethernet_mac_address": "fa:16:3e:ed:9a:59",
+ "mtu": None,
+ "type": "bridge",
+ "id": "tap1a81968a-79",
+ "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f",
+ },
+ ],
+ }
+ macs = {"fa:16:3e:ed:9a:59": "eth0"}
+ network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
+ with self.assertRaises(ValueError):
+ network_state.parse_net_config_data(network_cfg, skip_broken=False)
+
+ def test_invalid_network_mask_ipv4(self):
+ net_json = {
+ "services": [{"type": "dns", "address": "172.19.0.12"}],
+ "networks": [
+ {
+ "network_id": "public-ipv4",
+ "type": "ipv4",
+ "netmask": "",
+ "link": "tap1a81968a-79",
+ "routes": [
+ {
+ "gateway": "172.20.0.1",
+ "netmask": "255.234.255.0",
+ "network": "172.19.0.0",
+ },
+ ],
+ "ip_address": "172.20.0.10",
+ "id": "network1",
+ }
+ ],
+ "links": [
+ {
+ "ethernet_mac_address": "fa:16:3e:ed:9a:59",
+ "mtu": None,
+ "type": "bridge",
+ "id": "tap1a81968a-79",
+ "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f",
+ },
+ ],
+ }
+ macs = {"fa:16:3e:ed:9a:59": "eth0"}
+ network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
+ with self.assertRaises(ValueError):
+ network_state.parse_net_config_data(network_cfg, skip_broken=False)
+
def test_openstack_rendering_samples(self):
for os_sample in OS_SAMPLES:
render_dir = self.tmp_dir()
- ex_input = os_sample['in_data']
- ex_mac_addrs = os_sample['in_macs']
+ ex_input = os_sample["in_data"]
+ ex_mac_addrs = os_sample["in_macs"]
network_cfg = openstack.convert_net_json(
- ex_input, known_macs=ex_mac_addrs)
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ex_input, known_macs=ex_mac_addrs
+ )
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
renderer = self._get_renderer()
# render a multiple times to simulate reboots
renderer.render_network_state(ns, target=render_dir)
renderer.render_network_state(ns, target=render_dir)
renderer.render_network_state(ns, target=render_dir)
- for fn, expected_content in os_sample.get('out_sysconfig_rhel',
- []):
+ for fn, expected_content in os_sample.get(
+ "out_sysconfig_rhel", []
+ ):
with open(os.path.join(render_dir, fn)) as fh:
self.assertEqual(expected_content, fh.read())
@@ -3135,8 +3828,8 @@ USERCTL=no
renderer = self._get_renderer()
renderer.render_network_state(ns, target=render_dir)
found = dir2dict(render_dir)
- nspath = '/etc/sysconfig/network-scripts/'
- self.assertNotIn(nspath + 'ifcfg-lo', found.keys())
+ nspath = "/etc/sysconfig/network-scripts/"
+ self.assertNotIn(nspath + "ifcfg-lo", found.keys())
expected = """\
# Created by cloud-init on instance boot automatically, do not edit.
#
@@ -3152,10 +3845,10 @@ ONBOOT=yes
TYPE=Ethernet
USERCTL=no
"""
- self.assertEqual(expected, found[nspath + 'ifcfg-interface0'])
+ self.assertEqual(expected, found[nspath + "ifcfg-interface0"])
# The configuration has no nameserver information make sure we
# do not write the resolv.conf file
- respath = '/etc/resolv.conf'
+ respath = "/etc/resolv.conf"
self.assertNotIn(respath, found.keys())
def test_network_config_v1_multi_iface_samples(self):
@@ -3165,8 +3858,8 @@ USERCTL=no
renderer = self._get_renderer()
renderer.render_network_state(ns, target=render_dir)
found = dir2dict(render_dir)
- nspath = '/etc/sysconfig/network-scripts/'
- self.assertNotIn(nspath + 'ifcfg-lo', found.keys())
+ nspath = "/etc/sysconfig/network-scripts/"
+ self.assertNotIn(nspath + "ifcfg-lo", found.keys())
expected_i1 = """\
# Created by cloud-init on instance boot automatically, do not edit.
#
@@ -3183,7 +3876,7 @@ ONBOOT=yes
TYPE=Ethernet
USERCTL=no
"""
- self.assertEqual(expected_i1, found[nspath + 'ifcfg-eth0'])
+ self.assertEqual(expected_i1, found[nspath + "ifcfg-eth0"])
expected_i2 = """\
# Created by cloud-init on instance boot automatically, do not edit.
#
@@ -3197,21 +3890,21 @@ ONBOOT=yes
TYPE=Ethernet
USERCTL=no
"""
- self.assertEqual(expected_i2, found[nspath + 'ifcfg-eth1'])
+ self.assertEqual(expected_i2, found[nspath + "ifcfg-eth1"])
def test_config_with_explicit_loopback(self):
ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK)
render_dir = self.tmp_path("render")
os.makedirs(render_dir)
# write an etc/resolv.conf and expect it to not be modified
- resolvconf = os.path.join(render_dir, 'etc/resolv.conf')
+ resolvconf = os.path.join(render_dir, "etc/resolv.conf")
resolvconf_content = "# Original Content"
util.write_file(resolvconf, resolvconf_content)
renderer = self._get_renderer()
renderer.render_network_state(ns, target=render_dir)
found = dir2dict(render_dir)
- nspath = '/etc/sysconfig/network-scripts/'
- self.assertNotIn(nspath + 'ifcfg-lo', found.keys())
+ nspath = "/etc/sysconfig/network-scripts/"
+ self.assertNotIn(nspath + "ifcfg-lo", found.keys())
expected = """\
# Created by cloud-init on instance boot automatically, do not edit.
#
@@ -3222,171 +3915,188 @@ ONBOOT=yes
TYPE=Ethernet
USERCTL=no
"""
- self.assertEqual(expected, found[nspath + 'ifcfg-eth0'])
+ self.assertEqual(expected, found[nspath + "ifcfg-eth0"])
# a dhcp only config should not modify resolv.conf
- self.assertEqual(resolvconf_content, found['/etc/resolv.conf'])
+ self.assertEqual(resolvconf_content, found["/etc/resolv.conf"])
def test_bond_config(self):
- entry = NETWORK_CONFIGS['bond']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["bond"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_vlan_config(self):
- entry = NETWORK_CONFIGS['vlan']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["vlan"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_bridge_config(self):
- entry = NETWORK_CONFIGS['bridge']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["bridge"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_manual_config(self):
- entry = NETWORK_CONFIGS['manual']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["manual"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_all_config(self):
- entry = NETWORK_CONFIGS['all']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["all"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
self.assertNotIn(
- 'WARNING: Network config: ignoring eth0.101 device-level mtu',
- self.logs.getvalue())
+ "WARNING: Network config: ignoring eth0.101 device-level mtu",
+ self.logs.getvalue(),
+ )
def test_small_config(self):
- entry = NETWORK_CONFIGS['small']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["small"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_v4_and_v6_static_config(self):
- entry = NETWORK_CONFIGS['v4_and_v6_static']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["v4_and_v6_static"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
expected_msg = (
- 'WARNING: Network config: ignoring iface0 device-level mtu:8999'
- ' because ipv4 subnet-level mtu:9000 provided.')
+ "WARNING: Network config: ignoring iface0 device-level mtu:8999"
+ " because ipv4 subnet-level mtu:9000 provided."
+ )
self.assertIn(expected_msg, self.logs.getvalue())
def test_dhcpv6_only_config(self):
- entry = NETWORK_CONFIGS['dhcpv6_only']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_only"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_dhcpv6_accept_ra_config_v1(self):
- entry = NETWORK_CONFIGS['dhcpv6_accept_ra']
- found = self._render_and_read(network_config=yaml.load(
- entry['yaml_v1']))
+ entry = NETWORK_CONFIGS["dhcpv6_accept_ra"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v1"])
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_dhcpv6_accept_ra_config_v2(self):
- entry = NETWORK_CONFIGS['dhcpv6_accept_ra']
- found = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["dhcpv6_accept_ra"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_dhcpv6_reject_ra_config_v1(self):
- entry = NETWORK_CONFIGS['dhcpv6_reject_ra']
- found = self._render_and_read(network_config=yaml.load(
- entry['yaml_v1']))
+ entry = NETWORK_CONFIGS["dhcpv6_reject_ra"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v1"])
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_stattic6_from_json(self):
net_json = {
"services": [{"type": "dns", "address": "172.19.0.12"}],
- "networks": [{
- "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
- "type": "ipv4", "netmask": "255.255.252.0",
- "link": "tap1a81968a-79",
- "routes": [{
- "netmask": "0.0.0.0",
- "network": "0.0.0.0",
- "gateway": "172.19.3.254",
- }, {
- "netmask": "0.0.0.0", # A second default gateway
- "network": "0.0.0.0",
- "gateway": "172.20.3.254",
- }],
- "ip_address": "172.19.1.34", "id": "network0"
- }, {
- "network_id": "mgmt",
- "netmask": "ffff:ffff:ffff:ffff::",
- "link": "interface1",
- "mode": "link-local",
- "routes": [],
- "ip_address": "fe80::c096:67ff:fe5c:6e84",
- "type": "static6",
- "id": "network1",
- "services": [],
- "accept-ra": "false"
- }],
+ "networks": [
+ {
+ "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
+ "type": "ipv4",
+ "netmask": "255.255.252.0",
+ "link": "tap1a81968a-79",
+ "routes": [
+ {
+ "netmask": "0.0.0.0",
+ "network": "0.0.0.0",
+ "gateway": "172.19.3.254",
+ },
+ {
+ "netmask": "0.0.0.0", # A second default gateway
+ "network": "0.0.0.0",
+ "gateway": "172.20.3.254",
+ },
+ ],
+ "ip_address": "172.19.1.34",
+ "id": "network0",
+ },
+ {
+ "network_id": "mgmt",
+ "netmask": "ffff:ffff:ffff:ffff::",
+ "link": "interface1",
+ "mode": "link-local",
+ "routes": [],
+ "ip_address": "fe80::c096:67ff:fe5c:6e84",
+ "type": "static6",
+ "id": "network1",
+ "services": [],
+ "accept-ra": "false",
+ },
+ ],
"links": [
{
"ethernet_mac_address": "fa:16:3e:ed:9a:59",
- "mtu": None, "type": "bridge", "id":
- "tap1a81968a-79",
- "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+ "mtu": None,
+ "type": "bridge",
+ "id": "tap1a81968a-79",
+ "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f",
},
],
}
- macs = {'fa:16:3e:ed:9a:59': 'eth0'}
+ macs = {"fa:16:3e:ed:9a:59": "eth0"}
render_dir = self.tmp_dir()
network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
renderer = self._get_renderer()
with self.assertRaises(ValueError):
renderer.render_network_state(ns, target=render_dir)
self.assertEqual([], os.listdir(render_dir))
def test_static6_from_yaml(self):
- entry = NETWORK_CONFIGS['static6']
- found = self._render_and_read(network_config=yaml.load(
- entry['yaml']))
+ entry = NETWORK_CONFIGS["static6"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_dhcpv6_reject_ra_config_v2(self):
- entry = NETWORK_CONFIGS['dhcpv6_reject_ra']
- found = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["dhcpv6_reject_ra"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_dhcpv6_stateless_config(self):
- entry = NETWORK_CONFIGS['dhcpv6_stateless']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_stateless"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_dhcpv6_stateful_config(self):
- entry = NETWORK_CONFIGS['dhcpv6_stateful']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_stateful"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_wakeonlan_disabled_config_v2(self):
- entry = NETWORK_CONFIGS['wakeonlan_disabled']
- found = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["wakeonlan_disabled"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_wakeonlan_enabled_config_v2(self):
- entry = NETWORK_CONFIGS['wakeonlan_enabled']
- found = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["wakeonlan_enabled"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
@@ -3397,20 +4107,21 @@ USERCTL=no
util.ensure_dir(os.path.dirname(nm_cfg))
# write a template nm.conf, note plugins is a list here
- with open(nm_cfg, 'w') as fh:
- fh.write('# test_check_ifcfg_rh\n[main]\nplugins=foo,bar\n')
+ with open(nm_cfg, "w") as fh:
+ fh.write("# test_check_ifcfg_rh\n[main]\nplugins=foo,bar\n")
self.assertTrue(os.path.exists(nm_cfg))
# render and read
- entry = NETWORK_CONFIGS['small']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']),
- dir=render_dir)
+ entry = NETWORK_CONFIGS["small"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml"]), dir=render_dir
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
# check ifcfg-rh is in the 'plugins' list
config = sysconfig.ConfigObj(nm_cfg)
- self.assertIn('ifcfg-rh', config['main']['plugins'])
+ self.assertIn("ifcfg-rh", config["main"]["plugins"])
def test_check_ifcfg_rh_plugins_string(self):
"""ifcfg-rh plugin is append when plugins is a string."""
@@ -3420,22 +4131,23 @@ USERCTL=no
util.ensure_dir(os.path.dirname(nm_cfg))
# write a template nm.conf, note plugins is a value here
- util.write_file(nm_cfg, '# test_check_ifcfg_rh\n[main]\nplugins=foo\n')
+ util.write_file(nm_cfg, "# test_check_ifcfg_rh\n[main]\nplugins=foo\n")
# render and read
- entry = NETWORK_CONFIGS['small']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']),
- dir=render_dir)
+ entry = NETWORK_CONFIGS["small"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml"]), dir=render_dir
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
# check raw content has plugin
nm_file_content = util.load_file(nm_cfg)
- self.assertIn('ifcfg-rh', nm_file_content)
+ self.assertIn("ifcfg-rh", nm_file_content)
# check ifcfg-rh is in the 'plugins' list
config = sysconfig.ConfigObj(nm_cfg)
- self.assertIn('ifcfg-rh', config['main']['plugins'])
+ self.assertIn("ifcfg-rh", config["main"]["plugins"])
def test_check_ifcfg_rh_plugins_no_plugins(self):
"""enable_ifcfg_plugin creates plugins value if missing."""
@@ -3445,28 +4157,32 @@ USERCTL=no
util.ensure_dir(os.path.dirname(nm_cfg))
# write a template nm.conf, note plugins is missing
- util.write_file(nm_cfg, '# test_check_ifcfg_rh\n[main]\n')
+ util.write_file(nm_cfg, "# test_check_ifcfg_rh\n[main]\n")
self.assertTrue(os.path.exists(nm_cfg))
# render and read
- entry = NETWORK_CONFIGS['small']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']),
- dir=render_dir)
+ entry = NETWORK_CONFIGS["small"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml"]), dir=render_dir
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
# check ifcfg-rh is in the 'plugins' list
config = sysconfig.ConfigObj(nm_cfg)
- self.assertIn('ifcfg-rh', config['main']['plugins'])
+ self.assertIn("ifcfg-rh", config["main"]["plugins"])
def test_netplan_dhcp_false_disable_dhcp_in_state(self):
"""netplan config with dhcp[46]: False should not add dhcp in state"""
net_config = yaml.load(NETPLAN_DHCP_FALSE)
- ns = network_state.parse_net_config_data(net_config,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(net_config, skip_broken=False)
- dhcp_found = [snet for iface in ns.iter_interfaces()
- for snet in iface['subnets'] if 'dhcp' in snet['type']]
+ dhcp_found = [
+ snet
+ for iface in ns.iter_interfaces()
+ for snet in iface["subnets"]
+ if "dhcp" in snet["type"]
+ ]
self.assertEqual([], dhcp_found)
@@ -3474,9 +4190,10 @@ USERCTL=no
"""netplan cfg with dhcp[46]: False should not have bootproto=dhcp"""
entry = {
- 'yaml': NETPLAN_DHCP_FALSE,
- 'expected_sysconfig': {
- 'ifcfg-ens3': textwrap.dedent("""\
+ "yaml": NETPLAN_DHCP_FALSE,
+ "expected_sysconfig": {
+ "ifcfg-ens3": textwrap.dedent(
+ """\
BOOTPROTO=none
DEFROUTE=yes
DEVICE=ens3
@@ -3496,33 +4213,42 @@ USERCTL=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
- }
+ """
+ ),
+ },
}
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
- self._compare_files_to_expected(entry['expected_sysconfig'], found)
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+ self._compare_files_to_expected(entry["expected_sysconfig"], found)
self._assert_headers(found)
def test_from_v2_vlan_mtu(self):
"""verify mtu gets rendered on bond when source is netplan."""
v2data = {
- 'version': 2,
- 'ethernets': {'eno1': {}},
- 'vlans': {
- 'eno1.1000': {
- 'addresses': ["192.6.1.9/24"],
- 'id': 1000, 'link': 'eno1', 'mtu': 1495}}}
+ "version": 2,
+ "ethernets": {"eno1": {}},
+ "vlans": {
+ "eno1.1000": {
+ "addresses": ["192.6.1.9/24"],
+ "id": 1000,
+ "link": "eno1",
+ "mtu": 1495,
+ }
+ },
+ }
expected = {
- 'ifcfg-eno1': textwrap.dedent("""\
+ "ifcfg-eno1": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=eno1
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
- 'ifcfg-eno1.1000': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-eno1.1000": textwrap.dedent(
+ """\
BOOTPROTO=none
DEVICE=eno1.1000
IPADDR=192.6.1.9
@@ -3533,23 +4259,29 @@ USERCTL=no
PHYSDEV=eno1
USERCTL=no
VLAN=yes
- """)
+ """
+ ),
}
self._compare_files_to_expected(
- expected, self._render_and_read(network_config=v2data))
+ expected, self._render_and_read(network_config=v2data)
+ )
def test_from_v2_bond_mtu(self):
"""verify mtu gets rendered on bond when source is netplan."""
v2data = {
- 'version': 2,
- 'bonds': {
- 'bond0': {'addresses': ['10.101.8.65/26'],
- 'interfaces': ['enp0s0', 'enp0s1'],
- 'mtu': 1334,
- 'parameters': {}}}
+ "version": 2,
+ "bonds": {
+ "bond0": {
+ "addresses": ["10.101.8.65/26"],
+ "interfaces": ["enp0s0", "enp0s1"],
+ "mtu": 1334,
+ "parameters": {},
+ }
+ },
}
expected = {
- 'ifcfg-bond0': textwrap.dedent("""\
+ "ifcfg-bond0": textwrap.dedent(
+ """\
BONDING_MASTER=yes
BONDING_SLAVE0=enp0s0
BONDING_SLAVE1=enp0s1
@@ -3562,8 +4294,10 @@ USERCTL=no
ONBOOT=yes
TYPE=Bond
USERCTL=no
- """),
- 'ifcfg-enp0s0': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-enp0s0": textwrap.dedent(
+ """\
BONDING_MASTER=yes
BOOTPROTO=none
DEVICE=enp0s0
@@ -3573,8 +4307,10 @@ USERCTL=no
SLAVE=yes
TYPE=Bond
USERCTL=no
- """),
- 'ifcfg-enp0s1': textwrap.dedent("""\
+ """
+ ),
+ "ifcfg-enp0s1": textwrap.dedent(
+ """\
BONDING_MASTER=yes
BOOTPROTO=none
DEVICE=enp0s1
@@ -3584,21 +4320,28 @@ USERCTL=no
SLAVE=yes
TYPE=Bond
USERCTL=no
- """)
+ """
+ ),
}
self._compare_files_to_expected(
- expected, self._render_and_read(network_config=v2data))
+ expected, self._render_and_read(network_config=v2data)
+ )
def test_from_v2_route_metric(self):
"""verify route-metric gets rendered on nic when source is netplan."""
- overrides = {'route-metric': 100}
+ overrides = {"route-metric": 100}
v2base = {
- 'version': 2,
- 'ethernets': {
- 'eno1': {'dhcp4': True,
- 'match': {'macaddress': '07-1c-c6-75-a4-be'}}}}
+ "version": 2,
+ "ethernets": {
+ "eno1": {
+ "dhcp4": True,
+ "match": {"macaddress": "07-1c-c6-75-a4-be"},
+ }
+ },
+ }
expected = {
- 'ifcfg-eno1': textwrap.dedent("""\
+ "ifcfg-eno1": textwrap.dedent(
+ """\
BOOTPROTO=dhcp
DEVICE=eno1
HWADDR=07-1c-c6-75-a4-be
@@ -3607,32 +4350,42 @@ USERCTL=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
- """),
+ """
+ ),
}
- for dhcp_ver in ('dhcp4', 'dhcp6'):
+ for dhcp_ver in ("dhcp4", "dhcp6"):
v2data = copy.deepcopy(v2base)
- if dhcp_ver == 'dhcp6':
- expected['ifcfg-eno1'] += "IPV6INIT=yes\nDHCPV6C=yes\n"
- v2data['ethernets']['eno1'].update(
- {dhcp_ver: True, '{0}-overrides'.format(dhcp_ver): overrides})
+ if dhcp_ver == "dhcp6":
+ expected["ifcfg-eno1"] += "IPV6INIT=yes\nDHCPV6C=yes\n"
+ v2data["ethernets"]["eno1"].update(
+ {dhcp_ver: True, "{0}-overrides".format(dhcp_ver): overrides}
+ )
self._compare_files_to_expected(
- expected, self._render_and_read(network_config=v2data))
+ expected, self._render_and_read(network_config=v2data)
+ )
+@mock.patch(
+ "cloudinit.net.is_openvswitch_internal_interface",
+ mock.Mock(return_value=False),
+)
class TestOpenSuseSysConfigRendering(CiTestCase):
with_logs = True
- scripts_dir = '/etc/sysconfig/network'
- header = ('# Created by cloud-init on instance boot automatically, '
- 'do not edit.\n#\n')
+ scripts_dir = "/etc/sysconfig/network"
+ header = (
+ "# Created by cloud-init on instance boot automatically, "
+ "do not edit.\n#\n"
+ )
- expected_name = 'expected_sysconfig_opensuse'
+ expected_name = "expected_sysconfig_opensuse"
def _get_renderer(self):
- distro_cls = distros.fetch('opensuse')
+ distro_cls = distros.fetch("opensuse")
return sysconfig.Renderer(
- config=distro_cls.renderer_configs.get('sysconfig'))
+ config=distro_cls.renderer_configs.get("sysconfig")
+ )
def _render_and_read(self, network_config=None, state=None, dir=None):
if dir is None:
@@ -3653,12 +4406,15 @@ class TestOpenSuseSysConfigRendering(CiTestCase):
orig_maxdiff = self.maxDiff
expected_d = dict(
(os.path.join(self.scripts_dir, k), util.load_shell_content(v))
- for k, v in expected.items())
+ for k, v in expected.items()
+ )
# only compare the files in scripts_dir
scripts_found = dict(
- (k, util.load_shell_content(v)) for k, v in found.items()
- if k.startswith(self.scripts_dir))
+ (k, util.load_shell_content(v))
+ for k, v in found.items()
+ if k.startswith(self.scripts_dir)
+ )
try:
self.maxDiff = None
self.assertEqual(expected_d, scripts_found)
@@ -3666,9 +4422,14 @@ class TestOpenSuseSysConfigRendering(CiTestCase):
self.maxDiff = orig_maxdiff
def _assert_headers(self, found):
- missing = [f for f in found
- if (f.startswith(self.scripts_dir) and
- not found[f].startswith(self.header))]
+ missing = [
+ f
+ for f in found
+ if (
+ f.startswith(self.scripts_dir)
+ and not found[f].startswith(self.header)
+ )
+ ]
if missing:
raise AssertionError("Missing headers in: %s" % missing)
@@ -3676,16 +4437,22 @@ class TestOpenSuseSysConfigRendering(CiTestCase):
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@mock.patch("cloudinit.net.get_devicelist")
- def test_default_generation(self, mock_get_devicelist,
- mock_read_sys_net,
- mock_sys_dev_path, m_get_cmdline):
+ def test_default_generation(
+ self,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ m_get_cmdline,
+ ):
tmp_dir = self.tmp_dir()
- _setup_test(tmp_dir, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path)
+ _setup_test(
+ tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path
+ )
network_cfg = net.generate_fallback_config()
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
render_dir = os.path.join(tmp_dir, "render")
os.makedirs(render_dir)
@@ -3693,7 +4460,7 @@ class TestOpenSuseSysConfigRendering(CiTestCase):
renderer = self._get_renderer()
renderer.render_network_state(ns, target=render_dir)
- render_file = 'etc/sysconfig/network/ifcfg-eth1000'
+ render_file = "etc/sysconfig/network/ifcfg-eth1000"
with open(os.path.join(render_dir, render_file)) as fh:
content = fh.read()
expected_content = """
@@ -3707,98 +4474,101 @@ STARTMODE=auto
# TODO(rjschwei): re-enable test once route writing is implemented
# for SUSE distros
-# def test_multiple_ipv4_default_gateways(self):
-# """ValueError is raised when duplicate ipv4 gateways exist."""
-# net_json = {
-# "services": [{"type": "dns", "address": "172.19.0.12"}],
-# "networks": [{
-# "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
-# "type": "ipv4", "netmask": "255.255.252.0",
-# "link": "tap1a81968a-79",
-# "routes": [{
-# "netmask": "0.0.0.0",
-# "network": "0.0.0.0",
-# "gateway": "172.19.3.254",
-# }, {
-# "netmask": "0.0.0.0", # A second default gateway
-# "network": "0.0.0.0",
-# "gateway": "172.20.3.254",
-# }],
-# "ip_address": "172.19.1.34", "id": "network0"
-# }],
-# "links": [
-# {
-# "ethernet_mac_address": "fa:16:3e:ed:9a:59",
-# "mtu": None, "type": "bridge", "id":
-# "tap1a81968a-79",
-# "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
-# },
-# ],
-# }
-# macs = {'fa:16:3e:ed:9a:59': 'eth0'}
-# render_dir = self.tmp_dir()
-# network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
-# ns = network_state.parse_net_config_data(network_cfg,
-# skip_broken=False)
-# renderer = self._get_renderer()
-# with self.assertRaises(ValueError):
-# renderer.render_network_state(ns, target=render_dir)
-# self.assertEqual([], os.listdir(render_dir))
-#
-# def test_multiple_ipv6_default_gateways(self):
-# """ValueError is raised when duplicate ipv6 gateways exist."""
-# net_json = {
-# "services": [{"type": "dns", "address": "172.19.0.12"}],
-# "networks": [{
-# "network_id": "public-ipv6",
-# "type": "ipv6", "netmask": "",
-# "link": "tap1a81968a-79",
-# "routes": [{
-# "gateway": "2001:DB8::1",
-# "netmask": "::",
-# "network": "::"
-# }, {
-# "gateway": "2001:DB9::1",
-# "netmask": "::",
-# "network": "::"
-# }],
-# "ip_address": "2001:DB8::10", "id": "network1"
-# }],
-# "links": [
-# {
-# "ethernet_mac_address": "fa:16:3e:ed:9a:59",
-# "mtu": None, "type": "bridge", "id":
-# "tap1a81968a-79",
-# "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
-# },
-# ],
-# }
-# macs = {'fa:16:3e:ed:9a:59': 'eth0'}
-# render_dir = self.tmp_dir()
-# network_cfg = openstack.convert_net_json(net_json, known_macs=macs)
-# ns = network_state.parse_net_config_data(network_cfg,
-# skip_broken=False)
-# renderer = self._get_renderer()
-# with self.assertRaises(ValueError):
-# renderer.render_network_state(ns, target=render_dir)
-# self.assertEqual([], os.listdir(render_dir))
+ # def test_multiple_ipv4_default_gateways(self):
+ # """ValueError is raised when duplicate ipv4 gateways exist."""
+ # net_json = {
+ # "services": [{"type": "dns", "address": "172.19.0.12"}],
+ # "networks": [{
+ # "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
+ # "type": "ipv4", "netmask": "255.255.252.0",
+ # "link": "tap1a81968a-79",
+ # "routes": [{
+ # "netmask": "0.0.0.0",
+ # "network": "0.0.0.0",
+ # "gateway": "172.19.3.254",
+ # }, {
+ # "netmask": "0.0.0.0", # A second default gateway
+ # "network": "0.0.0.0",
+ # "gateway": "172.20.3.254",
+ # }],
+ # "ip_address": "172.19.1.34", "id": "network0"
+ # }],
+ # "links": [
+ # {
+ # "ethernet_mac_address": "fa:16:3e:ed:9a:59",
+ # "mtu": None, "type": "bridge", "id":
+ # "tap1a81968a-79",
+ # "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+ # },
+ # ],
+ # }
+ # macs = {'fa:16:3e:ed:9a:59': 'eth0'}
+ # render_dir = self.tmp_dir()
+ # network_cfg = openstack.convert_net_json(net_json, known_macs=macs) # noqa: E501
+ # ns = network_state.parse_net_config_data(network_cfg,
+ # skip_broken=False)
+ # renderer = self._get_renderer()
+ # with self.assertRaises(ValueError):
+ # renderer.render_network_state(ns, target=render_dir)
+ # self.assertEqual([], os.listdir(render_dir))
+ #
+ # def test_multiple_ipv6_default_gateways(self):
+ # """ValueError is raised when duplicate ipv6 gateways exist."""
+ # net_json = {
+ # "services": [{"type": "dns", "address": "172.19.0.12"}],
+ # "networks": [{
+ # "network_id": "public-ipv6",
+ # "type": "ipv6", "netmask": "",
+ # "link": "tap1a81968a-79",
+ # "routes": [{
+ # "gateway": "2001:DB8::1",
+ # "netmask": "::",
+ # "network": "::"
+ # }, {
+ # "gateway": "2001:DB9::1",
+ # "netmask": "::",
+ # "network": "::"
+ # }],
+ # "ip_address": "2001:DB8::10", "id": "network1"
+ # }],
+ # "links": [
+ # {
+ # "ethernet_mac_address": "fa:16:3e:ed:9a:59",
+ # "mtu": None, "type": "bridge", "id":
+ # "tap1a81968a-79",
+ # "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+ # },
+ # ],
+ # }
+ # macs = {'fa:16:3e:ed:9a:59': 'eth0'}
+ # render_dir = self.tmp_dir()
+ # network_cfg = openstack.convert_net_json(net_json, known_macs=macs) # noqa: E501
+ # ns = network_state.parse_net_config_data(network_cfg,
+ # skip_broken=False)
+ # renderer = self._get_renderer()
+ # with self.assertRaises(ValueError):
+ # renderer.render_network_state(ns, target=render_dir)
+ # self.assertEqual([], os.listdir(render_dir))
def test_openstack_rendering_samples(self):
for os_sample in OS_SAMPLES:
render_dir = self.tmp_dir()
- ex_input = os_sample['in_data']
- ex_mac_addrs = os_sample['in_macs']
+ ex_input = os_sample["in_data"]
+ ex_mac_addrs = os_sample["in_macs"]
network_cfg = openstack.convert_net_json(
- ex_input, known_macs=ex_mac_addrs)
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ex_input, known_macs=ex_mac_addrs
+ )
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
renderer = self._get_renderer()
# render a multiple times to simulate reboots
renderer.render_network_state(ns, target=render_dir)
renderer.render_network_state(ns, target=render_dir)
renderer.render_network_state(ns, target=render_dir)
- for fn, expected_content in os_sample.get('out_sysconfig_opensuse',
- []):
+ for fn, expected_content in os_sample.get(
+ "out_sysconfig_opensuse", []
+ ):
with open(os.path.join(render_dir, fn)) as fh:
self.assertEqual(expected_content, fh.read())
@@ -3809,8 +4579,8 @@ STARTMODE=auto
renderer = self._get_renderer()
renderer.render_network_state(ns, target=render_dir)
found = dir2dict(render_dir)
- nspath = '/etc/sysconfig/network/'
- self.assertNotIn(nspath + 'ifcfg-lo', found.keys())
+ nspath = "/etc/sysconfig/network/"
+ self.assertNotIn(nspath + "ifcfg-lo", found.keys())
expected = """\
# Created by cloud-init on instance boot automatically, do not edit.
#
@@ -3820,10 +4590,10 @@ LLADDR=52:54:00:12:34:00
NETMASK=255.255.255.0
STARTMODE=auto
"""
- self.assertEqual(expected, found[nspath + 'ifcfg-interface0'])
+ self.assertEqual(expected, found[nspath + "ifcfg-interface0"])
# The configuration has no nameserver information make sure we
# do not write the resolv.conf file
- respath = '/etc/resolv.conf'
+ respath = "/etc/resolv.conf"
self.assertNotIn(respath, found.keys())
def test_config_with_explicit_loopback(self):
@@ -3831,33 +4601,33 @@ STARTMODE=auto
render_dir = self.tmp_path("render")
os.makedirs(render_dir)
# write an etc/resolv.conf and expect it to not be modified
- resolvconf = os.path.join(render_dir, 'etc/resolv.conf')
+ resolvconf = os.path.join(render_dir, "etc/resolv.conf")
resolvconf_content = "# Original Content"
util.write_file(resolvconf, resolvconf_content)
renderer = self._get_renderer()
renderer.render_network_state(ns, target=render_dir)
found = dir2dict(render_dir)
- nspath = '/etc/sysconfig/network/'
- self.assertNotIn(nspath + 'ifcfg-lo', found.keys())
+ nspath = "/etc/sysconfig/network/"
+ self.assertNotIn(nspath + "ifcfg-lo", found.keys())
expected = """\
# Created by cloud-init on instance boot automatically, do not edit.
#
BOOTPROTO=dhcp
STARTMODE=auto
"""
- self.assertEqual(expected, found[nspath + 'ifcfg-eth0'])
+ self.assertEqual(expected, found[nspath + "ifcfg-eth0"])
# a dhcp only config should not modify resolv.conf
- self.assertEqual(resolvconf_content, found['/etc/resolv.conf'])
+ self.assertEqual(resolvconf_content, found["/etc/resolv.conf"])
def test_bond_config(self):
- expected_name = 'expected_sysconfig_opensuse'
- entry = NETWORK_CONFIGS['bond']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ expected_name = "expected_sysconfig_opensuse"
+ entry = NETWORK_CONFIGS["bond"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
for fname, contents in entry[expected_name].items():
print(fname)
print(contents)
print()
- print('-- expected ^ | v rendered --')
+ print("-- expected ^ | v rendered --")
for fname, contents in found.items():
print(fname)
print(contents)
@@ -3866,120 +4636,129 @@ STARTMODE=auto
self._assert_headers(found)
def test_vlan_config(self):
- entry = NETWORK_CONFIGS['vlan']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["vlan"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_bridge_config(self):
- entry = NETWORK_CONFIGS['bridge']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["bridge"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_manual_config(self):
- entry = NETWORK_CONFIGS['manual']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["manual"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_all_config(self):
- entry = NETWORK_CONFIGS['all']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["all"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
self.assertNotIn(
- 'WARNING: Network config: ignoring eth0.101 device-level mtu',
- self.logs.getvalue())
+ "WARNING: Network config: ignoring eth0.101 device-level mtu",
+ self.logs.getvalue(),
+ )
def test_small_config(self):
- entry = NETWORK_CONFIGS['small']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["small"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_v4_and_v6_static_config(self):
- entry = NETWORK_CONFIGS['v4_and_v6_static']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["v4_and_v6_static"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
expected_msg = (
- 'WARNING: Network config: ignoring iface0 device-level mtu:8999'
- ' because ipv4 subnet-level mtu:9000 provided.')
+ "WARNING: Network config: ignoring iface0 device-level mtu:8999"
+ " because ipv4 subnet-level mtu:9000 provided."
+ )
self.assertIn(expected_msg, self.logs.getvalue())
def test_dhcpv6_only_config(self):
- entry = NETWORK_CONFIGS['dhcpv6_only']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_only"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_simple_render_ipv6_slaac(self):
- entry = NETWORK_CONFIGS['ipv6_slaac']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["ipv6_slaac"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_dhcpv6_stateless_config(self):
- entry = NETWORK_CONFIGS['dhcpv6_stateless']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_stateless"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_wakeonlan_disabled_config_v2(self):
- entry = NETWORK_CONFIGS['wakeonlan_disabled']
- found = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["wakeonlan_disabled"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_wakeonlan_enabled_config_v2(self):
- entry = NETWORK_CONFIGS['wakeonlan_enabled']
- found = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["wakeonlan_enabled"]
+ found = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_render_v4_and_v6(self):
- entry = NETWORK_CONFIGS['v4_and_v6']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["v4_and_v6"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
def test_render_v6_and_v4(self):
- entry = NETWORK_CONFIGS['v6_and_v4']
- found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["v6_and_v4"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)
class TestEniNetRendering(CiTestCase):
-
@mock.patch("cloudinit.net.util.get_cmdline", return_value="root=myroot")
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@mock.patch("cloudinit.net.get_devicelist")
- def test_default_generation(self, mock_get_devicelist,
- mock_read_sys_net,
- mock_sys_dev_path, m_get_cmdline):
+ def test_default_generation(
+ self,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ m_get_cmdline,
+ ):
tmp_dir = self.tmp_dir()
- _setup_test(tmp_dir, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path)
+ _setup_test(
+ tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path
+ )
network_cfg = net.generate_fallback_config()
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
render_dir = os.path.join(tmp_dir, "render")
os.makedirs(render_dir)
renderer = eni.Renderer(
- {'eni_path': 'interfaces', 'netrules_path': None})
+ {"eni_path": "interfaces", "netrules_path": None}
+ )
renderer.render_network_state(ns, target=render_dir)
- self.assertTrue(os.path.exists(os.path.join(render_dir,
- 'interfaces')))
- with open(os.path.join(render_dir, 'interfaces')) as fh:
+ self.assertTrue(os.path.exists(os.path.join(render_dir, "interfaces")))
+ with open(os.path.join(render_dir, "interfaces")) as fh:
contents = fh.read()
expected = """
@@ -4004,62 +4783,74 @@ auto eth0
iface eth0 inet dhcp
"""
self.assertEqual(
- expected, dir2dict(tmp_dir)['/etc/network/interfaces'])
+ expected, dir2dict(tmp_dir)["/etc/network/interfaces"]
+ )
def test_v2_route_metric_to_eni(self):
"""Network v2 route-metric overrides are preserved in eni output"""
tmp_dir = self.tmp_dir()
renderer = eni.Renderer()
- expected_tmpl = textwrap.dedent("""\
+ expected_tmpl = textwrap.dedent(
+ """\
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet{suffix} dhcp
metric 100
- """)
- for dhcp_ver in ('dhcp4', 'dhcp6'):
- suffix = '6' if dhcp_ver == 'dhcp6' else ''
+ """
+ )
+ for dhcp_ver in ("dhcp4", "dhcp6"):
+ suffix = "6" if dhcp_ver == "dhcp6" else ""
dhcp_cfg = {
dhcp_ver: True,
- '{ver}-overrides'.format(ver=dhcp_ver): {'route-metric': 100}}
- v2_input = {'version': 2, 'ethernets': {'eth0': dhcp_cfg}}
+ "{ver}-overrides".format(ver=dhcp_ver): {"route-metric": 100},
+ }
+ v2_input = {"version": 2, "ethernets": {"eth0": dhcp_cfg}}
ns = network_state.parse_net_config_data(v2_input)
renderer.render_network_state(ns, target=tmp_dir)
self.assertEqual(
expected_tmpl.format(suffix=suffix),
- dir2dict(tmp_dir)['/etc/network/interfaces'])
+ dir2dict(tmp_dir)["/etc/network/interfaces"],
+ )
class TestNetplanNetRendering(CiTestCase):
-
@mock.patch("cloudinit.net.util.get_cmdline", return_value="root=myroot")
@mock.patch("cloudinit.net.netplan._clean_default")
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@mock.patch("cloudinit.net.get_devicelist")
- def test_default_generation(self, mock_get_devicelist,
- mock_read_sys_net,
- mock_sys_dev_path,
- mock_clean_default, m_get_cmdline):
+ def test_default_generation(
+ self,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ mock_clean_default,
+ m_get_cmdline,
+ ):
tmp_dir = self.tmp_dir()
- _setup_test(tmp_dir, mock_get_devicelist,
- mock_read_sys_net, mock_sys_dev_path)
+ _setup_test(
+ tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path
+ )
network_cfg = net.generate_fallback_config()
- ns = network_state.parse_net_config_data(network_cfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
render_dir = os.path.join(tmp_dir, "render")
os.makedirs(render_dir)
- render_target = 'netplan.yaml'
+ render_target = "netplan.yaml"
renderer = netplan.Renderer(
- {'netplan_path': render_target, 'postcmds': False})
+ {"netplan_path": render_target, "postcmds": False}
+ )
renderer.render_network_state(ns, target=render_dir)
- self.assertTrue(os.path.exists(os.path.join(render_dir,
- render_target)))
+ self.assertTrue(
+ os.path.exists(os.path.join(render_dir, render_target))
+ )
with open(os.path.join(render_dir, render_target)) as fh:
contents = fh.read()
print(contents)
@@ -4079,8 +4870,9 @@ network:
class TestNetplanCleanDefault(CiTestCase):
- snapd_known_path = 'etc/netplan/00-snapd-config.yaml'
- snapd_known_content = textwrap.dedent("""\
+ snapd_known_path = "etc/netplan/00-snapd-config.yaml"
+ snapd_known_content = textwrap.dedent(
+ """\
# This is the initial network config.
# It can be overwritten by cloud-init or console-conf.
network:
@@ -4094,15 +4886,18 @@ class TestNetplanCleanDefault(CiTestCase):
match:
name: "eth*"
dhcp4: true
- """)
+ """
+ )
stub_known = {
- 'run/systemd/network/10-netplan-all-en.network': 'foo-en',
- 'run/systemd/network/10-netplan-all-eth.network': 'foo-eth',
- 'run/systemd/generator/netplan.stamp': 'stamp',
+ "run/systemd/network/10-netplan-all-en.network": "foo-en",
+ "run/systemd/network/10-netplan-all-eth.network": "foo-eth",
+ "run/systemd/generator/netplan.stamp": "stamp",
}
def test_clean_known_config_cleaned(self):
- content = {self.snapd_known_path: self.snapd_known_content, }
+ content = {
+ self.snapd_known_path: self.snapd_known_content,
+ }
content.update(self.stub_known)
tmpd = self.tmp_dir()
files = sorted(populate_dir(tmpd, content))
@@ -4111,7 +4906,9 @@ class TestNetplanCleanDefault(CiTestCase):
self.assertEqual([], found)
def test_clean_unknown_config_not_cleaned(self):
- content = {self.snapd_known_path: self.snapd_known_content, }
+ content = {
+ self.snapd_known_path: self.snapd_known_content,
+ }
content.update(self.stub_known)
content[self.snapd_known_path] += "# user put a comment\n"
tmpd = self.tmp_dir()
@@ -4142,78 +4939,100 @@ class TestNetplanCleanDefault(CiTestCase):
class TestNetplanPostcommands(CiTestCase):
mycfg = {
- 'config': [{"type": "physical", "name": "eth0",
- "mac_address": "c0:d6:9f:2c:e8:80",
- "subnets": [{"type": "dhcp"}]}],
- 'version': 1}
-
- @mock.patch.object(netplan.Renderer, '_netplan_generate')
- @mock.patch.object(netplan.Renderer, '_net_setup_link')
- @mock.patch('cloudinit.subp.subp')
- def test_netplan_render_calls_postcmds(self, mock_subp,
- mock_netplan_generate,
- mock_net_setup_link):
+ "config": [
+ {
+ "type": "physical",
+ "name": "eth0",
+ "mac_address": "c0:d6:9f:2c:e8:80",
+ "subnets": [{"type": "dhcp"}],
+ }
+ ],
+ "version": 1,
+ }
+
+ @mock.patch.object(netplan.Renderer, "_netplan_generate")
+ @mock.patch.object(netplan.Renderer, "_net_setup_link")
+ @mock.patch("cloudinit.subp.subp")
+ def test_netplan_render_calls_postcmds(
+ self, mock_subp, mock_netplan_generate, mock_net_setup_link
+ ):
tmp_dir = self.tmp_dir()
- ns = network_state.parse_net_config_data(self.mycfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(self.mycfg, skip_broken=False)
render_dir = os.path.join(tmp_dir, "render")
os.makedirs(render_dir)
- render_target = 'netplan.yaml'
+ render_target = "netplan.yaml"
renderer = netplan.Renderer(
- {'netplan_path': render_target, 'postcmds': True})
+ {"netplan_path": render_target, "postcmds": True}
+ )
mock_subp.side_effect = iter([subp.ProcessExecutionError])
renderer.render_network_state(ns, target=render_dir)
mock_netplan_generate.assert_called_with(run=True)
mock_net_setup_link.assert_called_with(run=True)
- @mock.patch('cloudinit.util.SeLinuxGuard')
+ @mock.patch("cloudinit.util.SeLinuxGuard")
@mock.patch.object(netplan, "get_devicelist")
- @mock.patch('cloudinit.subp.subp')
+ @mock.patch("cloudinit.subp.subp")
def test_netplan_postcmds(self, mock_subp, mock_devlist, mock_sel):
mock_sel.__enter__ = mock.Mock(return_value=False)
mock_sel.__exit__ = mock.Mock()
- mock_devlist.side_effect = [['lo']]
+ mock_devlist.side_effect = [["lo"]]
tmp_dir = self.tmp_dir()
- ns = network_state.parse_net_config_data(self.mycfg,
- skip_broken=False)
+ ns = network_state.parse_net_config_data(self.mycfg, skip_broken=False)
render_dir = os.path.join(tmp_dir, "render")
os.makedirs(render_dir)
- render_target = 'netplan.yaml'
+ render_target = "netplan.yaml"
renderer = netplan.Renderer(
- {'netplan_path': render_target, 'postcmds': True})
- mock_subp.side_effect = iter([
- subp.ProcessExecutionError,
- ('', ''),
- ('', ''),
- ])
+ {"netplan_path": render_target, "postcmds": True}
+ )
+ mock_subp.side_effect = iter(
+ [
+ subp.ProcessExecutionError,
+ ("", ""),
+ ("", ""),
+ ]
+ )
expected = [
- mock.call(['netplan', 'info'], capture=True),
- mock.call(['netplan', 'generate'], capture=True),
- mock.call(['udevadm', 'test-builtin', 'net_setup_link',
- '/sys/class/net/lo'], capture=True),
+ mock.call(["netplan", "info"], capture=True),
+ mock.call(["netplan", "generate"], capture=True),
+ mock.call(
+ [
+ "udevadm",
+ "test-builtin",
+ "net_setup_link",
+ "/sys/class/net/lo",
+ ],
+ capture=True,
+ ),
]
- with mock.patch.object(os.path, 'islink', return_value=True):
+ with mock.patch.object(os.path, "islink", return_value=True):
renderer.render_network_state(ns, target=render_dir)
mock_subp.assert_has_calls(expected)
class TestEniNetworkStateToEni(CiTestCase):
mycfg = {
- 'config': [{"type": "physical", "name": "eth0",
- "mac_address": "c0:d6:9f:2c:e8:80",
- "subnets": [{"type": "dhcp"}]}],
- 'version': 1}
- my_mac = 'c0:d6:9f:2c:e8:80'
+ "config": [
+ {
+ "type": "physical",
+ "name": "eth0",
+ "mac_address": "c0:d6:9f:2c:e8:80",
+ "subnets": [{"type": "dhcp"}],
+ }
+ ],
+ "version": 1,
+ }
+ my_mac = "c0:d6:9f:2c:e8:80"
def test_no_header(self):
rendered = eni.network_state_to_eni(
network_state=network_state.parse_net_config_data(self.mycfg),
- render_hwaddress=True)
+ render_hwaddress=True,
+ )
self.assertIn(self.my_mac, rendered)
self.assertIn("hwaddress", rendered)
@@ -4221,14 +5040,17 @@ class TestEniNetworkStateToEni(CiTestCase):
header = "# hello world\n"
rendered = eni.network_state_to_eni(
network_state=network_state.parse_net_config_data(self.mycfg),
- header=header, render_hwaddress=True)
+ header=header,
+ render_hwaddress=True,
+ )
self.assertIn(header, rendered)
self.assertIn(self.my_mac, rendered)
def test_no_hwaddress(self):
rendered = eni.network_state_to_eni(
network_state=network_state.parse_net_config_data(self.mycfg),
- render_hwaddress=False)
+ render_hwaddress=False,
+ )
self.assertNotIn(self.my_mac, rendered)
self.assertNotIn("hwaddress", rendered)
@@ -4237,156 +5059,241 @@ class TestCmdlineConfigParsing(CiTestCase):
with_logs = True
simple_cfg = {
- 'config': [{"type": "physical", "name": "eth0",
- "mac_address": "c0:d6:9f:2c:e8:80",
- "subnets": [{"type": "dhcp"}]}]}
+ "config": [
+ {
+ "type": "physical",
+ "name": "eth0",
+ "mac_address": "c0:d6:9f:2c:e8:80",
+ "subnets": [{"type": "dhcp"}],
+ }
+ ]
+ }
def test_cmdline_convert_dhcp(self):
found = cmdline._klibc_to_config_entry(DHCP_CONTENT_1)
- self.assertEqual(found, ('eth0', DHCP_EXPECTED_1))
+ self.assertEqual(found, ("eth0", DHCP_EXPECTED_1))
def test_cmdline_convert_dhcp6(self):
found = cmdline._klibc_to_config_entry(DHCP6_CONTENT_1)
- self.assertEqual(found, ('eno1', DHCP6_EXPECTED_1))
+ self.assertEqual(found, ("eno1", DHCP6_EXPECTED_1))
def test_cmdline_convert_static(self):
found = cmdline._klibc_to_config_entry(STATIC_CONTENT_1)
- self.assertEqual(found, ('eth1', STATIC_EXPECTED_1))
+ self.assertEqual(found, ("eth1", STATIC_EXPECTED_1))
def test_config_from_cmdline_net_cfg(self):
files = []
- pairs = (('net-eth0.cfg', DHCP_CONTENT_1),
- ('net-eth1.cfg', STATIC_CONTENT_1))
+ pairs = (
+ ("net-eth0.cfg", DHCP_CONTENT_1),
+ ("net-eth1.cfg", STATIC_CONTENT_1),
+ )
- macs = {'eth1': 'b8:ae:ed:75:ff:2b',
- 'eth0': 'b8:ae:ed:75:ff:2a'}
+ macs = {"eth1": "b8:ae:ed:75:ff:2b", "eth0": "b8:ae:ed:75:ff:2a"}
dhcp = copy.deepcopy(DHCP_EXPECTED_1)
- dhcp['mac_address'] = macs['eth0']
+ dhcp["mac_address"] = macs["eth0"]
static = copy.deepcopy(STATIC_EXPECTED_1)
- static['mac_address'] = macs['eth1']
+ static["mac_address"] = macs["eth1"]
- expected = {'version': 1, 'config': [dhcp, static]}
+ expected = {"version": 1, "config": [dhcp, static]}
with temp_utils.tempdir() as tmpd:
for fname, content in pairs:
fp = os.path.join(tmpd, fname)
files.append(fp)
util.write_file(fp, content)
- found = cmdline.config_from_klibc_net_cfg(files=files,
- mac_addrs=macs)
+ found = cmdline.config_from_klibc_net_cfg(
+ files=files, mac_addrs=macs
+ )
self.assertEqual(found, expected)
def test_cmdline_with_b64(self):
data = base64.b64encode(json.dumps(self.simple_cfg).encode())
encoded_text = data.decode()
- raw_cmdline = 'ro network-config=' + encoded_text + ' root=foo'
+ raw_cmdline = "ro network-config=" + encoded_text + " root=foo"
found = cmdline.read_kernel_cmdline_config(cmdline=raw_cmdline)
self.assertEqual(found, self.simple_cfg)
def test_cmdline_with_net_config_disabled(self):
- raw_cmdline = 'ro network-config=disabled root=foo'
+ raw_cmdline = "ro network-config=disabled root=foo"
found = cmdline.read_kernel_cmdline_config(cmdline=raw_cmdline)
- self.assertEqual(found, {'config': 'disabled'})
+ self.assertEqual(found, {"config": "disabled"})
def test_cmdline_with_net_config_unencoded_logs_error(self):
"""network-config cannot be unencoded besides 'disabled'."""
- raw_cmdline = 'ro network-config={config:disabled} root=foo'
+ raw_cmdline = "ro network-config={config:disabled} root=foo"
found = cmdline.read_kernel_cmdline_config(cmdline=raw_cmdline)
self.assertIsNone(found)
expected_log = (
- 'ERROR: Expected base64 encoded kernel commandline parameter'
- ' network-config. Ignoring network-config={config:disabled}.')
+ "ERROR: Expected base64 encoded kernel commandline parameter"
+ " network-config. Ignoring network-config={config:disabled}."
+ )
self.assertIn(expected_log, self.logs.getvalue())
def test_cmdline_with_b64_gz(self):
data = _gzip_data(json.dumps(self.simple_cfg).encode())
encoded_text = base64.b64encode(data).decode()
- raw_cmdline = 'ro network-config=' + encoded_text + ' root=foo'
+ raw_cmdline = "ro network-config=" + encoded_text + " root=foo"
found = cmdline.read_kernel_cmdline_config(cmdline=raw_cmdline)
self.assertEqual(found, self.simple_cfg)
class TestCmdlineKlibcNetworkConfigSource(FilesystemMockingTestCase):
macs = {
- 'eth0': '14:02:ec:42:48:00',
- 'eno1': '14:02:ec:42:48:01',
+ "eth0": "14:02:ec:42:48:00",
+ "eno1": "14:02:ec:42:48:01",
}
def test_without_ip(self):
- content = {'/run/net-eth0.conf': DHCP_CONTENT_1,
- cmdline._OPEN_ISCSI_INTERFACE_FILE: "eth0\n"}
+ content = {
+ "/run/net-eth0.conf": DHCP_CONTENT_1,
+ cmdline._OPEN_ISCSI_INTERFACE_FILE: "eth0\n",
+ }
exp1 = copy.deepcopy(DHCP_EXPECTED_1)
- exp1['mac_address'] = self.macs['eth0']
+ exp1["mac_address"] = self.macs["eth0"]
root = self.tmp_dir()
populate_dir(root, content)
self.reRoot(root)
src = cmdline.KlibcNetworkConfigSource(
- _cmdline='foo root=/root/bar', _mac_addrs=self.macs,
+ _cmdline="foo root=/root/bar",
+ _mac_addrs=self.macs,
)
self.assertTrue(src.is_applicable())
found = src.render_config()
- self.assertEqual(found['version'], 1)
- self.assertEqual(found['config'], [exp1])
+ self.assertEqual(found["version"], 1)
+ self.assertEqual(found["config"], [exp1])
def test_with_ip(self):
- content = {'/run/net-eth0.conf': DHCP_CONTENT_1}
+ content = {"/run/net-eth0.conf": DHCP_CONTENT_1}
exp1 = copy.deepcopy(DHCP_EXPECTED_1)
- exp1['mac_address'] = self.macs['eth0']
+ exp1["mac_address"] = self.macs["eth0"]
root = self.tmp_dir()
populate_dir(root, content)
self.reRoot(root)
src = cmdline.KlibcNetworkConfigSource(
- _cmdline='foo ip=dhcp', _mac_addrs=self.macs,
+ _cmdline="foo ip=dhcp",
+ _mac_addrs=self.macs,
)
self.assertTrue(src.is_applicable())
found = src.render_config()
- self.assertEqual(found['version'], 1)
- self.assertEqual(found['config'], [exp1])
+ self.assertEqual(found["version"], 1)
+ self.assertEqual(found["config"], [exp1])
def test_with_ip6(self):
- content = {'/run/net6-eno1.conf': DHCP6_CONTENT_1}
+ content = {"/run/net6-eno1.conf": DHCP6_CONTENT_1}
root = self.tmp_dir()
populate_dir(root, content)
self.reRoot(root)
src = cmdline.KlibcNetworkConfigSource(
- _cmdline='foo ip6=dhcp root=/dev/sda', _mac_addrs=self.macs,
+ _cmdline="foo ip6=dhcp root=/dev/sda",
+ _mac_addrs=self.macs,
)
self.assertTrue(src.is_applicable())
found = src.render_config()
self.assertEqual(
found,
- {'version': 1, 'config': [
- {'type': 'physical', 'name': 'eno1',
- 'mac_address': self.macs['eno1'],
- 'subnets': [
- {'dns_nameservers': ['2001:67c:1562:8010::2:1'],
- 'control': 'manual', 'type': 'dhcp6', 'netmask': '64'}]}]})
+ {
+ "version": 1,
+ "config": [
+ {
+ "type": "physical",
+ "name": "eno1",
+ "mac_address": self.macs["eno1"],
+ "subnets": [
+ {
+ "dns_nameservers": ["2001:67c:1562:8010::2:1"],
+ "control": "manual",
+ "type": "dhcp6",
+ "netmask": "64",
+ }
+ ],
+ }
+ ],
+ },
+ )
def test_with_no_ip_or_ip6(self):
# if there is no ip= or ip6= on cmdline, return value should be None
- content = {'net6-eno1.conf': DHCP6_CONTENT_1}
+ content = {"net6-eno1.conf": DHCP6_CONTENT_1}
files = sorted(populate_dir(self.tmp_dir(), content))
src = cmdline.KlibcNetworkConfigSource(
- _files=files, _cmdline='foo root=/dev/sda', _mac_addrs=self.macs,
+ _files=files,
+ _cmdline="foo root=/dev/sda",
+ _mac_addrs=self.macs,
+ )
+ self.assertFalse(src.is_applicable())
+
+ def test_with_faux_ip(self):
+ content = {"net6-eno1.conf": DHCP6_CONTENT_1}
+ files = sorted(populate_dir(self.tmp_dir(), content))
+ src = cmdline.KlibcNetworkConfigSource(
+ _files=files,
+ _cmdline="foo iscsi_target_ip=root=/dev/sda",
+ _mac_addrs=self.macs,
+ )
+ self.assertFalse(src.is_applicable())
+
+ def test_empty_cmdline(self):
+ content = {"net6-eno1.conf": DHCP6_CONTENT_1}
+ files = sorted(populate_dir(self.tmp_dir(), content))
+ src = cmdline.KlibcNetworkConfigSource(
+ _files=files,
+ _cmdline="",
+ _mac_addrs=self.macs,
+ )
+ self.assertFalse(src.is_applicable())
+
+ def test_whitespace_cmdline(self):
+ content = {"net6-eno1.conf": DHCP6_CONTENT_1}
+ files = sorted(populate_dir(self.tmp_dir(), content))
+ src = cmdline.KlibcNetworkConfigSource(
+ _files=files,
+ _cmdline=" ",
+ _mac_addrs=self.macs,
+ )
+ self.assertFalse(src.is_applicable())
+
+ def test_cmdline_no_lhand(self):
+ content = {"net6-eno1.conf": DHCP6_CONTENT_1}
+ files = sorted(populate_dir(self.tmp_dir(), content))
+ src = cmdline.KlibcNetworkConfigSource(
+ _files=files,
+ _cmdline="=wut",
+ _mac_addrs=self.macs,
+ )
+ self.assertFalse(src.is_applicable())
+
+ def test_cmdline_embedded_ip(self):
+ content = {"net6-eno1.conf": DHCP6_CONTENT_1}
+ files = sorted(populate_dir(self.tmp_dir(), content))
+ src = cmdline.KlibcNetworkConfigSource(
+ _files=files,
+ _cmdline='opt="some things and ip=foo"',
+ _mac_addrs=self.macs,
)
self.assertFalse(src.is_applicable())
def test_with_both_ip_ip6(self):
content = {
- '/run/net-eth0.conf': DHCP_CONTENT_1,
- '/run/net6-eth0.conf': DHCP6_CONTENT_1.replace('eno1', 'eth0')}
+ "/run/net-eth0.conf": DHCP_CONTENT_1,
+ "/run/net6-eth0.conf": DHCP6_CONTENT_1.replace("eno1", "eth0"),
+ }
eth0 = copy.deepcopy(DHCP_EXPECTED_1)
- eth0['mac_address'] = self.macs['eth0']
- eth0['subnets'].append(
- {'control': 'manual', 'type': 'dhcp6',
- 'netmask': '64', 'dns_nameservers': ['2001:67c:1562:8010::2:1']})
+ eth0["mac_address"] = self.macs["eth0"]
+ eth0["subnets"].append(
+ {
+ "control": "manual",
+ "type": "dhcp6",
+ "netmask": "64",
+ "dns_nameservers": ["2001:67c:1562:8010::2:1"],
+ }
+ )
expected = [eth0]
root = self.tmp_dir()
@@ -4394,17 +5301,17 @@ class TestCmdlineKlibcNetworkConfigSource(FilesystemMockingTestCase):
self.reRoot(root)
src = cmdline.KlibcNetworkConfigSource(
- _cmdline='foo ip=dhcp ip6=dhcp', _mac_addrs=self.macs,
+ _cmdline="foo ip=dhcp ip6=dhcp",
+ _mac_addrs=self.macs,
)
self.assertTrue(src.is_applicable())
found = src.render_config()
- self.assertEqual(found['version'], 1)
- self.assertEqual(found['config'], expected)
+ self.assertEqual(found["version"], 1)
+ self.assertEqual(found["config"], expected)
class TestReadInitramfsConfig(CiTestCase):
-
def _config_source_cls_mock(self, is_applicable, render_config=None):
return lambda: mock.Mock(
is_applicable=lambda: is_applicable,
@@ -4412,7 +5319,7 @@ class TestReadInitramfsConfig(CiTestCase):
)
def test_no_sources(self):
- with mock.patch('cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES', []):
+ with mock.patch("cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES", []):
self.assertIsNone(cmdline.read_initramfs_config())
def test_no_applicable_sources(self):
@@ -4421,19 +5328,22 @@ class TestReadInitramfsConfig(CiTestCase):
self._config_source_cls_mock(is_applicable=False),
self._config_source_cls_mock(is_applicable=False),
]
- with mock.patch('cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES',
- sources):
+ with mock.patch(
+ "cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES", sources
+ ):
self.assertIsNone(cmdline.read_initramfs_config())
def test_one_applicable_source(self):
expected_config = object()
sources = [
self._config_source_cls_mock(
- is_applicable=True, render_config=expected_config,
+ is_applicable=True,
+ render_config=expected_config,
),
]
- with mock.patch('cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES',
- sources):
+ with mock.patch(
+ "cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES", sources
+ ):
self.assertEqual(expected_config, cmdline.read_initramfs_config())
def test_one_applicable_source_after_inapplicable_sources(self):
@@ -4442,45 +5352,53 @@ class TestReadInitramfsConfig(CiTestCase):
self._config_source_cls_mock(is_applicable=False),
self._config_source_cls_mock(is_applicable=False),
self._config_source_cls_mock(
- is_applicable=True, render_config=expected_config,
+ is_applicable=True,
+ render_config=expected_config,
),
]
- with mock.patch('cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES',
- sources):
+ with mock.patch(
+ "cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES", sources
+ ):
self.assertEqual(expected_config, cmdline.read_initramfs_config())
def test_first_applicable_source_is_used(self):
first_config, second_config = object(), object()
sources = [
self._config_source_cls_mock(
- is_applicable=True, render_config=first_config,
+ is_applicable=True,
+ render_config=first_config,
),
self._config_source_cls_mock(
- is_applicable=True, render_config=second_config,
+ is_applicable=True,
+ render_config=second_config,
),
]
- with mock.patch('cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES',
- sources):
+ with mock.patch(
+ "cloudinit.net.cmdline._INITRAMFS_CONFIG_SOURCES", sources
+ ):
self.assertEqual(first_config, cmdline.read_initramfs_config())
class TestNetplanRoundTrip(CiTestCase):
- NETPLAN_INFO_OUT = textwrap.dedent("""
+ NETPLAN_INFO_OUT = textwrap.dedent(
+ """
netplan.io:
features:
- dhcp-use-domains
- ipv6-mtu
website: https://netplan.io/
- """)
+ """
+ )
def setUp(self):
super(TestNetplanRoundTrip, self).setUp()
- self.add_patch('cloudinit.net.netplan.subp.subp', 'm_subp')
- self.m_subp.return_value = (self.NETPLAN_INFO_OUT, '')
+ self.add_patch("cloudinit.net.netplan.subp.subp", "m_subp")
+ self.m_subp.return_value = (self.NETPLAN_INFO_OUT, "")
- def _render_and_read(self, network_config=None, state=None,
- netplan_path=None, target=None):
+ def _render_and_read(
+ self, network_config=None, state=None, netplan_path=None, target=None
+ ):
if target is None:
target = self.tmp_dir()
@@ -4492,188 +5410,212 @@ class TestNetplanRoundTrip(CiTestCase):
raise ValueError("Expected data or state, got neither")
if netplan_path is None:
- netplan_path = 'etc/netplan/50-cloud-init.yaml'
+ netplan_path = "etc/netplan/50-cloud-init.yaml"
- renderer = netplan.Renderer(
- config={'netplan_path': netplan_path})
+ renderer = netplan.Renderer(config={"netplan_path": netplan_path})
renderer.render_network_state(ns, target=target)
return dir2dict(target)
def testsimple_render_bond_netplan(self):
- entry = NETWORK_CONFIGS['bond']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
- print(entry['expected_netplan'])
- print('-- expected ^ | v rendered --')
- print(files['/etc/netplan/50-cloud-init.yaml'])
+ entry = NETWORK_CONFIGS["bond"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+ print(entry["expected_netplan"])
+ print("-- expected ^ | v rendered --")
+ print(files["/etc/netplan/50-cloud-init.yaml"])
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_bond_v2_input_netplan(self):
- entry = NETWORK_CONFIGS['bond']
+ entry = NETWORK_CONFIGS["bond"]
files = self._render_and_read(
- network_config=yaml.load(entry['yaml-v2']))
- print(entry['expected_netplan-v2'])
- print('-- expected ^ | v rendered --')
- print(files['/etc/netplan/50-cloud-init.yaml'])
+ network_config=yaml.load(entry["yaml-v2"])
+ )
+ print(entry["expected_netplan-v2"])
+ print("-- expected ^ | v rendered --")
+ print(files["/etc/netplan/50-cloud-init.yaml"])
self.assertEqual(
- entry['expected_netplan-v2'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan-v2"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_small_netplan(self):
- entry = NETWORK_CONFIGS['small']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["small"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_v4_and_v6(self):
- entry = NETWORK_CONFIGS['v4_and_v6']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["v4_and_v6"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_v4_and_v6_static(self):
- entry = NETWORK_CONFIGS['v4_and_v6_static']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["v4_and_v6_static"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_dhcpv6_only(self):
- entry = NETWORK_CONFIGS['dhcpv6_only']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_only"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_dhcpv6_accept_ra(self):
- entry = NETWORK_CONFIGS['dhcpv6_accept_ra']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml_v1']))
+ entry = NETWORK_CONFIGS["dhcpv6_accept_ra"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v1"])
+ )
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_dhcpv6_reject_ra(self):
- entry = NETWORK_CONFIGS['dhcpv6_reject_ra']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml_v1']))
+ entry = NETWORK_CONFIGS["dhcpv6_reject_ra"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v1"])
+ )
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_ipv6_slaac(self):
- entry = NETWORK_CONFIGS['ipv6_slaac']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml']))
+ entry = NETWORK_CONFIGS["ipv6_slaac"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_dhcpv6_stateless(self):
- entry = NETWORK_CONFIGS['dhcpv6_stateless']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_stateless"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_dhcpv6_stateful(self):
- entry = NETWORK_CONFIGS['dhcpv6_stateful']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_stateful"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_wakeonlan_disabled_config_v2(self):
- entry = NETWORK_CONFIGS['wakeonlan_disabled']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["wakeonlan_disabled"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_wakeonlan_enabled_config_v2(self):
- entry = NETWORK_CONFIGS['wakeonlan_enabled']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["wakeonlan_enabled"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_all(self):
- entry = NETWORK_CONFIGS['all']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
- print(entry['expected_netplan'])
- print('-- expected ^ | v rendered --')
- print(files['/etc/netplan/50-cloud-init.yaml'])
+ entry = NETWORK_CONFIGS["all"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+ print(entry["expected_netplan"])
+ print("-- expected ^ | v rendered --")
+ print(files["/etc/netplan/50-cloud-init.yaml"])
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def testsimple_render_manual(self):
- entry = NETWORK_CONFIGS['manual']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["manual"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def test_render_output_has_yaml_no_aliases(self):
entry = {
- 'yaml': V1_NAMESERVER_ALIAS,
- 'expected_netplan': NETPLAN_NO_ALIAS,
+ "yaml": V1_NAMESERVER_ALIAS,
+ "expected_netplan": NETPLAN_NO_ALIAS,
}
- network_config = yaml.load(entry['yaml'])
+ network_config = yaml.load(entry["yaml"])
ns = network_state.parse_net_config_data(network_config)
files = self._render_and_read(state=ns)
# check for alias
- content = files['/etc/netplan/50-cloud-init.yaml']
+ content = files["/etc/netplan/50-cloud-init.yaml"]
# test load the yaml to ensure we don't render something not loadable
# this allows single aliases, but not duplicate ones
- parsed = yaml.load(files['/etc/netplan/50-cloud-init.yaml'])
+ parsed = yaml.load(files["/etc/netplan/50-cloud-init.yaml"])
self.assertNotEqual(None, parsed)
# now look for any alias, avoid rendering them entirely
# generate the first anchor string using the template
# as of this writing, looks like "&id001"
- anchor = r'&' + Serializer.ANCHOR_TEMPLATE % 1
+ anchor = r"&" + Serializer.ANCHOR_TEMPLATE % 1
found_alias = re.search(anchor, content, re.MULTILINE)
if found_alias:
msg = "Error at: %s\nContent:\n%s" % (found_alias, content)
- raise ValueError('Found yaml alias in rendered netplan: ' + msg)
+ raise ValueError("Found yaml alias in rendered netplan: " + msg)
- print(entry['expected_netplan'])
- print('-- expected ^ | v rendered --')
- print(files['/etc/netplan/50-cloud-init.yaml'])
+ print(entry["expected_netplan"])
+ print("-- expected ^ | v rendered --")
+ print(files["/etc/netplan/50-cloud-init.yaml"])
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
def test_render_output_supports_both_grat_arp_spelling(self):
entry = {
- 'yaml': NETPLAN_BOND_GRAT_ARP,
- 'expected_netplan': NETPLAN_BOND_GRAT_ARP.replace('gratuitous',
- 'gratuitious'),
+ "yaml": NETPLAN_BOND_GRAT_ARP,
+ "expected_netplan": NETPLAN_BOND_GRAT_ARP.replace(
+ "gratuitous", "gratuitious"
+ ),
}
- network_config = yaml.load(entry['yaml']).get('network')
+ network_config = yaml.load(entry["yaml"]).get("network")
files = self._render_and_read(network_config=network_config)
- print(entry['expected_netplan'])
- print('-- expected ^ | v rendered --')
- print(files['/etc/netplan/50-cloud-init.yaml'])
+ print(entry["expected_netplan"])
+ print("-- expected ^ | v rendered --")
+ print(files["/etc/netplan/50-cloud-init.yaml"])
self.assertEqual(
- entry['expected_netplan'].splitlines(),
- files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+ entry["expected_netplan"].splitlines(),
+ files["/etc/netplan/50-cloud-init.yaml"].splitlines(),
+ )
class TestEniRoundTrip(CiTestCase):
-
- def _render_and_read(self, network_config=None, state=None, eni_path=None,
- netrules_path=None, dir=None):
+ def _render_and_read(
+ self,
+ network_config=None,
+ state=None,
+ eni_path=None,
+ netrules_path=None,
+ dir=None,
+ ):
if dir is None:
dir = self.tmp_dir()
@@ -4685,10 +5627,11 @@ class TestEniRoundTrip(CiTestCase):
raise ValueError("Expected data or state, got neither")
if eni_path is None:
- eni_path = 'etc/network/interfaces'
+ eni_path = "etc/network/interfaces"
renderer = eni.Renderer(
- config={'eni_path': eni_path, 'netrules_path': netrules_path})
+ config={"eni_path": eni_path, "netrules_path": netrules_path}
+ )
renderer.render_network_state(ns, target=dir)
return dir2dict(dir)
@@ -4698,95 +5641,112 @@ class TestEniRoundTrip(CiTestCase):
files = self._render_and_read(network_config=network_config)
self.assertEqual(
RENDERED_ENI.splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_all(self):
- entry = NETWORK_CONFIGS['all']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["all"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_small(self):
- entry = NETWORK_CONFIGS['small']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["small"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_v4_and_v6(self):
- entry = NETWORK_CONFIGS['v4_and_v6']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["v4_and_v6"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_dhcpv6_only(self):
- entry = NETWORK_CONFIGS['dhcpv6_only']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_only"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_v4_and_v6_static(self):
- entry = NETWORK_CONFIGS['v4_and_v6_static']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["v4_and_v6_static"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_dhcpv6_stateless(self):
- entry = NETWORK_CONFIGS['dhcpv6_stateless']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_stateless"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_ipv6_slaac(self):
- entry = NETWORK_CONFIGS['ipv6_slaac']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["ipv6_slaac"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_dhcpv6_stateful(self):
- entry = NETWORK_CONFIGS['dhcpv6_stateless']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["dhcpv6_stateless"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_dhcpv6_accept_ra(self):
- entry = NETWORK_CONFIGS['dhcpv6_accept_ra']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml_v1']))
+ entry = NETWORK_CONFIGS["dhcpv6_accept_ra"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v1"])
+ )
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_dhcpv6_reject_ra(self):
- entry = NETWORK_CONFIGS['dhcpv6_reject_ra']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml_v1']))
+ entry = NETWORK_CONFIGS["dhcpv6_reject_ra"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v1"])
+ )
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_wakeonlan_disabled_config_v2(self):
- entry = NETWORK_CONFIGS['wakeonlan_disabled']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["wakeonlan_disabled"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_wakeonlan_enabled_config_v2(self):
- entry = NETWORK_CONFIGS['wakeonlan_enabled']
- files = self._render_and_read(network_config=yaml.load(
- entry['yaml_v2']))
+ entry = NETWORK_CONFIGS["wakeonlan_enabled"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def testsimple_render_manual(self):
"""Test rendering of 'manual' for 'type' and 'control'.
@@ -4796,165 +5756,471 @@ class TestEniRoundTrip(CiTestCase):
if there were no addresses to configure. Also strange is the fact
that in order to apply that MTU the ifupdown device must be set
to 'auto', or the MTU would not be set."""
- entry = NETWORK_CONFIGS['manual']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["manual"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
def test_routes_rendered(self):
# as reported in bug 1649652
conf = [
- {'name': 'eth0', 'type': 'physical',
- 'subnets': [{
- 'address': '172.23.31.42/26',
- 'dns_nameservers': [], 'gateway': '172.23.31.2',
- 'type': 'static'}]},
- {'type': 'route', 'id': 4,
- 'metric': 0, 'destination': '10.0.0.0/12',
- 'gateway': '172.23.31.1'},
- {'type': 'route', 'id': 5,
- 'metric': 0, 'destination': '192.168.2.0/16',
- 'gateway': '172.23.31.1'},
- {'type': 'route', 'id': 6,
- 'metric': 1, 'destination': '10.0.200.0/16',
- 'gateway': '172.23.31.1'},
+ {
+ "name": "eth0",
+ "type": "physical",
+ "subnets": [
+ {
+ "address": "172.23.31.42/26",
+ "dns_nameservers": [],
+ "gateway": "172.23.31.2",
+ "type": "static",
+ }
+ ],
+ },
+ {
+ "type": "route",
+ "id": 4,
+ "metric": 0,
+ "destination": "10.0.0.0/12",
+ "gateway": "172.23.31.1",
+ },
+ {
+ "type": "route",
+ "id": 5,
+ "metric": 0,
+ "destination": "192.168.2.0/16",
+ "gateway": "172.23.31.1",
+ },
+ {
+ "type": "route",
+ "id": 6,
+ "metric": 1,
+ "destination": "10.0.200.0/16",
+ "gateway": "172.23.31.1",
+ },
+ {
+ "type": "route",
+ "id": 7,
+ "metric": 1,
+ "destination": "10.0.0.100/32",
+ "gateway": "172.23.31.1",
+ },
]
files = self._render_and_read(
- network_config={'config': conf, 'version': 1})
+ network_config={"config": conf, "version": 1}
+ )
expected = [
- 'auto lo',
- 'iface lo inet loopback',
- 'auto eth0',
- 'iface eth0 inet static',
- ' address 172.23.31.42/26',
- ' gateway 172.23.31.2',
- ('post-up route add -net 10.0.0.0/12 gw '
- '172.23.31.1 metric 0 || true'),
- ('pre-down route del -net 10.0.0.0/12 gw '
- '172.23.31.1 metric 0 || true'),
- ('post-up route add -net 192.168.2.0/16 gw '
- '172.23.31.1 metric 0 || true'),
- ('pre-down route del -net 192.168.2.0/16 gw '
- '172.23.31.1 metric 0 || true'),
- ('post-up route add -net 10.0.200.0/16 gw '
- '172.23.31.1 metric 1 || true'),
- ('pre-down route del -net 10.0.200.0/16 gw '
- '172.23.31.1 metric 1 || true'),
+ "auto lo",
+ "iface lo inet loopback",
+ "auto eth0",
+ "iface eth0 inet static",
+ " address 172.23.31.42/26",
+ " gateway 172.23.31.2",
+ "post-up route add -net 10.0.0.0/12 gw "
+ "172.23.31.1 metric 0 || true",
+ "pre-down route del -net 10.0.0.0/12 gw "
+ "172.23.31.1 metric 0 || true",
+ "post-up route add -net 192.168.2.0/16 gw "
+ "172.23.31.1 metric 0 || true",
+ "pre-down route del -net 192.168.2.0/16 gw "
+ "172.23.31.1 metric 0 || true",
+ "post-up route add -net 10.0.200.0/16 gw "
+ "172.23.31.1 metric 1 || true",
+ "pre-down route del -net 10.0.200.0/16 gw "
+ "172.23.31.1 metric 1 || true",
+ "post-up route add -host 10.0.0.100/32 gw "
+ "172.23.31.1 metric 1 || true",
+ "pre-down route del -host 10.0.0.100/32 gw "
+ "172.23.31.1 metric 1 || true",
]
- found = files['/etc/network/interfaces'].splitlines()
+ found = files["/etc/network/interfaces"].splitlines()
- self.assertEqual(
- expected, [line for line in found if line])
+ self.assertEqual(expected, [line for line in found if line])
def test_ipv6_static_routes(self):
# as reported in bug 1818669
conf = [
- {'name': 'eno3', 'type': 'physical',
- 'subnets': [{
- 'address': 'fd00::12/64',
- 'dns_nameservers': ['fd00:2::15'],
- 'gateway': 'fd00::1',
- 'ipv6': True,
- 'type': 'static',
- 'routes': [{'netmask': '32',
- 'network': 'fd00:12::',
- 'gateway': 'fd00::2'},
- {'network': 'fd00:14::',
- 'gateway': 'fd00::3'},
- {'destination': 'fe00:14::/48',
- 'gateway': 'fe00::4',
- 'metric': 500},
- {'gateway': '192.168.23.1',
- 'metric': 999,
- 'netmask': 24,
- 'network': '192.168.23.0'},
- {'destination': '10.23.23.0/24',
- 'gateway': '10.23.23.2',
- 'metric': 300}]}]},
+ {
+ "name": "eno3",
+ "type": "physical",
+ "subnets": [
+ {
+ "address": "fd00::12/64",
+ "dns_nameservers": ["fd00:2::15"],
+ "gateway": "fd00::1",
+ "ipv6": True,
+ "type": "static",
+ "routes": [
+ {
+ "netmask": "32",
+ "network": "fd00:12::",
+ "gateway": "fd00::2",
+ },
+ {"network": "fd00:14::", "gateway": "fd00::3"},
+ {
+ "destination": "fe00:14::/48",
+ "gateway": "fe00::4",
+ "metric": 500,
+ },
+ {
+ "gateway": "192.168.23.1",
+ "metric": 999,
+ "netmask": 24,
+ "network": "192.168.23.0",
+ },
+ {
+ "destination": "10.23.23.0/24",
+ "gateway": "10.23.23.2",
+ "metric": 300,
+ },
+ ],
+ }
+ ],
+ },
]
files = self._render_and_read(
- network_config={'config': conf, 'version': 1})
+ network_config={"config": conf, "version": 1}
+ )
expected = [
- 'auto lo',
- 'iface lo inet loopback',
- 'auto eno3',
- 'iface eno3 inet6 static',
- ' address fd00::12/64',
- ' dns-nameservers fd00:2::15',
- ' gateway fd00::1',
- (' post-up route add -A inet6 fd00:12::/32 gw '
- 'fd00::2 || true'),
- (' pre-down route del -A inet6 fd00:12::/32 gw '
- 'fd00::2 || true'),
- (' post-up route add -A inet6 fd00:14::/64 gw '
- 'fd00::3 || true'),
- (' pre-down route del -A inet6 fd00:14::/64 gw '
- 'fd00::3 || true'),
- (' post-up route add -A inet6 fe00:14::/48 gw '
- 'fe00::4 metric 500 || true'),
- (' pre-down route del -A inet6 fe00:14::/48 gw '
- 'fe00::4 metric 500 || true'),
- (' post-up route add -net 192.168.23.0/24 gw '
- '192.168.23.1 metric 999 || true'),
- (' pre-down route del -net 192.168.23.0/24 gw '
- '192.168.23.1 metric 999 || true'),
- (' post-up route add -net 10.23.23.0/24 gw '
- '10.23.23.2 metric 300 || true'),
- (' pre-down route del -net 10.23.23.0/24 gw '
- '10.23.23.2 metric 300 || true'),
-
+ "auto lo",
+ "iface lo inet loopback",
+ "auto eno3",
+ "iface eno3 inet6 static",
+ " address fd00::12/64",
+ " dns-nameservers fd00:2::15",
+ " gateway fd00::1",
+ " post-up route add -A inet6 fd00:12::/32 gw fd00::2 || true",
+ " pre-down route del -A inet6 fd00:12::/32 gw fd00::2 || true",
+ " post-up route add -A inet6 fd00:14::/64 gw fd00::3 || true",
+ " pre-down route del -A inet6 fd00:14::/64 gw fd00::3 || true",
+ " post-up route add -A inet6 fe00:14::/48 gw "
+ "fe00::4 metric 500 || true",
+ " pre-down route del -A inet6 fe00:14::/48 gw "
+ "fe00::4 metric 500 || true",
+ " post-up route add -net 192.168.23.0/24 gw "
+ "192.168.23.1 metric 999 || true",
+ " pre-down route del -net 192.168.23.0/24 gw "
+ "192.168.23.1 metric 999 || true",
+ " post-up route add -net 10.23.23.0/24 gw "
+ "10.23.23.2 metric 300 || true",
+ " pre-down route del -net 10.23.23.0/24 gw "
+ "10.23.23.2 metric 300 || true",
]
- found = files['/etc/network/interfaces'].splitlines()
+ found = files["/etc/network/interfaces"].splitlines()
- self.assertEqual(
- expected, [line for line in found if line])
+ self.assertEqual(expected, [line for line in found if line])
def testsimple_render_bond(self):
- entry = NETWORK_CONFIGS['bond']
- files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ entry = NETWORK_CONFIGS["bond"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
self.assertEqual(
- entry['expected_eni'].splitlines(),
- files['/etc/network/interfaces'].splitlines())
+ entry["expected_eni"].splitlines(),
+ files["/etc/network/interfaces"].splitlines(),
+ )
-class TestRenderersSelect:
+class TestNetworkdNetRendering(CiTestCase):
+ def create_conf_dict(self, contents):
+ content_dict = {}
+ for line in contents:
+ if line:
+ line = line.strip()
+ if line and re.search(r"^\[(.+)\]$", line):
+ content_dict[line] = []
+ key = line
+ elif line:
+ content_dict[key].append(line)
+
+ return content_dict
+
+ def compare_dicts(self, actual, expected):
+ for k, v in actual.items():
+ self.assertEqual(sorted(expected[k]), sorted(v))
+
+ @mock.patch("cloudinit.net.util.chownbyname", return_value=True)
+ @mock.patch("cloudinit.net.util.get_cmdline", return_value="root=myroot")
+ @mock.patch("cloudinit.net.sys_dev_path")
+ @mock.patch("cloudinit.net.read_sys_net")
+ @mock.patch("cloudinit.net.get_devicelist")
+ def test_networkd_default_generation(
+ self,
+ mock_get_devicelist,
+ mock_read_sys_net,
+ mock_sys_dev_path,
+ m_get_cmdline,
+ m_chown,
+ ):
+ tmp_dir = self.tmp_dir()
+ _setup_test(
+ tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path
+ )
+
+ network_cfg = net.generate_fallback_config()
+ ns = network_state.parse_net_config_data(
+ network_cfg, skip_broken=False
+ )
+
+ render_dir = os.path.join(tmp_dir, "render")
+ os.makedirs(render_dir)
+
+ render_target = "etc/systemd/network/10-cloud-init-eth1000.network"
+ renderer = networkd.Renderer({})
+ renderer.render_network_state(ns, target=render_dir)
+
+ self.assertTrue(
+ os.path.exists(os.path.join(render_dir, render_target))
+ )
+ with open(os.path.join(render_dir, render_target)) as fh:
+ contents = fh.readlines()
+
+ actual = self.create_conf_dict(contents)
+ print(actual)
+
+ expected = textwrap.dedent(
+ """\
+ [Match]
+ Name=eth1000
+ MACAddress=07-1c-c6-75-a4-be
+ [Network]
+ DHCP=ipv4"""
+ ).rstrip(" ")
+
+ expected = self.create_conf_dict(expected.splitlines())
+
+ self.compare_dicts(actual, expected)
+
+
+class TestNetworkdRoundTrip(CiTestCase):
+ def create_conf_dict(self, contents):
+ content_dict = {}
+ for line in contents:
+ if line:
+ line = line.strip()
+ if line and re.search(r"^\[(.+)\]$", line):
+ content_dict[line] = []
+ key = line
+ elif line:
+ content_dict[key].append(line)
+
+ return content_dict
+
+ def compare_dicts(self, actual, expected):
+ for k, v in actual.items():
+ self.assertEqual(sorted(expected[k]), sorted(v))
+
+ def _render_and_read(
+ self, network_config=None, state=None, nwkd_path=None, dir=None
+ ):
+ if dir is None:
+ dir = self.tmp_dir()
+
+ if network_config:
+ ns = network_state.parse_net_config_data(network_config)
+ elif state:
+ ns = state
+ else:
+ raise ValueError("Expected data or state, got neither")
+
+ if not nwkd_path:
+ nwkd_path = "/etc/systemd/network/"
+
+ renderer = networkd.Renderer(config={"network_conf_dir": nwkd_path})
+
+ renderer.render_network_state(ns, target=dir)
+ return dir2dict(dir)
+
+ @mock.patch("cloudinit.net.util.chownbyname", return_value=True)
+ def testsimple_render_small_networkd(self, m_chown):
+ nwk_fn1 = "/etc/systemd/network/10-cloud-init-eth99.network"
+ nwk_fn2 = "/etc/systemd/network/10-cloud-init-eth1.network"
+ entry = NETWORK_CONFIGS["small"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+
+ actual = files[nwk_fn1].splitlines()
+ actual = self.create_conf_dict(actual)
+
+ expected = entry["expected_networkd_eth99"].splitlines()
+ expected = self.create_conf_dict(expected)
+
+ self.compare_dicts(actual, expected)
+
+ actual = files[nwk_fn2].splitlines()
+ actual = self.create_conf_dict(actual)
+
+ expected = entry["expected_networkd_eth1"].splitlines()
+ expected = self.create_conf_dict(expected)
+
+ self.compare_dicts(actual, expected)
+
+ @mock.patch("cloudinit.net.util.chownbyname", return_value=True)
+ def testsimple_render_v4_and_v6(self, m_chown):
+ nwk_fn = "/etc/systemd/network/10-cloud-init-iface0.network"
+ entry = NETWORK_CONFIGS["v4_and_v6"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+
+ actual = files[nwk_fn].splitlines()
+ actual = self.create_conf_dict(actual)
+
+ expected = entry["expected_networkd"].splitlines()
+ expected = self.create_conf_dict(expected)
+
+ self.compare_dicts(actual, expected)
+
+ @mock.patch("cloudinit.net.util.chownbyname", return_value=True)
+ def testsimple_render_v4_and_v6_static(self, m_chown):
+ nwk_fn = "/etc/systemd/network/10-cloud-init-iface0.network"
+ entry = NETWORK_CONFIGS["v4_and_v6_static"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+
+ actual = files[nwk_fn].splitlines()
+ actual = self.create_conf_dict(actual)
+
+ expected = entry["expected_networkd"].splitlines()
+ expected = self.create_conf_dict(expected)
+
+ self.compare_dicts(actual, expected)
+
+ @mock.patch("cloudinit.net.util.chownbyname", return_value=True)
+ def testsimple_render_dhcpv6_only(self, m_chown):
+ nwk_fn = "/etc/systemd/network/10-cloud-init-iface0.network"
+ entry = NETWORK_CONFIGS["dhcpv6_only"]
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+
+ actual = files[nwk_fn].splitlines()
+ actual = self.create_conf_dict(actual)
+
+ expected = entry["expected_networkd"].splitlines()
+ expected = self.create_conf_dict(expected)
+
+ self.compare_dicts(actual, expected)
+
+ @mock.patch("cloudinit.net.util.chownbyname", return_value=True)
+ def test_dhcpv6_accept_ra_config_v1(self, m_chown):
+ nwk_fn = "/etc/systemd/network/10-cloud-init-iface0.network"
+ entry = NETWORK_CONFIGS["dhcpv6_accept_ra"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v1"])
+ )
+
+ actual = files[nwk_fn].splitlines()
+ actual = self.create_conf_dict(actual)
+ expected = entry["expected_networkd"].splitlines()
+ expected = self.create_conf_dict(expected)
+
+ self.compare_dicts(actual, expected)
+
+ @mock.patch("cloudinit.net.util.chownbyname", return_value=True)
+ def test_dhcpv6_accept_ra_config_v2(self, m_chown):
+ nwk_fn = "/etc/systemd/network/10-cloud-init-iface0.network"
+ entry = NETWORK_CONFIGS["dhcpv6_accept_ra"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
+
+ actual = files[nwk_fn].splitlines()
+ actual = self.create_conf_dict(actual)
+
+ expected = entry["expected_networkd"].splitlines()
+ expected = self.create_conf_dict(expected)
+
+ self.compare_dicts(actual, expected)
+
+ @mock.patch("cloudinit.net.util.chownbyname", return_value=True)
+ def test_dhcpv6_reject_ra_config_v1(self, m_chown):
+ nwk_fn = "/etc/systemd/network/10-cloud-init-iface0.network"
+ entry = NETWORK_CONFIGS["dhcpv6_reject_ra"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v1"])
+ )
+
+ actual = files[nwk_fn].splitlines()
+ actual = self.create_conf_dict(actual)
+
+ expected = entry["expected_networkd"].splitlines()
+ expected = self.create_conf_dict(expected)
+
+ self.compare_dicts(actual, expected)
+
+ @mock.patch("cloudinit.net.util.chownbyname", return_value=True)
+ def test_dhcpv6_reject_ra_config_v2(self, m_chown):
+ nwk_fn = "/etc/systemd/network/10-cloud-init-iface0.network"
+ entry = NETWORK_CONFIGS["dhcpv6_reject_ra"]
+ files = self._render_and_read(
+ network_config=yaml.load(entry["yaml_v2"])
+ )
+
+ actual = files[nwk_fn].splitlines()
+ actual = self.create_conf_dict(actual)
+
+ expected = entry["expected_networkd"].splitlines()
+ expected = self.create_conf_dict(expected)
+
+ self.compare_dicts(actual, expected)
+
+
+class TestRenderersSelect:
@pytest.mark.parametrize(
- 'renderer_selected,netplan,eni,nm,scfg,sys', (
+ "renderer_selected,netplan,eni,nm,scfg,sys,networkd",
+ (
# -netplan -ifupdown -nm -scfg -sys raises error
- (net.RendererNotFoundError, False, False, False, False, False),
+ (
+ net.RendererNotFoundError,
+ False,
+ False,
+ False,
+ False,
+ False,
+ False,
+ ),
# -netplan +ifupdown -nm -scfg -sys selects eni
- ('eni', False, True, False, False, False),
+ ("eni", False, True, False, False, False, False),
# +netplan +ifupdown -nm -scfg -sys selects eni
- ('eni', True, True, False, False, False),
+ ("eni", True, True, False, False, False, False),
# +netplan -ifupdown -nm -scfg -sys selects netplan
- ('netplan', True, False, False, False, False),
+ ("netplan", True, False, False, False, False, False),
# Ubuntu with Network-Manager installed
# +netplan -ifupdown +nm -scfg -sys selects netplan
- ('netplan', True, False, True, False, False),
+ ("netplan", True, False, True, False, False, False),
# Centos/OpenSuse with Network-Manager installed selects sysconfig
# -netplan -ifupdown +nm -scfg +sys selects netplan
- ('sysconfig', False, False, True, False, True),
+ ("sysconfig", False, False, True, False, True, False),
+ # -netplan -ifupdown -nm -scfg -sys +networkd selects networkd
+ ("networkd", False, False, False, False, False, True),
),
)
+ @mock.patch("cloudinit.net.renderers.networkd.available")
@mock.patch("cloudinit.net.renderers.netplan.available")
@mock.patch("cloudinit.net.renderers.sysconfig.available")
@mock.patch("cloudinit.net.renderers.sysconfig.available_sysconfig")
@mock.patch("cloudinit.net.renderers.sysconfig.available_nm")
@mock.patch("cloudinit.net.renderers.eni.available")
def test_valid_renderer_from_defaults_depending_on_availability(
- self, m_eni_avail, m_nm_avail, m_scfg_avail, m_sys_avail,
- m_netplan_avail, renderer_selected, netplan, eni, nm, scfg, sys
+ self,
+ m_eni_avail,
+ m_nm_avail,
+ m_scfg_avail,
+ m_sys_avail,
+ m_netplan_avail,
+ m_networkd_avail,
+ renderer_selected,
+ netplan,
+ eni,
+ nm,
+ scfg,
+ sys,
+ networkd,
):
"""Assert proper renderer per DEFAULT_PRIORITY given availability."""
- m_eni_avail.return_value = eni # ifupdown pkg presence
- m_nm_avail.return_value = nm # network-manager presence
- m_scfg_avail.return_value = scfg # sysconfig presence
- m_sys_avail.return_value = sys # sysconfig/ifup/down presence
+ m_eni_avail.return_value = eni # ifupdown pkg presence
+ m_nm_avail.return_value = nm # network-manager presence
+ m_scfg_avail.return_value = scfg # sysconfig presence
+ m_sys_avail.return_value = sys # sysconfig/ifup/down presence
m_netplan_avail.return_value = netplan # netplan presence
+ m_networkd_avail.return_value = networkd # networkd presence
if isinstance(renderer_selected, str):
(renderer_name, _rnd_class) = renderers.select(
priority=renderers.DEFAULT_PRIORITY
@@ -4971,14 +6237,14 @@ class TestNetRenderers(CiTestCase):
def test_eni_and_sysconfig_available(self, m_eni_avail, m_sysc_avail):
m_eni_avail.return_value = True
m_sysc_avail.return_value = True
- found = renderers.search(priority=['sysconfig', 'eni'], first=False)
+ found = renderers.search(priority=["sysconfig", "eni"], first=False)
names = [f[0] for f in found]
- self.assertEqual(['sysconfig', 'eni'], names)
+ self.assertEqual(["sysconfig", "eni"], names)
@mock.patch("cloudinit.net.renderers.eni.available")
def test_search_returns_empty_on_none(self, m_eni_avail):
m_eni_avail.return_value = False
- found = renderers.search(priority=['eni'], first=False)
+ found = renderers.search(priority=["eni"], first=False)
self.assertEqual([], found)
@mock.patch("cloudinit.net.renderers.sysconfig.available")
@@ -4987,16 +6253,16 @@ class TestNetRenderers(CiTestCase):
# available should only be called until one is found.
m_eni_avail.return_value = True
m_sysc_avail.side_effect = Exception("Should not call me")
- found = renderers.search(priority=['eni', 'sysconfig'], first=True)
- self.assertEqual(['eni'], [found[0]])
+ found = renderers.search(priority=["eni", "sysconfig"], first=True)[0]
+ self.assertEqual(["eni"], [found[0]])
@mock.patch("cloudinit.net.renderers.sysconfig.available")
@mock.patch("cloudinit.net.renderers.eni.available")
def test_select_positive(self, m_eni_avail, m_sysc_avail):
m_eni_avail.return_value = True
m_sysc_avail.return_value = False
- found = renderers.select(priority=['sysconfig', 'eni'])
- self.assertEqual('eni', found[0])
+ found = renderers.select(priority=["sysconfig", "eni"])
+ self.assertEqual("eni", found[0])
@mock.patch("cloudinit.net.renderers.sysconfig.available")
@mock.patch("cloudinit.net.renderers.eni.available")
@@ -5005,89 +6271,120 @@ class TestNetRenderers(CiTestCase):
m_eni_avail.return_value = False
m_sysc_avail.return_value = False
- self.assertRaises(net.RendererNotFoundError, renderers.select,
- priority=['sysconfig', 'eni'])
+ self.assertRaises(
+ net.RendererNotFoundError,
+ renderers.select,
+ priority=["sysconfig", "eni"],
+ )
@mock.patch("cloudinit.net.sysconfig.available_sysconfig")
- @mock.patch("cloudinit.util.get_linux_distro")
- def test_sysconfig_available_uses_variant_mapping(self, m_distro, m_avail):
+ @mock.patch("cloudinit.util.system_info")
+ def test_sysconfig_available_uses_variant_mapping(self, m_info, m_avail):
m_avail.return_value = True
- distro_values = [
- ('opensuse', '', ''),
- ('opensuse-leap', '', ''),
- ('opensuse-tumbleweed', '', ''),
- ('sles', '', ''),
- ('centos', '', ''),
- ('fedora', '', ''),
- ('redhat', '', ''),
+ variants = [
+ "suse",
+ "centos",
+ "eurolinux",
+ "fedora",
+ "rhel",
]
- for (distro_name, distro_version, flavor) in distro_values:
- m_distro.return_value = (distro_name, distro_version, flavor)
+ for distro_name in variants:
+ m_info.return_value = {"variant": distro_name}
if hasattr(util.system_info, "cache_clear"):
util.system_info.cache_clear()
result = sysconfig.available()
self.assertTrue(result)
+ @mock.patch("cloudinit.net.renderers.networkd.available")
+ def test_networkd_available(self, m_nwkd_avail):
+ m_nwkd_avail.return_value = True
+ found = renderers.search(priority=["networkd"], first=False)
+ self.assertEqual("networkd", found[0][0])
+
+@mock.patch(
+ "cloudinit.net.is_openvswitch_internal_interface",
+ mock.Mock(return_value=False),
+)
class TestGetInterfaces(CiTestCase):
- _data = {'bonds': ['bond1'],
- 'bridges': ['bridge1'],
- 'vlans': ['bond1.101'],
- 'own_macs': ['enp0s1', 'enp0s2', 'bridge1-nic', 'bridge1',
- 'bond1.101', 'lo', 'eth1'],
- 'macs': {'enp0s1': 'aa:aa:aa:aa:aa:01',
- 'enp0s2': 'aa:aa:aa:aa:aa:02',
- 'bond1': 'aa:aa:aa:aa:aa:01',
- 'bond1.101': 'aa:aa:aa:aa:aa:01',
- 'bridge1': 'aa:aa:aa:aa:aa:03',
- 'bridge1-nic': 'aa:aa:aa:aa:aa:03',
- 'lo': '00:00:00:00:00:00',
- 'greptap0': '00:00:00:00:00:00',
- 'eth1': 'aa:aa:aa:aa:aa:01',
- 'tun0': None},
- 'drivers': {'enp0s1': 'virtio_net',
- 'enp0s2': 'e1000',
- 'bond1': None,
- 'bond1.101': None,
- 'bridge1': None,
- 'bridge1-nic': None,
- 'lo': None,
- 'greptap0': None,
- 'eth1': 'mlx4_core',
- 'tun0': None}}
+ _data = {
+ "bonds": ["bond1"],
+ "bridges": ["bridge1"],
+ "vlans": ["bond1.101"],
+ "own_macs": [
+ "enp0s1",
+ "enp0s2",
+ "bridge1-nic",
+ "bridge1",
+ "bond1.101",
+ "lo",
+ "eth1",
+ ],
+ "macs": {
+ "enp0s1": "aa:aa:aa:aa:aa:01",
+ "enp0s2": "aa:aa:aa:aa:aa:02",
+ "bond1": "aa:aa:aa:aa:aa:01",
+ "bond1.101": "aa:aa:aa:aa:aa:01",
+ "bridge1": "aa:aa:aa:aa:aa:03",
+ "bridge1-nic": "aa:aa:aa:aa:aa:03",
+ "lo": "00:00:00:00:00:00",
+ "greptap0": "00:00:00:00:00:00",
+ "eth1": "aa:aa:aa:aa:aa:01",
+ "tun0": None,
+ },
+ "drivers": {
+ "enp0s1": "virtio_net",
+ "enp0s2": "e1000",
+ "bond1": None,
+ "bond1.101": None,
+ "bridge1": None,
+ "bridge1-nic": None,
+ "lo": None,
+ "greptap0": None,
+ "eth1": "mlx4_core",
+ "tun0": None,
+ },
+ }
data = {}
def _se_get_devicelist(self):
- return list(self.data['devices'])
+ return list(self.data["devices"])
def _se_device_driver(self, name):
- return self.data['drivers'][name]
+ return self.data["drivers"][name]
def _se_device_devid(self, name):
- return '0x%s' % sorted(list(self.data['drivers'].keys())).index(name)
+ return "0x%s" % sorted(list(self.data["drivers"].keys())).index(name)
def _se_get_interface_mac(self, name):
- return self.data['macs'][name]
+ return self.data["macs"][name]
def _se_is_bridge(self, name):
- return name in self.data['bridges']
+ return name in self.data["bridges"]
def _se_is_vlan(self, name):
- return name in self.data['vlans']
+ return name in self.data["vlans"]
def _se_interface_has_own_mac(self, name):
- return name in self.data['own_macs']
+ return name in self.data["own_macs"]
def _mock_setup(self):
self.data = copy.deepcopy(self._data)
- self.data['devices'] = set(list(self.data['macs'].keys()))
- mocks = ('get_devicelist', 'get_interface_mac', 'is_bridge',
- 'interface_has_own_mac', 'is_vlan', 'device_driver',
- 'device_devid')
+ self.data["devices"] = set(list(self.data["macs"].keys()))
+ mocks = (
+ "get_devicelist",
+ "get_interface_mac",
+ "is_bridge",
+ "interface_has_own_mac",
+ "is_vlan",
+ "device_driver",
+ "device_devid",
+ )
self.mocks = {}
for n in mocks:
- m = mock.patch('cloudinit.net.' + n,
- side_effect=getattr(self, '_se_' + n))
+ m = mock.patch(
+ "cloudinit.net." + n, side_effect=getattr(self, "_se_" + n)
+ )
self.addCleanup(m.stop)
self.mocks[n] = m.start()
@@ -5095,30 +6392,31 @@ class TestGetInterfaces(CiTestCase):
self._mock_setup()
ret = net.get_interfaces()
- self.assertIn('enp0s1', self._se_get_devicelist())
- self.assertIn('eth1', self._se_get_devicelist())
- found = [ent for ent in ret if 'aa:aa:aa:aa:aa:01' in ent]
+ self.assertIn("enp0s1", self._se_get_devicelist())
+ self.assertIn("eth1", self._se_get_devicelist())
+ found = [ent for ent in ret if "aa:aa:aa:aa:aa:01" in ent]
self.assertEqual(len(found), 2)
def test_gi_excludes_any_without_mac_address(self):
self._mock_setup()
ret = net.get_interfaces()
- self.assertIn('tun0', self._se_get_devicelist())
- found = [ent for ent in ret if 'tun0' in ent]
+ self.assertIn("tun0", self._se_get_devicelist())
+ found = [ent for ent in ret if "tun0" in ent]
self.assertEqual(len(found), 0)
def test_gi_excludes_stolen_macs(self):
self._mock_setup()
ret = net.get_interfaces()
- self.mocks['interface_has_own_mac'].assert_has_calls(
- [mock.call('enp0s1'), mock.call('bond1')], any_order=True)
+ self.mocks["interface_has_own_mac"].assert_has_calls(
+ [mock.call("enp0s1"), mock.call("bond1")], any_order=True
+ )
expected = [
- ('enp0s2', 'aa:aa:aa:aa:aa:02', 'e1000', '0x5'),
- ('enp0s1', 'aa:aa:aa:aa:aa:01', 'virtio_net', '0x4'),
- ('eth1', 'aa:aa:aa:aa:aa:01', 'mlx4_core', '0x6'),
- ('lo', '00:00:00:00:00:00', None, '0x8'),
- ('bridge1-nic', 'aa:aa:aa:aa:aa:03', None, '0x3'),
+ ("enp0s2", "aa:aa:aa:aa:aa:02", "e1000", "0x5"),
+ ("enp0s1", "aa:aa:aa:aa:aa:01", "virtio_net", "0x4"),
+ ("eth1", "aa:aa:aa:aa:aa:01", "mlx4_core", "0x6"),
+ ("lo", "00:00:00:00:00:00", None, "0x8"),
+ ("bridge1-nic", "aa:aa:aa:aa:aa:03", None, "0x3"),
]
self.assertEqual(sorted(expected), sorted(ret))
@@ -5127,24 +6425,29 @@ class TestGetInterfaces(CiTestCase):
# add a device 'b1', make all return they have their "own mac",
# set everything other than 'b1' to be a bridge.
# then expect b1 is the only thing left.
- self.data['macs']['b1'] = 'aa:aa:aa:aa:aa:b1'
- self.data['drivers']['b1'] = None
- self.data['devices'].add('b1')
- self.data['bonds'] = []
- self.data['own_macs'] = self.data['devices']
- self.data['bridges'] = [f for f in self.data['devices'] if f != "b1"]
+ self.data["macs"]["b1"] = "aa:aa:aa:aa:aa:b1"
+ self.data["drivers"]["b1"] = None
+ self.data["devices"].add("b1")
+ self.data["bonds"] = []
+ self.data["own_macs"] = self.data["devices"]
+ self.data["bridges"] = [f for f in self.data["devices"] if f != "b1"]
ret = net.get_interfaces()
- self.assertEqual([('b1', 'aa:aa:aa:aa:aa:b1', None, '0x0')], ret)
- self.mocks['is_bridge'].assert_has_calls(
- [mock.call('bridge1'), mock.call('enp0s1'), mock.call('bond1'),
- mock.call('b1')],
- any_order=True)
+ self.assertEqual([("b1", "aa:aa:aa:aa:aa:b1", None, "0x0")], ret)
+ self.mocks["is_bridge"].assert_has_calls(
+ [
+ mock.call("bridge1"),
+ mock.call("enp0s1"),
+ mock.call("bond1"),
+ mock.call("b1"),
+ ],
+ any_order=True,
+ )
class TestInterfaceHasOwnMac(CiTestCase):
"""Test interface_has_own_mac. This is admittedly a bit whitebox."""
- @mock.patch('cloudinit.net.read_sys_net_int', return_value=None)
+ @mock.patch("cloudinit.net.read_sys_net_int", return_value=None)
def test_non_strict_with_no_addr_assign_type(self, m_read_sys_net_int):
"""If nic does not have addr_assign_type, it is not "stolen".
@@ -5161,229 +6464,301 @@ class TestInterfaceHasOwnMac(CiTestCase):
"""
self.assertTrue(interface_has_own_mac("eth0"))
- @mock.patch('cloudinit.net.read_sys_net_int', return_value=None)
+ @mock.patch("cloudinit.net.read_sys_net_int", return_value=None)
def test_strict_with_no_addr_assign_type_raises(self, m_read_sys_net_int):
with self.assertRaises(ValueError):
interface_has_own_mac("eth0", True)
- @mock.patch('cloudinit.net.read_sys_net_int')
+ @mock.patch("cloudinit.net.read_sys_net_int")
def test_expected_values(self, m_read_sys_net_int):
msg = "address_assign_type=%d said to not have own mac"
for address_assign_type in (0, 1, 3):
m_read_sys_net_int.return_value = address_assign_type
self.assertTrue(
- interface_has_own_mac("eth0", msg % address_assign_type))
+ interface_has_own_mac("eth0", msg % address_assign_type)
+ )
m_read_sys_net_int.return_value = 2
self.assertFalse(interface_has_own_mac("eth0"))
+@mock.patch(
+ "cloudinit.net.is_openvswitch_internal_interface",
+ mock.Mock(return_value=False),
+)
class TestGetInterfacesByMac(CiTestCase):
- _data = {'bonds': ['bond1'],
- 'bridges': ['bridge1'],
- 'vlans': ['bond1.101'],
- 'own_macs': ['enp0s1', 'enp0s2', 'bridge1-nic', 'bridge1',
- 'bond1.101', 'lo'],
- 'macs': {'enp0s1': 'aa:aa:aa:aa:aa:01',
- 'enp0s2': 'aa:aa:aa:aa:aa:02',
- 'bond1': 'aa:aa:aa:aa:aa:01',
- 'bond1.101': 'aa:aa:aa:aa:aa:01',
- 'bridge1': 'aa:aa:aa:aa:aa:03',
- 'bridge1-nic': 'aa:aa:aa:aa:aa:03',
- 'lo': '00:00:00:00:00:00',
- 'greptap0': '00:00:00:00:00:00',
- 'tun0': None}}
+ _data = {
+ "bonds": ["bond1"],
+ "bridges": ["bridge1"],
+ "vlans": ["bond1.101"],
+ "own_macs": [
+ "enp0s1",
+ "enp0s2",
+ "bridge1-nic",
+ "bridge1",
+ "bond1.101",
+ "lo",
+ ],
+ "macs": {
+ "enp0s1": "aa:aa:aa:aa:aa:01",
+ "enp0s2": "aa:aa:aa:aa:aa:02",
+ "bond1": "aa:aa:aa:aa:aa:01",
+ "bond1.101": "aa:aa:aa:aa:aa:01",
+ "bridge1": "aa:aa:aa:aa:aa:03",
+ "bridge1-nic": "aa:aa:aa:aa:aa:03",
+ "lo": "00:00:00:00:00:00",
+ "greptap0": "00:00:00:00:00:00",
+ "tun0": None,
+ },
+ }
data = {}
def _se_get_devicelist(self):
- return list(self.data['devices'])
+ return list(self.data["devices"])
def _se_get_interface_mac(self, name):
- return self.data['macs'][name]
+ return self.data["macs"][name]
def _se_is_bridge(self, name):
- return name in self.data['bridges']
+ return name in self.data["bridges"]
def _se_is_vlan(self, name):
- return name in self.data['vlans']
+ return name in self.data["vlans"]
def _se_interface_has_own_mac(self, name):
- return name in self.data['own_macs']
+ return name in self.data["own_macs"]
def _se_get_ib_interface_hwaddr(self, name, ethernet_format):
- ib_hwaddr = self.data.get('ib_hwaddr', {})
+ ib_hwaddr = self.data.get("ib_hwaddr", {})
return ib_hwaddr.get(name, {}).get(ethernet_format)
def _mock_setup(self):
self.data = copy.deepcopy(self._data)
- self.data['devices'] = set(list(self.data['macs'].keys()))
- mocks = ('get_devicelist', 'get_interface_mac', 'is_bridge',
- 'interface_has_own_mac', 'is_vlan', 'get_ib_interface_hwaddr')
+ self.data["devices"] = set(list(self.data["macs"].keys()))
+ mocks = (
+ "get_devicelist",
+ "get_interface_mac",
+ "is_bridge",
+ "interface_has_own_mac",
+ "is_vlan",
+ "get_ib_interface_hwaddr",
+ )
self.mocks = {}
for n in mocks:
- m = mock.patch('cloudinit.net.' + n,
- side_effect=getattr(self, '_se_' + n))
+ m = mock.patch(
+ "cloudinit.net." + n, side_effect=getattr(self, "_se_" + n)
+ )
self.addCleanup(m.stop)
self.mocks[n] = m.start()
def test_raise_exception_on_duplicate_macs(self):
self._mock_setup()
- self.data['macs']['bridge1-nic'] = self.data['macs']['enp0s1']
+ self.data["macs"]["bridge1-nic"] = self.data["macs"]["enp0s1"]
self.assertRaises(RuntimeError, net.get_interfaces_by_mac)
def test_excludes_any_without_mac_address(self):
self._mock_setup()
ret = net.get_interfaces_by_mac()
- self.assertIn('tun0', self._se_get_devicelist())
- self.assertNotIn('tun0', ret.values())
+ self.assertIn("tun0", self._se_get_devicelist())
+ self.assertNotIn("tun0", ret.values())
def test_excludes_stolen_macs(self):
self._mock_setup()
ret = net.get_interfaces_by_mac()
- self.mocks['interface_has_own_mac'].assert_has_calls(
- [mock.call('enp0s1'), mock.call('bond1')], any_order=True)
+ self.mocks["interface_has_own_mac"].assert_has_calls(
+ [mock.call("enp0s1"), mock.call("bond1")], any_order=True
+ )
self.assertEqual(
- {'aa:aa:aa:aa:aa:01': 'enp0s1', 'aa:aa:aa:aa:aa:02': 'enp0s2',
- 'aa:aa:aa:aa:aa:03': 'bridge1-nic', '00:00:00:00:00:00': 'lo'},
- ret)
+ {
+ "aa:aa:aa:aa:aa:01": "enp0s1",
+ "aa:aa:aa:aa:aa:02": "enp0s2",
+ "aa:aa:aa:aa:aa:03": "bridge1-nic",
+ "00:00:00:00:00:00": "lo",
+ },
+ ret,
+ )
def test_excludes_bridges(self):
self._mock_setup()
# add a device 'b1', make all return they have their "own mac",
# set everything other than 'b1' to be a bridge.
# then expect b1 is the only thing left.
- self.data['macs']['b1'] = 'aa:aa:aa:aa:aa:b1'
- self.data['devices'].add('b1')
- self.data['bonds'] = []
- self.data['own_macs'] = self.data['devices']
- self.data['bridges'] = [f for f in self.data['devices'] if f != "b1"]
+ self.data["macs"]["b1"] = "aa:aa:aa:aa:aa:b1"
+ self.data["devices"].add("b1")
+ self.data["bonds"] = []
+ self.data["own_macs"] = self.data["devices"]
+ self.data["bridges"] = [f for f in self.data["devices"] if f != "b1"]
ret = net.get_interfaces_by_mac()
- self.assertEqual({'aa:aa:aa:aa:aa:b1': 'b1'}, ret)
- self.mocks['is_bridge'].assert_has_calls(
- [mock.call('bridge1'), mock.call('enp0s1'), mock.call('bond1'),
- mock.call('b1')],
- any_order=True)
+ self.assertEqual({"aa:aa:aa:aa:aa:b1": "b1"}, ret)
+ self.mocks["is_bridge"].assert_has_calls(
+ [
+ mock.call("bridge1"),
+ mock.call("enp0s1"),
+ mock.call("bond1"),
+ mock.call("b1"),
+ ],
+ any_order=True,
+ )
def test_excludes_vlans(self):
self._mock_setup()
# add a device 'b1', make all return they have their "own mac",
# set everything other than 'b1' to be a vlan.
# then expect b1 is the only thing left.
- self.data['macs']['b1'] = 'aa:aa:aa:aa:aa:b1'
- self.data['devices'].add('b1')
- self.data['bonds'] = []
- self.data['bridges'] = []
- self.data['own_macs'] = self.data['devices']
- self.data['vlans'] = [f for f in self.data['devices'] if f != "b1"]
+ self.data["macs"]["b1"] = "aa:aa:aa:aa:aa:b1"
+ self.data["devices"].add("b1")
+ self.data["bonds"] = []
+ self.data["bridges"] = []
+ self.data["own_macs"] = self.data["devices"]
+ self.data["vlans"] = [f for f in self.data["devices"] if f != "b1"]
ret = net.get_interfaces_by_mac()
- self.assertEqual({'aa:aa:aa:aa:aa:b1': 'b1'}, ret)
- self.mocks['is_vlan'].assert_has_calls(
- [mock.call('bridge1'), mock.call('enp0s1'), mock.call('bond1'),
- mock.call('b1')],
- any_order=True)
+ self.assertEqual({"aa:aa:aa:aa:aa:b1": "b1"}, ret)
+ self.mocks["is_vlan"].assert_has_calls(
+ [
+ mock.call("bridge1"),
+ mock.call("enp0s1"),
+ mock.call("bond1"),
+ mock.call("b1"),
+ ],
+ any_order=True,
+ )
def test_duplicates_of_empty_mac_are_ok(self):
"""Duplicate macs of 00:00:00:00:00:00 should be skipped."""
self._mock_setup()
empty_mac = "00:00:00:00:00:00"
- addnics = ('greptap1', 'lo', 'greptap2')
- self.data['macs'].update(dict((k, empty_mac) for k in addnics))
- self.data['devices'].update(set(addnics))
- self.data['own_macs'].extend(list(addnics))
+ addnics = ("greptap1", "lo", "greptap2")
+ self.data["macs"].update(dict((k, empty_mac) for k in addnics))
+ self.data["devices"].update(set(addnics))
+ self.data["own_macs"].extend(list(addnics))
ret = net.get_interfaces_by_mac()
- self.assertEqual('lo', ret[empty_mac])
+ self.assertEqual("lo", ret[empty_mac])
def test_skip_all_zeros(self):
"""Any mac of 00:... should be skipped."""
self._mock_setup()
emac1, emac2, emac4, emac6 = (
- '00', '00:00', '00:00:00:00', '00:00:00:00:00:00')
- addnics = {'empty1': emac1, 'emac2a': emac2, 'emac2b': emac2,
- 'emac4': emac4, 'emac6': emac6}
- self.data['macs'].update(addnics)
- self.data['devices'].update(set(addnics))
- self.data['own_macs'].extend(addnics.keys())
+ "00",
+ "00:00",
+ "00:00:00:00",
+ "00:00:00:00:00:00",
+ )
+ addnics = {
+ "empty1": emac1,
+ "emac2a": emac2,
+ "emac2b": emac2,
+ "emac4": emac4,
+ "emac6": emac6,
+ }
+ self.data["macs"].update(addnics)
+ self.data["devices"].update(set(addnics))
+ self.data["own_macs"].extend(addnics.keys())
ret = net.get_interfaces_by_mac()
- self.assertEqual('lo', ret['00:00:00:00:00:00'])
+ self.assertEqual("lo", ret["00:00:00:00:00:00"])
def test_ib(self):
- ib_addr = '80:00:00:28:fe:80:00:00:00:00:00:00:00:11:22:03:00:33:44:56'
- ib_addr_eth_format = '00:11:22:33:44:56'
+ ib_addr = "80:00:00:28:fe:80:00:00:00:00:00:00:00:11:22:03:00:33:44:56"
+ ib_addr_eth_format = "00:11:22:33:44:56"
self._mock_setup()
- self.data['devices'] = ['enp0s1', 'ib0']
- self.data['own_macs'].append('ib0')
- self.data['macs']['ib0'] = ib_addr
- self.data['ib_hwaddr'] = {'ib0': {True: ib_addr_eth_format,
- False: ib_addr}}
+ self.data["devices"] = ["enp0s1", "ib0"]
+ self.data["own_macs"].append("ib0")
+ self.data["macs"]["ib0"] = ib_addr
+ self.data["ib_hwaddr"] = {
+ "ib0": {True: ib_addr_eth_format, False: ib_addr}
+ }
result = net.get_interfaces_by_mac()
- expected = {'aa:aa:aa:aa:aa:01': 'enp0s1',
- ib_addr_eth_format: 'ib0', ib_addr: 'ib0'}
+ expected = {
+ "aa:aa:aa:aa:aa:01": "enp0s1",
+ ib_addr_eth_format: "ib0",
+ ib_addr: "ib0",
+ }
self.assertEqual(expected, result)
class TestInterfacesSorting(CiTestCase):
-
def test_natural_order(self):
- data = ['ens5', 'ens6', 'ens3', 'ens20', 'ens13', 'ens2']
+ data = ["ens5", "ens6", "ens3", "ens20", "ens13", "ens2"]
self.assertEqual(
sorted(data, key=natural_sort_key),
- ['ens2', 'ens3', 'ens5', 'ens6', 'ens13', 'ens20'])
- data2 = ['enp2s0', 'enp2s3', 'enp0s3', 'enp0s13', 'enp0s8', 'enp1s2']
+ ["ens2", "ens3", "ens5", "ens6", "ens13", "ens20"],
+ )
+ data2 = ["enp2s0", "enp2s3", "enp0s3", "enp0s13", "enp0s8", "enp1s2"]
self.assertEqual(
sorted(data2, key=natural_sort_key),
- ['enp0s3', 'enp0s8', 'enp0s13', 'enp1s2', 'enp2s0', 'enp2s3'])
+ ["enp0s3", "enp0s8", "enp0s13", "enp1s2", "enp2s0", "enp2s3"],
+ )
+@mock.patch(
+ "cloudinit.net.is_openvswitch_internal_interface",
+ mock.Mock(return_value=False),
+)
class TestGetIBHwaddrsByInterface(CiTestCase):
- _ib_addr = '80:00:00:28:fe:80:00:00:00:00:00:00:00:11:22:03:00:33:44:56'
- _ib_addr_eth_format = '00:11:22:33:44:56'
- _data = {'devices': ['enp0s1', 'enp0s2', 'bond1', 'bridge1',
- 'bridge1-nic', 'tun0', 'ib0'],
- 'bonds': ['bond1'],
- 'bridges': ['bridge1'],
- 'own_macs': ['enp0s1', 'enp0s2', 'bridge1-nic', 'bridge1', 'ib0'],
- 'macs': {'enp0s1': 'aa:aa:aa:aa:aa:01',
- 'enp0s2': 'aa:aa:aa:aa:aa:02',
- 'bond1': 'aa:aa:aa:aa:aa:01',
- 'bridge1': 'aa:aa:aa:aa:aa:03',
- 'bridge1-nic': 'aa:aa:aa:aa:aa:03',
- 'tun0': None,
- 'ib0': _ib_addr},
- 'ib_hwaddr': {'ib0': {True: _ib_addr_eth_format,
- False: _ib_addr}}}
+ _ib_addr = "80:00:00:28:fe:80:00:00:00:00:00:00:00:11:22:03:00:33:44:56"
+ _ib_addr_eth_format = "00:11:22:33:44:56"
+ _data = {
+ "devices": [
+ "enp0s1",
+ "enp0s2",
+ "bond1",
+ "bridge1",
+ "bridge1-nic",
+ "tun0",
+ "ib0",
+ ],
+ "bonds": ["bond1"],
+ "bridges": ["bridge1"],
+ "own_macs": ["enp0s1", "enp0s2", "bridge1-nic", "bridge1", "ib0"],
+ "macs": {
+ "enp0s1": "aa:aa:aa:aa:aa:01",
+ "enp0s2": "aa:aa:aa:aa:aa:02",
+ "bond1": "aa:aa:aa:aa:aa:01",
+ "bridge1": "aa:aa:aa:aa:aa:03",
+ "bridge1-nic": "aa:aa:aa:aa:aa:03",
+ "tun0": None,
+ "ib0": _ib_addr,
+ },
+ "ib_hwaddr": {"ib0": {True: _ib_addr_eth_format, False: _ib_addr}},
+ }
data = {}
def _mock_setup(self):
self.data = copy.deepcopy(self._data)
- mocks = ('get_devicelist', 'get_interface_mac', 'is_bridge',
- 'interface_has_own_mac', 'get_ib_interface_hwaddr')
+ mocks = (
+ "get_devicelist",
+ "get_interface_mac",
+ "is_bridge",
+ "interface_has_own_mac",
+ "get_ib_interface_hwaddr",
+ )
self.mocks = {}
for n in mocks:
- m = mock.patch('cloudinit.net.' + n,
- side_effect=getattr(self, '_se_' + n))
+ m = mock.patch(
+ "cloudinit.net." + n, side_effect=getattr(self, "_se_" + n)
+ )
self.addCleanup(m.stop)
self.mocks[n] = m.start()
def _se_get_devicelist(self):
- return self.data['devices']
+ return self.data["devices"]
def _se_get_interface_mac(self, name):
- return self.data['macs'][name]
+ return self.data["macs"][name]
def _se_is_bridge(self, name):
- return name in self.data['bridges']
+ return name in self.data["bridges"]
def _se_interface_has_own_mac(self, name):
- return name in self.data['own_macs']
+ return name in self.data["own_macs"]
def _se_get_ib_interface_hwaddr(self, name, ethernet_format):
- ib_hwaddr = self.data.get('ib_hwaddr', {})
+ ib_hwaddr = self.data.get("ib_hwaddr", {})
return ib_hwaddr.get(name, {}).get(ethernet_format)
def test_ethernet(self):
self._mock_setup()
- self.data['devices'].remove('ib0')
+ self.data["devices"].remove("ib0")
result = net.get_ib_hwaddrs_by_interface()
expected = {}
self.assertEqual(expected, result)
@@ -5391,7 +6766,7 @@ class TestGetIBHwaddrsByInterface(CiTestCase):
def test_ib(self):
self._mock_setup()
result = net.get_ib_hwaddrs_by_interface()
- expected = {'ib0': self._ib_addr}
+ expected = {"ib0": self._ib_addr}
self.assertEqual(expected, result)
@@ -5404,239 +6779,305 @@ def _gzip_data(data):
class TestRenameInterfaces(CiTestCase):
-
- @mock.patch('cloudinit.subp.subp')
+ @mock.patch("cloudinit.subp.subp")
def test_rename_all(self, mock_subp):
renames = [
- ('00:11:22:33:44:55', 'interface0', 'virtio_net', '0x3'),
- ('00:11:22:33:44:aa', 'interface2', 'virtio_net', '0x5'),
+ ("00:11:22:33:44:55", "interface0", "virtio_net", "0x3"),
+ ("00:11:22:33:44:aa", "interface2", "virtio_net", "0x5"),
]
current_info = {
- 'ens3': {
- 'downable': True,
- 'device_id': '0x3',
- 'driver': 'virtio_net',
- 'mac': '00:11:22:33:44:55',
- 'name': 'ens3',
- 'up': False},
- 'ens5': {
- 'downable': True,
- 'device_id': '0x5',
- 'driver': 'virtio_net',
- 'mac': '00:11:22:33:44:aa',
- 'name': 'ens5',
- 'up': False},
+ "ens3": {
+ "downable": True,
+ "device_id": "0x3",
+ "driver": "virtio_net",
+ "mac": "00:11:22:33:44:55",
+ "name": "ens3",
+ "up": False,
+ },
+ "ens5": {
+ "downable": True,
+ "device_id": "0x5",
+ "driver": "virtio_net",
+ "mac": "00:11:22:33:44:aa",
+ "name": "ens5",
+ "up": False,
+ },
}
net._rename_interfaces(renames, current_info=current_info)
print(mock_subp.call_args_list)
- mock_subp.assert_has_calls([
- mock.call(['ip', 'link', 'set', 'ens3', 'name', 'interface0'],
- capture=True),
- mock.call(['ip', 'link', 'set', 'ens5', 'name', 'interface2'],
- capture=True),
- ])
-
- @mock.patch('cloudinit.subp.subp')
+ mock_subp.assert_has_calls(
+ [
+ mock.call(
+ ["ip", "link", "set", "ens3", "name", "interface0"],
+ capture=True,
+ ),
+ mock.call(
+ ["ip", "link", "set", "ens5", "name", "interface2"],
+ capture=True,
+ ),
+ ]
+ )
+
+ @mock.patch("cloudinit.subp.subp")
def test_rename_no_driver_no_device_id(self, mock_subp):
renames = [
- ('00:11:22:33:44:55', 'interface0', None, None),
- ('00:11:22:33:44:aa', 'interface1', None, None),
+ ("00:11:22:33:44:55", "interface0", None, None),
+ ("00:11:22:33:44:aa", "interface1", None, None),
]
current_info = {
- 'eth0': {
- 'downable': True,
- 'device_id': None,
- 'driver': None,
- 'mac': '00:11:22:33:44:55',
- 'name': 'eth0',
- 'up': False},
- 'eth1': {
- 'downable': True,
- 'device_id': None,
- 'driver': None,
- 'mac': '00:11:22:33:44:aa',
- 'name': 'eth1',
- 'up': False},
+ "eth0": {
+ "downable": True,
+ "device_id": None,
+ "driver": None,
+ "mac": "00:11:22:33:44:55",
+ "name": "eth0",
+ "up": False,
+ },
+ "eth1": {
+ "downable": True,
+ "device_id": None,
+ "driver": None,
+ "mac": "00:11:22:33:44:aa",
+ "name": "eth1",
+ "up": False,
+ },
}
net._rename_interfaces(renames, current_info=current_info)
print(mock_subp.call_args_list)
- mock_subp.assert_has_calls([
- mock.call(['ip', 'link', 'set', 'eth0', 'name', 'interface0'],
- capture=True),
- mock.call(['ip', 'link', 'set', 'eth1', 'name', 'interface1'],
- capture=True),
- ])
-
- @mock.patch('cloudinit.subp.subp')
+ mock_subp.assert_has_calls(
+ [
+ mock.call(
+ ["ip", "link", "set", "eth0", "name", "interface0"],
+ capture=True,
+ ),
+ mock.call(
+ ["ip", "link", "set", "eth1", "name", "interface1"],
+ capture=True,
+ ),
+ ]
+ )
+
+ @mock.patch("cloudinit.subp.subp")
def test_rename_all_bounce(self, mock_subp):
renames = [
- ('00:11:22:33:44:55', 'interface0', 'virtio_net', '0x3'),
- ('00:11:22:33:44:aa', 'interface2', 'virtio_net', '0x5'),
+ ("00:11:22:33:44:55", "interface0", "virtio_net", "0x3"),
+ ("00:11:22:33:44:aa", "interface2", "virtio_net", "0x5"),
]
current_info = {
- 'ens3': {
- 'downable': True,
- 'device_id': '0x3',
- 'driver': 'virtio_net',
- 'mac': '00:11:22:33:44:55',
- 'name': 'ens3',
- 'up': True},
- 'ens5': {
- 'downable': True,
- 'device_id': '0x5',
- 'driver': 'virtio_net',
- 'mac': '00:11:22:33:44:aa',
- 'name': 'ens5',
- 'up': True},
+ "ens3": {
+ "downable": True,
+ "device_id": "0x3",
+ "driver": "virtio_net",
+ "mac": "00:11:22:33:44:55",
+ "name": "ens3",
+ "up": True,
+ },
+ "ens5": {
+ "downable": True,
+ "device_id": "0x5",
+ "driver": "virtio_net",
+ "mac": "00:11:22:33:44:aa",
+ "name": "ens5",
+ "up": True,
+ },
}
net._rename_interfaces(renames, current_info=current_info)
print(mock_subp.call_args_list)
- mock_subp.assert_has_calls([
- mock.call(['ip', 'link', 'set', 'ens3', 'down'], capture=True),
- mock.call(['ip', 'link', 'set', 'ens3', 'name', 'interface0'],
- capture=True),
- mock.call(['ip', 'link', 'set', 'ens5', 'down'], capture=True),
- mock.call(['ip', 'link', 'set', 'ens5', 'name', 'interface2'],
- capture=True),
- mock.call(['ip', 'link', 'set', 'interface0', 'up'], capture=True),
- mock.call(['ip', 'link', 'set', 'interface2', 'up'], capture=True)
- ])
-
- @mock.patch('cloudinit.subp.subp')
+ mock_subp.assert_has_calls(
+ [
+ mock.call(["ip", "link", "set", "ens3", "down"], capture=True),
+ mock.call(
+ ["ip", "link", "set", "ens3", "name", "interface0"],
+ capture=True,
+ ),
+ mock.call(["ip", "link", "set", "ens5", "down"], capture=True),
+ mock.call(
+ ["ip", "link", "set", "ens5", "name", "interface2"],
+ capture=True,
+ ),
+ mock.call(
+ ["ip", "link", "set", "interface0", "up"], capture=True
+ ),
+ mock.call(
+ ["ip", "link", "set", "interface2", "up"], capture=True
+ ),
+ ]
+ )
+
+ @mock.patch("cloudinit.subp.subp")
def test_rename_duplicate_macs(self, mock_subp):
renames = [
- ('00:11:22:33:44:55', 'eth0', 'hv_netsvc', '0x3'),
- ('00:11:22:33:44:55', 'vf1', 'mlx4_core', '0x5'),
+ ("00:11:22:33:44:55", "eth0", "hv_netsvc", "0x3"),
+ ("00:11:22:33:44:55", "vf1", "mlx4_core", "0x5"),
]
current_info = {
- 'eth0': {
- 'downable': True,
- 'device_id': '0x3',
- 'driver': 'hv_netsvc',
- 'mac': '00:11:22:33:44:55',
- 'name': 'eth0',
- 'up': False},
- 'eth1': {
- 'downable': True,
- 'device_id': '0x5',
- 'driver': 'mlx4_core',
- 'mac': '00:11:22:33:44:55',
- 'name': 'eth1',
- 'up': False},
+ "eth0": {
+ "downable": True,
+ "device_id": "0x3",
+ "driver": "hv_netsvc",
+ "mac": "00:11:22:33:44:55",
+ "name": "eth0",
+ "up": False,
+ },
+ "eth1": {
+ "downable": True,
+ "device_id": "0x5",
+ "driver": "mlx4_core",
+ "mac": "00:11:22:33:44:55",
+ "name": "eth1",
+ "up": False,
+ },
}
net._rename_interfaces(renames, current_info=current_info)
print(mock_subp.call_args_list)
- mock_subp.assert_has_calls([
- mock.call(['ip', 'link', 'set', 'eth1', 'name', 'vf1'],
- capture=True),
- ])
+ mock_subp.assert_has_calls(
+ [
+ mock.call(
+ ["ip", "link", "set", "eth1", "name", "vf1"], capture=True
+ ),
+ ]
+ )
- @mock.patch('cloudinit.subp.subp')
+ @mock.patch("cloudinit.subp.subp")
def test_rename_duplicate_macs_driver_no_devid(self, mock_subp):
renames = [
- ('00:11:22:33:44:55', 'eth0', 'hv_netsvc', None),
- ('00:11:22:33:44:55', 'vf1', 'mlx4_core', None),
+ ("00:11:22:33:44:55", "eth0", "hv_netsvc", None),
+ ("00:11:22:33:44:55", "vf1", "mlx4_core", None),
]
current_info = {
- 'eth0': {
- 'downable': True,
- 'device_id': '0x3',
- 'driver': 'hv_netsvc',
- 'mac': '00:11:22:33:44:55',
- 'name': 'eth0',
- 'up': False},
- 'eth1': {
- 'downable': True,
- 'device_id': '0x5',
- 'driver': 'mlx4_core',
- 'mac': '00:11:22:33:44:55',
- 'name': 'eth1',
- 'up': False},
+ "eth0": {
+ "downable": True,
+ "device_id": "0x3",
+ "driver": "hv_netsvc",
+ "mac": "00:11:22:33:44:55",
+ "name": "eth0",
+ "up": False,
+ },
+ "eth1": {
+ "downable": True,
+ "device_id": "0x5",
+ "driver": "mlx4_core",
+ "mac": "00:11:22:33:44:55",
+ "name": "eth1",
+ "up": False,
+ },
}
net._rename_interfaces(renames, current_info=current_info)
print(mock_subp.call_args_list)
- mock_subp.assert_has_calls([
- mock.call(['ip', 'link', 'set', 'eth1', 'name', 'vf1'],
- capture=True),
- ])
+ mock_subp.assert_has_calls(
+ [
+ mock.call(
+ ["ip", "link", "set", "eth1", "name", "vf1"], capture=True
+ ),
+ ]
+ )
- @mock.patch('cloudinit.subp.subp')
+ @mock.patch("cloudinit.subp.subp")
def test_rename_multi_mac_dups(self, mock_subp):
renames = [
- ('00:11:22:33:44:55', 'eth0', 'hv_netsvc', '0x3'),
- ('00:11:22:33:44:55', 'vf1', 'mlx4_core', '0x5'),
- ('00:11:22:33:44:55', 'vf2', 'mlx4_core', '0x7'),
+ ("00:11:22:33:44:55", "eth0", "hv_netsvc", "0x3"),
+ ("00:11:22:33:44:55", "vf1", "mlx4_core", "0x5"),
+ ("00:11:22:33:44:55", "vf2", "mlx4_core", "0x7"),
]
current_info = {
- 'eth0': {
- 'downable': True,
- 'device_id': '0x3',
- 'driver': 'hv_netsvc',
- 'mac': '00:11:22:33:44:55',
- 'name': 'eth0',
- 'up': False},
- 'eth1': {
- 'downable': True,
- 'device_id': '0x5',
- 'driver': 'mlx4_core',
- 'mac': '00:11:22:33:44:55',
- 'name': 'eth1',
- 'up': False},
- 'eth2': {
- 'downable': True,
- 'device_id': '0x7',
- 'driver': 'mlx4_core',
- 'mac': '00:11:22:33:44:55',
- 'name': 'eth2',
- 'up': False},
+ "eth0": {
+ "downable": True,
+ "device_id": "0x3",
+ "driver": "hv_netsvc",
+ "mac": "00:11:22:33:44:55",
+ "name": "eth0",
+ "up": False,
+ },
+ "eth1": {
+ "downable": True,
+ "device_id": "0x5",
+ "driver": "mlx4_core",
+ "mac": "00:11:22:33:44:55",
+ "name": "eth1",
+ "up": False,
+ },
+ "eth2": {
+ "downable": True,
+ "device_id": "0x7",
+ "driver": "mlx4_core",
+ "mac": "00:11:22:33:44:55",
+ "name": "eth2",
+ "up": False,
+ },
}
net._rename_interfaces(renames, current_info=current_info)
print(mock_subp.call_args_list)
- mock_subp.assert_has_calls([
- mock.call(['ip', 'link', 'set', 'eth1', 'name', 'vf1'],
- capture=True),
- mock.call(['ip', 'link', 'set', 'eth2', 'name', 'vf2'],
- capture=True),
- ])
-
- @mock.patch('cloudinit.subp.subp')
+ mock_subp.assert_has_calls(
+ [
+ mock.call(
+ ["ip", "link", "set", "eth1", "name", "vf1"], capture=True
+ ),
+ mock.call(
+ ["ip", "link", "set", "eth2", "name", "vf2"], capture=True
+ ),
+ ]
+ )
+
+ @mock.patch("cloudinit.subp.subp")
def test_rename_macs_case_insensitive(self, mock_subp):
"""_rename_interfaces must support upper or lower case macs."""
renames = [
- ('aa:aa:aa:aa:aa:aa', 'en0', None, None),
- ('BB:BB:BB:BB:BB:BB', 'en1', None, None),
- ('cc:cc:cc:cc:cc:cc', 'en2', None, None),
- ('DD:DD:DD:DD:DD:DD', 'en3', None, None),
+ ("aa:aa:aa:aa:aa:aa", "en0", None, None),
+ ("BB:BB:BB:BB:BB:BB", "en1", None, None),
+ ("cc:cc:cc:cc:cc:cc", "en2", None, None),
+ ("DD:DD:DD:DD:DD:DD", "en3", None, None),
]
current_info = {
- 'eth0': {'downable': True, 'mac': 'AA:AA:AA:AA:AA:AA',
- 'name': 'eth0', 'up': False},
- 'eth1': {'downable': True, 'mac': 'bb:bb:bb:bb:bb:bb',
- 'name': 'eth1', 'up': False},
- 'eth2': {'downable': True, 'mac': 'cc:cc:cc:cc:cc:cc',
- 'name': 'eth2', 'up': False},
- 'eth3': {'downable': True, 'mac': 'DD:DD:DD:DD:DD:DD',
- 'name': 'eth3', 'up': False},
+ "eth0": {
+ "downable": True,
+ "mac": "AA:AA:AA:AA:AA:AA",
+ "name": "eth0",
+ "up": False,
+ },
+ "eth1": {
+ "downable": True,
+ "mac": "bb:bb:bb:bb:bb:bb",
+ "name": "eth1",
+ "up": False,
+ },
+ "eth2": {
+ "downable": True,
+ "mac": "cc:cc:cc:cc:cc:cc",
+ "name": "eth2",
+ "up": False,
+ },
+ "eth3": {
+ "downable": True,
+ "mac": "DD:DD:DD:DD:DD:DD",
+ "name": "eth3",
+ "up": False,
+ },
}
net._rename_interfaces(renames, current_info=current_info)
expected = [
- mock.call(['ip', 'link', 'set', 'eth%d' % i, 'name', 'en%d' % i],
- capture=True)
- for i in range(len(renames))]
+ mock.call(
+ ["ip", "link", "set", "eth%d" % i, "name", "en%d" % i],
+ capture=True,
+ )
+ for i in range(len(renames))
+ ]
mock_subp.assert_has_calls(expected)
class TestNetworkState(CiTestCase):
-
def test_bcast_addr(self):
"""Test mask_and_ipv4_to_bcast_addr proper execution."""
bcast_addr = network_state.mask_and_ipv4_to_bcast_addr
- self.assertEqual("192.168.1.255",
- bcast_addr("255.255.255.0", "192.168.1.1"))
- self.assertEqual("128.42.7.255",
- bcast_addr("255.255.248.0", "128.42.5.4"))
- self.assertEqual("10.1.21.255",
- bcast_addr("255.255.255.0", "10.1.21.4"))
+ self.assertEqual(
+ "192.168.1.255", bcast_addr("255.255.255.0", "192.168.1.1")
+ )
+ self.assertEqual(
+ "128.42.7.255", bcast_addr("255.255.248.0", "128.42.5.4")
+ )
+ self.assertEqual(
+ "10.1.21.255", bcast_addr("255.255.255.0", "10.1.21.4")
+ )
+
# vi: ts=4 expandtab