diff --git a/0004-net-network_manager-do-not-set-may-fail-to-False-for.patch b/0004-net-network_manager-do-not-set-may-fail-to-False-for.patch new file mode 100644 index 0000000..f8de026 --- /dev/null +++ b/0004-net-network_manager-do-not-set-may-fail-to-False-for.patch @@ -0,0 +1,140 @@ +From 5fa8113a9efaa90f293b95477c4fa44e3d4b6537 Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Thu, 23 Nov 2023 12:27:51 +0530 +Subject: [PATCH] net/network_manager: do not set "may-fail" to False for both + ipv4 and ipv6 dhcp + +If "may-fail" is set to False in the Network Manager keyfile for both ipv4 +and ipv6 for dhcp configuration, it essentially means both ipv4 and ipv6 network +initialization using dhcp must succeed for the overall network configuration to +succeed. This means, for environments where only ipv4 or ipv6 is available but +not both and we need to configure both ipv4 and ipv6 dhcp, the overall +network configuration will fail. This is not what we want. When both ipv4 +and ipv6 dhcp are configured, it is enough for the overall configuration to +succeed if any one succeeds. +Therefore, set "may-fail" to True for both ipv4 and ipv6 if and only if both +ipv4 and ipv6 are configured as dhcp in the Network Manager keyfile and +"may-fail" is set to False for both. If both ipv4 and ipv6 are configured +in the keyfile and if for any of them "may-fail" is already set to True,then +do nothing. +All other cases remain same as before. + +Please see discussions in PR #4474. + +Co-authored-by: James Falcon +Signed-off-by: Ani Sinha +(cherry picked from commit 29dd5ace73ad60c7452c39b840045fb47fe0711f) +--- + cloudinit/net/network_manager.py | 59 ++++++++++++++++++++++++++++++++ + tests/unittests/test_net.py | 8 ++--- + 2 files changed, 63 insertions(+), 4 deletions(-) + +diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py +index 8374cfcc..8a99eb3a 100644 +--- a/cloudinit/net/network_manager.py ++++ b/cloudinit/net/network_manager.py +@@ -71,6 +71,57 @@ class NMConnection: + if not self.config.has_option(section, option): + self.config[section][option] = value + ++ def _config_option_is_set(self, section, option): ++ """ ++ Checks if a config option is set. Returns True if it is, ++ else returns False. ++ """ ++ return self.config.has_section(section) and self.config.has_option( ++ section, option ++ ) ++ ++ def _get_config_option(self, section, option): ++ """ ++ Returns the value of a config option if its set, ++ else returns None. ++ """ ++ if self._config_option_is_set(section, option): ++ return self.config[section][option] ++ else: ++ return None ++ ++ def _change_set_config_option(self, section, option, value): ++ """ ++ Overrides the value of a config option if its already set. ++ Else, if the config option is not set, it does nothing. ++ """ ++ if self._config_option_is_set(section, option): ++ self.config[section][option] = value ++ ++ def _set_mayfail_true_if_both_false_dhcp(self): ++ """ ++ If for both ipv4 and ipv6, 'may-fail' is set to be False, ++ set it to True for both of them. ++ """ ++ for family in ["ipv4", "ipv6"]: ++ if self._get_config_option(family, "may-fail") != "false": ++ # if either ipv4 or ipv6 sections are not set/configured, ++ # or if both are configured but for either ipv4 or ipv6, ++ # 'may-fail' is not 'false', do not do anything. ++ return ++ if self._get_config_option(family, "method") not in [ ++ "dhcp", ++ "auto", ++ ]: ++ # if both v4 and v6 are not dhcp, do not do anything. ++ return ++ ++ # If we landed here, it means both ipv4 and ipv6 are configured ++ # with dhcp/auto and both have 'may-fail' set to 'false'. So set ++ # both to 'true'. ++ for family in ["ipv4", "ipv6"]: ++ self._change_set_config_option(family, "may-fail", "true") ++ + def _set_ip_method(self, family, subnet_type): + """ + Ensures there's appropriate [ipv4]/[ipv6] for given family +@@ -271,6 +322,14 @@ class NMConnection: + if family == "ipv4" and "mtu" in subnet: + ipv4_mtu = subnet["mtu"] + ++ # we do not want to set may-fail to false for both ipv4 and ipv6 dhcp ++ # at the at the same time. This will make the network configuration ++ # work only when both ipv4 and ipv6 dhcp succeeds. This may not be ++ # what we want. If we have configured both ipv4 and ipv6 dhcp, any one ++ # succeeding should be enough. Therefore, if "may-fail" is set to ++ # False for both ipv4 and ipv6 dhcp, set them both to True. ++ self._set_mayfail_true_if_both_false_dhcp() ++ + if ipv4_mtu is None: + ipv4_mtu = device_mtu + if not ipv4_mtu == device_mtu: +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index cef4fa2d..fb4c863c 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -1477,11 +1477,11 @@ NETWORK_CONFIGS = { + + [ipv4] + method=auto +- may-fail=false ++ may-fail=true + + [ipv6] + method=auto +- may-fail=false ++ may-fail=true + + """ + ), +@@ -1650,11 +1650,11 @@ NETWORK_CONFIGS = { + + [ipv6] + method=auto +- may-fail=false ++ may-fail=true + + [ipv4] + method=auto +- may-fail=false ++ may-fail=true + + """ + ), diff --git a/0005-net-allow-dhcp6-configuration-from-generate_fallback.patch b/0005-net-allow-dhcp6-configuration-from-generate_fallback.patch new file mode 100644 index 0000000..56a4ca7 --- /dev/null +++ b/0005-net-allow-dhcp6-configuration-from-generate_fallback.patch @@ -0,0 +1,172 @@ +From 54e87eaad7841270e530beff2dcfe68292ae87ef Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Tue, 21 Nov 2023 13:57:15 +0530 +Subject: [PATCH] net: allow dhcp6 configuration from + generate_fallback_configuration() + +This will make sure on Azure we can use both dhcp4 and dhcp6 when IMDS is not +used. This is useful in situations where only ipv6 network is available and +there is no dhcp4 running. + +This change is mostly a reversal of commit 29ed5f5b646ee and therefore, +re-application of the commit 518047aea9 with some small changes. + +The issue that caused the reversal of 518047aea9 is fixed by the earlier commit: +cab0eaf290af7 ("net/network_manager: do not set "may-fail" to False for both ipv4 and ipv6 dhcp") + +Fixes GH-4439 + +Signed-off-by: Ani Sinha +(cherry picked from commit 0264e969166846b2f5cf87ccdb051a3a795eca15) +--- + cloudinit/net/__init__.py | 7 ++++++- + tests/unittests/net/test_init.py | 4 ++++ + tests/unittests/test_net.py | 24 +++++++++++++++++++++--- + 3 files changed, 31 insertions(+), 4 deletions(-) + +diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py +index bf21633b..c0888f52 100644 +--- a/cloudinit/net/__init__.py ++++ b/cloudinit/net/__init__.py +@@ -571,7 +571,12 @@ def generate_fallback_config(config_driver=None): + match = { + "macaddress": read_sys_net_safe(target_name, "address").lower() + } +- cfg = {"dhcp4": True, "set-name": target_name, "match": match} ++ cfg = { ++ "dhcp4": True, ++ "dhcp6": True, ++ "set-name": target_name, ++ "match": match, ++ } + if config_driver: + driver = device_driver(target_name) + if driver: +diff --git a/tests/unittests/net/test_init.py b/tests/unittests/net/test_init.py +index 561d5151..60a44186 100644 +--- a/tests/unittests/net/test_init.py ++++ b/tests/unittests/net/test_init.py +@@ -261,6 +261,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "eth1": { + "match": {"macaddress": mac}, + "dhcp4": True, ++ "dhcp6": True, + "set-name": "eth1", + } + }, +@@ -278,6 +279,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "eth0": { + "match": {"macaddress": mac}, + "dhcp4": True, ++ "dhcp6": True, + "set-name": "eth0", + } + }, +@@ -293,6 +295,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "ethernets": { + "eth0": { + "dhcp4": True, ++ "dhcp6": True, + "match": {"macaddress": mac}, + "set-name": "eth0", + } +@@ -359,6 +362,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "ethernets": { + "ens3": { + "dhcp4": True, ++ "dhcp6": True, + "match": {"name": "ens3"}, + "set-name": "ens3", + } +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index fb4c863c..d9ef493b 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -4339,6 +4339,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "ethernets": { + "eth0": { + "dhcp4": True, ++ "dhcp6": True, + "set-name": "eth0", + "match": { + "macaddress": "00:11:22:33:44:55", +@@ -4423,6 +4424,9 @@ iface lo inet loopback + + auto eth0 + iface eth0 inet dhcp ++ ++# control-alias eth0 ++iface eth0 inet6 dhcp + """ + self.assertEqual(expected.lstrip(), contents.lstrip()) + +@@ -4512,6 +4516,9 @@ iface lo inet loopback + + auto eth1 + iface eth1 inet dhcp ++ ++# control-alias eth1 ++iface eth1 inet6 dhcp + """ + self.assertEqual(expected.lstrip(), contents.lstrip()) + +@@ -4736,7 +4743,9 @@ class TestRhelSysConfigRendering(CiTestCase): + AUTOCONNECT_PRIORITY=120 + BOOTPROTO=dhcp + DEVICE=eth1000 ++DHCPV6C=yes + HWADDR=07-1c-c6-75-a4-be ++IPV6INIT=yes + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -5646,7 +5655,8 @@ class TestOpenSuseSysConfigRendering(CiTestCase): + expected_content = """ + # Created by cloud-init automatically, do not edit. + # +-BOOTPROTO=dhcp4 ++BOOTPROTO=dhcp ++DHCLIENT6_MODE=managed + LLADDR=07-1c-c6-75-a4-be + STARTMODE=auto + """.lstrip() +@@ -6032,7 +6042,11 @@ class TestNetworkManagerRendering(CiTestCase): + + [ipv4] + method=auto +- may-fail=false ++ may-fail=true ++ ++ [ipv6] ++ method=auto ++ may-fail=true + + """ + ), +@@ -6298,6 +6312,9 @@ iface lo inet loopback + + auto eth1000 + iface eth1000 inet dhcp ++ ++# control-alias eth1000 ++iface eth1000 inet6 dhcp + """ + self.assertEqual(expected.lstrip(), contents.lstrip()) + +@@ -6357,6 +6374,7 @@ class TestNetplanNetRendering: + ethernets: + eth1000: + dhcp4: true ++ dhcp6: true + match: + macaddress: 07-1c-c6-75-a4-be + set-name: eth1000 +@@ -7856,7 +7874,7 @@ class TestNetworkdNetRendering(CiTestCase): + Name=eth1000 + MACAddress=07-1c-c6-75-a4-be + [Network] +- DHCP=ipv4""" ++ DHCP=yes""" + ).rstrip(" ") + + expected = self.create_conf_dict(expected.splitlines()) diff --git a/0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch b/0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch new file mode 100644 index 0000000..40c2490 --- /dev/null +++ b/0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch @@ -0,0 +1,113 @@ +From c0df864e373e1e34bf23c4869acdf7d20aea7aaf Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Thu, 7 Dec 2023 02:39:51 +0530 +Subject: [PATCH] net/nm: check for presence of ifcfg files when nm connection + files are absent (#4645) + +On systems that use network manager to manage connections and activate network +interfaces, they may also use ifcfg files for configuring +interfaces using ifcfg-rh network manager plugin. When network manager is used +as the activator, we need to also check for the presence of ifcfg interface +config file when the network manager connection file is absent and if ifcfg-rh +plugin is present. +Hence, with this change, network manager activator first tries to use network +manager connection files to bring up or bring down the interface. If the +connection files are not present and if ifcfg-rh plugin is present, it tries to +use ifcfg files for the interface. If the plugin or the ifcfg files are not +present, the activator fails to activate or deactivate the interface and it +bails out with warning log. + +Fixes: GH-4640 + +Signed-off-by: Ani Sinha +(cherry picked from commit d1d5166895da471cff3606c70d4e8ab6eec1c006) +--- + cloudinit/net/activators.py | 7 +++++++ + cloudinit/net/network_manager.py | 33 ++++++++++++++++++++++++++++++-- + 2 files changed, 38 insertions(+), 2 deletions(-) + +diff --git a/cloudinit/net/activators.py b/cloudinit/net/activators.py +index e69da40d..dd858862 100644 +--- a/cloudinit/net/activators.py ++++ b/cloudinit/net/activators.py +@@ -117,6 +117,13 @@ class NetworkManagerActivator(NetworkActivator): + from cloudinit.net.network_manager import conn_filename + + filename = conn_filename(device_name) ++ if filename is None: ++ LOG.warning( ++ "Unable to find an interface config file. " ++ "Unable to bring up interface." ++ ) ++ return False ++ + cmd = ["nmcli", "connection", "load", filename] + if _alter_interface(cmd, device_name): + cmd = ["nmcli", "connection", "up", "filename", filename] +diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py +index 8a99eb3a..76a0ac15 100644 +--- a/cloudinit/net/network_manager.py ++++ b/cloudinit/net/network_manager.py +@@ -17,10 +17,12 @@ from typing import Optional + from cloudinit import subp, util + from cloudinit.net import is_ipv6_address, renderer, subnet_is_ipv6 + from cloudinit.net.network_state import NetworkState ++from cloudinit.net.sysconfig import available_nm_ifcfg_rh + + NM_RUN_DIR = "/etc/NetworkManager" + NM_LIB_DIR = "/usr/lib/NetworkManager" + NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf" ++IFCFG_CFG_FILE = "/etc/sysconfig/network-scripts" + NM_IPV6_ADDR_GEN_CONF = """# This is generated by cloud-init. Do not edit. + # + [.config] +@@ -442,7 +444,7 @@ class Renderer(renderer.Renderer): + for con_id, conn in self.connections.items(): + if not conn.valid(): + continue +- name = conn_filename(con_id, target) ++ name = nm_conn_filename(con_id, target) + util.write_file(name, conn.dump(), 0o600) + + # Select EUI64 to be used by default by NM for creating the address +@@ -452,12 +454,39 @@ class Renderer(renderer.Renderer): + ) + + +-def conn_filename(con_id, target=None): ++def nm_conn_filename(con_id, target=None): + target_con_dir = subp.target_path(target, NM_RUN_DIR) + con_file = f"cloud-init-{con_id}.nmconnection" + return f"{target_con_dir}/system-connections/{con_file}" + + ++def sysconfig_conn_filename(devname, target=None): ++ target_con_dir = subp.target_path(target, IFCFG_CFG_FILE) ++ con_file = f"ifcfg-{devname}" ++ return f"{target_con_dir}/{con_file}" ++ ++ ++def conn_filename(devname): ++ """ ++ This function returns the name of the interface config file. ++ It first checks for presence of network manager connection file. ++ If absent and ifcfg-rh plugin for network manager is available, ++ it returns the name of the ifcfg file if it is present. If the ++ plugin is not present or the plugin is present but ifcfg file is ++ not, it returns None. ++ This function is called from NetworkManagerActivator class in ++ activators.py. ++ """ ++ conn_file = nm_conn_filename(devname) ++ # If the network manager connection file is absent, also check for ++ # presence of ifcfg files for the same interface (if nm-ifcfg-rh plugin is ++ # present, network manager can handle ifcfg files). If both network manager ++ # connection file and ifcfg files are absent, return None. ++ if not os.path.isfile(conn_file) and available_nm_ifcfg_rh(): ++ conn_file = sysconfig_conn_filename(devname) ++ return conn_file if os.path.isfile(conn_file) else None ++ ++ + def cloud_init_nm_conf_filename(target=None): + target_con_dir = subp.target_path(target, NM_RUN_DIR) + conf_file = "30-cloud-init-ip6-addr-gen-mode.conf" diff --git a/0007-test-jsonschema-Pin-jsonschema-version-4781.patch b/0007-test-jsonschema-Pin-jsonschema-version-4781.patch new file mode 100644 index 0000000..ad7e5d6 --- /dev/null +++ b/0007-test-jsonschema-Pin-jsonschema-version-4781.patch @@ -0,0 +1,38 @@ +From e5258b60a3dbf44ef1faac91db2b45dab09de0b5 Mon Sep 17 00:00:00 2001 +From: Brett Holman +Date: Tue, 16 Jan 2024 12:43:17 -0700 +Subject: [PATCH] test(jsonschema): Pin jsonschema version (#4781) + +Release 4.21.0 broke tests + +(cherry picked from commit 034a5cdf10582da0492321f861b2b8b42182a54e) +--- + requirements.txt | 2 +- + test-requirements.txt | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/requirements.txt b/requirements.txt +index edec46a7..a095de18 100644 +--- a/requirements.txt ++++ b/requirements.txt +@@ -28,7 +28,7 @@ requests + jsonpatch + + # For validating cloud-config sections per schema definitions +-jsonschema ++jsonschema<=4.20.0 + + # Used by DataSourceVMware to inspect the host's network configuration during + # the "setup()" function. +diff --git a/test-requirements.txt b/test-requirements.txt +index 19488b94..46a98b4c 100644 +--- a/test-requirements.txt ++++ b/test-requirements.txt +@@ -9,6 +9,6 @@ pytest!=7.3.2 + pytest-cov + pytest-mock + setuptools +-jsonschema ++jsonschema<=4.20.0 + responses + passlib diff --git a/cloud-init.spec b/cloud-init.spec index a52c0ad..4cab542 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -1,6 +1,6 @@ Name: cloud-init Version: 23.4 -Release: 2%{?dist} +Release: 3%{?dist} Summary: Cloud instance init scripts License: ASL 2.0 or GPLv3 URL: http://launchpad.net/cloud-init @@ -11,6 +11,10 @@ Source1: cloud-init-tmpfiles.conf Patch1: 0001-Add-initial-redhat-changes.patch Patch2: 0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch Patch3: 0003-Setting-autoconnect-priority-setting-for-network-scr.patch +Patch4: 0004-net-network_manager-do-not-set-may-fail-to-False-for.patch +Patch5: 0005-net-allow-dhcp6-configuration-from-generate_fallback.patch +Patch6: 0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch +Patch7: 0007-test-jsonschema-Pin-jsonschema-version-4781.patch BuildArch: noarch @@ -228,6 +232,14 @@ fi %config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf %changelog +* Wed Jan 17 2024 Camilla Conte - 23.4-3 +- 0004-net-network_manager-do-not-set-may-fail-to-False-for.patch [RHEL-21629] +- 0005-net-allow-dhcp6-configuration-from-generate_fallback.patch [RHEL-21629] +- Resolves: RHEL-21629 +- 0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch [RHEL-17609] +- Resolves: RHEL-17609 +- 0007-test-jsonschema-Pin-jsonschema-version-4781.patch + * Wed Jan 10 2024 Camilla Conte - 23.4-2 - 0003-Setting-autoconnect-priority-setting-for-network-scr.patch [RHEL-18313] - Resolves: RHEL-18313