- 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)
This commit is contained in:
eabdullin 2024-12-23 12:00:37 +03:00
parent 0eba1956d3
commit 8e36dd5e7f
7 changed files with 987 additions and 1 deletions

View File

@ -0,0 +1,23 @@
From 09b70436b3a0aae1fe24fdde6e8cdd7ee98d9c15 Mon Sep 17 00:00:00 2001
From: Brett Holman <brett.holman@canonical.com>
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:

View File

@ -0,0 +1,146 @@
From 2da948152c4b7b2f30dc6189d0072f7562df1ad5 Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
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 <xiachen@redhat.com>
RH-MergeRequest: 112: Fix metric setting for ifcfg network connections for rhel (#5777)
RH-Jira: RHEL-65016
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
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 <xiachen@redhat.com>
---
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

View File

@ -0,0 +1,248 @@
From ab36aacfb2f98d865d9e03df81f9102b04d307dd Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
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 <anisinha@redhat.com>
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 <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
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 <anisinha@redhat.com>
(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

View File

@ -0,0 +1,306 @@
From 60eca5a45a35982f42db58dd0d6d53bd2587e477 Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
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 <xiachen@redhat.com>
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 <eesposit@redhat.com>
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
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 <xiachen@redhat.com>
---
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

View File

@ -0,0 +1,160 @@
From 59079c817ead856135ce40698f4d350a425cd65e Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
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 <xiachen@redhat.com>
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 <eesposit@redhat.com>
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
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 <xiachen@redhat.com>
---
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

View File

@ -0,0 +1,78 @@
From 436e6f5ce3fbb8b391a2158538873644058904e6 Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
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

View File

@ -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 <eabdullin@almalinux.org> - 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 <elkhan@almalinux.org> - 23.4-19.alma.1
- 0031-Improvements-for-AlmaLinux-OS-and-CloudLinux-OS.patch