diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py index 40b1ee0f5a9..751c99855d4 100644 --- a/cloudinit/net/network_state.py +++ b/cloudinit/net/network_state.py @@ -229,7 +229,6 @@ def to_passthrough(cls, network_state: dict) -> "NetworkState": class NetworkStateInterpreter(metaclass=CommandHandlerMeta): - initial_network_state = { "interfaces": {}, "routes": [], @@ -644,7 +643,6 @@ def handle_bonds(self, command): self._handle_bond_bridge(command, cmd_type="bond") def handle_bridges(self, command): - """ v2_command = { br0: { @@ -931,6 +929,7 @@ def _add_dhcp_overrides(overrides, subnet): { "destination": route.get("to"), "gateway": route.get("via"), + "metric": route.get("metric"), } ) ) diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py index f1e91ef699d..1ed8cc1eb48 100644 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py @@ -988,7 +988,7 @@ """.lstrip() NETWORK_CONFIGS = { - "small": { + "small_v1": { "expected_networkd_eth99": textwrap.dedent( """\ [Match] @@ -1195,6 +1195,178 @@ """ ), }, + # 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 + NM_CONTROLLED=no + 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 + NM_CONTROLLED=no + 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( """\ @@ -4391,7 +4563,6 @@ def test_unstable_names_disabled( mock.Mock(return_value=False), ) class TestRhelSysConfigRendering(CiTestCase): - with_logs = True scripts_dir = "/etc/sysconfig/network-scripts" @@ -4824,8 +4995,14 @@ def test_all_config(self): 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) @@ -5311,7 +5488,6 @@ def test_iface_name_from_device_with_matching_mac_address( mock.Mock(return_value=False), ) class TestOpenSuseSysConfigRendering(CiTestCase): - with_logs = True scripts_dir = "/etc/sysconfig/network" @@ -5604,8 +5780,14 @@ def test_all_config(self): 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) @@ -5673,7 +5855,6 @@ def test_render_v6_and_v4(self): mock.Mock(return_value=False), ) class TestNetworkManagerRendering(CiTestCase): - with_logs = True scripts_dir = "/etc/NetworkManager/system-connections" @@ -5887,8 +6068,13 @@ def test_all_config(self): 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) + + 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) @@ -6929,7 +7115,6 @@ def test_first_applicable_source_is_used(self): class TestNetplanRoundTrip(CiTestCase): - NETPLAN_INFO_OUT = textwrap.dedent( """ netplan.io: @@ -6991,7 +7176,7 @@ def testsimple_render_bond_v2_input_netplan(self): ) 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(), @@ -7201,8 +7386,17 @@ def testsimple_render_all(self): 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(), @@ -7582,10 +7776,33 @@ def _render_and_read( 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() @@ -8310,7 +8527,6 @@ def test_natural_order(self): 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 = {