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.py427
1 files changed, 404 insertions, 23 deletions
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 525706d1..056aaeb6 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -8,6 +8,7 @@ import json
import os
import re
import textwrap
+from typing import Optional
import pytest
from yaml.serializer import Serializer
@@ -33,6 +34,7 @@ from tests.unittests.helpers import (
CiTestCase,
FilesystemMockingTestCase,
dir2dict,
+ does_not_raise,
mock,
populate_dir,
)
@@ -379,7 +381,6 @@ network:
bondM:
addresses:
- 10.101.10.47/23
- gateway4: 10.101.11.254
interfaces:
- eno1
- eno3
@@ -401,6 +402,9 @@ network:
mode: 802.3ad
transmit-hash-policy: layer3+4
up-delay: 0
+ routes:
+ - to: default
+ via: 10.101.11.254
vlans:
bond0.3502:
addresses:
@@ -2247,7 +2251,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
addresses:
- 192.168.0.2/24
- 192.168.2.10/24
- gateway4: 192.168.0.1
id: 101
link: eth0
macaddress: aa:bb:cc:dd:ee:11
@@ -2260,6 +2263,9 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
- barley.maas
- sacchromyces.maas
- brettanomyces.maas
+ routes:
+ - to: default
+ via: 192.168.0.1
"""
).rstrip(" "),
"expected_sysconfig_opensuse": {
@@ -2971,7 +2977,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
- 192.168.0.2/24
- 192.168.1.2/24
- 2001:1::1/92
- gateway4: 192.168.0.1
interfaces:
- bond0s0
- bond0s1
@@ -2988,6 +2993,8 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
transmit-hash-policy: layer3+4
up-delay: 20
routes:
+ - to: default
+ via: 192.168.0.1
- to: 10.1.3.0/24
via: 192.168.0.3
- to: 2001:67c::/32
@@ -5219,7 +5226,7 @@ USERCTL=no
# Created by cloud-init on instance boot automatically, do not edit.
#
2a00:1730:fff9:100::1/128 via ::0 dev eth0
- ::0/64 via 2a00:1730:fff9:100::1 dev eth0
+ ::0/0 via 2a00:1730:fff9:100::1 dev eth0
""" # noqa: E501
),
}
@@ -5993,26 +6000,368 @@ iface eth0 inet dhcp
)
-class TestNetplanNetRendering(CiTestCase):
+class TestNetplanNetRendering:
+ @pytest.mark.parametrize(
+ "network_cfg,expected",
+ [
+ pytest.param(
+ None,
+ """
+ network:
+ ethernets:
+ eth1000:
+ dhcp4: true
+ match:
+ macaddress: 07-1c-c6-75-a4-be
+ set-name: eth1000
+ version: 2
+ """,
+ id="default_generation",
+ ),
+ # Asserts a netconf v1 with a physical device and two gateways
+ # does not produce deprecated keys, `gateway{46}`, in Netplan v2
+ pytest.param(
+ """
+ version: 1
+ config:
+ - type: physical
+ name: interface0
+ mac_address: '00:11:22:33:44:55'
+ subnets:
+ - type: static
+ address: 192.168.23.14/27
+ gateway: 192.168.23.1
+ - type: static
+ address: 11.0.0.11/24
+ gateway: 11.0.0.1
+ """,
+ """
+ network:
+ version: 2
+ ethernets:
+ interface0:
+ addresses:
+ - 192.168.23.14/27
+ - 11.0.0.11/24
+ match:
+ macaddress: 00:11:22:33:44:55
+ set-name: interface0
+ routes:
+ - to: default
+ via: 192.168.23.1
+ - to: default
+ via: 11.0.0.1
+ """,
+ id="physical_gateway46",
+ ),
+ # Asserts a netconf v1 with a bond device and two gateways
+ # does not produce deprecated keys, `gateway{46}`, in Netplan v2
+ pytest.param(
+ """
+ version: 1
+ config:
+ - type: bond
+ name: bond0
+ bond_interfaces:
+ - eth0
+ - eth1
+ params: {}
+ subnets:
+ - type: static
+ address: 192.168.23.14/27
+ gateway: 192.168.23.1
+ - type: static
+ address: 11.0.0.11/24
+ gateway: 11.0.0.1
+ """,
+ """
+ network:
+ version: 2
+ bonds:
+ bond0:
+ addresses:
+ - 192.168.23.14/27
+ - 11.0.0.11/24
+ interfaces:
+ - eth0
+ - eth1
+ routes:
+ - to: default
+ via: 192.168.23.1
+ - to: default
+ via: 11.0.0.1
+ eth0: {}
+ eth1: {}
+ """,
+ id="bond_gateway46",
+ ),
+ # Asserts a netconf v1 with a bridge device and two gateways
+ # does not produce deprecated keys, `gateway{46}`, in Netplan v2
+ pytest.param(
+ """
+ version: 1
+ config:
+ - type: bridge
+ name: bridge0
+ bridge_interfaces:
+ - eth0
+ params: {}
+ subnets:
+ - type: static
+ address: 192.168.23.14/27
+ gateway: 192.168.23.1
+ - type: static
+ address: 11.0.0.11/24
+ gateway: 11.0.0.1
+ """,
+ """
+ network:
+ version: 2
+ bridges:
+ bridge0:
+ addresses:
+ - 192.168.23.14/27
+ - 11.0.0.11/24
+ interfaces:
+ - eth0
+ routes:
+ - to: default
+ via: 192.168.23.1
+ - to: default
+ via: 11.0.0.1
+ """,
+ id="bridge_gateway46",
+ ),
+ # Asserts a netconf v1 with a vlan device and two gateways
+ # does not produce deprecated keys, `gateway{46}`, in Netplan v2
+ pytest.param(
+ """
+ version: 1
+ config:
+ - type: vlan
+ name: vlan0
+ vlan_link: eth0
+ vlan_id: 101
+ subnets:
+ - type: static
+ address: 192.168.23.14/27
+ gateway: 192.168.23.1
+ - type: static
+ address: 11.0.0.11/24
+ gateway: 11.0.0.1
+ """,
+ """
+ network:
+ version: 2
+ vlans:
+ vlan0:
+ addresses:
+ - 192.168.23.14/27
+ - 11.0.0.11/24
+ id: 101
+ link: eth0
+ routes:
+ - to: default
+ via: 192.168.23.1
+ - to: default
+ via: 11.0.0.1
+ """,
+ id="vlan_gateway46",
+ ),
+ # Asserts a netconf v1 with a nameserver device and two gateways
+ # does not produce deprecated keys, `gateway{46}`, in Netplan v2
+ pytest.param(
+ """
+ version: 1
+ config:
+ - type: physical
+ name: interface0
+ mac_address: '00:11:22:33:44:55'
+ subnets:
+ - type: static
+ address: 192.168.23.14/27
+ gateway: 192.168.23.1
+ - type: nameserver
+ address:
+ - 192.168.23.14/27
+ - 11.0.0.11/24
+ search:
+ - exemplary
+ subnets:
+ - type: static
+ address: 192.168.23.14/27
+ gateway: 192.168.23.1
+ - type: static
+ address: 11.0.0.11/24
+ gateway: 11.0.0.1
+ """,
+ """
+ network:
+ version: 2
+ ethernets:
+ interface0:
+ addresses:
+ - 192.168.23.14/27
+ match:
+ macaddress: 00:11:22:33:44:55
+ nameservers:
+ addresses:
+ - 192.168.23.14/27
+ - 11.0.0.11/24
+ search:
+ - exemplary
+ set-name: interface0
+ routes:
+ - to: default
+ via: 192.168.23.1
+ """,
+ id="nameserver_gateway4",
+ ),
+ # Asserts a netconf v1 with two subnets with two gateways does
+ # not clash
+ pytest.param(
+ """
+ version: 1
+ config:
+ - type: physical
+ name: interface0
+ mac_address: '00:11:22:33:44:55'
+ subnets:
+ - type: static
+ address: 192.168.23.14/24
+ gateway: 192.168.23.1
+ - type: static
+ address: 10.184.225.122
+ routes:
+ - network: 10.176.0.0
+ gateway: 10.184.225.121
+ """,
+ """
+ network:
+ version: 2
+ ethernets:
+ interface0:
+ addresses:
+ - 192.168.23.14/24
+ - 10.184.225.122/24
+ match:
+ macaddress: 00:11:22:33:44:55
+ routes:
+ - to: default
+ via: 192.168.23.1
+ - to: 10.176.0.0/24
+ via: 10.184.225.121
+ set-name: interface0
+ """,
+ id="two_subnets_old_new_gateway46",
+ ),
+ # Asserts a netconf v1 with one subnet with two gateways does
+ # not clash
+ pytest.param(
+ """
+ version: 1
+ config:
+ - type: physical
+ name: interface0
+ mac_address: '00:11:22:33:44:55'
+ subnets:
+ - type: static
+ address: 192.168.23.14/24
+ gateway: 192.168.23.1
+ routes:
+ - network: 192.167.225.122
+ gateway: 192.168.23.1
+ """,
+ """
+ network:
+ version: 2
+ ethernets:
+ interface0:
+ addresses:
+ - 192.168.23.14/24
+ match:
+ macaddress: 00:11:22:33:44:55
+ routes:
+ - to: default
+ via: 192.168.23.1
+ - to: 192.167.225.122/24
+ via: 192.168.23.1
+ set-name: interface0
+ """,
+ id="one_subnet_old_new_gateway46",
+ ),
+ # Assert gateways outside of the subnet's network are added with
+ # the on-link flag
+ pytest.param(
+ """
+ version: 1
+ config:
+ - type: physical
+ name: interface0
+ mac_address: '00:11:22:33:44:55'
+ subnets:
+ - type: static
+ address: 192.168.23.14/24
+ gateway: 192.168.255.1
+ - type: static
+ address: 2001:cafe::/64
+ gateway: 2001:ffff::1
+ """,
+ """
+ network:
+ version: 2
+ ethernets:
+ interface0:
+ addresses:
+ - 192.168.23.14/24
+ - 2001:cafe::/64
+ match:
+ macaddress: 00:11:22:33:44:55
+ routes:
+ - to: default
+ via: 192.168.255.1
+ on-link: true
+ - to: default
+ via: 2001:ffff::1
+ on-link: true
+ set-name: interface0
+ """,
+ id="onlink_gateways",
+ ),
+ ],
+ )
+ @mock.patch(
+ "cloudinit.net.netplan.Renderer.features",
+ new_callable=mock.PropertyMock(return_value=[]),
+ )
@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(
+ def test_render(
self,
mock_get_devicelist,
mock_read_sys_net,
mock_sys_dev_path,
mock_clean_default,
m_get_cmdline,
+ m_renderer_features,
+ network_cfg: Optional[str],
+ expected: str,
+ tmpdir,
):
- tmp_dir = self.tmp_dir()
+ tmp_dir = str(tmpdir)
_setup_test(
tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path
)
- network_cfg = net.generate_fallback_config()
+ if network_cfg is None:
+ network_cfg = net.generate_fallback_config()
+ else:
+ network_cfg = yaml.load(network_cfg)
+ assert isinstance(network_cfg, dict)
+
ns = network_state.parse_net_config_data(
network_cfg, skip_broken=False
)
@@ -6026,25 +6375,13 @@ class TestNetplanNetRendering(CiTestCase):
)
renderer.render_network_state(ns, target=render_dir)
- self.assertTrue(
- os.path.exists(os.path.join(render_dir, render_target))
- )
+ assert 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)
- expected = """
-network:
- ethernets:
- eth1000:
- dhcp4: true
- match:
- macaddress: 07-1c-c6-75-a4-be
- set-name: eth1000
- version: 2
-"""
- self.assertEqual(expected.lstrip(), contents.lstrip())
- self.assertEqual(1, mock_clean_default.call_count)
+ assert yaml.load(expected) == yaml.load(contents)
+ assert 1, mock_clean_default.call_count
class TestNetplanCleanDefault(CiTestCase):
@@ -7672,6 +8009,7 @@ class TestInterfaceHasOwnMac(CiTestCase):
mock.Mock(return_value=False),
)
class TestGetInterfacesByMac(CiTestCase):
+ with_logs = True
_data = {
"bonds": ["bond1"],
"bridges": ["bridge1"],
@@ -7683,6 +8021,10 @@ class TestGetInterfacesByMac(CiTestCase):
"bridge1",
"bond1.101",
"lo",
+ "netvsc0-vf",
+ "netvsc0",
+ "netvsc1",
+ "netvsc1-vf",
],
"macs": {
"enp0s1": "aa:aa:aa:aa:aa:01",
@@ -7693,14 +8035,27 @@ class TestGetInterfacesByMac(CiTestCase):
"bridge1-nic": "aa:aa:aa:aa:aa:03",
"lo": "00:00:00:00:00:00",
"greptap0": "00:00:00:00:00:00",
+ "netvsc0-vf": "aa:aa:aa:aa:aa:04",
+ "netvsc0": "aa:aa:aa:aa:aa:04",
+ "netvsc1-vf": "aa:aa:aa:aa:aa:05",
+ "netvsc1": "aa:aa:aa:aa:aa:05",
"tun0": None,
},
+ "drivers": {
+ "netvsc0": "hv_netvsc",
+ "netvsc0-vf": "foo",
+ "netvsc1": "hv_netvsc",
+ "netvsc1-vf": "bar",
+ },
}
data: dict = {}
def _se_get_devicelist(self):
return list(self.data["devices"])
+ def _se_device_driver(self, name):
+ return self.data["drivers"].get(name, None)
+
def _se_get_interface_mac(self, name):
return self.data["macs"][name]
@@ -7722,6 +8077,7 @@ class TestGetInterfacesByMac(CiTestCase):
self.data["devices"] = set(list(self.data["macs"].keys()))
mocks = (
"get_devicelist",
+ "device_driver",
"get_interface_mac",
"is_bridge",
"interface_has_own_mac",
@@ -7741,6 +8097,11 @@ class TestGetInterfacesByMac(CiTestCase):
self.data["macs"]["bridge1-nic"] = self.data["macs"]["enp0s1"]
self.assertRaises(RuntimeError, net.get_interfaces_by_mac)
+ def test_raise_exception_on_duplicate_netvsc_macs(self):
+ self._mock_setup()
+ self.data["macs"]["netvsc0"] = self.data["macs"]["netvsc1"]
+ 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()
@@ -7759,6 +8120,8 @@ class TestGetInterfacesByMac(CiTestCase):
"aa:aa:aa:aa:aa:02": "enp0s2",
"aa:aa:aa:aa:aa:03": "bridge1-nic",
"00:00:00:00:00:00": "lo",
+ "aa:aa:aa:aa:aa:04": "netvsc0",
+ "aa:aa:aa:aa:aa:05": "netvsc1",
},
ret,
)
@@ -7859,6 +8222,24 @@ class TestGetInterfacesByMac(CiTestCase):
}
self.assertEqual(expected, result)
+ def test_duplicate_ignored_macs(self):
+ # LP: #199792
+ self._data = copy.deepcopy(self._data)
+ self._data["macs"]["swp0"] = "9a:57:7d:78:47:c0"
+ self._data["macs"]["swp1"] = "9a:57:7d:78:47:c0"
+ self._data["own_macs"].append("swp0")
+ self._data["own_macs"].append("swp1")
+ self._data["drivers"]["swp0"] = "mscc_felix"
+ self._data["drivers"]["swp1"] = "mscc_felix"
+ self._mock_setup()
+ with does_not_raise():
+ net.get_interfaces_by_mac()
+ pattern = (
+ "Ignoring duplicate macs from 'swp[0-1]' and 'swp[0-1]' due to "
+ "driver 'mscc_felix'."
+ )
+ assert re.search(pattern, self.logs.getvalue())
+
class TestInterfacesSorting(CiTestCase):
def test_natural_order(self):