Compare commits

...

No commits in common. 'c9' and 'i9.5-beta' have entirely different histories.

@ -0,0 +1,631 @@
From 82bd152879f808bab3e70cf2321453794b11f040 Mon Sep 17 00:00:00 2001
From: tigro <tigro@msvsphere-os.ru>
Date: Wed, 3 Apr 2024 11:20:26 +0300
Subject: [PATCH] Add MSVSphere support
---
cloudinit/config/cc_ca_certs.py | 8 ++++
cloudinit/config/cc_ntp.py | 9 ++++
cloudinit/config/cc_yum_add_repo.py | 1 +
cloudinit/distros/__init__.py | 1 +
cloudinit/distros/msvsphere.py | 10 ++++
cloudinit/net/sysconfig.py | 1 +
cloudinit/sources/DataSourceRbxCloud.py | 2 +-
cloudinit/util.py | 1 +
config/cloud.cfg.tmpl | 2 +-
doc/rtd/reference/availability.rst | 2 +-
doc/rtd/reference/network-config.rst | 4 +-
packages/pkg-deps.json | 14 ++++++
systemd/cloud-final.service.tmpl | 2 +-
systemd/cloud-init-generator.tmpl | 2 +-
systemd/cloud-init-local.service.tmpl | 10 ++--
systemd/cloud-init.service.tmpl | 4 +-
templates/chrony.conf.msvsphere.tmpl | 45 ++++++++++++++++++
templates/ntp.conf.msvsphere.tmpl | 61 +++++++++++++++++++++++++
tests/unittests/test_cli.py | 2 +-
tests/unittests/test_net.py | 1 +
tests/unittests/test_render_template.py | 1 +
tests/unittests/test_util.py | 44 ++++++++++++++++++
tools/read-dependencies | 5 +-
tools/render-template | 1 +
tools/run-container | 4 +-
25 files changed, 219 insertions(+), 18 deletions(-)
create mode 100644 cloudinit/distros/msvsphere.py
create mode 100644 templates/chrony.conf.msvsphere.tmpl
create mode 100644 templates/ntp.conf.msvsphere.tmpl
diff --git a/cloudinit/config/cc_ca_certs.py b/cloudinit/config/cc_ca_certs.py
index 8d3fd9a..419bca7 100644
--- a/cloudinit/config/cc_ca_certs.py
+++ b/cloudinit/config/cc_ca_certs.py
@@ -38,6 +38,13 @@ DISTRO_OVERRIDES = {
"ca_cert_config": None,
"ca_cert_update_cmd": ["update-ca-trust"],
},
+ "msvsphere": {
+ "ca_cert_path": "/usr/share/pki/ca-trust-source/",
+ "ca_cert_filename": "anchors/cloud-init-ca-certs.crt",
+ "ca_cert_config": None,
+ "ca_cert_system_path": "/etc/pki/ca-trust/",
+ "ca_cert_update_cmd": ["update-ca-trust"],
+ },
"opensuse": {
"ca_cert_path": "/etc/pki/trust/",
"ca_cert_local_path": "/usr/share/pki/trust/",
@@ -75,6 +82,7 @@ distros = [
"alpine",
"debian",
"fedora",
+ "msvsphere",
"rhel",
"opensuse",
"opensuse-microos",
diff --git a/cloudinit/config/cc_ntp.py b/cloudinit/config/cc_ntp.py
index 9eef24f..fdefcc7 100644
--- a/cloudinit/config/cc_ntp.py
+++ b/cloudinit/config/cc_ntp.py
@@ -34,6 +34,7 @@ distros = [
"freebsd",
"mariner",
"miraclelinux",
+ "msvsphere",
"openbsd",
"openeuler",
"OpenCloudOS",
@@ -172,6 +173,14 @@ DISTRO_CLIENT_CONFIG = {
"check_exe": "/lib/systemd/systemd-timesyncd",
},
},
+ "msvsphere": {
+ "chrony": {
+ "service_name": "chronyd",
+ },
+ "ntp": {
+ "service_name": "ntpd",
+ },
+ },
"opensuse": {
"chrony": {
"service_name": "chronyd",
diff --git a/cloudinit/config/cc_yum_add_repo.py b/cloudinit/config/cc_yum_add_repo.py
index 1ab5008..cdc3c4d 100644
--- a/cloudinit/config/cc_yum_add_repo.py
+++ b/cloudinit/config/cc_yum_add_repo.py
@@ -31,6 +31,7 @@ distros = [
"cloudlinux",
"eurolinux",
"fedora",
+ "msvsphere",
"mariner",
"openeuler",
"OpenCloudOS",
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index 79e2623..72114f4 100644
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -73,6 +73,7 @@ OSFAMILIES = {
"fedora",
"mariner",
"miraclelinux",
+ "msvsphere",
"openmandriva",
"photon",
"rhel",
diff --git a/cloudinit/distros/msvsphere.py b/cloudinit/distros/msvsphere.py
new file mode 100644
index 0000000..3dc0a34
--- /dev/null
+++ b/cloudinit/distros/msvsphere.py
@@ -0,0 +1,10 @@
+# This file is part of cloud-init. See LICENSE file for license information.
+
+from cloudinit.distros import rhel
+
+
+class Distro(rhel.Distro):
+ pass
+
+
+# vi: ts=4 expandtab
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
index 7570a5e..5fd0bc9 100644
--- a/cloudinit/net/sysconfig.py
+++ b/cloudinit/net/sysconfig.py
@@ -27,6 +27,7 @@ KNOWN_DISTROS = [
"eurolinux",
"fedora",
"miraclelinux",
+ "msvsphere",
"openeuler",
"OpenCloudOS",
"openmandriva",
diff --git a/cloudinit/sources/DataSourceRbxCloud.py b/cloudinit/sources/DataSourceRbxCloud.py
index 9214f1b..f76291b 100644
--- a/cloudinit/sources/DataSourceRbxCloud.py
+++ b/cloudinit/sources/DataSourceRbxCloud.py
@@ -60,7 +60,7 @@ def _sub_arp(cmd):
def gratuitous_arp(items, distro):
source_param = "-S"
- if distro.name in ["fedora", "centos", "rhel"]:
+ if distro.name in ["fedora", "centos", "msvsphere", "rhel"]:
source_param = "-s"
for item in items:
try:
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 3295735..5fda111 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -651,6 +651,7 @@ def _get_variant(info):
"fedora",
"mariner",
"miraclelinux",
+ "msvsphere",
"openeuler",
"opencloudos",
"openmandriva",
diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl
index de0bf7b..9aee03c 100644
--- a/config/cloud.cfg.tmpl
+++ b/config/cloud.cfg.tmpl
@@ -3,7 +3,7 @@
# and base configuration.
{% set is_bsd = variant in ["dragonfly", "freebsd", "netbsd", "openbsd"] %}
{% set is_rhel = variant in ["almalinux", "centos", "cloudlinux", "eurolinux",
- "miraclelinux", "rhel", "rocky", "virtuozzo"] %}
+ "miraclelinux", "msvsphere", "rhel", "rocky", "virtuozzo"] %}
{% set gecos = ({"amazon": "EC2 Default User", "centos": "Cloud User",
"debian": "Debian", "dragonfly": "DragonFly",
"freebsd": "FreeBSD", "mariner": "MarinerOS",
diff --git a/doc/rtd/reference/availability.rst b/doc/rtd/reference/availability.rst
index f26417d..3aa1cc3 100644
--- a/doc/rtd/reference/availability.rst
+++ b/doc/rtd/reference/availability.rst
@@ -27,7 +27,7 @@ NetBSD, OpenBSD and DragonFlyBSD:
- NetBSD
- OpenBSD
- Photon OS
-- RHEL/CentOS/AlmaLinux/Rocky Linux/EuroLinux
+- RHEL/CentOS/AlmaLinux/Rocky Linux/EuroLinux/MSVSphere
- SLES/openSUSE
- Ubuntu
diff --git a/doc/rtd/reference/network-config.rst b/doc/rtd/reference/network-config.rst
index d9e67cf..b4a89fa 100644
--- a/doc/rtd/reference/network-config.rst
+++ b/doc/rtd/reference/network-config.rst
@@ -273,7 +273,7 @@ Example output:
.. code-block::
usage: /usr/bin/cloud-init devel net-convert [-h] -p PATH -k {eni,network_data.json,yaml,azure-imds,vmware-imc} -d PATH -D
- {alpine,arch,debian,ubuntu,freebsd,dragonfly,gentoo,cos,netbsd,openbsd,almalinux,amazon,centos,cloudlinux,eurolinux,fedora,mariner,miraclelinux,openmandriva,photon,rhel,rocky,virtuozzo,opensuse,sles,openEuler}
+ {alpine,arch,debian,ubuntu,freebsd,dragonfly,gentoo,cos,netbsd,openbsd,almalinux,amazon,centos,cloudlinux,eurolinux,fedora,mariner,miraclelinux,msvsphere,openmandriva,photon,rhel,rocky,virtuozzo,opensuse,sles,openEuler}
[-m name,mac] [--debug] -O {eni,netplan,networkd,sysconfig,network-manager}
options:
@@ -284,7 +284,7 @@ Example output:
The format of the given network config
-d PATH, --directory PATH
directory to place output in
- -D {alpine,arch,debian,ubuntu,freebsd,dragonfly,gentoo,cos,netbsd,openbsd,almalinux,amazon,centos,cloudlinux,eurolinux,fedora,mariner,miraclelinux,openmandriva,photon,rhel,rocky,virtuozzo,opensuse,sles,openeuler}, --distro {alpine,arch,debian,ubuntu,freebsd,dragonfly,gentoo,cos,netbsd,openbsd,almalinux,amazon,centos,cloudlinux,eurolinux,fedora,mariner,miraclelinux,openmandriva,photon,rhel,rocky,virtuozzo,opensuse,sles,openEuler}
+ -D {alpine,arch,debian,ubuntu,freebsd,dragonfly,gentoo,cos,netbsd,openbsd,almalinux,amazon,centos,cloudlinux,eurolinux,fedora,mariner,miraclelinux,msvsphere,openmandriva,photon,rhel,rocky,virtuozzo,opensuse,sles,openeuler}, --distro {alpine,arch,debian,ubuntu,freebsd,dragonfly,gentoo,cos,netbsd,openbsd,almalinux,amazon,centos,cloudlinux,eurolinux,fedora,mariner,miraclelinux,openmandriva,photon,rhel,rocky,virtuozzo,opensuse,sles,openEuler}
-m name,mac, --mac name,mac
interface name to mac mapping
--debug enable debug logging to stderr.
diff --git a/packages/pkg-deps.json b/packages/pkg-deps.json
index 4ee0982..df7596c 100644
--- a/packages/pkg-deps.json
+++ b/packages/pkg-deps.json
@@ -41,6 +41,20 @@
"sudo"
]
},
+ "msvsphere" : {
+ "build-requires" : [
+ "python3-devel"
+ ],
+ "requires" : [
+ "e2fsprogs",
+ "iproute",
+ "net-tools",
+ "procps",
+ "rsyslog",
+ "shadow-utils",
+ "sudo"
+ ]
+ },
"redhat" : {
"build-requires" : [
"python3-devel"
diff --git a/systemd/cloud-final.service.tmpl b/systemd/cloud-final.service.tmpl
index bcf8b00..8b69bca 100644
--- a/systemd/cloud-final.service.tmpl
+++ b/systemd/cloud-final.service.tmpl
@@ -18,7 +18,7 @@ ExecStart=/usr/bin/cloud-init modules --mode=final
RemainAfterExit=yes
TimeoutSec=0
KillMode=process
-{% if variant == "rhel" %}
+{% if variant == ["msvsphere", "rhel"] %}
# Restart NetworkManager if it is present and running.
ExecStartPost=/bin/sh -c 'u=NetworkManager.service; \
out=$(systemctl show --property=SubState $u) || exit; \
diff --git a/systemd/cloud-init-generator.tmpl b/systemd/cloud-init-generator.tmpl
index 3c9ca16..7aaecf8 100644
--- a/systemd/cloud-init-generator.tmpl
+++ b/systemd/cloud-init-generator.tmpl
@@ -21,7 +21,7 @@ CLOUD_SYSTEM_TARGET="/usr/lib/systemd/system/cloud-init.target"
CLOUD_SYSTEM_TARGET="/lib/systemd/system/cloud-init.target"
{% endif %}
{% if variant in ["almalinux", "centos", "cloudlinux", "eurolinux", "fedora",
- "miraclelinux", "openeuler", "OpenCloudOS", "openmandriva", "rhel", "rocky", "TencentOS", "virtuozzo"] %}
+ "miraclelinux", "openeuler", "OpenCloudOS", "openmandriva", "msvsphere", "rhel", "rocky", "TencentOS", "virtuozzo"] %}
dsidentify="/usr/libexec/cloud-init/ds-identify"
{% elif variant == "benchmark" %}
dsidentify="/bin/true"
diff --git a/systemd/cloud-init-local.service.tmpl b/systemd/cloud-init-local.service.tmpl
index 3a1ca7f..07c77c4 100644
--- a/systemd/cloud-init-local.service.tmpl
+++ b/systemd/cloud-init-local.service.tmpl
@@ -1,23 +1,23 @@
## template:jinja
[Unit]
Description=Initial cloud-init job (pre-networking)
-{% if variant in ["ubuntu", "unknown", "debian", "rhel" ] %}
+{% if variant in ["ubuntu", "unknown", "debian", "msvsphere", "rhel" ] %}
DefaultDependencies=no
{% endif %}
Wants=network-pre.target
After=hv_kvp_daemon.service
After=systemd-remount-fs.service
-{% if variant == "rhel" %}
+{% if variant == ["msvsphere", "rhel"] %}
Requires=dbus.socket
After=dbus.socket
{% endif %}
Before=NetworkManager.service
-{% if variant == "rhel" %}
+{% if variant == ["msvsphere", "rhel"] %}
Before=network.service
{% endif %}
Before=network-pre.target
Before=shutdown.target
-{% if variant == "rhel" %}
+{% if variant == ["msvsphere", "rhel"] %}
Before=firewalld.target
Conflicts=shutdown.target
{% endif %}
@@ -32,7 +32,7 @@ ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled
[Service]
Type=oneshot
-{% if variant == "rhel" %}
+{% if variant == ["msvsphere", "rhel"] %}
ExecStartPre=/bin/mkdir -p /run/cloud-init
ExecStartPre=/sbin/restorecon /run/cloud-init
ExecStartPre=/usr/bin/touch /run/cloud-init/enabled
diff --git a/systemd/cloud-init.service.tmpl b/systemd/cloud-init.service.tmpl
index bf91164..91b59b7 100644
--- a/systemd/cloud-init.service.tmpl
+++ b/systemd/cloud-init.service.tmpl
@@ -1,7 +1,7 @@
## template:jinja
[Unit]
Description=Initial cloud-init job (metadata service crawler)
-{% if variant not in ["photon", "rhel"] %}
+{% if variant not in ["photon", "msvsphere", "rhel"] %}
DefaultDependencies=no
{% endif %}
Wants=cloud-init-local.service
@@ -13,7 +13,7 @@ After=systemd-networkd-wait-online.service
After=networking.service
{% endif %}
{% if variant in ["almalinux", "centos", "cloudlinux", "eurolinux", "fedora",
- "miraclelinux", "openeuler", "OpenCloudOS", "openmandriva", "rhel", "rocky",
+ "miraclelinux", "openeuler", "OpenCloudOS", "openmandriva", "msvsphere", "rhel", "rocky",
"suse", "TencentOS", "virtuozzo"] %}
After=network.service
diff --git a/templates/chrony.conf.msvsphere.tmpl b/templates/chrony.conf.msvsphere.tmpl
new file mode 100644
index 0000000..5b3542e
--- /dev/null
+++ b/templates/chrony.conf.msvsphere.tmpl
@@ -0,0 +1,45 @@
+## template:jinja
+# Use public servers from the pool.ntp.org project.
+# Please consider joining the pool (http://www.pool.ntp.org/join.html).
+{% if pools %}# pools
+{% endif %}
+{% for pool in pools -%}
+pool {{pool}} iburst
+{% endfor %}
+{%- if servers %}# servers
+{% endif %}
+{% for server in servers -%}
+server {{server}} iburst
+{% endfor %}
+
+# Record the rate at which the system clock gains/losses time.
+driftfile /var/lib/chrony/drift
+
+# Allow the system clock to be stepped in the first three updates
+# if its offset is larger than 1 second.
+makestep 1.0 3
+
+# Enable kernel synchronization of the real-time clock (RTC).
+rtcsync
+
+# Enable hardware timestamping on all interfaces that support it.
+#hwtimestamp *
+
+# Increase the minimum number of selectable sources required to adjust
+# the system clock.
+#minsources 2
+
+# Allow NTP client access from local network.
+#allow 192.168.0.0/16
+
+# Serve time even if not synchronized to a time source.
+#local stratum 10
+
+# Specify file containing keys for NTP authentication.
+#keyfile /etc/chrony.keys
+
+# Specify directory for log files.
+logdir /var/log/chrony
+
+# Select which information is logged.
+#log measurements statistics tracking
diff --git a/templates/ntp.conf.msvsphere.tmpl b/templates/ntp.conf.msvsphere.tmpl
new file mode 100644
index 0000000..68c4563
--- /dev/null
+++ b/templates/ntp.conf.msvsphere.tmpl
@@ -0,0 +1,61 @@
+## template:jinja
+
+# For more information about this file, see the man pages
+# ntp.conf(5), ntp_acc(5), ntp_auth(5), ntp_clock(5), ntp_misc(5), ntp_mon(5).
+
+driftfile /var/lib/ntp/drift
+
+# Permit time synchronization with our time source, but do not
+# permit the source to query or modify the service on this system.
+restrict default kod nomodify notrap nopeer noquery
+restrict -6 default kod nomodify notrap nopeer noquery
+
+# Permit all access over the loopback interface. This could
+# be tightened as well, but to do so would effect some of
+# the administrative functions.
+restrict 127.0.0.1
+restrict -6 ::1
+
+# Hosts on local network are less restricted.
+#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
+
+# Use public servers from the pool.ntp.org project.
+# Please consider joining the pool (http://www.pool.ntp.org/join.html).
+{% if pools %}# pools
+{% endif %}
+{% for pool in pools -%}
+pool {{pool}} iburst
+{% endfor %}
+{%- if servers %}# servers
+{% endif %}
+{% for server in servers -%}
+server {{server}} iburst
+{% endfor %}
+
+#broadcast 192.168.1.255 autokey # broadcast server
+#broadcastclient # broadcast client
+#broadcast 224.0.1.1 autokey # multicast server
+#multicastclient 224.0.1.1 # multicast client
+#manycastserver 239.255.254.254 # manycast server
+#manycastclient 239.255.254.254 autokey # manycast client
+
+# Enable public key cryptography.
+#crypto
+
+includefile /etc/ntp/crypto/pw
+
+# Key file containing the keys and key identifiers used when operating
+# with symmetric key cryptography.
+keys /etc/ntp/keys
+
+# Specify the key identifiers which are trusted.
+#trustedkey 4 8 42
+
+# Specify the key identifier to use with the ntpdc utility.
+#requestkey 8
+
+# Specify the key identifier to use with the ntpq utility.
+#controlkey 8
+
+# Enable writing of statistics records.
+#statistics clockstats cryptostats loopstats peerstats
diff --git a/tests/unittests/test_cli.py b/tests/unittests/test_cli.py
index 1713d98..7faf499 100644
--- a/tests/unittests/test_cli.py
+++ b/tests/unittests/test_cli.py
@@ -266,7 +266,7 @@ class TestCLI:
"mariner, miraclelinux, "
"openbsd, openeuler, OpenCloudOS, openmandriva, "
"opensuse, opensuse-microos, opensuse-tumbleweed, "
- "opensuse-leap, photon, rhel, rocky, sle_hpc, "
+ "opensuse-leap, photon, msvsphere, rhel, rocky, sle_hpc, "
"sle-micro, sles, TencentOS, ubuntu, virtuozzo",
" **resize_rootfs:** ",
"(``true``/``false``/``noblock``)",
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index c550953..01ef563 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -8180,6 +8180,7 @@ class TestNetRenderers(CiTestCase):
"eurolinux",
"fedora",
"rhel",
+ "msvsphere",
]
for distro_name in variants:
m_info.return_value = {"variant": distro_name}
diff --git a/tests/unittests/test_render_template.py b/tests/unittests/test_render_template.py
index 6fd62f0..9648187 100644
--- a/tests/unittests/test_render_template.py
+++ b/tests/unittests/test_render_template.py
@@ -21,6 +21,7 @@ DISTRO_VARIANTS = [
"netbsd",
"openbsd",
"photon",
+ "msvsphere",
"rhel",
"suse",
"ubuntu",
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 519ef63..42dc04b 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -209,6 +209,28 @@ OS_RELEASE_MIRACLELINUX_8 = dedent(
"""
)
+OS_RELEASE_MSVSPHERE_9 = dedent(
+ """\
+ NAME="MSVSphere"
+ VERSION="9.4 (Inferit)"
+ ID="msvsphere"
+ ID_LIKE="rhel centos fedora"
+ VERSION_ID="9.4"
+ PLATFORM_ID="platform:el9"
+ PRETTY_NAME="MSVSphere 9.4 (Inferit)"
+ ANSI_COLOR="0;34"
+ LOGO="fedora-logo-icon"
+ CPE_NAME="cpe:/o:ncsd:msvsphere:9::baseos"
+ HOME_URL="https://msvsphere-os.ru/"
+ BUG_REPORT_URL="https://bugs.msvsphere-os.ru/"
+
+ MSVSPHERE_MANTISBT_PROJECT="MSVSphere-9"
+ MSVSPHERE_MANTISBT_PROJECT_VERSION="9.4"
+ REDHAT_SUPPORT_PRODUCT="MSVSphere"
+ REDHAT_SUPPORT_PRODUCT_VERSION="9.4"
+"""
+)
+
OS_RELEASE_ROCKY_8 = dedent(
"""\
NAME="Rocky Linux"
@@ -310,6 +332,7 @@ REDHAT_RELEASE_ALMALINUX_8 = "AlmaLinux release 8.3 (Purple Manul)"
REDHAT_RELEASE_EUROLINUX_7 = "EuroLinux release 7.9 (Minsk)"
REDHAT_RELEASE_EUROLINUX_8 = "EuroLinux release 8.4 (Vaduz)"
REDHAT_RELEASE_MIRACLELINUX_8 = "MIRACLE LINUX release 8.4 (Peony)"
+REDHAT_RELEASE_MSVSPHERE_9 = "MSVSphere release 9.3 (Inferit)"
REDHAT_RELEASE_ROCKY_8 = "Rocky Linux release 8.3 (Green Obsidian)"
REDHAT_RELEASE_VIRTUOZZO_8 = "Virtuozzo Linux release 8"
REDHAT_RELEASE_CLOUDLINUX_8 = "CloudLinux release 8.4 (Valery Rozhdestvensky)"
@@ -1098,6 +1121,26 @@ class TestGetLinuxDistro(CiTestCase):
dist = util.get_linux_distro()
self.assertEqual(("miraclelinux", "8", "Peony"), dist)
+ @mock.patch("cloudinit.util.load_file")
+ def test_get_linux_msvsphere9_rhrelease(
+ self, m_os_release, m_path_exists
+ ):
+ """Verify msvsphere 9 read from redhat-release."""
+ m_os_release.return_value = REDHAT_RELEASE_MSVSPHERE_9
+ m_path_exists.side_effect = TestGetLinuxDistro.redhat_release_exists
+ dist = util.get_linux_distro()
+ self.assertEqual(("msvsphere", "9.4", "Inferit"), dist)
+
+ @mock.patch("cloudinit.util.load_file")
+ def test_get_linux_msvsphere9_osrelease(
+ self, m_os_release, m_path_exists
+ ):
+ """Verify msvsphere 9 read from os-release."""
+ m_os_release.return_value = OS_RELEASE_MSVSPHERE_9
+ m_path_exists.side_effect = TestGetLinuxDistro.os_release_exists
+ dist = util.get_linux_distro()
+ self.assertEqual(("msvsphere", "9.4", "Inferit"), dist)
+
@mock.patch(M_PATH + "load_file")
def test_get_linux_rocky8_rhrelease(self, m_os_release, m_path_exists):
"""Verify rocky linux 8 read from redhat-release."""
@@ -1304,6 +1347,7 @@ class TestGetVariant:
({"system": "linux", "dist": ("ubuntu",)}, "ubuntu"),
({"system": "linux", "dist": ("linuxmint",)}, "ubuntu"),
({"system": "linux", "dist": ("mint",)}, "ubuntu"),
+ ({"system": "linux", "dist": ("msvsphere",)}, "msvsphere"),
({"system": "linux", "dist": ("redhat",)}, "rhel"),
({"system": "linux", "dist": ("opensuse",)}, "suse"),
({"system": "linux", "dist": ("opensuse-tumbleweed",)}, "suse"),
diff --git a/tools/read-dependencies b/tools/read-dependencies
index 9d83ba5..4b7217b 100755
--- a/tools/read-dependencies
+++ b/tools/read-dependencies
@@ -26,6 +26,7 @@ DISTRO_PKG_TYPE_MAP = {
"centos": "redhat",
"eurolinux": "redhat",
"miraclelinux": "redhat",
+ "msvsphere": "redhat",
"rocky": "redhat",
"redhat": "redhat",
"debian": "debian",
@@ -95,6 +96,7 @@ CI_SYSTEM_BASE_PKGS = {
"common": ["make", "sudo", "tar"],
"eurolinux": ["python3-tox"],
"miraclelinux": ["python3-tox"],
+ "msvsphere": ["python3-tox"],
"redhat": ["python3-tox"],
"centos": ["python3-tox"],
"ubuntu": ["devscripts", "python3-dev", "libssl-dev", "tox", "sbuild"],
@@ -336,12 +338,13 @@ def pkg_install(pkg_list, distro, test_distro=False, dry_run=False):
cmd = DISTRO_INSTALL_PKG_CMD[distro_family]
install_cmd.extend(cmd)
- if distro in ["centos", "redhat", "rocky", "eurolinux"]:
+ if distro in ["centos", "redhat", "rocky", "eurolinux", "msvsphere"]:
# CentOS and Redhat need epel-release to access oauthlib and jsonschema
subprocess.check_call(install_cmd + ["epel-release"])
if distro in [
"suse",
"opensuse",
+ "msvsphere",
"redhat",
"rocky",
"centos",
diff --git a/tools/render-template b/tools/render-template
index 5ef5a37..80e991f 100755
--- a/tools/render-template
+++ b/tools/render-template
@@ -26,6 +26,7 @@ def main():
"gentoo",
"mariner",
"miraclelinux",
+ "msvsphere",
"netbsd",
"openbsd",
"openeuler",
diff --git a/tools/run-container b/tools/run-container
index f27c021..15d2ac5 100755
--- a/tools/run-container
+++ b/tools/run-container
@@ -249,7 +249,7 @@ apt_install() {
install_packages() {
get_os_info || return
case "$OS_NAME" in
- centos|rocky*) yum_install "$@";;
+ centos|msvsphere|rocky*) yum_install "$@";;
opensuse*) zypper_install "$@";;
debian|ubuntu) apt_install "$@" -y;;
*) error "Do not know how to install packages on ${OS_NAME}";
@@ -499,7 +499,7 @@ main() {
local build_pkg="" build_srcpkg="" pkg_ext="" distflag=""
case "$OS_NAME" in
- centos|rocky*) distflag="--distro=redhat";;
+ centos|msvsphere|rocky*) distflag="--distro=redhat";;
opensuse*) distflag="--distro=suse";;
esac
--
2.44.0

@ -1,145 +0,0 @@
From 94c0cd9c656877250f7e5cfe05325a42bbdec182 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/2] Fix metric setting for ifcfg network connections for rhel
(#5777)
RH-Author: xiachen <xiachen@redhat.com>
RH-MergeRequest: 145: Fix metric setting for ifcfg network connections for rhel (#5777)
RH-Jira: RHEL-65018
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
RH-Commit: [1/2] a18205f1ffa455a2ccd836ba6baa12b7da0afbde (xiachen/cloud-init)
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 7eb430ed1..b50a6a8a0 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 2d716f4b5..4673e4eaf 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"""
@@ -1521,7 +1521,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"""
@@ -5725,24 +5725,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

@ -1,248 +0,0 @@
From 038a391b7016f16a7336d67965762a7dbf3ba662 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: 150: Prevent NM from handling DNS when network interfaces have DNS config (#5846)
RH-Jira: RHEL-65778
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] b464ef219eba1a0c718dda5ed96b6f88e1273f99
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 e4a65187f..4898a2fd1 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 ddb45dc69..47b36d052 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

@ -1,306 +0,0 @@
From 1df31428c87f08c790c300ba402318378cea8d65 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 1/2] fix: Render bridges correctly for v2 on sysconfig with
set-name (#5674)
RH-Author: xiachen <xiachen@redhat.com>
RH-MergeRequest: 147: fix: Render bridges correctly for v2 on sysconfig with set-name (#5674)
RH-Jira: RHEL-65021
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
RH-Commit: [1/2] 7f7fce173ee9a3ba719fc36580fbce813c5bfbd0 (xiachen/cloud-init)
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 486fa22dc..ac0306d6a 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 14c57cdcc..226421bd0 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 b50a6a8a0..e4a65187f 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
@@ -924,7 +924,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()
@@ -1005,23 +1007,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 4673e4eaf..004da81ab 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

@ -1,160 +0,0 @@
From 58904df7d689df6e3d1d4ddf47b5cb5a267006da 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 2/2] fix: Render v2 bridges correctly on network-manager with
set-name (#5740)
RH-Author: xiachen <xiachen@redhat.com>
RH-MergeRequest: 147: fix: Render bridges correctly for v2 on sysconfig with set-name (#5674)
RH-Jira: RHEL-65021
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
RH-Commit: [2/2] e101d8ff06a379752958a3eb19d209bcb7d1e0ed (xiachen/cloud-init)
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 0ba210b74..f50fafa39 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 004da81ab..ddb45dc69 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

@ -1,34 +0,0 @@
From e6e7c274235d924fde752b228f68ec5773e39029 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 2/2] fix(python3.13): Fix import error for passlib on Python
3.13 (#4669)
RH-Author: xiachen <xiachen@redhat.com>
RH-MergeRequest: 145: Fix metric setting for ifcfg network connections for rhel (#5777)
RH-Jira: RHEL-65018
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
RH-Commit: [2/2] 226ae26a9f903774cb36f8f72b89071ba4545a66 (xiachen/cloud-init)
(cherry picked from commit 09b70436b3a0aae1fe24fdde6e8cdd7ee98d9c15)
Signed-off-by: Amy Chen <xiachen@redhat.com>
---
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 eb0304c3d..939210100 100644
--- a/cloudinit/sources/DataSourceAzure.py
+++ b/cloudinit/sources/DataSourceAzure.py
@@ -58,7 +58,7 @@ try:
)
except (ImportError, AttributeError):
try:
- import passlib
+ import passlib.hash
blowfish_hash = passlib.hash.sha512_crypt.hash
except ImportError:
--
2.39.3

@ -1,91 +0,0 @@
From 9a3c16dc89d2813c90df2e57e71ae5df704083be 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)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 152: refactor: Ensure internal DNS state same for v1 and v2 (#4756)
RH-Jira: RHEL-68409
RH-Acked-by: xiachen <xiachen@redhat.com>
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Commit: [1/1] f006996f7b418103ffaf73ff9ded5b5d149bedf6
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.
(cherry picked from commit 436e6f5ce3fbb8b391a2158538873644058904e6)
Signed-off-by: Ani Sinha <anisinha@redhat.com>
---
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 226421bd0..82c3bf894 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 0978849c8..29f466eda 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 7d304ca3a..74a6bb34c 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
--
2.39.3

@ -1,6 +1,6 @@
Name: cloud-init Name: cloud-init
Version: 23.4 Version: 23.4
Release: 19%{?dist}.4 Release: 19%{?dist}.inferit
Summary: Cloud instance init scripts Summary: Cloud instance init scripts
License: ASL 2.0 or GPLv3 License: ASL 2.0 or GPLv3
URL: http://launchpad.net/cloud-init URL: http://launchpad.net/cloud-init
@ -67,18 +67,9 @@ Patch32: ci-Support-setting-mirrorlist-in-yum-repository-config-.patch
Patch33: ci-Revert-fix-vmware-Set-IPv6-to-dhcp-when-there-is-no-.patch 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. # For RHEL-54686 - [RHEL-9.5] cloud-init schema validation fails.
Patch34: ci-fix-Add-subnet-ipv4-ipv6-to-network-schema-5191.patch Patch34: ci-fix-Add-subnet-ipv4-ipv6-to-network-schema-5191.patch
# For RHEL-65018 - Configuring metric for default gateway is not working [rhel-9.5.z]
Patch35: ci-Fix-metric-setting-for-ifcfg-network-connections-for.patch # MSVSphere patches
# For RHEL-65018 - Configuring metric for default gateway is not working [rhel-9.5.z] Patch100: 0001-Add-MSVSphere-support.patch
Patch36: ci-fix-python3.13-Fix-import-error-for-passlib-on-Pytho.patch
# For RHEL-65021 - NoCloud - network_config bridges incorrectly configured [rhel-9.5.z]
Patch37: ci-fix-Render-bridges-correctly-for-v2-on-sysconfig-wit.patch
# For RHEL-65021 - NoCloud - network_config bridges incorrectly configured [rhel-9.5.z]
Patch38: ci-fix-Render-v2-bridges-correctly-on-network-manager-w.patch
# For RHEL-65778 - [RHEL-9] Prevent NM from handling DNS when network interfaces have DNS config [rhel-9.5.z]
Patch39: ci-Prevent-NM-from-handling-DNS-when-network-interfaces.patch
# For RHEL-68409 - cloud-init fails to configure DNS and search domain [rhel-9.5.z]
Patch40: ci-refactor-Ensure-internal-DNS-state-same-for-v1-and-v.patch
BuildArch: noarch BuildArch: noarch
@ -293,27 +284,8 @@ fi
%config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf %config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf
%changelog %changelog
* Wed Nov 27 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-19.el9_5.4 * Sun Oct 13 2024 Arkady L. Shane <tigro@msvsphere-os.ru> - 23.4-19.inferit
- ci-refactor-Ensure-internal-DNS-state-same-for-v1-and-v.patch [RHEL-68409] - Added MSVSphere support
- Resolves: RHEL-68409
(cloud-init fails to configure DNS and search domain [rhel-9.5.z])
* Mon Nov 18 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-19.el9_5.3
- ci-Prevent-NM-from-handling-DNS-when-network-interfaces.patch [RHEL-65778]
- Resolves: RHEL-65778
([RHEL-9] Prevent NM from handling DNS when network interfaces have DNS config [rhel-9.5.z])
* Wed Nov 06 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-19.el9_5.2
- ci-fix-Render-bridges-correctly-for-v2-on-sysconfig-wit.patch [RHEL-65021]
- ci-fix-Render-v2-bridges-correctly-on-network-manager-w.patch [RHEL-65021]
- Resolves: RHEL-65021
(NoCloud - network_config bridges incorrectly configured [rhel-9.5.z])
* Thu Oct 31 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-19.el9_5.1
- ci-Fix-metric-setting-for-ifcfg-network-connections-for.patch [RHEL-65018]
- ci-fix-python3.13-Fix-import-error-for-passlib-on-Pytho.patch [RHEL-65018]
- Resolves: RHEL-65018
(Configuring metric for default gateway is not working [rhel-9.5.z])
* Mon Aug 26 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-19 * Mon Aug 26 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-19
- ci-fix-Add-subnet-ipv4-ipv6-to-network-schema-5191.patch [RHEL-54686] - ci-fix-Add-subnet-ipv4-ipv6-to-network-schema-5191.patch [RHEL-54686]
@ -486,6 +458,9 @@ fi
- 0007-rhel-make-sure-previous-hostname-file-ends-with-a-ne.patch [bz#2184608] - 0007-rhel-make-sure-previous-hostname-file-ends-with-a-ne.patch [bz#2184608]
- Resolves: bz#2184608 - Resolves: bz#2184608
* Fri Apr 14 2023 MSVSphere Packaging Team <packager@msvsphere.ru> - 23.1.1-1
- Rebuilt for MSVSphere 9.2 beta
* Thu Mar 30 2023 Camilla Conte <cconte@redhat.com> - 23.1.1-1 * Thu Mar 30 2023 Camilla Conte <cconte@redhat.com> - 23.1.1-1
- Rebase to 23.1.1 [bz#2172811] - Rebase to 23.1.1 [bz#2172811]
- Resolves: bz#2172811 - Resolves: bz#2172811

Loading…
Cancel
Save