389 lines
14 KiB
Diff
389 lines
14 KiB
Diff
From c68305a91791e28031df8b9ebd33bfe7ffd7e75d Mon Sep 17 00:00:00 2001
|
|
From: James Falcon <james.falcon@canonical.com>
|
|
Date: Tue, 4 Jul 2023 07:00:22 -0500
|
|
Subject: [PATCH] Fix network v2 metric rendering (#4220)
|
|
|
|
Reference:https://github.com/canonical/cloud-init/commit/c68305a91791e28031df8b9ebd33bfe7ffd7e75d
|
|
Conflict:(1)change 'small' to 'small_v1'
|
|
(2)do not change TestNetworkManagerRendering.
|
|
(3)do not add "NM_CONTROLLED=no" in test because of cloud-init-20.4-nm-controlled.patch.
|
|
(4)format diffs.
|
|
|
|
Metric info was not being included in v2-based routes.
|
|
|
|
Fixes GH-4217
|
|
---
|
|
cloudinit/net/network_state.py | 4 +-
|
|
tests/unittests/test_net.py | 232 ++++++++++++++++++++++++++++++---
|
|
2 files changed, 216 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py
|
|
index 4862bf9..ac44304 100644
|
|
--- a/cloudinit/net/network_state.py
|
|
+++ b/cloudinit/net/network_state.py
|
|
@@ -187,7 +187,6 @@ class NetworkState(object):
|
|
|
|
|
|
class NetworkStateInterpreter(metaclass=CommandHandlerMeta):
|
|
-
|
|
initial_network_state = {
|
|
'interfaces': {},
|
|
'routes': [],
|
|
@@ -582,7 +581,6 @@ class NetworkStateInterpreter(metaclass=CommandHandlerMeta):
|
|
self._handle_bond_bridge(command, cmd_type='bond')
|
|
|
|
def handle_bridges(self, command):
|
|
-
|
|
'''
|
|
v2_command = {
|
|
br0: {
|
|
@@ -815,7 +813,7 @@ class NetworkStateInterpreter(metaclass=CommandHandlerMeta):
|
|
routes = []
|
|
for route in cfg.get('routes', []):
|
|
routes.append(_normalize_route(
|
|
- {'destination': route.get('to'), 'gateway': route.get('via')}))
|
|
+ {'destination': route.get('to'), 'gateway': route.get('via'), "metric": route.get("metric"),}))
|
|
|
|
# v2 routes are bound to the interface, in v1 we add them under
|
|
# the first subnet since there isn't an equivalent interface level.
|
|
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
|
|
index 7cde102..764e1c7 100644
|
|
--- a/tests/unittests/test_net.py
|
|
+++ b/tests/unittests/test_net.py
|
|
@@ -818,7 +818,7 @@ iface eth1 inet static
|
|
""".lstrip()
|
|
|
|
NETWORK_CONFIGS = {
|
|
- 'small': {
|
|
+ 'small_v1': {
|
|
'expected_networkd_eth99': textwrap.dedent("""\
|
|
[Match]
|
|
Name=eth99
|
|
@@ -959,6 +959,164 @@ NETWORK_CONFIGS = {
|
|
- wark.maas
|
|
"""),
|
|
},
|
|
+ # We test a separate set of configs here because v2 doesn't support
|
|
+ # generic nameservers, so that aspect needs to be modified
|
|
+ "small_v2": {
|
|
+ "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
|
|
+ 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
|
|
+ """
|
|
+ ).rstrip(" "),
|
|
+ "expected_eni": textwrap.dedent(
|
|
+ """\
|
|
+ auto lo
|
|
+ iface lo inet loopback
|
|
+ dns-nameservers 8.8.8.8 8.8.4.4
|
|
+ dns-search wark.maas
|
|
+ iface eth1 inet manual
|
|
+ auto eth99
|
|
+ iface eth99 inet dhcp
|
|
+ # control-alias eth99
|
|
+ iface eth99 inet static
|
|
+ address 192.168.21.3/24
|
|
+ dns-nameservers 8.8.8.8 8.8.4.4
|
|
+ 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_sysconfig_opensuse": {
|
|
+ "ifcfg-eth1": textwrap.dedent(
|
|
+ """\
|
|
+ BOOTPROTO=static
|
|
+ LLADDR=cf:d6:af:48:e8:80
|
|
+ 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"""
|
|
+ ),
|
|
+ },
|
|
+ "expected_sysconfig_rhel": {
|
|
+ "ifcfg-eth1": textwrap.dedent(
|
|
+ """\
|
|
+ BOOTPROTO=none
|
|
+ DEVICE=eth1
|
|
+ HWADDR=cf:d6:af:48:e8:80
|
|
+ ONBOOT=yes
|
|
+ TYPE=Ethernet
|
|
+ USERCTL=no"""
|
|
+ ),
|
|
+ "ifcfg-eth99": textwrap.dedent(
|
|
+ """\
|
|
+ BOOTPROTO=dhcp
|
|
+ DEFROUTE=yes
|
|
+ DEVICE=eth99
|
|
+ DHCLIENT_SET_DEFAULT_ROUTE=yes
|
|
+ DNS1=8.8.8.8
|
|
+ DNS2=8.8.4.4
|
|
+ DOMAIN="barley.maas sach.maas"
|
|
+ GATEWAY=65.61.151.37
|
|
+ HWADDR=c0:d6:9f:2c:e8:80
|
|
+ IPADDR=192.168.21.3
|
|
+ NETMASK=255.255.255.0
|
|
+ METRIC=10000
|
|
+ ONBOOT=yes
|
|
+ TYPE=Ethernet
|
|
+ USERCTL=no"""
|
|
+ ),
|
|
+ },
|
|
+ "expected_network_manager": {
|
|
+ "cloud-init-eth1.nmconnection": textwrap.dedent(
|
|
+ """\
|
|
+ # Generated by cloud-init. Changes will be lost.
|
|
+ [connection]
|
|
+ id=cloud-init eth1
|
|
+ uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58
|
|
+ autoconnect-priority=120
|
|
+ type=ethernet
|
|
+ [user]
|
|
+ org.freedesktop.NetworkManager.origin=cloud-init
|
|
+ [ethernet]
|
|
+ mac-address=CF:D6:AF:48:E8:80
|
|
+ """
|
|
+ ),
|
|
+ "cloud-init-eth99.nmconnection": textwrap.dedent(
|
|
+ """\
|
|
+ # Generated by cloud-init. Changes will be lost.
|
|
+ [connection]
|
|
+ id=cloud-init eth99
|
|
+ uuid=b1b88000-1f03-5360-8377-1a2205efffb4
|
|
+ autoconnect-priority=120
|
|
+ type=ethernet
|
|
+ [user]
|
|
+ org.freedesktop.NetworkManager.origin=cloud-init
|
|
+ [ethernet]
|
|
+ mac-address=C0:D6:9F:2C:E8:80
|
|
+ [ipv4]
|
|
+ method=auto
|
|
+ may-fail=false
|
|
+ route1=0.0.0.0/0,65.61.151.37
|
|
+ address1=192.168.21.3/24
|
|
+ dns=8.8.8.8;8.8.4.4;
|
|
+ dns-search=barley.maas;sach.maas;
|
|
+ """
|
|
+ ),
|
|
+ },
|
|
+ "yaml": textwrap.dedent(
|
|
+ """
|
|
+ version: 2
|
|
+ ethernets:
|
|
+ eth1:
|
|
+ match:
|
|
+ macaddress: cf:d6:af:48:e8:80
|
|
+ set-name: eth1
|
|
+ eth99:
|
|
+ addresses:
|
|
+ - 192.168.21.3/24
|
|
+ dhcp4: true
|
|
+ match:
|
|
+ macaddress: c0:d6:9f:2c:e8:80
|
|
+ nameservers:
|
|
+ addresses:
|
|
+ - 8.8.8.8
|
|
+ - 8.8.4.4
|
|
+ search:
|
|
+ - barley.maas
|
|
+ - sach.maas
|
|
+ routes:
|
|
+ - metric: 10000
|
|
+ to: 0.0.0.0/0
|
|
+ via: 65.61.151.37
|
|
+ set-name: eth99
|
|
+ """
|
|
+ ),
|
|
+ },
|
|
'v4_and_v6': {
|
|
'expected_networkd': textwrap.dedent("""\
|
|
[Match]
|
|
@@ -2965,7 +3123,6 @@ iface eth1 inet dhcp
|
|
mock.Mock(return_value=False)
|
|
)
|
|
class TestRhelSysConfigRendering(CiTestCase):
|
|
-
|
|
with_logs = True
|
|
|
|
nm_cfg_file = "/etc/NetworkManager/NetworkManager.conf"
|
|
@@ -3286,8 +3443,14 @@ USERCTL=no
|
|
'WARNING: Network config: ignoring eth0.101 device-level mtu',
|
|
self.logs.getvalue())
|
|
|
|
- def test_small_config(self):
|
|
- entry = NETWORK_CONFIGS['small']
|
|
+ def test_small_config_v1(self):
|
|
+ entry = NETWORK_CONFIGS["small_v1"]
|
|
+ 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_small_config_v2(self):
|
|
+ entry = NETWORK_CONFIGS["small_v2"]
|
|
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)
|
|
@@ -3429,7 +3592,7 @@ USERCTL=no
|
|
self.assertTrue(os.path.exists(nm_cfg))
|
|
|
|
# render and read
|
|
- entry = NETWORK_CONFIGS['small']
|
|
+ entry = NETWORK_CONFIGS['small_v1']
|
|
found = self._render_and_read(network_config=yaml.load(entry['yaml']),
|
|
dir=render_dir)
|
|
self._compare_files_to_expected(entry[self.expected_name], found)
|
|
@@ -3450,7 +3613,7 @@ USERCTL=no
|
|
util.write_file(nm_cfg, '# test_check_ifcfg_rh\n[main]\nplugins=foo\n')
|
|
|
|
# render and read
|
|
- entry = NETWORK_CONFIGS['small']
|
|
+ entry = NETWORK_CONFIGS['small_v1']
|
|
found = self._render_and_read(network_config=yaml.load(entry['yaml']),
|
|
dir=render_dir)
|
|
self._compare_files_to_expected(entry[self.expected_name], found)
|
|
@@ -3476,7 +3639,7 @@ USERCTL=no
|
|
self.assertTrue(os.path.exists(nm_cfg))
|
|
|
|
# render and read
|
|
- entry = NETWORK_CONFIGS['small']
|
|
+ entry = NETWORK_CONFIGS['small_v1']
|
|
found = self._render_and_read(network_config=yaml.load(entry['yaml']),
|
|
dir=render_dir)
|
|
self._compare_files_to_expected(entry[self.expected_name], found)
|
|
@@ -3644,7 +3807,6 @@ USERCTL=no
|
|
mock.Mock(return_value=False)
|
|
)
|
|
class TestOpenSuseSysConfigRendering(CiTestCase):
|
|
-
|
|
with_logs = True
|
|
|
|
scripts_dir = '/etc/sysconfig/network'
|
|
@@ -3916,8 +4078,14 @@ STARTMODE=auto
|
|
'WARNING: Network config: ignoring eth0.101 device-level mtu',
|
|
self.logs.getvalue())
|
|
|
|
- def test_small_config(self):
|
|
- entry = NETWORK_CONFIGS['small']
|
|
+ def test_small_config_v1(self):
|
|
+ entry = NETWORK_CONFIGS["small_v1"]
|
|
+ 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_small_config_v2(self):
|
|
+ entry = NETWORK_CONFIGS["small_v1"]
|
|
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)
|
|
@@ -4539,7 +4707,6 @@ class TestReadInitramfsConfig(CiTestCase):
|
|
|
|
|
|
class TestNetplanRoundTrip(CiTestCase):
|
|
-
|
|
NETPLAN_INFO_OUT = textwrap.dedent("""
|
|
netplan.io:
|
|
features:
|
|
@@ -4596,7 +4763,7 @@ class TestNetplanRoundTrip(CiTestCase):
|
|
files['/etc/netplan/50-cloud-init.yaml'].splitlines())
|
|
|
|
def testsimple_render_small_netplan(self):
|
|
- entry = NETWORK_CONFIGS['small']
|
|
+ entry = NETWORK_CONFIGS['small_v1']
|
|
files = self._render_and_read(network_config=yaml.load(entry['yaml']))
|
|
self.assertEqual(
|
|
entry['expected_netplan'].splitlines(),
|
|
@@ -4781,8 +4948,17 @@ class TestEniRoundTrip(CiTestCase):
|
|
entry['expected_eni'].splitlines(),
|
|
files['/etc/network/interfaces'].splitlines())
|
|
|
|
- def testsimple_render_small(self):
|
|
- entry = NETWORK_CONFIGS['small']
|
|
+ def testsimple_render_small_v1(self):
|
|
+ entry = NETWORK_CONFIGS["small_v1"]
|
|
+ files = self._render_and_read(network_config=yaml.load(entry["yaml"]))
|
|
+ self.assertEqual(
|
|
+ entry["expected_eni"].splitlines(),
|
|
+ files["/etc/network/interfaces"].splitlines(),
|
|
+ )
|
|
+
|
|
+ @pytest.mark.xfail(reason="GH-4219")
|
|
+ def testsimple_render_small_v2(self):
|
|
+ entry = NETWORK_CONFIGS["small_v2"]
|
|
files = self._render_and_read(network_config=yaml.load(entry['yaml']))
|
|
self.assertEqual(
|
|
entry['expected_eni'].splitlines(),
|
|
@@ -5105,10 +5281,33 @@ class TestNetworkdRoundTrip(CiTestCase):
|
|
return dir2dict(dir)
|
|
|
|
@mock.patch("cloudinit.net.util.chownbyname", return_value=True)
|
|
- def testsimple_render_small_networkd(self, m_chown):
|
|
+ def testsimple_render_small_networkd_v1(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_v1"]
|
|
+ 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_small_networkd_v2(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']
|
|
+ entry = NETWORK_CONFIGS['small_v2']
|
|
files = self._render_and_read(network_config=yaml.load(entry['yaml']))
|
|
|
|
actual = files[nwk_fn1].splitlines()
|
|
@@ -5735,7 +5934,6 @@ class TestInterfacesSorting(CiTestCase):
|
|
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',
|
|
--
|
|
2.33.0
|
|
|
|
|