diff --git a/SOURCES/ci-Fix-import-error-for-passlib-on-Python-3.13.patch b/SOURCES/ci-Fix-import-error-for-passlib-on-Python-3.13.patch new file mode 100644 index 0000000..b6e54c5 --- /dev/null +++ b/SOURCES/ci-Fix-import-error-for-passlib-on-Python-3.13.patch @@ -0,0 +1,23 @@ +From 09b70436b3a0aae1fe24fdde6e8cdd7ee98d9c15 Mon Sep 17 00:00:00 2001 +From: Brett Holman +Date: Tue, 5 Dec 2023 16:40:03 -0700 +Subject: [PATCH] fix(python3.13): Fix import error for passlib on Python 3.13 + (#4669) + +--- + cloudinit/sources/DataSourceAzure.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py +index 11c14e2001f..4c5780f767d 100644 +--- a/cloudinit/sources/DataSourceAzure.py ++++ b/cloudinit/sources/DataSourceAzure.py +@@ -58,7 +58,7 @@ + ) + except (ImportError, AttributeError): + try: +- import passlib ++ import passlib.hash + + blowfish_hash = passlib.hash.sha512_crypt.hash + except ImportError: diff --git a/SOURCES/ci-Fix-metric-setting-for-ifcfg-network-connections-for.patch b/SOURCES/ci-Fix-metric-setting-for-ifcfg-network-connections-for.patch new file mode 100644 index 0000000..7cc3bc1 --- /dev/null +++ b/SOURCES/ci-Fix-metric-setting-for-ifcfg-network-connections-for.patch @@ -0,0 +1,146 @@ +From 2da948152c4b7b2f30dc6189d0072f7562df1ad5 Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Fri, 4 Oct 2024 02:38:23 +0530 +Subject: [PATCH 1/3] Fix metric setting for ifcfg network connections for rhel + (#5777) + +RH-Author: xiachen +RH-MergeRequest: 112: Fix metric setting for ifcfg network connections for rhel (#5777) +RH-Jira: RHEL-65016 +RH-Acked-by: Emanuele Giuseppe Esposito +RH-Acked-by: Ani Sinha +RH-Commit: [1/1] ee573dfb2dccc59f2c9b74ca3f95026f96c49998 (xiachen/cloud-init-centos) + +Most RHEL systems use Network manager to bring up manage network connections. +Network manager does not recognize "METRIC" option for network connections. +It uses IPV4_ROUTE_METRIC and IPV6_ROUTE_METRIC options. Please see +https://people.freedesktop.org/~lkundrak/nm-docs/nm-settings-ifcfg-rh.html + +This change ensures that cloud-init generates ifcfg network connection files +with IPV{4/6}_ROUTE_METRIC options that are compatible with RHEL and +network manager. + +Fixes GH-5776 + +(cherry picked from commit a399f4b0815234e3fe11255178c737902b2d243d) + +Signed-off-by: Amy Chen +--- + cloudinit/net/sysconfig.py | 21 ++++++++++++++++++--- + tests/unittests/test_net.py | 37 ++++++++++++++++++++----------------- + 2 files changed, 38 insertions(+), 20 deletions(-) + +diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py +index 32ee7901..503b6993 100644 +--- a/cloudinit/net/sysconfig.py ++++ b/cloudinit/net/sysconfig.py +@@ -205,7 +205,7 @@ class Route(ConfigMap): + ) + metric_key = "METRIC" + index + if metric_key in self._conf: +- metric_value = str(self._conf["METRIC" + index]) ++ metric_value = str(self._conf[metric_key]) + buf.write( + "%s=%s\n" + % ("METRIC" + str(reindex), _quote_value(metric_value)) +@@ -549,7 +549,12 @@ class Renderer(renderer.Renderer): + subnet_type = subnet.get("type") + # metric may apply to both dhcp and static config + if "metric" in subnet: +- if flavor != "suse": ++ if flavor == "rhel": ++ if subnet_is_ipv6(subnet): ++ iface_cfg["IPV6_ROUTE_METRIC"] = subnet["metric"] ++ else: ++ iface_cfg["IPV4_ROUTE_METRIC"] = subnet["metric"] ++ elif flavor != "suse": + iface_cfg["METRIC"] = subnet["metric"] + if subnet_type in ["dhcp", "dhcp4"]: + # On SUSE distros 'DHCLIENT_SET_DEFAULT_ROUTE' is a global +@@ -656,7 +661,17 @@ class Renderer(renderer.Renderer): + iface_cfg["GATEWAY"] = route["gateway"] + route_cfg.has_set_default_ipv4 = True + if "metric" in route: +- iface_cfg["METRIC"] = route["metric"] ++ if flavor == "rhel": ++ if subnet_is_ipv6(subnet): ++ iface_cfg["IPV6_ROUTE_METRIC"] = route[ ++ "metric" ++ ] ++ else: ++ iface_cfg["IPV4_ROUTE_METRIC"] = route[ ++ "metric" ++ ] ++ else: ++ iface_cfg["METRIC"] = route["metric"] + + else: + # add default routes only to ifcfg files, not +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index de149f5e..00198232 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -1345,7 +1345,7 @@ NETWORK_CONFIGS = { + HWADDR=c0:d6:9f:2c:e8:80 + IPADDR=192.168.21.3 + NETMASK=255.255.255.0 +- METRIC=10000 ++ IPV4_ROUTE_METRIC=10000 + ONBOOT=yes + TYPE=Ethernet + USERCTL=no""" +@@ -1519,7 +1519,7 @@ NETWORK_CONFIGS = { + HWADDR=c0:d6:9f:2c:e8:80 + IPADDR=192.168.21.3 + NETMASK=255.255.255.0 +- METRIC=10000 ++ IPV4_ROUTE_METRIC=10000 + ONBOOT=yes + TYPE=Ethernet + USERCTL=no""" +@@ -6072,24 +6072,27 @@ USERCTL=no + } + }, + } +- expected = { +- "ifcfg-eno1": textwrap.dedent( +- """\ +- AUTOCONNECT_PRIORITY=120 +- BOOTPROTO=dhcp +- DEVICE=eno1 +- HWADDR=07-1c-c6-75-a4-be +- METRIC=100 +- ONBOOT=yes +- TYPE=Ethernet +- USERCTL=no +- """ +- ), +- } + for dhcp_ver in ("dhcp4", "dhcp6"): ++ expected = { ++ "ifcfg-eno1": textwrap.dedent( ++ """\ ++ AUTOCONNECT_PRIORITY=120 ++ BOOTPROTO=dhcp ++ DEVICE=eno1 ++ HWADDR=07-1c-c6-75-a4-be ++ ONBOOT=yes ++ TYPE=Ethernet ++ USERCTL=no ++ """ ++ ), ++ } + v2data = copy.deepcopy(v2base) + if dhcp_ver == "dhcp6": +- expected["ifcfg-eno1"] += "IPV6INIT=yes\nDHCPV6C=yes\n" ++ expected[ ++ "ifcfg-eno1" ++ ] += "IPV6INIT=yes\nDHCPV6C=yes\nIPV6_ROUTE_METRIC=100\n" ++ else: ++ expected["ifcfg-eno1"] += "IPV4_ROUTE_METRIC=100\n" + v2data["ethernets"]["eno1"].update( + {dhcp_ver: True, "{0}-overrides".format(dhcp_ver): overrides} + ) +-- +2.39.3 + diff --git a/SOURCES/ci-Prevent-NM-from-handling-DNS-when-network-interfaces.patch b/SOURCES/ci-Prevent-NM-from-handling-DNS-when-network-interfaces.patch new file mode 100644 index 0000000..781bcef --- /dev/null +++ b/SOURCES/ci-Prevent-NM-from-handling-DNS-when-network-interfaces.patch @@ -0,0 +1,248 @@ +From ab36aacfb2f98d865d9e03df81f9102b04d307dd Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Tue, 5 Nov 2024 04:07:36 +0530 +Subject: [PATCH] Prevent NM from handling DNS when network interfaces have DNS + config (#5846) + +RH-Author: Ani Sinha +RH-MergeRequest: 117: Prevent NM from handling DNS when network interfaces have DNS config (#5846) +RH-Jira: RHEL-65769 +RH-Acked-by: Emanuele Giuseppe Esposito +RH-Acked-by: Miroslav Rezanina +RH-Commit: [1/1] cc175ec567ba5500f2a69d7943e8d5ee5c3822c8 (anisinha/cloud-init) + +In the change under PR #5401, we use global DNS configuration as well as +DNS and search domain information from interface config and use it to populate +/etc/resolv.conf. Therefore, if either or both global DNS/search domain config +is present along with per-interface DNS/search domain information, we should add +a network manager configuration to prevent network manager from manipulating +/etc/resolv.conf. +This is in addition to what we already do when only global DNS data is +configured. + +Fixes bug added in 1b8030e0 . + +Signed-off-by: Ani Sinha +(cherry picked from commit 2df49b652471999434f06d9d83ed9db8b4055895) +--- + cloudinit/net/sysconfig.py | 28 +++++-- + tests/unittests/test_net.py | 158 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 181 insertions(+), 5 deletions(-) + +diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py +index 96652e15..363d052a 100644 +--- a/cloudinit/net/sysconfig.py ++++ b/cloudinit/net/sysconfig.py +@@ -905,17 +905,35 @@ class Renderer(renderer.Renderer): + + @staticmethod + def _render_networkmanager_conf(network_state, templates=None): ++ iface_dns = False + content = networkmanager_conf.NetworkManagerConf("") +- +- # If DNS server information is provided, configure +- # NetworkManager to not manage dns, so that /etc/resolv.conf +- # does not get clobbered. ++ # check if there is interface specific DNS information configured ++ for iface in network_state.iter_interfaces(): ++ for subnet in iface["subnets"]: ++ if "dns_nameservers" in subnet or "dns_search" in subnet: ++ iface_dns = True ++ break ++ if ( ++ not iface_dns ++ and "dns" in iface ++ and (iface["dns"]["nameservers"] or iface["dns"]["search"]) ++ ): ++ iface_dns = True ++ break ++ ++ # If DNS server and/or dns search information is provided either ++ # globally or per interface basis, configure NetworkManager to ++ # not manage dns, so that /etc/resolv.conf does not get clobbered. + # This is not required for NetworkManager renderer as it + # does not write /etc/resolv.conf directly. DNS information is + # written to the interface keyfile and NetworkManager is then + # responsible for using the DNS information from the keyfile, + # including managing /etc/resolv.conf. +- if network_state.dns_nameservers: ++ if ( ++ network_state.dns_nameservers ++ or network_state.dns_searchdomains ++ or iface_dns ++ ): + content.set_section_keypair("main", "dns", "none") + + if len(content) == 0: +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index 8a75c42b..215807ba 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -967,6 +967,164 @@ dns = none + ), + ], + }, ++ { ++ "in_data": { ++ "networks": [ ++ { ++ "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4", ++ "type": "ipv4", ++ "netmask": "255.255.252.0", ++ "link": "eth0", ++ "routes": [ ++ { ++ "netmask": "0.0.0.0", ++ "network": "0.0.0.0", ++ "gateway": "172.19.3.254", ++ } ++ ], ++ "ip_address": "172.19.1.34", ++ "dns_search": ["example3.com"], ++ "dns_nameservers": ["172.19.0.12"], ++ "id": "network0", ++ } ++ ], ++ "links": [ ++ { ++ "ethernet_mac_address": "fa:16:3e:ed:9a:59", ++ "mtu": None, ++ "type": "physical", ++ "id": "eth0", ++ }, ++ ], ++ }, ++ "in_macs": { ++ "fa:16:3e:ed:9a:59": "eth0", ++ }, ++ "out_sysconfig_opensuse": [ ++ ( ++ "etc/sysconfig/network/ifcfg-eth0", ++ """ ++# Created by cloud-init automatically, do not edit. ++# ++BOOTPROTO=static ++IPADDR=172.19.1.34 ++LLADDR=fa:16:3e:ed:9a:59 ++NETMASK=255.255.252.0 ++STARTMODE=auto ++""".lstrip(), ++ ), ++ ( ++ "etc/resolv.conf", ++ """ ++; Created by cloud-init automatically, do not edit. ++; ++nameserver 172.19.0.12 ++search example3.com ++""".lstrip(), ++ ), ++ ( ++ "etc/NetworkManager/conf.d/99-cloud-init.conf", ++ """ ++# Created by cloud-init 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", ++ """ ++# Created by cloud-init automatically, do not edit. ++# ++AUTOCONNECT_PRIORITY=120 ++BOOTPROTO=none ++DEFROUTE=yes ++DEVICE=eth0 ++DNS1=172.19.0.12 ++DOMAIN=example3.com ++GATEWAY=172.19.3.254 ++HWADDR=fa:16:3e:ed:9a:59 ++IPADDR=172.19.1.34 ++NETMASK=255.255.252.0 ++ONBOOT=yes ++TYPE=Ethernet ++USERCTL=no ++""".lstrip(), ++ ), ++ ( ++ "etc/resolv.conf", ++ """ ++; Created by cloud-init automatically, do not edit. ++; ++nameserver 172.19.0.12 ++search example3.com ++""".lstrip(), ++ ), ++ ( ++ "etc/NetworkManager/conf.d/99-cloud-init.conf", ++ """ ++# Created by cloud-init 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', ++ ] ++ ), ++ ), ++ ], ++ "expected_network_manager": [ ++ ( ++ "".join( ++ [ ++ "etc/NetworkManager/system-connections", ++ "/cloud-init-eth0.nmconnection", ++ ] ++ ), ++ """ ++# Generated by cloud-init. Changes will be lost. ++ ++[connection] ++id=cloud-init eth0 ++uuid=1dd9a779-d327-56e1-8454-c65e2556c12c ++autoconnect-priority=120 ++type=ethernet ++ ++[user] ++org.freedesktop.NetworkManager.origin=cloud-init ++ ++[ethernet] ++mac-address=FA:16:3E:ED:9A:59 ++ ++[ipv4] ++method=manual ++may-fail=false ++address1=172.19.1.34/22 ++route1=0.0.0.0/0,172.19.3.254 ++dns=172.19.0.12; ++dns-search=example3.com; ++ ++""".lstrip(), ++ ), ++ ], ++ }, + { + "in_data": { + "services": [{"type": "dns", "address": "172.19.0.12"}], +-- +2.39.3 + diff --git a/SOURCES/ci-fix-Render-bridges-correctly-for-v2-on-sysconfig-wit.patch b/SOURCES/ci-fix-Render-bridges-correctly-for-v2-on-sysconfig-wit.patch new file mode 100644 index 0000000..c86895b --- /dev/null +++ b/SOURCES/ci-fix-Render-bridges-correctly-for-v2-on-sysconfig-wit.patch @@ -0,0 +1,306 @@ +From 60eca5a45a35982f42db58dd0d6d53bd2587e477 Mon Sep 17 00:00:00 2001 +From: James Falcon +Date: Thu, 10 Oct 2024 23:19:28 -0500 +Subject: [PATCH 2/3] fix: Render bridges correctly for v2 on sysconfig with + set-name (#5674) + +RH-Author: xiachen +RH-MergeRequest: 114: fix: Render bridges correctly for v2 on sysconfig with set-name (#5674) +RH-Jira: RHEL-65019 +RH-Acked-by: Emanuele Giuseppe Esposito +RH-Acked-by: Ani Sinha +RH-Commit: [1/2] 4171be9d48c4c4f7b8aa8d231cea8591daec9c93 (xiachen/cloud-init-centos) + +When listing interfaces in v2 format, we should expect to be able to +reference other interfaces using the name in the configuration, not +the name the interface will eventually take. This was broken when +using `set-name`. + +To fix this, we now store the configuration id alongside the eventual +name, and reference that instead of the name. + +Fixes GH-5574 + +(cherry picked from commit a8f69409e5cebf43767d3bb54fbad7ced1e8fc7b) +Signed-off-by: Amy Chen +--- + cloudinit/net/eni.py | 6 +++ + cloudinit/net/network_state.py | 30 ++++------- + cloudinit/net/sysconfig.py | 24 ++++++--- + tests/unittests/test_net.py | 96 ++++++++++++++++++++++++++++++++++ + 4 files changed, 128 insertions(+), 28 deletions(-) + +diff --git a/cloudinit/net/eni.py b/cloudinit/net/eni.py +index 59dc395f..fa0b47af 100644 +--- a/cloudinit/net/eni.py ++++ b/cloudinit/net/eni.py +@@ -5,6 +5,7 @@ import glob + import logging + import os + import re ++from contextlib import suppress + from typing import Optional + + from cloudinit import subp, util +@@ -421,6 +422,11 @@ class Renderer(renderer.Renderer): + return content + + def _render_iface(self, iface, render_hwaddress=False): ++ iface = copy.deepcopy(iface) ++ ++ # Remove irrelevant keys ++ with suppress(KeyError): ++ iface.pop("config_id") + sections = [] + subnets = iface.get("subnets", {}) + accept_ra = iface.pop("accept-ra", None) +diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py +index 9f34467b..fb08491f 100644 +--- a/cloudinit/net/network_state.py ++++ b/cloudinit/net/network_state.py +@@ -411,6 +411,7 @@ class NetworkStateInterpreter: + wakeonlan = util.is_true(wakeonlan) + iface.update( + { ++ "config_id": command.get("config_id"), + "name": command.get("name"), + "type": command.get("type"), + "mac_address": command.get("mac_address"), +@@ -424,7 +425,8 @@ class NetworkStateInterpreter: + "wakeonlan": wakeonlan, + } + ) +- self._network_state["interfaces"].update({command.get("name"): iface}) ++ iface_key = command.get("config_id", command.get("name")) ++ self._network_state["interfaces"].update({iface_key: iface}) + self.dump_network_state() + + @ensure_command_keys(["name", "vlan_id", "vlan_link"]) +@@ -712,6 +714,7 @@ class NetworkStateInterpreter: + + for eth, cfg in command.items(): + phy_cmd = { ++ "config_id": eth, + "type": "physical", + } + match = cfg.get("match", {}) +@@ -800,28 +803,15 @@ class NetworkStateInterpreter: + def _v2_common(self, cfg) -> None: + LOG.debug("v2_common: handling config:\n%s", cfg) + for iface, dev_cfg in cfg.items(): +- if "set-name" in dev_cfg: +- set_name_iface = dev_cfg.get("set-name") +- if set_name_iface: +- iface = set_name_iface + if "nameservers" in dev_cfg: +- search = dev_cfg.get("nameservers").get("search", []) +- dns = dev_cfg.get("nameservers").get("addresses", []) ++ search = dev_cfg.get("nameservers").get("search") ++ dns = dev_cfg.get("nameservers").get("addresses") + name_cmd = {"type": "nameserver"} +- if len(search) > 0: +- name_cmd.update({"search": search}) +- if len(dns) > 0: +- name_cmd.update({"address": dns}) ++ if search: ++ name_cmd["search"] = search ++ if dns: ++ name_cmd["address"] = dns + self.handle_nameserver(name_cmd) +- +- mac_address: Optional[str] = dev_cfg.get("match", {}).get( +- "macaddress" +- ) +- if mac_address: +- real_if_name = find_interface_name_from_mac(mac_address) +- if real_if_name: +- iface = real_if_name +- + self._handle_individual_nameserver(name_cmd, iface) + + def _handle_bond_bridge(self, command, cmd_type=None): +diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py +index 503b6993..96652e15 100644 +--- a/cloudinit/net/sysconfig.py ++++ b/cloudinit/net/sysconfig.py +@@ -6,7 +6,7 @@ import io + import logging + import os + import re +-from typing import Mapping, Optional ++from typing import Dict, Optional + + from cloudinit import subp, util + from cloudinit.distros.parsers import networkmanager_conf, resolv_conf +@@ -721,7 +721,7 @@ class Renderer(renderer.Renderer): + ): + physical_filter = renderer.filter_by_physical + for iface in network_state.iter_interfaces(physical_filter): +- iface_name = iface["name"] ++ iface_name = iface.get("config_id") or iface["name"] + iface_subnets = iface.get("subnets", []) + iface_cfg = iface_contents[iface_name] + route_cfg = iface_cfg.routes +@@ -926,7 +926,9 @@ class Renderer(renderer.Renderer): + return out + + @classmethod +- def _render_bridge_interfaces(cls, network_state, iface_contents, flavor): ++ def _render_bridge_interfaces( ++ cls, network_state: NetworkState, iface_contents, flavor ++ ): + bridge_key_map = { + old_k: new_k + for old_k, new_k in cls.cfg_key_maps[flavor].items() +@@ -1007,23 +1009,29 @@ class Renderer(renderer.Renderer): + + @classmethod + def _render_sysconfig( +- cls, base_sysconf_dir, network_state, flavor, templates=None ++ cls, ++ base_sysconf_dir, ++ network_state: NetworkState, ++ flavor, ++ templates=None, + ): + """Given state, return /etc/sysconfig files + contents""" + if not templates: + templates = cls.templates +- iface_contents: Mapping[str, NetInterface] = {} ++ iface_contents: Dict[str, NetInterface] = {} + for iface in network_state.iter_interfaces(): + if iface["type"] == "loopback": + continue +- iface_name = iface["name"] +- iface_cfg = NetInterface(iface_name, base_sysconf_dir, templates) ++ config_id: str = iface.get("config_id") or iface["name"] ++ iface_cfg = NetInterface( ++ iface["name"], base_sysconf_dir, templates ++ ) + if flavor == "suse": + iface_cfg.drop("DEVICE") + # If type detection fails it is considered a bug in SUSE + iface_cfg.drop("TYPE") + cls._render_iface_shared(iface, iface_cfg, flavor) +- iface_contents[iface_name] = iface_cfg ++ iface_contents[config_id] = iface_cfg + cls._render_physical_interfaces(network_state, iface_contents, flavor) + cls._render_bond_interfaces(network_state, iface_contents, flavor) + cls._render_vlan_interfaces(network_state, iface_contents, flavor) +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index 00198232..41e6fa56 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -4489,6 +4489,95 @@ iface bond0 inet6 static + """ + ), + }, ++ "v2-bridges-set-name": { ++ "yaml": textwrap.dedent( ++ """\ ++ version: 2 ++ ethernets: ++ baremetalport: ++ match: ++ macaddress: 52:54:00:bd:8f:cb ++ set-name: baremetal0 ++ provisioningport: ++ match: ++ macaddress: 52:54:00:25:ae:12 ++ set-name: provisioning0 ++ bridges: ++ baremetal: ++ addresses: ++ - fc00:1:1::2/64 ++ interfaces: ++ - baremetalport ++ provisioning: ++ addresses: ++ - fc00:1:2::2/64 ++ interfaces: ++ - provisioningport ++ """ ++ ), ++ "expected_sysconfig_rhel": { ++ "ifcfg-baremetal": textwrap.dedent( ++ """\ ++ # Created by cloud-init automatically, do not edit. ++ # ++ AUTOCONNECT_PRIORITY=120 ++ BOOTPROTO=none ++ DEVICE=baremetal ++ IPV6ADDR=fc00:1:1::2/64 ++ IPV6INIT=yes ++ IPV6_AUTOCONF=no ++ IPV6_FORCE_ACCEPT_RA=no ++ ONBOOT=yes ++ TYPE=Bridge ++ USERCTL=no ++ """ ++ ), ++ "ifcfg-baremetal0": textwrap.dedent( ++ """\ ++ # Created by cloud-init automatically, do not edit. ++ # ++ AUTOCONNECT_PRIORITY=120 ++ BOOTPROTO=none ++ BRIDGE=baremetal ++ DEVICE=baremetal0 ++ HWADDR=52:54:00:bd:8f:cb ++ ONBOOT=yes ++ TYPE=Ethernet ++ USERCTL=no ++ """ ++ ), ++ "ifcfg-provisioning": textwrap.dedent( ++ """\ ++ # Created by cloud-init automatically, do not edit. ++ # ++ AUTOCONNECT_PRIORITY=120 ++ BOOTPROTO=none ++ DEVICE=provisioning ++ IPV6ADDR=fc00:1:2::2/64 ++ IPV6INIT=yes ++ IPV6_AUTOCONF=no ++ IPV6_FORCE_ACCEPT_RA=no ++ ONBOOT=yes ++ TYPE=Bridge ++ USERCTL=no ++ """ ++ ), ++ "ifcfg-provisioning0": textwrap.dedent( ++ """\ ++ # Created by cloud-init automatically, do not edit. ++ # ++ AUTOCONNECT_PRIORITY=120 ++ BOOTPROTO=none ++ BRIDGE=provisioning ++ DEVICE=provisioning0 ++ HWADDR=52:54:00:25:ae:12 ++ ONBOOT=yes ++ TYPE=Ethernet ++ USERCTL=no ++ """ ++ ), ++ }, ++ }, + } + + +@@ -5558,6 +5647,13 @@ USERCTL=no + self._compare_files_to_expected(entry[self.expected_name], found) + self._assert_headers(found) + ++ def test_bridges_set_name_config(self): ++ entry = NETWORK_CONFIGS["v2-bridges-set-name"] ++ 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_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) +-- +2.39.3 + diff --git a/SOURCES/ci-fix-Render-v2-bridges-correctly-on-network-manager-w.patch b/SOURCES/ci-fix-Render-v2-bridges-correctly-on-network-manager-w.patch new file mode 100644 index 0000000..8aa2305 --- /dev/null +++ b/SOURCES/ci-fix-Render-v2-bridges-correctly-on-network-manager-w.patch @@ -0,0 +1,160 @@ +From 59079c817ead856135ce40698f4d350a425cd65e Mon Sep 17 00:00:00 2001 +From: James Falcon +Date: Fri, 11 Oct 2024 13:58:19 -0500 +Subject: [PATCH 3/3] fix: Render v2 bridges correctly on network-manager with + set-name (#5740) + +RH-Author: xiachen +RH-MergeRequest: 114: fix: Render bridges correctly for v2 on sysconfig with set-name (#5674) +RH-Jira: RHEL-65019 +RH-Acked-by: Emanuele Giuseppe Esposito +RH-Acked-by: Ani Sinha +RH-Commit: [2/2] a33642f97a8e5cb3816f17ce726187aa33825362 (xiachen/cloud-init-centos) + +Similar to the recent sysconfig fix, ensure bridges render correctly +for configs that contain `set-name`. + +Fixes GH-5717 + +(cherry picked from commit 9554338e6ecf49c66324cc637eaf0fa7bf10e407) +Signed-off-by: Amy Chen +--- + cloudinit/net/network_manager.py | 6 +- + tests/unittests/test_net.py | 94 ++++++++++++++++++++++++++++++++ + 2 files changed, 98 insertions(+), 2 deletions(-) + +diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py +index a13d4c14..67614399 100644 +--- a/cloudinit/net/network_manager.py ++++ b/cloudinit/net/network_manager.py +@@ -464,11 +464,13 @@ class Renderer(renderer.Renderer): + # interfaces that have UUIDs that can be linked to from related + # interfaces + for iface in network_state.iter_interfaces(): +- self.connections[iface["name"]] = NMConnection(iface["name"]) ++ conn_key = iface.get("config_id") or iface["name"] ++ self.connections[conn_key] = NMConnection(iface["name"]) + + # Now render the actual interface configuration + for iface in network_state.iter_interfaces(): +- conn = self.connections[iface["name"]] ++ conn_key = iface.get("config_id") or iface["name"] ++ conn = self.connections[conn_key] + conn.render_interface(iface, network_state, self) + + # And finally write the files +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index 41e6fa56..8a75c42b 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -4577,6 +4577,94 @@ iface bond0 inet6 static + """ + ), + }, ++ "expected_network_manager": { ++ "cloud-init-baremetal.nmconnection": textwrap.dedent( ++ """\ ++ # Generated by cloud-init. Changes will be lost. ++ ++ [connection] ++ id=cloud-init baremetal ++ uuid=e63eed9a-cd1c-55de-8d5e-1e80b756a482 ++ autoconnect-priority=120 ++ type=bridge ++ interface-name=baremetal ++ ++ [user] ++ org.freedesktop.NetworkManager.origin=cloud-init ++ ++ [bridge] ++ ++ [ipv6] ++ method=manual ++ may-fail=false ++ address1=fc00:1:1::2/64 ++ ++ """ ++ ), ++ "cloud-init-baremetalport.nmconnection": textwrap.dedent( ++ """\ ++ # Generated by cloud-init. Changes will be lost. ++ ++ [connection] ++ id=cloud-init baremetal0 ++ uuid=8e326690-51d6-5157-ab84-e4e822b06503 ++ autoconnect-priority=120 ++ type=ethernet ++ slave-type=bridge ++ master=e63eed9a-cd1c-55de-8d5e-1e80b756a482 ++ ++ [user] ++ org.freedesktop.NetworkManager.origin=cloud-init ++ ++ [ethernet] ++ mac-address=52:54:00:BD:8F:CB ++ ++ """ ++ ), ++ "cloud-init-provisioning.nmconnection": textwrap.dedent( ++ """\ ++ # Generated by cloud-init. Changes will be lost. ++ ++ [connection] ++ id=cloud-init provisioning ++ uuid=e5bd3f1a-cdcc-55d3-a6d8-88f1ba73bd0e ++ autoconnect-priority=120 ++ type=bridge ++ interface-name=provisioning ++ ++ [user] ++ org.freedesktop.NetworkManager.origin=cloud-init ++ ++ [bridge] ++ ++ [ipv6] ++ method=manual ++ may-fail=false ++ address1=fc00:1:2::2/64 ++ ++ """ ++ ), ++ "cloud-init-provisioningport.nmconnection": textwrap.dedent( ++ """\ ++ # Generated by cloud-init. Changes will be lost. ++ ++ [connection] ++ id=cloud-init provisioning0 ++ uuid=d79b7b70-e9df-596f-ace7-89537db45684 ++ autoconnect-priority=120 ++ type=ethernet ++ slave-type=bridge ++ master=e5bd3f1a-cdcc-55d3-a6d8-88f1ba73bd0e ++ ++ [user] ++ org.freedesktop.NetworkManager.origin=cloud-init ++ ++ [ethernet] ++ mac-address=52:54:00:25:AE:12 ++ ++ """ ++ ), ++ }, + }, + } + +@@ -6722,6 +6810,12 @@ class TestNetworkManagerRendering(CiTestCase): + entry[self.expected_name], self.expected_conf_d, found + ) + ++ def test_v2_bridges_set_name(self): ++ entry = NETWORK_CONFIGS["v2-bridges-set-name"] ++ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) ++ self._compare_files_to_expected( ++ entry[self.expected_name], self.expected_conf_d, found ++ ) + + @mock.patch( + "cloudinit.net.is_openvswitch_internal_interface", +-- +2.39.3 + diff --git a/SOURCES/ci-refactor-Ensure-internal-DNS-state-same-for-v1-and-v2.patch b/SOURCES/ci-refactor-Ensure-internal-DNS-state-same-for-v1-and-v2.patch new file mode 100644 index 0000000..0c3a8f7 --- /dev/null +++ b/SOURCES/ci-refactor-Ensure-internal-DNS-state-same-for-v1-and-v2.patch @@ -0,0 +1,78 @@ +From 436e6f5ce3fbb8b391a2158538873644058904e6 Mon Sep 17 00:00:00 2001 +From: James Falcon +Date: Tue, 9 Jan 2024 10:32:12 -0600 +Subject: [PATCH] refactor: Ensure internal DNS state same for v1 and v2 + (#4756) + +When defining interface-level DNS on the network state, v1 uses the +"nameservers" key whereas v2 was using an "addresses" key. +This commit updates the v2 parsing to set the key as "nameservers". + +Also update networkd renderer as this was only renderer using the v2 +"addresses" key. +--- + cloudinit/net/network_state.py | 2 +- + cloudinit/net/networkd.py | 13 ++++--------- + tests/unittests/net/test_network_state.py | 5 ++++- + 3 files changed, 9 insertions(+), 11 deletions(-) + +diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py +index b6851080bba..e35288b46de 100644 +--- a/cloudinit/net/network_state.py ++++ b/cloudinit/net/network_state.py +@@ -336,7 +336,7 @@ class NetworkStateInterpreter: + if iface: + nameservers, search = dns + iface["dns"] = { +- "addresses": nameservers, ++ "nameservers": nameservers, + "search": search, + } + +diff --git a/cloudinit/net/networkd.py b/cloudinit/net/networkd.py +index 0978849c898..29f466eda54 100644 +--- a/cloudinit/net/networkd.py ++++ b/cloudinit/net/networkd.py +@@ -221,12 +221,6 @@ class Renderer(renderer.Renderer): + def parse_dns(self, iface, cfg: CfgParser, ns: NetworkState): + sec = "Network" + +- dns_cfg_map = { +- "search": "Domains", +- "nameservers": "DNS", +- "addresses": "DNS", +- } +- + dns = iface.get("dns") + if not dns and ns.version == 1: + dns = { +@@ -236,9 +230,10 @@ class Renderer(renderer.Renderer): + elif not dns and ns.version == 2: + return + +- for k, v in dns_cfg_map.items(): +- if k in dns and dns[k]: +- cfg.update_section(sec, v, " ".join(dns[k])) ++ if dns.get("search"): ++ cfg.update_section(sec, "Domains", " ".join(dns["search"])) ++ if dns.get("nameservers"): ++ cfg.update_section(sec, "DNS", " ".join(dns["nameservers"])) + + def parse_dhcp_overrides(self, cfg: CfgParser, device, dhcp, version): + dhcp_config_maps = { +diff --git a/tests/unittests/net/test_network_state.py b/tests/unittests/net/test_network_state.py +index 7d304ca3ad5..74a6bb34c88 100644 +--- a/tests/unittests/net/test_network_state.py ++++ b/tests/unittests/net/test_network_state.py +@@ -258,7 +258,10 @@ class TestNetworkStateParseNameservers: + # If an interface was specified, DNS should be part of the interface + for iface in config.iter_interfaces(): + if iface["name"] == "eth1": +- assert iface["dns"]["addresses"] == ["192.168.1.1", "8.8.8.8"] ++ assert iface["dns"]["nameservers"] == [ ++ "192.168.1.1", ++ "8.8.8.8", ++ ] + assert iface["dns"]["search"] == ["spam.local"] + else: + assert "dns" not in iface diff --git a/SPECS/cloud-init.spec b/SPECS/cloud-init.spec index f41b97b..4b3401f 100644 --- a/SPECS/cloud-init.spec +++ b/SPECS/cloud-init.spec @@ -1,6 +1,6 @@ Name: cloud-init Version: 23.4 -Release: 19%{?dist}.alma.1 +Release: 19%{?dist}.4.alma.1 Summary: Cloud instance init scripts License: ASL 2.0 or GPLv3 URL: http://launchpad.net/cloud-init @@ -68,6 +68,17 @@ Patch33: ci-Revert-fix-vmware-Set-IPv6-to-dhcp-when-there-is-no-.patch # For RHEL-54686 - [RHEL-9.5] cloud-init schema validation fails. Patch34: ci-fix-Add-subnet-ipv4-ipv6-to-network-schema-5191.patch +Patch35: ci-Fix-metric-setting-for-ifcfg-network-connections-for.patch +Patch36: ci-Prevent-NM-from-handling-DNS-when-network-interfaces.patch +Patch37: ci-fix-Render-bridges-correctly-for-v2-on-sysconfig-wit.patch +Patch38: ci-fix-Render-v2-bridges-correctly-on-network-manager-w.patch + +# Patches were taken from: +# https://github.com/canonical/cloud-init/commit/09b70436b3a0aae1fe24fdde6e8cdd7ee98d9c15.patch +Patch39: ci-Fix-import-error-for-passlib-on-Python-3.13.patch +# https://github.com/canonical/cloud-init/commit/436e6f5ce3fbb8b391a2158538873644058904e6.patch +Patch40: ci-refactor-Ensure-internal-DNS-state-same-for-v1-and-v2.patch + # AlmaLinux OS patches Patch3100: 0031-Improvements-for-AlmaLinux-OS-and-CloudLinux-OS.patch @@ -284,6 +295,20 @@ fi %config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf %changelog +* Mon Dec 23 2024 Eduard Abdullin - 23.4-19.el9_5.4.alma.1 +- Fix import error for passlib on Python 3.13 + (#4669) +- Fix metric setting for ifcfg network connections for rhel + (#5777) +- fix: Render bridges correctly for v2 on sysconfig with + set-name (#5674) +- fix: Render v2 bridges correctly on network-manager with + set-name (#5740) +- Prevent NM from handling DNS when network interfaces have DNS + config (#5846) +- refactor: Ensure internal DNS state same for v1 and v2 + (#4756) + * Mon Sep 30 2024 Elkhan Mammadli - 23.4-19.alma.1 - 0031-Improvements-for-AlmaLinux-OS-and-CloudLinux-OS.patch