From 942a7c212425bae5812def9834d6ef6a29e9b120 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Thu, 28 Mar 2024 09:52:30 +0000 Subject: [PATCH] import CS cloud-init-23.4-6.el9 --- .cloud-init.metadata | 2 +- .gitignore | 2 +- SOURCES/0001-Add-initial-redhat-changes.patch | 52 +- ...CONTROLLED-no-in-generated-interface.patch | 366 ++++- ...ct-priority-setting-for-network-scr.patch} | 233 ++- ...autoconnect-priority-for-network-scr.patch | 42 - ...04-limit-permissions-on-def_log_file.patch | 69 - ...ger-do-not-set-may-fail-to-False-for.patch | 140 ++ ...e-Network-Manager-and-Netplan-as-def.patch | 92 -- ...configuration-from-generate_fallback.patch | 172 ++ ...d-native-NetworkManager-support-1224.patch | 1387 ---------------- ...-presence-of-ifcfg-files-when-nm-con.patch | 113 ++ ...revious-hostname-file-ends-with-a-ne.patch | 54 - ...onschema-Pin-jsonschema-version-4781.patch | 38 + ...-permissions-of-netrules-target-2076.patch | 121 -- ...arning-when-running-clean-command-47.patch | 121 ++ ...-data-sensitive-and-remove-log-permi.patch | 295 ---- ...dsa-and-ed25519-key-types-when-crypt.patch | 206 --- ...vert-Use-Network-Manager-and-Netplan.patch | 93 -- ...d-native-NetworkManager-support-1224.patch | 1391 ----------------- ...-not-use-the-highest-autoconnect-pri.patch | 33 - ...ysconfig-cosmetic-fix-tox-formatting.patch | 43 - ...-stateful-dhcp-config-at-par-with-sy.patch | 49 - ...add-a-method-for-ipv6-static-IP-conf.patch | 31 - ...able-sysconfig-renderer-if-network-m.patch | 62 - ...Set-higher-autoconnect-priority-for-.patch | 401 ----- ...renderer-as-sysconfig-for-c9s-RHEL-9.patch | 42 - ...lt-renderer-as-sysconfig-for-c9s-RHE.patch | 25 - ...erer-as-sysconfig-for-centos-rhel-41.patch | 35 - ...s-remove-NM_CONTROLLED-no-from-tests.patch | 283 ---- ...rt-limit-permissions-on-def_log_file.patch | 58 - ...es-to-apply-RHEL-specific-config-set.patch | 43 - ...E-based-distros-for-ca-handling-2036.patch | 90 -- ...istent-ca-cert-config-situation-2073.patch | 85 - ...rent-file-mode-of-log-file-if-its-st.patch | 172 -- ...S-VMware-modify-a-few-log-level-4284.patch | 62 - ...default-IPv6-addr-gen-mode-for-all-i.patch | 283 ---- SOURCES/ci-Pin-pythes-8.0.0.patch | 44 + ...for-faster-parsing-of-cloud-config-i.patch | 242 +++ ...-Add-types-to-network-v1-schema-4841.patch | 110 ++ SPECS/cloud-init.spec | 104 +- 41 files changed, 1562 insertions(+), 5724 deletions(-) rename SOURCES/{0022-test-fixes-update-tests-to-reflect-AUTOCONNECT_PRIOR.patch => 0003-Setting-autoconnect-priority-setting-for-network-scr.patch} (68%) delete mode 100644 SOURCES/0003-Setting-highest-autoconnect-priority-for-network-scr.patch delete mode 100644 SOURCES/0004-limit-permissions-on-def_log_file.patch create mode 100644 SOURCES/0004-net-network_manager-do-not-set-may-fail-to-False-for.patch delete mode 100644 SOURCES/0005-Manual-revert-Use-Network-Manager-and-Netplan-as-def.patch create mode 100644 SOURCES/0005-net-allow-dhcp6-configuration-from-generate_fallback.patch delete mode 100644 SOURCES/0006-Revert-Add-native-NetworkManager-support-1224.patch create mode 100644 SOURCES/0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch delete mode 100644 SOURCES/0007-rhel-make-sure-previous-hostname-file-ends-with-a-ne.patch create mode 100644 SOURCES/0007-test-jsonschema-Pin-jsonschema-version-4781.patch delete mode 100644 SOURCES/0008-Don-t-change-permissions-of-netrules-target-2076.patch create mode 100644 SOURCES/0008-fix-clean-stop-warning-when-running-clean-command-47.patch delete mode 100644 SOURCES/0009-Make-user-vendor-data-sensitive-and-remove-log-permi.patch delete mode 100644 SOURCES/0010-Do-not-generate-dsa-and-ed25519-key-types-when-crypt.patch delete mode 100644 SOURCES/0011-Revert-Manual-revert-Use-Network-Manager-and-Netplan.patch delete mode 100644 SOURCES/0012-Revert-Revert-Add-native-NetworkManager-support-1224.patch delete mode 100644 SOURCES/0013-net-sysconfig-do-not-use-the-highest-autoconnect-pri.patch delete mode 100644 SOURCES/0014-net-sysconfig-cosmetic-fix-tox-formatting.patch delete mode 100644 SOURCES/0015-nm-generate-ipv6-stateful-dhcp-config-at-par-with-sy.patch delete mode 100644 SOURCES/0016-network_manager-add-a-method-for-ipv6-static-IP-conf.patch delete mode 100644 SOURCES/0017-net-sysconfig-enable-sysconfig-renderer-if-network-m.patch delete mode 100644 SOURCES/0018-network-manager-Set-higher-autoconnect-priority-for-.patch delete mode 100644 SOURCES/0019-Set-default-renderer-as-sysconfig-for-c9s-RHEL-9.patch delete mode 100644 SOURCES/0020-Revert-Set-default-renderer-as-sysconfig-for-c9s-RHE.patch delete mode 100644 SOURCES/0021-Set-default-renderer-as-sysconfig-for-centos-rhel-41.patch delete mode 100644 SOURCES/0023-test-fixes-remove-NM_CONTROLLED-no-from-tests.patch delete mode 100644 SOURCES/0024-Revert-limit-permissions-on-def_log_file.patch delete mode 100644 SOURCES/0025-test-fixes-changes-to-apply-RHEL-specific-config-set.patch delete mode 100644 SOURCES/0026-Enable-SUSE-based-distros-for-ca-handling-2036.patch delete mode 100644 SOURCES/0027-Handle-non-existent-ca-cert-config-situation-2073.patch delete mode 100644 SOURCES/0028-logging-keep-current-file-mode-of-log-file-if-its-st.patch delete mode 100644 SOURCES/0029-DS-VMware-modify-a-few-log-level-4284.patch delete mode 100644 SOURCES/0030-NM-renderer-set-default-IPv6-addr-gen-mode-for-all-i.patch create mode 100644 SOURCES/ci-Pin-pythes-8.0.0.patch create mode 100644 SOURCES/ci-Revert-Use-grep-for-faster-parsing-of-cloud-config-i.patch create mode 100644 SOURCES/ci-fix-Add-types-to-network-v1-schema-4841.patch diff --git a/.cloud-init.metadata b/.cloud-init.metadata index 1426224..061dfea 100644 --- a/.cloud-init.metadata +++ b/.cloud-init.metadata @@ -1 +1 @@ -0b491818abcdce5ba6c1b30c75dd680d6ee3983e SOURCES/23.1.1.tar.gz +e73116733f5636eb4bc1a5e47e802c3635b9bfa2 SOURCES/23.4.tar.gz diff --git a/.gitignore b/.gitignore index 2595433..7fc7ce6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/23.1.1.tar.gz +SOURCES/23.4.tar.gz diff --git a/SOURCES/0001-Add-initial-redhat-changes.patch b/SOURCES/0001-Add-initial-redhat-changes.patch index d8bd385..5024340 100644 --- a/SOURCES/0001-Add-initial-redhat-changes.patch +++ b/SOURCES/0001-Add-initial-redhat-changes.patch @@ -1,11 +1,18 @@ -From c4d66915520554adedff9be7396f877cd1a5525c Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Mon, 6 Mar 2023 16:37:20 +0100 +From 03345a88b8b0008a4a81e010d46290f5ba643ebc Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Wed, 13 Dec 2023 11:54:55 +0530 Subject: [PATCH] Add initial redhat changes Adding minimal set of changes necessary for successful build of the package on RHEL/CentOS 9 Stream koji. +Additional changes on top of the changes in 23.1.1 rebase: + - Updated VERSION, TARSHA512, MARKER and BUILD_TARGET_RHEL parameters in + Makefile.common in .dist/ + - Squashed unit test fixes for the downstream changes in cloudinit/settings.py. + +Changes from 23.1.1 rebase follows: + Merged patches (23.1.1): 724a80ac Add TargetRelease 967a4405b rhel/cloud.cfg: remove ssh_genkeytypes in settings.py and set in cloud.cfg @@ -33,16 +40,19 @@ fe09305a5479a4814d6c46df07a906bafa29d637 Delete .gitlab-ci.yml Conflicts: missing rhel/ static files and "" instead of '' in setup.py +X-downstram-only: true Signed-off-by: Emanuele Giuseppe Esposito +Signed-off-by: Ani Sinha --- - cloudinit/settings.py | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) + cloudinit/settings.py | 5 +++-- + tests/unittests/cmd/test_main.py | 15 +++++++++------ + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/cloudinit/settings.py b/cloudinit/settings.py -index 8684d003..edbb217d 100644 +index 592e144d..5ced21bd 100644 --- a/cloudinit/settings.py +++ b/cloudinit/settings.py -@@ -53,13 +53,14 @@ CFG_BUILTIN = { +@@ -54,13 +54,14 @@ CFG_BUILTIN = { ], "def_log_file": "/var/log/cloud-init.log", "log_cfgs": [], @@ -59,3 +69,31 @@ index 8684d003..edbb217d 100644 "network": {"renderers": None}, }, "vendor_data": {"enabled": True, "prefix": []}, +diff --git a/tests/unittests/cmd/test_main.py b/tests/unittests/cmd/test_main.py +index ab427115..19d26ebe 100644 +--- a/tests/unittests/cmd/test_main.py ++++ b/tests/unittests/cmd/test_main.py +@@ -119,14 +119,17 @@ class TestMain(FilesystemMockingTestCase): + { + "def_log_file": "/var/log/cloud-init.log", + "log_cfgs": [], +- "syslog_fix_perms": [ +- "syslog:adm", +- "root:adm", +- "root:wheel", +- "root:root", +- ], + "vendor_data": {"enabled": True, "prefix": []}, + "vendor_data2": {"enabled": True, "prefix": []}, ++ "syslog_fix_perms": [], ++ "mount_default_fields": [ ++ None, ++ None, ++ "auto", ++ "defaults,nofail", ++ "0", ++ "2", ++ ], + } + ) + updated_cfg.pop("system_info") diff --git a/SOURCES/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch b/SOURCES/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch index 2d32e2c..7a224d1 100644 --- a/SOURCES/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch +++ b/SOURCES/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch @@ -1,4 +1,4 @@ -From b3b96bff187e9d0bfcbfefd5fca05c61bd50d368 Mon Sep 17 00:00:00 2001 +From 5129908caa1867c7f584ec8d38607cf56b20521a Mon Sep 17 00:00:00 2001 From: Eduardo Otubo Date: Fri, 7 May 2021 13:36:06 +0200 Subject: [PATCH] Do not write NM_CONTROLLED=no in generated interface config @@ -15,16 +15,20 @@ Merged patches (21.1): X-downstream-only: true Signed-off-by: Eduardo Otubo Signed-off-by: Ryan McCabe + +Signed-off-by: Ani Sinha --- - cloudinit/net/sysconfig.py | 12 ++++++++++-- - tests/unittests/test_net.py | 28 ---------------------------- - 2 files changed, 10 insertions(+), 30 deletions(-) + cloudinit/net/sysconfig.py | 12 ++++- + tests/unittests/cmd/devel/test_net_convert.py | 1 - + tests/unittests/distros/test_netconfig.py | 8 --- + tests/unittests/test_net.py | 53 ------------------- + 4 files changed, 10 insertions(+), 64 deletions(-) diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index d4daa78f..a7dbe55b 100644 +index 7570a5e3..f01c4236 100644 --- a/cloudinit/net/sysconfig.py +++ b/cloudinit/net/sysconfig.py -@@ -316,7 +316,6 @@ class Renderer(renderer.Renderer): +@@ -317,7 +317,6 @@ class Renderer(renderer.Renderer): "rhel": { "ONBOOT": True, "USERCTL": False, @@ -32,26 +36,106 @@ index d4daa78f..a7dbe55b 100644 "BOOTPROTO": "none", }, "suse": {"BOOTPROTO": "static", "STARTMODE": "auto"}, -@@ -1019,7 +1018,16 @@ class Renderer(renderer.Renderer): +@@ -1030,7 +1029,16 @@ class Renderer(renderer.Renderer): # Distros configuring /etc/sysconfig/network as a file e.g. Centos if sysconfig_path.endswith("network"): util.ensure_dir(os.path.dirname(sysconfig_path)) - netcfg = [_make_header(), "NETWORKING=yes"] + netcfg = [] -+ for line in util.load_file(sysconfig_path, quiet=True).split('\n'): -+ if 'cloud-init' in line: ++ for line in util.load_file(sysconfig_path, quiet=True).split("\n"): ++ if "cloud-init" in line: + break -+ if not line.startswith(('NETWORKING=', -+ 'IPV6_AUTOCONF=', -+ 'NETWORKING_IPV6=')): ++ if not line.startswith( ++ ("NETWORKING=", "IPV6_AUTOCONF=", "NETWORKING_IPV6=") ++ ): + netcfg.append(line) + # Now generate the cloud-init portion of sysconfig/network -+ netcfg.extend([_make_header(), 'NETWORKING=yes']) ++ netcfg.extend([_make_header(), "NETWORKING=yes"]) if network_state.use_ipv6: netcfg.append("NETWORKING_IPV6=yes") netcfg.append("IPV6_AUTOCONF=no") +diff --git a/tests/unittests/cmd/devel/test_net_convert.py b/tests/unittests/cmd/devel/test_net_convert.py +index fb72963f..7b9121b2 100644 +--- a/tests/unittests/cmd/devel/test_net_convert.py ++++ b/tests/unittests/cmd/devel/test_net_convert.py +@@ -62,7 +62,6 @@ SAMPLE_SYSCONFIG_CONTENT = """\ + # + BOOTPROTO=dhcp + DEVICE=eth0 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +diff --git a/tests/unittests/distros/test_netconfig.py b/tests/unittests/distros/test_netconfig.py +index 7ba430f2..962ff7fb 100644 +--- a/tests/unittests/distros/test_netconfig.py ++++ b/tests/unittests/distros/test_netconfig.py +@@ -723,7 +723,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + GATEWAY=192.168.1.254 + IPADDR=192.168.1.5 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -733,7 +732,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + """\ + BOOTPROTO=dhcp + DEVICE=eth1 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -764,7 +762,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + IPV6_AUTOCONF=no + IPV6_DEFAULTGW=2607:f0d0:1002:0011::1 + IPV6_FORCE_ACCEPT_RA=no +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -774,7 +771,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + """\ + BOOTPROTO=dhcp + DEVICE=eth1 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -821,7 +817,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + HWADDR=00:16:3e:60:7c:df + IPADDR=192.10.1.2 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -833,7 +828,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + DEVICE=infra0 + IPADDR=10.0.1.2 + NETMASK=255.255.0.0 +- NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=eth0 + USERCTL=no +@@ -869,7 +863,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + DEVICE=eth0 + IPADDR=192.10.1.2 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -881,7 +874,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + DEVICE=eth0.1001 + IPADDR=10.0.1.2 + NETMASK=255.255.0.0 +- NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=eth0 + USERCTL=no diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index 056aaeb6..0f523ff8 100644 +index c5509536..052b0674 100644 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py @@ -585,7 +585,6 @@ GATEWAY=172.19.3.254 @@ -62,7 +146,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -749,7 +748,6 @@ IPADDR=172.19.1.34 +@@ -750,7 +749,6 @@ IPADDR=172.19.1.34 IPADDR1=10.0.0.10 NETMASK=255.255.252.0 NETMASK1=255.255.255.0 @@ -70,7 +154,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -911,7 +909,6 @@ IPV6_AUTOCONF=no +@@ -912,7 +910,6 @@ IPV6_AUTOCONF=no IPV6_DEFAULTGW=2001:DB8::1 IPV6_FORCE_ACCEPT_RA=no NETMASK=255.255.252.0 @@ -78,7 +162,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -1090,7 +1087,6 @@ NETWORK_CONFIGS = { +@@ -1143,7 +1140,6 @@ NETWORK_CONFIGS = { BOOTPROTO=none DEVICE=eth1 HWADDR=cf:d6:af:48:e8:80 @@ -86,7 +170,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -1109,7 +1105,6 @@ NETWORK_CONFIGS = { +@@ -1162,7 +1158,6 @@ NETWORK_CONFIGS = { IPADDR=192.168.21.3 NETMASK=255.255.255.0 METRIC=10000 @@ -94,7 +178,23 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -1353,7 +1348,6 @@ NETWORK_CONFIGS = { +@@ -1319,7 +1314,6 @@ NETWORK_CONFIGS = { + BOOTPROTO=none + DEVICE=eth1 + HWADDR=cf:d6:af:48:e8:80 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no""" +@@ -1338,7 +1332,6 @@ NETWORK_CONFIGS = { + IPADDR=192.168.21.3 + NETMASK=255.255.255.0 + METRIC=10000 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no""" +@@ -1581,7 +1574,6 @@ NETWORK_CONFIGS = { IPV6_AUTOCONF=no IPV6_FORCE_ACCEPT_RA=no NETMASK=255.255.255.0 @@ -102,7 +202,79 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -2377,7 +2371,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -1725,7 +1717,6 @@ NETWORK_CONFIGS = { + DHCPV6C=yes + IPV6INIT=yes + DEVICE=iface0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -1816,7 +1807,6 @@ NETWORK_CONFIGS = { + IPV6INIT=yes + IPV6_FORCE_ACCEPT_RA=yes + DEVICE=iface0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -1892,7 +1882,6 @@ NETWORK_CONFIGS = { + IPV6INIT=yes + IPV6_FORCE_ACCEPT_RA=no + DEVICE=iface0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -1956,7 +1945,6 @@ NETWORK_CONFIGS = { + IPV6_AUTOCONF=yes + IPV6INIT=yes + DEVICE=iface0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -2014,7 +2002,6 @@ NETWORK_CONFIGS = { + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no + DEVICE=iface0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -2071,7 +2058,6 @@ NETWORK_CONFIGS = { + IPV6_AUTOCONF=yes + IPV6INIT=yes + DEVICE=iface0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -2157,7 +2143,6 @@ NETWORK_CONFIGS = { + IPV6_FAILURE_FATAL=yes + IPV6_FORCE_ACCEPT_RA=yes + DEVICE=iface0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -2198,7 +2183,6 @@ NETWORK_CONFIGS = { + """\ + BOOTPROTO=dhcp + DEVICE=iface0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -2275,7 +2259,6 @@ NETWORK_CONFIGS = { + BOOTPROTO=dhcp + DEVICE=iface0 + ETHTOOL_OPTS="wol g" +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -2619,7 +2602,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true DHCPV6C=yes IPV6INIT=yes MACADDR=aa:bb:cc:dd:ee:ff @@ -110,7 +282,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Bond USERCTL=no""" -@@ -2387,7 +2380,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2629,7 +2611,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true BOOTPROTO=dhcp DEVICE=bond0.200 DHCLIENT_SET_DEFAULT_ROUTE=no @@ -118,7 +290,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes PHYSDEV=bond0 USERCTL=no -@@ -2407,7 +2399,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2649,7 +2630,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true IPV6_DEFAULTGW=2001:4800:78ff:1b::1 MACADDR=bb:bb:bb:bb:bb:aa NETMASK=255.255.255.0 @@ -126,7 +298,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes PRIO=22 STP=no -@@ -2419,7 +2410,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2661,7 +2641,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true BOOTPROTO=none DEVICE=eth0 HWADDR=c0:d6:9f:2c:e8:80 @@ -134,7 +306,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -2438,7 +2428,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2680,7 +2659,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true MTU=1500 NETMASK=255.255.255.0 NETMASK1=255.255.255.0 @@ -142,7 +314,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes PHYSDEV=eth0 USERCTL=no -@@ -2450,7 +2439,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2692,7 +2670,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true DEVICE=eth1 HWADDR=aa:d6:9f:2c:e8:80 MASTER=bond0 @@ -150,7 +322,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes SLAVE=yes TYPE=Ethernet -@@ -2462,7 +2450,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2704,7 +2681,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true DEVICE=eth2 HWADDR=c0:bb:9f:2c:e8:80 MASTER=bond0 @@ -158,7 +330,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes SLAVE=yes TYPE=Ethernet -@@ -2474,7 +2461,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2716,7 +2692,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true BRIDGE=br0 DEVICE=eth3 HWADDR=66:bb:9f:2c:e8:80 @@ -166,7 +338,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -2485,7 +2471,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2727,7 +2702,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true BRIDGE=br0 DEVICE=eth4 HWADDR=98:bb:9f:2c:e8:80 @@ -174,7 +346,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -2496,7 +2481,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2738,7 +2712,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true DEVICE=eth5 DHCLIENT_SET_DEFAULT_ROUTE=no HWADDR=98:bb:9f:2c:e8:8a @@ -182,7 +354,15 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=no TYPE=Ethernet USERCTL=no""" -@@ -3220,7 +3204,6 @@ iface bond0 inet6 static +@@ -2751,7 +2724,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true + IPADDR=192.168.200.7 + MTU=9000 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=InfiniBand + USERCTL=no""" +@@ -3473,7 +3445,6 @@ iface bond0 inet6 static MTU=9000 NETMASK=255.255.255.0 NETMASK1=255.255.255.0 @@ -190,7 +370,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Bond USERCTL=no -@@ -3232,7 +3215,6 @@ iface bond0 inet6 static +@@ -3485,7 +3456,6 @@ iface bond0 inet6 static DEVICE=bond0s0 HWADDR=aa:bb:cc:dd:e8:00 MASTER=bond0 @@ -198,7 +378,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes SLAVE=yes TYPE=Ethernet -@@ -3260,7 +3242,6 @@ iface bond0 inet6 static +@@ -3513,7 +3483,6 @@ iface bond0 inet6 static DEVICE=bond0s1 HWADDR=aa:bb:cc:dd:e8:01 MASTER=bond0 @@ -206,7 +386,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes SLAVE=yes TYPE=Ethernet -@@ -3406,7 +3387,6 @@ iface bond0 inet6 static +@@ -3662,7 +3631,6 @@ iface bond0 inet6 static BOOTPROTO=none DEVICE=en0 HWADDR=aa:bb:cc:dd:e8:00 @@ -214,7 +394,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -3427,7 +3407,6 @@ iface bond0 inet6 static +@@ -3683,7 +3651,6 @@ iface bond0 inet6 static MTU=2222 NETMASK=255.255.255.0 NETMASK1=255.255.255.0 @@ -222,7 +402,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes PHYSDEV=en0 USERCTL=no -@@ -3553,7 +3532,6 @@ iface bond0 inet6 static +@@ -3811,7 +3778,6 @@ iface bond0 inet6 static DEVICE=br0 IPADDR=192.168.2.2 NETMASK=255.255.255.0 @@ -230,7 +410,23 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes PRIO=22 STP=no -@@ -3769,7 +3747,6 @@ iface bond0 inet6 static +@@ -3829,7 +3795,6 @@ iface bond0 inet6 static + IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -3845,7 +3810,6 @@ iface bond0 inet6 static + IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -4030,7 +3994,6 @@ iface bond0 inet6 static HWADDR=52:54:00:12:34:00 IPADDR=192.168.1.2 NETMASK=255.255.255.0 @@ -238,7 +434,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=no TYPE=Ethernet USERCTL=no -@@ -3781,7 +3758,6 @@ iface bond0 inet6 static +@@ -4042,7 +4005,6 @@ iface bond0 inet6 static DEVICE=eth1 HWADDR=52:54:00:12:34:aa MTU=1480 @@ -246,7 +442,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -3792,7 +3768,6 @@ iface bond0 inet6 static +@@ -4053,7 +4015,6 @@ iface bond0 inet6 static BOOTPROTO=none DEVICE=eth2 HWADDR=52:54:00:12:34:ff @@ -254,7 +450,15 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=no TYPE=Ethernet USERCTL=no -@@ -4469,7 +4444,6 @@ class TestRhelSysConfigRendering(CiTestCase): +@@ -4138,7 +4099,6 @@ iface bond0 inet6 static + BOOTPROTO=none + DEVICE=eth0 + HWADDR=cf:d6:af:48:e8:80 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no""" +@@ -4736,7 +4696,6 @@ class TestRhelSysConfigRendering(CiTestCase): BOOTPROTO=dhcp DEVICE=eth1000 HWADDR=07-1c-c6-75-a4-be @@ -262,7 +466,7 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -4681,7 +4655,6 @@ GATEWAY=10.0.2.2 +@@ -4948,7 +4907,6 @@ GATEWAY=10.0.2.2 HWADDR=52:54:00:12:34:00 IPADDR=10.0.2.15 NETMASK=255.255.255.0 @@ -270,7 +474,23 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -4751,7 +4724,6 @@ USERCTL=no +@@ -4979,7 +4937,6 @@ HWADDR=fa:16:3e:25:b4:59 + IPADDR=51.68.89.122 + MTU=1500 + NETMASK=255.255.240.0 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -4993,7 +4950,6 @@ DEVICE=eth1 + DHCLIENT_SET_DEFAULT_ROUTE=no + HWADDR=fa:16:3e:b1:ca:29 + MTU=9000 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -5018,7 +4974,6 @@ USERCTL=no # BOOTPROTO=dhcp DEVICE=eth0 @@ -278,3 +498,67 @@ index 056aaeb6..0f523ff8 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no +@@ -5251,7 +5206,6 @@ USERCTL=no + IPV6_FORCE_ACCEPT_RA=no + IPV6_DEFAULTGW=2001:db8::1 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -5283,7 +5237,6 @@ USERCTL=no + """\ + BOOTPROTO=none + DEVICE=eno1 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -5296,7 +5249,6 @@ USERCTL=no + IPADDR=192.6.1.9 + MTU=1495 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=eno1 + USERCTL=no +@@ -5332,7 +5284,6 @@ USERCTL=no + IPADDR=10.101.8.65 + MTU=1334 + NETMASK=255.255.255.192 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Bond + USERCTL=no +@@ -5344,7 +5295,6 @@ USERCTL=no + BOOTPROTO=none + DEVICE=enp0s0 + MASTER=bond0 +- NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes + TYPE=Bond +@@ -5357,7 +5307,6 @@ USERCTL=no + BOOTPROTO=none + DEVICE=enp0s1 + MASTER=bond0 +- NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes + TYPE=Bond +@@ -5388,7 +5337,6 @@ USERCTL=no + DEVICE=eno1 + HWADDR=07-1c-c6-75-a4-be + METRIC=100 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -5479,7 +5427,6 @@ USERCTL=no + IPV6_FORCE_ACCEPT_RA=no + MTU=1400 + NETMASK=255.255.248.0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no diff --git a/SOURCES/0022-test-fixes-update-tests-to-reflect-AUTOCONNECT_PRIOR.patch b/SOURCES/0003-Setting-autoconnect-priority-setting-for-network-scr.patch similarity index 68% rename from SOURCES/0022-test-fixes-update-tests-to-reflect-AUTOCONNECT_PRIOR.patch rename to SOURCES/0003-Setting-autoconnect-priority-setting-for-network-scr.patch index eb85d1a..3a1513b 100644 --- a/SOURCES/0022-test-fixes-update-tests-to-reflect-AUTOCONNECT_PRIOR.patch +++ b/SOURCES/0003-Setting-autoconnect-priority-setting-for-network-scr.patch @@ -1,8 +1,52 @@ -From 908387bc0a73ae3431c0ad90f83e6a4a4e902edb Mon Sep 17 00:00:00 2001 +From 8a2fcbbcfdfc1df6f6c18f96588154f40083a239 Mon Sep 17 00:00:00 2001 From: Ani Sinha -Date: Fri, 23 Jun 2023 15:47:09 +0530 -Subject: [PATCH] test fixes: update tests to reflect AUTOCONNECT_PRIORITY - setting +Date: Wed, 13 Dec 2023 11:55:16 +0530 +Subject: [PATCH] Setting autoconnect priority setting for network-scripts + +Squashed the following three downstream only commits from RHEL 9.3: + +Commit 1: + +Setting highest autoconnect priority for network-scripts + +RH-Author: Eduardo Otubo +RH-MergeRequest: 22: Setting highest autoconnect priority for network-scripts +RH-Commit: [1/1] 34f1d62f8934a983a124df95b861a1e448681d3b (otubo/cloud-init-src) +RH-Bugzilla: 2036060 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Emanuele Giuseppe Esposito + +Set the highest autoconnect priority for network-scripts which is +loaded by NetworkManager ifcfg-rh plugin. Note that keyfile is the only +and default existing plugin on RHEL9, by setting the highest autoconnect +priority for network-scripts, NetworkManager will activate +network-scripts but keyfile. Network-scripts path: + +Since this is a blocking issue, we decided to have this one-liner +downstream-only patch so we can move forward and have a better +NetworkManager support later on the release. + +rhbz: 2036060 +x-downstream-only: yes + +Commit 2: + +net/sysconfig: do not use the highest autoconnect priority + +Using the highest priority is a very big hammer that we may not want to use. We +may want users to override the cloud init generated ifcfg files for custom +configuration of interfaces. If cloud init uses the highest priority, nothing +can beat it. Hence lower the priority to 120 allowing values from 121 to 999 +to be used by users if they want to use a custom interface nm keyfile. + +X-downstream-only: true + +Suggested-by: thaller@redhat.com +fixes: c589da20eb92231 ("Setting highest autoconnect priority for network-scripts") + +Commit 3: + +test fixes: update tests to reflect AUTOCONNECT_PRIORITY setting X-downstream-only: true fixes: 0a2c6b6118ff ("net/sysconfig: do not use the highest autoconnect priority") @@ -10,25 +54,38 @@ fixes: c589da20eb92 ("Setting highest autoconnect priority for network-scripts") Signed-off-by: Ani Sinha --- + cloudinit/net/sysconfig.py | 1 + tests/unittests/cmd/devel/test_net_convert.py | 1 + tests/unittests/distros/test_netconfig.py | 8 +++ - tests/unittests/test_net.py | 51 +++++++++++++++++++ - 3 files changed, 60 insertions(+) + tests/unittests/test_net.py | 53 +++++++++++++++++++ + 4 files changed, 63 insertions(+) +diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py +index f01c4236..d39f4fe3 100644 +--- a/cloudinit/net/sysconfig.py ++++ b/cloudinit/net/sysconfig.py +@@ -318,6 +318,7 @@ class Renderer(renderer.Renderer): + "ONBOOT": True, + "USERCTL": False, + "BOOTPROTO": "none", ++ "AUTOCONNECT_PRIORITY": 120, + }, + "suse": {"BOOTPROTO": "static", "STARTMODE": "auto"}, + } diff --git a/tests/unittests/cmd/devel/test_net_convert.py b/tests/unittests/cmd/devel/test_net_convert.py -index 71654750..43e879f7 100644 +index 7b9121b2..288e3e37 100644 --- a/tests/unittests/cmd/devel/test_net_convert.py +++ b/tests/unittests/cmd/devel/test_net_convert.py @@ -60,6 +60,7 @@ DHCP=ipv4 SAMPLE_SYSCONFIG_CONTENT = """\ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # +AUTOCONNECT_PRIORITY=120 BOOTPROTO=dhcp DEVICE=eth0 - NM_CONTROLLED=no + ONBOOT=yes diff --git a/tests/unittests/distros/test_netconfig.py b/tests/unittests/distros/test_netconfig.py -index b1c89ce3..eaf723c8 100644 +index 962ff7fb..4c624079 100644 --- a/tests/unittests/distros/test_netconfig.py +++ b/tests/unittests/distros/test_netconfig.py @@ -717,6 +717,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): @@ -39,15 +96,15 @@ index b1c89ce3..eaf723c8 100644 BOOTPROTO=none DEFROUTE=yes DEVICE=eth0 -@@ -731,6 +732,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): +@@ -730,6 +731,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): ), self.ifcfg_path("eth1"): dedent( """\ + AUTOCONNECT_PRIORITY=120 BOOTPROTO=dhcp DEVICE=eth1 - NM_CONTROLLED=no -@@ -756,6 +758,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + ONBOOT=yes +@@ -754,6 +756,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): expected_cfgs = { self.ifcfg_path("eth0"): dedent( """\ @@ -55,15 +112,15 @@ index b1c89ce3..eaf723c8 100644 BOOTPROTO=none DEFROUTE=yes DEVICE=eth0 -@@ -772,6 +775,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): +@@ -769,6 +772,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): ), self.ifcfg_path("eth1"): dedent( """\ + AUTOCONNECT_PRIORITY=120 BOOTPROTO=dhcp DEVICE=eth1 - NM_CONTROLLED=no -@@ -816,6 +820,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + ONBOOT=yes +@@ -812,6 +816,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): expected_cfgs = { self.ifcfg_path("eth0"): dedent( """\ @@ -71,7 +128,7 @@ index b1c89ce3..eaf723c8 100644 BOOTPROTO=none DEVICE=eth0 HWADDR=00:16:3e:60:7c:df -@@ -829,6 +834,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): +@@ -824,6 +829,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): ), self.ifcfg_path("infra0"): dedent( """\ @@ -79,7 +136,7 @@ index b1c89ce3..eaf723c8 100644 BOOTPROTO=none DEVICE=infra0 IPADDR=10.0.1.2 -@@ -865,6 +871,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): +@@ -859,6 +865,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): expected_cfgs = { self.ifcfg_path("eth0"): dedent( """\ @@ -87,7 +144,7 @@ index b1c89ce3..eaf723c8 100644 BOOTPROTO=none DEVICE=eth0 IPADDR=192.10.1.2 -@@ -877,6 +884,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): +@@ -870,6 +877,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): ), self.ifcfg_path("eth0.1001"): dedent( """\ @@ -96,12 +153,12 @@ index b1c89ce3..eaf723c8 100644 DEVICE=eth0.1001 IPADDR=10.0.1.2 diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index 7abe61b9..1261840b 100644 +index 052b0674..cef4fa2d 100644 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py @@ -578,6 +578,7 @@ dns = none """ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # +AUTOCONNECT_PRIORITY=120 BOOTPROTO=none @@ -109,7 +166,7 @@ index 7abe61b9..1261840b 100644 DEVICE=eth0 @@ -740,6 +741,7 @@ dns = none """ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # +AUTOCONNECT_PRIORITY=120 BOOTPROTO=none @@ -117,13 +174,13 @@ index 7abe61b9..1261840b 100644 DEVICE=eth0 @@ -897,6 +899,7 @@ dns = none """ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # +AUTOCONNECT_PRIORITY=120 BOOTPROTO=none DEFROUTE=yes DEVICE=eth0 -@@ -1085,6 +1088,7 @@ NETWORK_CONFIGS = { +@@ -1137,6 +1140,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-eth1": textwrap.dedent( """\ @@ -131,7 +188,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=eth1 HWADDR=cf:d6:af:48:e8:80 -@@ -1094,6 +1098,7 @@ NETWORK_CONFIGS = { +@@ -1146,6 +1150,7 @@ NETWORK_CONFIGS = { ), "ifcfg-eth99": textwrap.dedent( """\ @@ -139,7 +196,23 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=dhcp DEFROUTE=yes DEVICE=eth99 -@@ -1344,6 +1349,7 @@ NETWORK_CONFIGS = { +@@ -1311,6 +1316,7 @@ NETWORK_CONFIGS = { + "expected_sysconfig_rhel": { + "ifcfg-eth1": textwrap.dedent( + """\ ++ AUTOCONNECT_PRIORITY=120 + BOOTPROTO=none + DEVICE=eth1 + HWADDR=cf:d6:af:48:e8:80 +@@ -1320,6 +1326,7 @@ NETWORK_CONFIGS = { + ), + "ifcfg-eth99": textwrap.dedent( + """\ ++ AUTOCONNECT_PRIORITY=120 + BOOTPROTO=dhcp + DEFROUTE=yes + DEVICE=eth99 +@@ -1566,6 +1573,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ @@ -147,7 +220,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=iface0 IPADDR=192.168.14.2 -@@ -1490,6 +1496,7 @@ NETWORK_CONFIGS = { +@@ -1712,6 +1720,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ @@ -155,7 +228,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=iface0 DHCPV6C=yes -@@ -1580,6 +1587,7 @@ NETWORK_CONFIGS = { +@@ -1801,6 +1810,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ @@ -163,7 +236,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=iface0 DHCPV6C=yes -@@ -1656,6 +1664,7 @@ NETWORK_CONFIGS = { +@@ -1876,6 +1886,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ @@ -171,7 +244,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=iface0 DHCPV6C=yes -@@ -1721,6 +1730,7 @@ NETWORK_CONFIGS = { +@@ -1940,6 +1951,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ @@ -179,7 +252,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=iface0 IPV6_AUTOCONF=yes -@@ -1774,6 +1784,7 @@ NETWORK_CONFIGS = { +@@ -1995,6 +2007,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ @@ -187,7 +260,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=iface0 IPV6ADDR=2001:1::1/64 -@@ -1831,6 +1842,7 @@ NETWORK_CONFIGS = { +@@ -2051,6 +2064,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ @@ -195,23 +268,23 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=iface0 DHCPV6C=yes -@@ -1913,6 +1925,7 @@ NETWORK_CONFIGS = { +@@ -2135,6 +2149,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ + AUTOCONNECT_PRIORITY=120 - BOOTPROTO=dhcp + BOOTPROTO=none DEVICE=iface0 DHCPV6C=yes -@@ -1959,6 +1972,7 @@ NETWORK_CONFIGS = { +@@ -2181,6 +2196,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ + AUTOCONNECT_PRIORITY=120 BOOTPROTO=dhcp DEVICE=iface0 - NM_CONTROLLED=no -@@ -2035,6 +2049,7 @@ NETWORK_CONFIGS = { + ONBOOT=yes +@@ -2256,6 +2272,7 @@ NETWORK_CONFIGS = { "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ @@ -219,7 +292,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=dhcp DEVICE=iface0 ETHTOOL_OPTS="wol g" -@@ -2371,6 +2386,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2591,6 +2608,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true "expected_sysconfig_rhel": { "ifcfg-bond0": textwrap.dedent( """\ @@ -227,7 +300,7 @@ index 7abe61b9..1261840b 100644 BONDING_MASTER=yes BONDING_OPTS="mode=active-backup """ """xmit_hash_policy=layer3+4 """ -@@ -2388,6 +2404,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2608,6 +2626,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true ), "ifcfg-bond0.200": textwrap.dedent( """\ @@ -235,7 +308,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=dhcp DEVICE=bond0.200 DHCLIENT_SET_DEFAULT_ROUTE=no -@@ -2399,6 +2416,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2619,6 +2638,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true "ifcfg-br0": textwrap.dedent( """\ AGEING=250 @@ -243,7 +316,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEFROUTE=yes DEVICE=br0 -@@ -2418,6 +2436,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2638,6 +2658,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true ), "ifcfg-eth0": textwrap.dedent( """\ @@ -251,7 +324,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=eth0 HWADDR=c0:d6:9f:2c:e8:80 -@@ -2427,6 +2446,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2647,6 +2668,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true ), "ifcfg-eth0.101": textwrap.dedent( """\ @@ -259,7 +332,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEFROUTE=yes DEVICE=eth0.101 -@@ -2446,6 +2466,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2666,6 +2688,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true ), "ifcfg-eth1": textwrap.dedent( """\ @@ -267,7 +340,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=eth1 HWADDR=aa:d6:9f:2c:e8:80 -@@ -2457,6 +2478,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2677,6 +2700,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true ), "ifcfg-eth2": textwrap.dedent( """\ @@ -275,7 +348,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=eth2 HWADDR=c0:bb:9f:2c:e8:80 -@@ -2468,6 +2490,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2688,6 +2712,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true ), "ifcfg-eth3": textwrap.dedent( """\ @@ -283,7 +356,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none BRIDGE=br0 DEVICE=eth3 -@@ -2478,6 +2501,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2698,6 +2723,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true ), "ifcfg-eth4": textwrap.dedent( """\ @@ -291,7 +364,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none BRIDGE=br0 DEVICE=eth4 -@@ -2488,6 +2512,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2708,6 +2734,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true ), "ifcfg-eth5": textwrap.dedent( """\ @@ -299,7 +372,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=dhcp DEVICE=eth5 DHCLIENT_SET_DEFAULT_ROUTE=no -@@ -2498,6 +2523,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2718,6 +2745,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true ), "ifcfg-ib0": textwrap.dedent( """\ @@ -307,7 +380,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=ib0 HWADDR=a0:00:02:20:fe:80:00:00:00:00:00:00:ec:0d:9a:03:00:15:e2:c1 -@@ -3203,6 +3229,7 @@ iface bond0 inet6 static +@@ -3422,6 +3450,7 @@ iface bond0 inet6 static "expected_sysconfig_rhel": { "ifcfg-bond0": textwrap.dedent( """\ @@ -315,7 +388,7 @@ index 7abe61b9..1261840b 100644 BONDING_MASTER=yes BONDING_OPTS="mode=active-backup xmit_hash_policy=layer3+4 """ """miimon=100 num_grat_arp=5 """ -@@ -3233,6 +3260,7 @@ iface bond0 inet6 static +@@ -3452,6 +3481,7 @@ iface bond0 inet6 static ), "ifcfg-bond0s0": textwrap.dedent( """\ @@ -323,7 +396,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=bond0s0 HWADDR=aa:bb:cc:dd:e8:00 -@@ -3260,6 +3288,7 @@ iface bond0 inet6 static +@@ -3479,6 +3509,7 @@ iface bond0 inet6 static ), "ifcfg-bond0s1": textwrap.dedent( """\ @@ -331,7 +404,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=bond0s1 HWADDR=aa:bb:cc:dd:e8:01 -@@ -3409,6 +3438,7 @@ iface bond0 inet6 static +@@ -3628,6 +3659,7 @@ iface bond0 inet6 static "expected_sysconfig_rhel": { "ifcfg-en0": textwrap.dedent( """\ @@ -339,7 +412,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=en0 HWADDR=aa:bb:cc:dd:e8:00 -@@ -3418,6 +3448,7 @@ iface bond0 inet6 static +@@ -3637,6 +3669,7 @@ iface bond0 inet6 static ), "ifcfg-en0.99": textwrap.dedent( """\ @@ -347,7 +420,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEFROUTE=yes DEVICE=en0.99 -@@ -3555,6 +3586,7 @@ iface bond0 inet6 static +@@ -3774,6 +3807,7 @@ iface bond0 inet6 static "expected_sysconfig_rhel": { "ifcfg-br0": textwrap.dedent( """\ @@ -355,7 +428,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=br0 IPADDR=192.168.2.2 -@@ -3568,6 +3600,7 @@ iface bond0 inet6 static +@@ -3787,6 +3821,7 @@ iface bond0 inet6 static ), "ifcfg-eth0": textwrap.dedent( """\ @@ -363,7 +436,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none BRIDGE=br0 DEVICE=eth0 -@@ -3584,6 +3617,7 @@ iface bond0 inet6 static +@@ -3802,6 +3837,7 @@ iface bond0 inet6 static ), "ifcfg-eth1": textwrap.dedent( """\ @@ -371,7 +444,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none BRIDGE=br0 DEVICE=eth1 -@@ -3772,6 +3806,7 @@ iface bond0 inet6 static +@@ -3989,6 +4025,7 @@ iface bond0 inet6 static "expected_sysconfig_rhel": { "ifcfg-eth0": textwrap.dedent( """\ @@ -379,7 +452,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=eth0 HWADDR=52:54:00:12:34:00 -@@ -3784,6 +3819,7 @@ iface bond0 inet6 static +@@ -4001,6 +4038,7 @@ iface bond0 inet6 static ), "ifcfg-eth1": textwrap.dedent( """\ @@ -387,7 +460,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=eth1 HWADDR=52:54:00:12:34:aa -@@ -3795,6 +3831,7 @@ iface bond0 inet6 static +@@ -4012,6 +4050,7 @@ iface bond0 inet6 static ), "ifcfg-eth2": textwrap.dedent( """\ @@ -395,7 +468,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=eth2 HWADDR=52:54:00:12:34:ff -@@ -3879,6 +3916,7 @@ iface bond0 inet6 static +@@ -4096,6 +4135,7 @@ iface bond0 inet6 static "expected_sysconfig_rhel": { "ifcfg-eth0": textwrap.dedent( """\ @@ -403,47 +476,47 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=eth0 HWADDR=cf:d6:af:48:e8:80 -@@ -4474,6 +4512,7 @@ class TestRhelSysConfigRendering(CiTestCase): +@@ -4693,6 +4733,7 @@ class TestRhelSysConfigRendering(CiTestCase): expected_content = """ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # +AUTOCONNECT_PRIORITY=120 BOOTPROTO=dhcp DEVICE=eth1000 HWADDR=07-1c-c6-75-a4-be -@@ -4681,6 +4720,7 @@ USERCTL=no +@@ -4900,6 +4941,7 @@ USERCTL=no expected = """\ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # +AUTOCONNECT_PRIORITY=120 BOOTPROTO=none DEFROUTE=yes DEVICE=interface0 -@@ -4710,6 +4750,7 @@ USERCTL=no +@@ -4929,6 +4971,7 @@ USERCTL=no expected_i1 = """\ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # +AUTOCONNECT_PRIORITY=120 BOOTPROTO=none DEFROUTE=yes DEVICE=eth0 -@@ -4727,6 +4768,7 @@ USERCTL=no +@@ -4945,6 +4988,7 @@ USERCTL=no expected_i2 = """\ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # +AUTOCONNECT_PRIORITY=120 BOOTPROTO=dhcp DEVICE=eth1 DHCLIENT_SET_DEFAULT_ROUTE=no -@@ -4755,6 +4797,7 @@ USERCTL=no +@@ -4972,6 +5016,7 @@ USERCTL=no expected = """\ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # +AUTOCONNECT_PRIORITY=120 BOOTPROTO=dhcp DEVICE=eth0 ONBOOT=yes -@@ -4968,6 +5011,7 @@ USERCTL=no +@@ -5191,6 +5236,7 @@ USERCTL=no "expected_sysconfig": { "ifcfg-ens3": textwrap.dedent( """\ @@ -451,15 +524,15 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEFROUTE=yes DEVICE=ens3 -@@ -5013,6 +5057,7 @@ USERCTL=no +@@ -5235,6 +5281,7 @@ USERCTL=no expected = { "ifcfg-eno1": textwrap.dedent( """\ + AUTOCONNECT_PRIORITY=120 BOOTPROTO=none DEVICE=eno1 - NM_CONTROLLED=no -@@ -5023,6 +5068,7 @@ USERCTL=no + ONBOOT=yes +@@ -5244,6 +5291,7 @@ USERCTL=no ), "ifcfg-eno1.1000": textwrap.dedent( """\ @@ -467,7 +540,7 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=none DEVICE=eno1.1000 IPADDR=192.6.1.9 -@@ -5056,6 +5102,7 @@ USERCTL=no +@@ -5276,6 +5324,7 @@ USERCTL=no expected = { "ifcfg-bond0": textwrap.dedent( """\ @@ -475,7 +548,7 @@ index 7abe61b9..1261840b 100644 BONDING_MASTER=yes BONDING_SLAVE0=enp0s0 BONDING_SLAVE1=enp0s1 -@@ -5072,6 +5119,7 @@ USERCTL=no +@@ -5291,6 +5340,7 @@ USERCTL=no ), "ifcfg-enp0s0": textwrap.dedent( """\ @@ -483,7 +556,7 @@ index 7abe61b9..1261840b 100644 BONDING_MASTER=yes BOOTPROTO=none DEVICE=enp0s0 -@@ -5085,6 +5133,7 @@ USERCTL=no +@@ -5303,6 +5353,7 @@ USERCTL=no ), "ifcfg-enp0s1": textwrap.dedent( """\ @@ -491,7 +564,7 @@ index 7abe61b9..1261840b 100644 BONDING_MASTER=yes BOOTPROTO=none DEVICE=enp0s1 -@@ -5116,6 +5165,7 @@ USERCTL=no +@@ -5333,6 +5384,7 @@ USERCTL=no expected = { "ifcfg-eno1": textwrap.dedent( """\ @@ -499,9 +572,9 @@ index 7abe61b9..1261840b 100644 BOOTPROTO=dhcp DEVICE=eno1 HWADDR=07-1c-c6-75-a4-be -@@ -5195,6 +5245,7 @@ USERCTL=no +@@ -5411,6 +5463,7 @@ USERCTL=no """\ - # Created by cloud-init on instance boot automatically, do not edit. + # Created by cloud-init automatically, do not edit. # + AUTOCONNECT_PRIORITY=120 BOOTPROTO=none diff --git a/SOURCES/0003-Setting-highest-autoconnect-priority-for-network-scr.patch b/SOURCES/0003-Setting-highest-autoconnect-priority-for-network-scr.patch deleted file mode 100644 index c9b7740..0000000 --- a/SOURCES/0003-Setting-highest-autoconnect-priority-for-network-scr.patch +++ /dev/null @@ -1,42 +0,0 @@ -From c589da20eb92231ef08e10c9724e3e6c663e6ce2 Mon Sep 17 00:00:00 2001 -From: Eduardo Otubo -Date: Thu, 17 Feb 2022 15:32:35 +0100 -Subject: [PATCH] Setting highest autoconnect priority for network-scripts - -RH-Author: Eduardo Otubo -RH-MergeRequest: 22: Setting highest autoconnect priority for network-scripts -RH-Commit: [1/1] 34f1d62f8934a983a124df95b861a1e448681d3b (otubo/cloud-init-src) -RH-Bugzilla: 2036060 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Emanuele Giuseppe Esposito - -Set the highest autoconnect priority for network-scripts which is -loaded by NetworkManager ifcfg-rh plugin. Note that keyfile is the only -and default existing plugin on RHEL9, by setting the highest autoconnect -priority for network-scripts, NetworkManager will activate -network-scripts but keyfile. Network-scripts path: - -Since this is a blocking issue, we decided to have this one-liner -downstream-only patch so we can move forward and have a better -NetworkManager support later on the release. - -rhbz: 2036060 -x-downstream-only: yes - -Signed-off-by: Eduardo Otubo ---- - cloudinit/net/sysconfig.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index a7dbe55b..4262cd48 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -317,6 +317,7 @@ class Renderer(renderer.Renderer): - "ONBOOT": True, - "USERCTL": False, - "BOOTPROTO": "none", -+ "AUTOCONNECT_PRIORITY": 999 - }, - "suse": {"BOOTPROTO": "static", "STARTMODE": "auto"}, - } diff --git a/SOURCES/0004-limit-permissions-on-def_log_file.patch b/SOURCES/0004-limit-permissions-on-def_log_file.patch deleted file mode 100644 index e69dd15..0000000 --- a/SOURCES/0004-limit-permissions-on-def_log_file.patch +++ /dev/null @@ -1,69 +0,0 @@ -From dfff374f66904e84fb07ca157ba010fac6b5f1de Mon Sep 17 00:00:00 2001 -From: Eduardo Otubo -Date: Fri, 7 May 2021 13:36:08 +0200 -Subject: [PATCH] limit permissions on def_log_file - -This sets a default mode of 0600 on def_log_file, and makes this -configurable via the def_log_file_mode option in cloud.cfg. - -LP: #1541196 -Resolves: rhbz#1424612 -X-approved-upstream: true - -Conflicts 21.1: - cloudinit/stages.py: adjusting call of ensure_file() to use more -recent version -Confilicts 23.1.1: - use "" instead of '' - -Signed-off-by: Emanuele Giuseppe Esposito -Signed-off-by: Eduardo Otubo ---- - cloudinit/settings.py | 1 + - cloudinit/stages.py | 1 + - doc/examples/cloud-config.txt | 4 ++++ - 3 files changed, 6 insertions(+) - -diff --git a/cloudinit/settings.py b/cloudinit/settings.py -index edbb217d..3d541141 100644 ---- a/cloudinit/settings.py -+++ b/cloudinit/settings.py -@@ -52,6 +52,7 @@ CFG_BUILTIN = { - "None", - ], - "def_log_file": "/var/log/cloud-init.log", -+ "def_log_file_mode": 0o600, - "log_cfgs": [], - "mount_default_fields": [None, None, "auto", "defaults,nofail", "0", "2"], - "syslog_fix_perms": [], -diff --git a/cloudinit/stages.py b/cloudinit/stages.py -index 9494a0bf..a624a6fb 100644 ---- a/cloudinit/stages.py -+++ b/cloudinit/stages.py -@@ -202,6 +202,7 @@ class Init: - def _initialize_filesystem(self): - util.ensure_dirs(self._initial_subdirs()) - log_file = util.get_cfg_option_str(self.cfg, "def_log_file") -+ log_file_mode = util.get_cfg_option_int(self.cfg, "def_log_file_mode") - if log_file: - util.ensure_file(log_file, mode=0o640, preserve_mode=True) - perms = self.cfg.get("syslog_fix_perms") -diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt -index 15d788f3..b6d16c9c 100644 ---- a/doc/examples/cloud-config.txt -+++ b/doc/examples/cloud-config.txt -@@ -383,10 +383,14 @@ timezone: US/Eastern - # if syslog_fix_perms is a list, it will iterate through and use the - # first pair that does not raise error. - # -+# 'def_log_file' will be created with mode 'def_log_file_mode', which -+# is specified as a numeric value and defaults to 0600. -+# - # the default values are '/var/log/cloud-init.log' and 'syslog:adm' - # the value of 'def_log_file' should match what is configured in logging - # if either is empty, then no change of ownership will be done - def_log_file: /var/log/my-logging-file.log -+def_log_file_mode: 0600 - syslog_fix_perms: syslog:root - - # you can set passwords for a user or multiple users diff --git a/SOURCES/0004-net-network_manager-do-not-set-may-fail-to-False-for.patch b/SOURCES/0004-net-network_manager-do-not-set-may-fail-to-False-for.patch new file mode 100644 index 0000000..f8de026 --- /dev/null +++ b/SOURCES/0004-net-network_manager-do-not-set-may-fail-to-False-for.patch @@ -0,0 +1,140 @@ +From 5fa8113a9efaa90f293b95477c4fa44e3d4b6537 Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Thu, 23 Nov 2023 12:27:51 +0530 +Subject: [PATCH] net/network_manager: do not set "may-fail" to False for both + ipv4 and ipv6 dhcp + +If "may-fail" is set to False in the Network Manager keyfile for both ipv4 +and ipv6 for dhcp configuration, it essentially means both ipv4 and ipv6 network +initialization using dhcp must succeed for the overall network configuration to +succeed. This means, for environments where only ipv4 or ipv6 is available but +not both and we need to configure both ipv4 and ipv6 dhcp, the overall +network configuration will fail. This is not what we want. When both ipv4 +and ipv6 dhcp are configured, it is enough for the overall configuration to +succeed if any one succeeds. +Therefore, set "may-fail" to True for both ipv4 and ipv6 if and only if both +ipv4 and ipv6 are configured as dhcp in the Network Manager keyfile and +"may-fail" is set to False for both. If both ipv4 and ipv6 are configured +in the keyfile and if for any of them "may-fail" is already set to True,then +do nothing. +All other cases remain same as before. + +Please see discussions in PR #4474. + +Co-authored-by: James Falcon +Signed-off-by: Ani Sinha +(cherry picked from commit 29dd5ace73ad60c7452c39b840045fb47fe0711f) +--- + cloudinit/net/network_manager.py | 59 ++++++++++++++++++++++++++++++++ + tests/unittests/test_net.py | 8 ++--- + 2 files changed, 63 insertions(+), 4 deletions(-) + +diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py +index 8374cfcc..8a99eb3a 100644 +--- a/cloudinit/net/network_manager.py ++++ b/cloudinit/net/network_manager.py +@@ -71,6 +71,57 @@ class NMConnection: + if not self.config.has_option(section, option): + self.config[section][option] = value + ++ def _config_option_is_set(self, section, option): ++ """ ++ Checks if a config option is set. Returns True if it is, ++ else returns False. ++ """ ++ return self.config.has_section(section) and self.config.has_option( ++ section, option ++ ) ++ ++ def _get_config_option(self, section, option): ++ """ ++ Returns the value of a config option if its set, ++ else returns None. ++ """ ++ if self._config_option_is_set(section, option): ++ return self.config[section][option] ++ else: ++ return None ++ ++ def _change_set_config_option(self, section, option, value): ++ """ ++ Overrides the value of a config option if its already set. ++ Else, if the config option is not set, it does nothing. ++ """ ++ if self._config_option_is_set(section, option): ++ self.config[section][option] = value ++ ++ def _set_mayfail_true_if_both_false_dhcp(self): ++ """ ++ If for both ipv4 and ipv6, 'may-fail' is set to be False, ++ set it to True for both of them. ++ """ ++ for family in ["ipv4", "ipv6"]: ++ if self._get_config_option(family, "may-fail") != "false": ++ # if either ipv4 or ipv6 sections are not set/configured, ++ # or if both are configured but for either ipv4 or ipv6, ++ # 'may-fail' is not 'false', do not do anything. ++ return ++ if self._get_config_option(family, "method") not in [ ++ "dhcp", ++ "auto", ++ ]: ++ # if both v4 and v6 are not dhcp, do not do anything. ++ return ++ ++ # If we landed here, it means both ipv4 and ipv6 are configured ++ # with dhcp/auto and both have 'may-fail' set to 'false'. So set ++ # both to 'true'. ++ for family in ["ipv4", "ipv6"]: ++ self._change_set_config_option(family, "may-fail", "true") ++ + def _set_ip_method(self, family, subnet_type): + """ + Ensures there's appropriate [ipv4]/[ipv6] for given family +@@ -271,6 +322,14 @@ class NMConnection: + if family == "ipv4" and "mtu" in subnet: + ipv4_mtu = subnet["mtu"] + ++ # we do not want to set may-fail to false for both ipv4 and ipv6 dhcp ++ # at the at the same time. This will make the network configuration ++ # work only when both ipv4 and ipv6 dhcp succeeds. This may not be ++ # what we want. If we have configured both ipv4 and ipv6 dhcp, any one ++ # succeeding should be enough. Therefore, if "may-fail" is set to ++ # False for both ipv4 and ipv6 dhcp, set them both to True. ++ self._set_mayfail_true_if_both_false_dhcp() ++ + if ipv4_mtu is None: + ipv4_mtu = device_mtu + if not ipv4_mtu == device_mtu: +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index cef4fa2d..fb4c863c 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -1477,11 +1477,11 @@ NETWORK_CONFIGS = { + + [ipv4] + method=auto +- may-fail=false ++ may-fail=true + + [ipv6] + method=auto +- may-fail=false ++ may-fail=true + + """ + ), +@@ -1650,11 +1650,11 @@ NETWORK_CONFIGS = { + + [ipv6] + method=auto +- may-fail=false ++ may-fail=true + + [ipv4] + method=auto +- may-fail=false ++ may-fail=true + + """ + ), diff --git a/SOURCES/0005-Manual-revert-Use-Network-Manager-and-Netplan-as-def.patch b/SOURCES/0005-Manual-revert-Use-Network-Manager-and-Netplan-as-def.patch deleted file mode 100644 index b1d3933..0000000 --- a/SOURCES/0005-Manual-revert-Use-Network-Manager-and-Netplan-as-def.patch +++ /dev/null @@ -1,92 +0,0 @@ -From ecae81f98ce230266eb99671b74534a4ede660f0 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Fri, 10 Mar 2023 11:51:48 +0100 -Subject: [PATCH] Manual revert "Use Network-Manager and Netplan as default - renderers for RHEL and Fedora (#1465)" - -This reverts changes done in commit 7703aa98b. -Done by hand because the doc file affected by that commit has changed. - -X-downstream-only: true - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/net/renderers.py | 1 - - config/cloud.cfg.tmpl | 3 --- - doc/rtd/reference/network-config.rst | 16 ++-------------- - 3 files changed, 2 insertions(+), 18 deletions(-) - -diff --git a/cloudinit/net/renderers.py b/cloudinit/net/renderers.py -index fcf7feba..b241683f 100644 ---- a/cloudinit/net/renderers.py -+++ b/cloudinit/net/renderers.py -@@ -30,7 +30,6 @@ DEFAULT_PRIORITY = [ - "eni", - "sysconfig", - "netplan", -- "network-manager", - "freebsd", - "netbsd", - "openbsd", -diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl -index 7238c102..12f32c51 100644 ---- a/config/cloud.cfg.tmpl -+++ b/config/cloud.cfg.tmpl -@@ -381,9 +381,6 @@ system_info: - {% elif variant in ["dragonfly"] %} - network: - renderers: ['freebsd'] --{% elif variant in ["fedora"] or is_rhel %} -- network: -- renderers: ['netplan', 'network-manager', 'networkd', 'sysconfig', 'eni'] - {% elif variant == "openmandriva" %} - network: - renderers: ['network-manager', 'networkd'] -diff --git a/doc/rtd/reference/network-config.rst b/doc/rtd/reference/network-config.rst -index ea331f1c..bc52afa5 100644 ---- a/doc/rtd/reference/network-config.rst -+++ b/doc/rtd/reference/network-config.rst -@@ -176,16 +176,6 @@ this state, ``cloud-init`` delegates rendering of the configuration to - distro-supported formats. The following ``renderers`` are supported in - ``cloud-init``: - --NetworkManager ---------------- -- --`NetworkManager`_ is the standard Linux network configuration tool suite. It --supports a wide range of networking setups. Configuration is typically stored --in :file:`/etc/NetworkManager`. -- --It is the default for a number of Linux distributions; notably Fedora, --CentOS/RHEL, and their derivatives. -- - ENI - --- - -@@ -223,7 +213,6 @@ preference) is as follows: - - ENI - - Sysconfig - - Netplan --- NetworkManager - - FreeBSD - - NetBSD - - OpenBSD -@@ -234,7 +223,6 @@ preference) is as follows: - - - **ENI**: using ``ifup``, ``ifdown`` to manage device setup/teardown - - **Netplan**: using ``netplan apply`` to manage device setup/teardown --- **NetworkManager**: using ``nmcli`` to manage device setup/teardown - - **Networkd**: using ``ip`` to manage device setup/teardown - - When applying the policy, ``cloud-init`` checks if the current instance has the -@@ -244,8 +232,8 @@ supplying an updated configuration in cloud-config. :: - - system_info: - network: -- renderers: ['netplan', 'network-manager', 'eni', 'sysconfig', 'freebsd', 'netbsd', 'openbsd'] -- activators: ['eni', 'netplan', 'network-manager', 'networkd'] -+ renderers: ['netplan', 'eni', 'sysconfig', 'freebsd', 'netbsd', 'openbsd'] -+ activators: ['eni', 'netplan', 'networkd'] - - Network configuration tools - =========================== diff --git a/SOURCES/0005-net-allow-dhcp6-configuration-from-generate_fallback.patch b/SOURCES/0005-net-allow-dhcp6-configuration-from-generate_fallback.patch new file mode 100644 index 0000000..56a4ca7 --- /dev/null +++ b/SOURCES/0005-net-allow-dhcp6-configuration-from-generate_fallback.patch @@ -0,0 +1,172 @@ +From 54e87eaad7841270e530beff2dcfe68292ae87ef Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Tue, 21 Nov 2023 13:57:15 +0530 +Subject: [PATCH] net: allow dhcp6 configuration from + generate_fallback_configuration() + +This will make sure on Azure we can use both dhcp4 and dhcp6 when IMDS is not +used. This is useful in situations where only ipv6 network is available and +there is no dhcp4 running. + +This change is mostly a reversal of commit 29ed5f5b646ee and therefore, +re-application of the commit 518047aea9 with some small changes. + +The issue that caused the reversal of 518047aea9 is fixed by the earlier commit: +cab0eaf290af7 ("net/network_manager: do not set "may-fail" to False for both ipv4 and ipv6 dhcp") + +Fixes GH-4439 + +Signed-off-by: Ani Sinha +(cherry picked from commit 0264e969166846b2f5cf87ccdb051a3a795eca15) +--- + cloudinit/net/__init__.py | 7 ++++++- + tests/unittests/net/test_init.py | 4 ++++ + tests/unittests/test_net.py | 24 +++++++++++++++++++++--- + 3 files changed, 31 insertions(+), 4 deletions(-) + +diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py +index bf21633b..c0888f52 100644 +--- a/cloudinit/net/__init__.py ++++ b/cloudinit/net/__init__.py +@@ -571,7 +571,12 @@ def generate_fallback_config(config_driver=None): + match = { + "macaddress": read_sys_net_safe(target_name, "address").lower() + } +- cfg = {"dhcp4": True, "set-name": target_name, "match": match} ++ cfg = { ++ "dhcp4": True, ++ "dhcp6": True, ++ "set-name": target_name, ++ "match": match, ++ } + if config_driver: + driver = device_driver(target_name) + if driver: +diff --git a/tests/unittests/net/test_init.py b/tests/unittests/net/test_init.py +index 561d5151..60a44186 100644 +--- a/tests/unittests/net/test_init.py ++++ b/tests/unittests/net/test_init.py +@@ -261,6 +261,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "eth1": { + "match": {"macaddress": mac}, + "dhcp4": True, ++ "dhcp6": True, + "set-name": "eth1", + } + }, +@@ -278,6 +279,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "eth0": { + "match": {"macaddress": mac}, + "dhcp4": True, ++ "dhcp6": True, + "set-name": "eth0", + } + }, +@@ -293,6 +295,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "ethernets": { + "eth0": { + "dhcp4": True, ++ "dhcp6": True, + "match": {"macaddress": mac}, + "set-name": "eth0", + } +@@ -359,6 +362,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "ethernets": { + "ens3": { + "dhcp4": True, ++ "dhcp6": True, + "match": {"name": "ens3"}, + "set-name": "ens3", + } +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index fb4c863c..d9ef493b 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -4339,6 +4339,7 @@ class TestGenerateFallbackConfig(CiTestCase): + "ethernets": { + "eth0": { + "dhcp4": True, ++ "dhcp6": True, + "set-name": "eth0", + "match": { + "macaddress": "00:11:22:33:44:55", +@@ -4423,6 +4424,9 @@ iface lo inet loopback + + auto eth0 + iface eth0 inet dhcp ++ ++# control-alias eth0 ++iface eth0 inet6 dhcp + """ + self.assertEqual(expected.lstrip(), contents.lstrip()) + +@@ -4512,6 +4516,9 @@ iface lo inet loopback + + auto eth1 + iface eth1 inet dhcp ++ ++# control-alias eth1 ++iface eth1 inet6 dhcp + """ + self.assertEqual(expected.lstrip(), contents.lstrip()) + +@@ -4736,7 +4743,9 @@ class TestRhelSysConfigRendering(CiTestCase): + AUTOCONNECT_PRIORITY=120 + BOOTPROTO=dhcp + DEVICE=eth1000 ++DHCPV6C=yes + HWADDR=07-1c-c6-75-a4-be ++IPV6INIT=yes + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -5646,7 +5655,8 @@ class TestOpenSuseSysConfigRendering(CiTestCase): + expected_content = """ + # Created by cloud-init automatically, do not edit. + # +-BOOTPROTO=dhcp4 ++BOOTPROTO=dhcp ++DHCLIENT6_MODE=managed + LLADDR=07-1c-c6-75-a4-be + STARTMODE=auto + """.lstrip() +@@ -6032,7 +6042,11 @@ class TestNetworkManagerRendering(CiTestCase): + + [ipv4] + method=auto +- may-fail=false ++ may-fail=true ++ ++ [ipv6] ++ method=auto ++ may-fail=true + + """ + ), +@@ -6298,6 +6312,9 @@ iface lo inet loopback + + auto eth1000 + iface eth1000 inet dhcp ++ ++# control-alias eth1000 ++iface eth1000 inet6 dhcp + """ + self.assertEqual(expected.lstrip(), contents.lstrip()) + +@@ -6357,6 +6374,7 @@ class TestNetplanNetRendering: + ethernets: + eth1000: + dhcp4: true ++ dhcp6: true + match: + macaddress: 07-1c-c6-75-a4-be + set-name: eth1000 +@@ -7856,7 +7874,7 @@ class TestNetworkdNetRendering(CiTestCase): + Name=eth1000 + MACAddress=07-1c-c6-75-a4-be + [Network] +- DHCP=ipv4""" ++ DHCP=yes""" + ).rstrip(" ") + + expected = self.create_conf_dict(expected.splitlines()) diff --git a/SOURCES/0006-Revert-Add-native-NetworkManager-support-1224.patch b/SOURCES/0006-Revert-Add-native-NetworkManager-support-1224.patch deleted file mode 100644 index 8941797..0000000 --- a/SOURCES/0006-Revert-Add-native-NetworkManager-support-1224.patch +++ /dev/null @@ -1,1387 +0,0 @@ -From b1dd14ffafad2d2ca84326c525962b2ca086b292 Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Wed, 22 Mar 2023 16:31:58 +0530 -Subject: [PATCH] Revert "Add native NetworkManager support (#1224)" - -This reverts commit feda344e6cf9d37b09bc13cf333a717d1654c26c. - -Signed-off-by: Ani Sinha ---- - cloudinit/cmd/devel/net_convert.py | 14 +- - cloudinit/net/activators.py | 25 +- - cloudinit/net/network_manager.py | 393 ---------------- - cloudinit/net/renderers.py | 2 - - cloudinit/net/sysconfig.py | 42 +- - tests/unittests/test_net.py | 597 +++++-------------------- - tests/unittests/test_net_activators.py | 11 +- - 7 files changed, 161 insertions(+), 923 deletions(-) - delete mode 100644 cloudinit/net/network_manager.py - -diff --git a/cloudinit/cmd/devel/net_convert.py b/cloudinit/cmd/devel/net_convert.py -index eee49860..1a0a31ac 100755 ---- a/cloudinit/cmd/devel/net_convert.py -+++ b/cloudinit/cmd/devel/net_convert.py -@@ -10,14 +10,7 @@ import sys - import yaml - - from cloudinit import distros, log, safeyaml --from cloudinit.net import ( -- eni, -- netplan, -- network_manager, -- network_state, -- networkd, -- sysconfig, --) -+from cloudinit.net import eni, netplan, network_state, networkd, sysconfig - from cloudinit.sources import DataSourceAzure as azure - from cloudinit.sources.helpers import openstack - from cloudinit.sources.helpers.vmware.imc import guestcust_util -@@ -84,7 +77,7 @@ def get_parser(parser=None): - parser.add_argument( - "-O", - "--output-kind", -- choices=["eni", "netplan", "networkd", "sysconfig", "network-manager"], -+ choices=["eni", "netplan", "networkd", "sysconfig"], - required=True, - help="The network config format to emit", - ) -@@ -157,9 +150,6 @@ def handle_args(name, args): - elif args.output_kind == "sysconfig": - r_cls = sysconfig.Renderer - config = distro.renderer_configs.get("sysconfig") -- elif args.output_kind == "network-manager": -- r_cls = network_manager.Renderer -- config = distro.renderer_configs.get("network-manager") - else: - raise RuntimeError("Invalid output_kind") - -diff --git a/cloudinit/net/activators.py b/cloudinit/net/activators.py -index 7d11a02c..d9a8c4d7 100644 ---- a/cloudinit/net/activators.py -+++ b/cloudinit/net/activators.py -@@ -1,14 +1,15 @@ - # This file is part of cloud-init. See LICENSE file for license information. - import logging -+import os - from abc import ABC, abstractmethod - from typing import Dict, Iterable, List, Optional, Type, Union - - from cloudinit import subp, util - from cloudinit.net.eni import available as eni_available - from cloudinit.net.netplan import available as netplan_available --from cloudinit.net.network_manager import available as nm_available - from cloudinit.net.network_state import NetworkState - from cloudinit.net.networkd import available as networkd_available -+from cloudinit.net.sysconfig import NM_CFG_FILE - - LOG = logging.getLogger(__name__) - -@@ -123,24 +124,20 @@ class IfUpDownActivator(NetworkActivator): - class NetworkManagerActivator(NetworkActivator): - @staticmethod - def available(target=None) -> bool: -- """Return true if NetworkManager can be used on this system.""" -- return nm_available(target=target) -+ """Return true if network manager can be used on this system.""" -+ config_present = os.path.isfile( -+ subp.target_path(target, path=NM_CFG_FILE) -+ ) -+ nmcli_present = subp.which("nmcli", target=target) -+ return config_present and bool(nmcli_present) - - @staticmethod - def bring_up_interface(device_name: str) -> bool: -- """Bring up connection using nmcli. -+ """Bring up interface using nmcli. - - Return True is successful, otherwise return False - """ -- from cloudinit.net.network_manager import conn_filename -- -- filename = conn_filename(device_name) -- cmd = ["nmcli", "connection", "load", filename] -- if _alter_interface(cmd, device_name): -- cmd = ["nmcli", "connection", "up", "filename", filename] -- else: -- _alter_interface(["nmcli", "connection", "reload"], device_name) -- cmd = ["nmcli", "connection", "up", "ifname", device_name] -+ cmd = ["nmcli", "connection", "up", "ifname", device_name] - return _alter_interface(cmd, device_name) - - @staticmethod -@@ -149,7 +146,7 @@ class NetworkManagerActivator(NetworkActivator): - - Return True is successful, otherwise return False - """ -- cmd = ["nmcli", "device", "disconnect", device_name] -+ cmd = ["nmcli", "connection", "down", device_name] - return _alter_interface(cmd, device_name) - - -diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py -deleted file mode 100644 -index 53763d15..00000000 ---- a/cloudinit/net/network_manager.py -+++ /dev/null -@@ -1,393 +0,0 @@ --# Copyright 2022 Red Hat, Inc. --# --# Author: Lubomir Rintel --# Fixes and suggestions contributed by James Falcon, Neal Gompa, --# Zbigniew Jędrzejewski-Szmek and Emanuele Giuseppe Esposito. --# --# This file is part of cloud-init. See LICENSE file for license information. -- --import configparser --import io --import itertools --import os --import uuid --from typing import Optional -- --from cloudinit import log as logging --from cloudinit import subp, util --from cloudinit.net import is_ipv6_address, renderer, subnet_is_ipv6 --from cloudinit.net.network_state import NetworkState -- --NM_RUN_DIR = "/etc/NetworkManager" --NM_LIB_DIR = "/usr/lib/NetworkManager" --NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf" --LOG = logging.getLogger(__name__) -- -- --class NMConnection: -- """Represents a NetworkManager connection profile.""" -- -- def __init__(self, con_id): -- """ -- Initializes the connection with some very basic properties, -- notably the UUID so that the connection can be referred to. -- """ -- -- # Chosen by fair dice roll -- CI_NM_UUID = uuid.UUID("a3924cb8-09e0-43e9-890b-77972a800108") -- -- self.config = configparser.ConfigParser() -- # Identity option name mapping, to achieve case sensitivity -- self.config.optionxform = str -- -- self.config["connection"] = { -- "id": f"cloud-init {con_id}", -- "uuid": str(uuid.uuid5(CI_NM_UUID, con_id)), -- } -- -- # This is not actually used anywhere, but may be useful in future -- self.config["user"] = { -- "org.freedesktop.NetworkManager.origin": "cloud-init" -- } -- -- def _set_default(self, section, option, value): -- """ -- Sets a property unless it's already set, ensuring the section -- exists. -- """ -- -- if not self.config.has_section(section): -- self.config[section] = {} -- if not self.config.has_option(section, option): -- self.config[section][option] = value -- -- def _set_ip_method(self, family, subnet_type): -- """ -- Ensures there's appropriate [ipv4]/[ipv6] for given family -- appropriate for given configuration type -- """ -- -- method_map = { -- "static": "manual", -- "dhcp6": "auto", -- "ipv6_slaac": "auto", -- "ipv6_dhcpv6-stateless": "auto", -- "ipv6_dhcpv6-stateful": "auto", -- "dhcp4": "auto", -- "dhcp": "auto", -- } -- -- # Ensure we got an [ipvX] section -- self._set_default(family, "method", "disabled") -- -- try: -- method = method_map[subnet_type] -- except KeyError: -- # What else can we do -- method = "auto" -- self.config[family]["may-fail"] = "true" -- -- # Make sure we don't "downgrade" the method in case -- # we got conflicting subnets (e.g. static along with dhcp) -- if self.config[family]["method"] == "dhcp": -- return -- if self.config[family]["method"] == "auto" and method == "manual": -- return -- -- self.config[family]["method"] = method -- self._set_default(family, "may-fail", "false") -- -- def _add_numbered(self, section, key_prefix, value): -- """ -- Adds a numbered property, such as address or route, ensuring -- the appropriate value gets used for . -- """ -- -- for index in itertools.count(1): -- key = f"{key_prefix}{index}" -- if not self.config.has_option(section, key): -- self.config[section][key] = value -- break -- -- def _add_address(self, family, subnet): -- """ -- Adds an ipv[46]address property. -- """ -- -- value = subnet["address"] + "/" + str(subnet["prefix"]) -- self._add_numbered(family, "address", value) -- -- def _add_route(self, family, route): -- """ -- Adds a ipv[46].route property. -- """ -- -- value = route["network"] + "/" + str(route["prefix"]) -- if "gateway" in route: -- value = value + "," + route["gateway"] -- self._add_numbered(family, "route", value) -- -- def _add_nameserver(self, dns): -- """ -- Extends the ipv[46].dns property with a name server. -- """ -- -- # FIXME: the subnet contains IPv4 and IPv6 name server mixed -- # together. We might be getting an IPv6 name server while -- # we're dealing with an IPv4 subnet. Sort this out by figuring -- # out the correct family and making sure a valid section exist. -- family = "ipv6" if is_ipv6_address(dns) else "ipv4" -- self._set_default(family, "method", "disabled") -- -- self._set_default(family, "dns", "") -- self.config[family]["dns"] = self.config[family]["dns"] + dns + ";" -- -- def _add_dns_search(self, family, dns_search): -- """ -- Extends the ipv[46].dns-search property with a name server. -- """ -- -- self._set_default(family, "dns-search", "") -- self.config[family]["dns-search"] = ( -- self.config[family]["dns-search"] + ";".join(dns_search) + ";" -- ) -- -- def con_uuid(self): -- """ -- Returns the connection UUID -- """ -- return self.config["connection"]["uuid"] -- -- def valid(self): -- """ -- Can this be serialized into a meaningful connection profile? -- """ -- return self.config.has_option("connection", "type") -- -- @staticmethod -- def mac_addr(addr): -- """ -- Sanitize a MAC address. -- """ -- return addr.replace("-", ":").upper() -- -- def render_interface(self, iface, renderer): -- """ -- Integrate information from network state interface information -- into the connection. Most of the work is done here. -- """ -- -- # Initialize type & connectivity -- _type_map = { -- "physical": "ethernet", -- "vlan": "vlan", -- "bond": "bond", -- "bridge": "bridge", -- "infiniband": "infiniband", -- "loopback": None, -- } -- -- if_type = _type_map[iface["type"]] -- if if_type is None: -- return -- if "bond-master" in iface: -- slave_type = "bond" -- else: -- slave_type = None -- -- self.config["connection"]["type"] = if_type -- if slave_type is not None: -- self.config["connection"]["slave-type"] = slave_type -- self.config["connection"]["master"] = renderer.con_ref( -- iface[slave_type + "-master"] -- ) -- -- # Add type specific-section -- self.config[if_type] = {} -- -- # These are the interface properties that map nicely -- # to NetworkManager properties -- _prop_map = { -- "bond": { -- "mode": "bond-mode", -- "miimon": "bond_miimon", -- "xmit_hash_policy": "bond-xmit-hash-policy", -- "num_grat_arp": "bond-num-grat-arp", -- "downdelay": "bond-downdelay", -- "updelay": "bond-updelay", -- "fail_over_mac": "bond-fail-over-mac", -- "primary_reselect": "bond-primary-reselect", -- "primary": "bond-primary", -- }, -- "bridge": { -- "stp": "bridge_stp", -- "priority": "bridge_bridgeprio", -- }, -- "vlan": { -- "id": "vlan_id", -- }, -- "ethernet": {}, -- "infiniband": {}, -- } -- -- device_mtu = iface["mtu"] -- ipv4_mtu = None -- -- # Deal with Layer 3 configuration -- for subnet in iface["subnets"]: -- family = "ipv6" if subnet_is_ipv6(subnet) else "ipv4" -- -- self._set_ip_method(family, subnet["type"]) -- if "address" in subnet: -- self._add_address(family, subnet) -- if "gateway" in subnet: -- self.config[family]["gateway"] = subnet["gateway"] -- for route in subnet["routes"]: -- self._add_route(family, route) -- if "dns_nameservers" in subnet: -- for nameserver in subnet["dns_nameservers"]: -- self._add_nameserver(nameserver) -- if "dns_search" in subnet: -- self._add_dns_search(family, subnet["dns_search"]) -- if family == "ipv4" and "mtu" in subnet: -- ipv4_mtu = subnet["mtu"] -- -- if ipv4_mtu is None: -- ipv4_mtu = device_mtu -- if not ipv4_mtu == device_mtu: -- LOG.warning( -- "Network config: ignoring %s device-level mtu:%s" -- " because ipv4 subnet-level mtu:%s provided.", -- iface["name"], -- device_mtu, -- ipv4_mtu, -- ) -- -- # Parse type-specific properties -- for nm_prop, key in _prop_map[if_type].items(): -- if key not in iface: -- continue -- if iface[key] is None: -- continue -- if isinstance(iface[key], bool): -- self.config[if_type][nm_prop] = ( -- "true" if iface[key] else "false" -- ) -- else: -- self.config[if_type][nm_prop] = str(iface[key]) -- -- # These ones need special treatment -- if if_type == "ethernet": -- if iface["wakeonlan"] is True: -- # NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC -- self.config["ethernet"]["wake-on-lan"] = str(0x40) -- if ipv4_mtu is not None: -- self.config["ethernet"]["mtu"] = str(ipv4_mtu) -- if iface["mac_address"] is not None: -- self.config["ethernet"]["mac-address"] = self.mac_addr( -- iface["mac_address"] -- ) -- if if_type == "vlan" and "vlan-raw-device" in iface: -- self.config["vlan"]["parent"] = renderer.con_ref( -- iface["vlan-raw-device"] -- ) -- if if_type == "bridge": -- # Bridge is ass-backwards compared to bond -- for port in iface["bridge_ports"]: -- port = renderer.get_conn(port) -- port._set_default("connection", "slave-type", "bridge") -- port._set_default("connection", "master", self.con_uuid()) -- if iface["mac_address"] is not None: -- self.config["bridge"]["mac-address"] = self.mac_addr( -- iface["mac_address"] -- ) -- if if_type == "infiniband" and ipv4_mtu is not None: -- self.config["infiniband"]["transport-mode"] = "datagram" -- self.config["infiniband"]["mtu"] = str(ipv4_mtu) -- if iface["mac_address"] is not None: -- self.config["infiniband"]["mac-address"] = self.mac_addr( -- iface["mac_address"] -- ) -- -- # Finish up -- if if_type == "bridge" or not self.config.has_option( -- if_type, "mac-address" -- ): -- self.config["connection"]["interface-name"] = iface["name"] -- -- def dump(self): -- """ -- Stringify. -- """ -- -- buf = io.StringIO() -- self.config.write(buf, space_around_delimiters=False) -- header = "# Generated by cloud-init. Changes will be lost.\n\n" -- return header + buf.getvalue() -- -- --class Renderer(renderer.Renderer): -- """Renders network information in a NetworkManager keyfile format.""" -- -- def __init__(self, config=None): -- self.connections = {} -- -- def get_conn(self, con_id): -- return self.connections[con_id] -- -- def con_ref(self, con_id): -- if con_id in self.connections: -- return self.connections[con_id].con_uuid() -- else: -- # Well, what can we do... -- return con_id -- -- def render_network_state( -- self, -- network_state: NetworkState, -- templates: Optional[dict] = None, -- target=None, -- ) -> None: -- # First pass makes sure there's NMConnections for all known -- # 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"]) -- -- # Now render the actual interface configuration -- for iface in network_state.iter_interfaces(): -- conn = self.connections[iface["name"]] -- conn.render_interface(iface, self) -- -- # And finally write the files -- for con_id, conn in self.connections.items(): -- if not conn.valid(): -- continue -- name = conn_filename(con_id, target) -- util.write_file(name, conn.dump(), 0o600) -- -- --def conn_filename(con_id, target=None): -- target_con_dir = subp.target_path(target, NM_RUN_DIR) -- con_file = f"cloud-init-{con_id}.nmconnection" -- return f"{target_con_dir}/system-connections/{con_file}" -- -- --def available(target=None): -- # TODO: Move `uses_systemd` to a more appropriate location -- # It is imported here to avoid circular import -- from cloudinit.distros import uses_systemd -- -- config_present = os.path.isfile(subp.target_path(target, path=NM_CFG_FILE)) -- nmcli_present = subp.which("nmcli", target=target) -- service_active = True -- if uses_systemd(): -- try: -- subp.subp(["systemctl", "is-enabled", "NetworkManager.service"]) -- except subp.ProcessExecutionError: -- service_active = False -- -- return config_present and bool(nmcli_present) and service_active -- -- --# vi: ts=4 expandtab -diff --git a/cloudinit/net/renderers.py b/cloudinit/net/renderers.py -index b241683f..c92b9dcf 100644 ---- a/cloudinit/net/renderers.py -+++ b/cloudinit/net/renderers.py -@@ -8,7 +8,6 @@ from cloudinit.net import ( - freebsd, - netbsd, - netplan, -- network_manager, - networkd, - openbsd, - renderer, -@@ -20,7 +19,6 @@ NAME_TO_RENDERER = { - "freebsd": freebsd, - "netbsd": netbsd, - "netplan": netplan, -- "network-manager": network_manager, - "networkd": networkd, - "openbsd": openbsd, - "sysconfig": sysconfig, -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index 4262cd48..765c248a 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -6,6 +6,8 @@ import os - import re - from typing import Mapping, Optional - -+from configobj import ConfigObj -+ - from cloudinit import log as logging - from cloudinit import subp, util - from cloudinit.distros.parsers import networkmanager_conf, resolv_conf -@@ -35,7 +37,7 @@ KNOWN_DISTROS = [ - "TencentOS", - "virtuozzo", - ] -- -+NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf" - - def _make_header(sep="#"): - lines = [ -@@ -66,7 +68,26 @@ def _quote_value(value): - return value - - --class ConfigMap: -+ -+def enable_ifcfg_rh(path): -+ """Add ifcfg-rh to NetworkManager.cfg plugins if main section is present""" -+ config = ConfigObj(path) -+ if "main" in config: -+ if "plugins" in config["main"]: -+ if "ifcfg-rh" in config["main"]["plugins"]: -+ return -+ else: -+ config["main"]["plugins"] = [] -+ -+ if isinstance(config["main"]["plugins"], list): -+ config["main"]["plugins"].append("ifcfg-rh") -+ else: -+ config["main"]["plugins"] = [config["main"]["plugins"], "ifcfg-rh"] -+ config.write() -+ LOG.debug("Enabled ifcfg-rh NetworkManager plugins") -+ -+ -+class ConfigMap(object): - """Sysconfig like dictionary object.""" - - # Why does redhat prefer yes/no to true/false?? -@@ -1014,6 +1035,8 @@ class Renderer(renderer.Renderer): - netrules_content = self._render_persistent_net(network_state) - netrules_path = subp.target_path(target, self.netrules_path) - util.write_file(netrules_path, netrules_content, file_mode) -+ if available_nm(target=target): -+ enable_ifcfg_rh(subp.target_path(target, path=NM_CFG_FILE)) - - sysconfig_path = subp.target_path(target, templates.get("control")) - # Distros configuring /etc/sysconfig/network as a file e.g. Centos -@@ -1052,9 +1075,14 @@ def _supported_vlan_names(rdev, vid): - - - def available(target=None): -- if not util.system_info()["variant"] in KNOWN_DISTROS: -- return False -+ sysconfig = available_sysconfig(target=target) -+ nm = available_nm(target=target) -+ return util.system_info()["variant"] in KNOWN_DISTROS and any( -+ [nm, sysconfig] -+ ) -+ - -+def available_sysconfig(target=None): - expected = ["ifup", "ifdown"] - search = ["/sbin", "/usr/sbin"] - for p in expected: -@@ -1071,4 +1099,10 @@ def available(target=None): - return False - - -+def available_nm(target=None): -+ if not os.path.isfile(subp.target_path(target, path=NM_CFG_FILE)): -+ return False -+ return True -+ -+ - # vi: ts=4 expandtab -diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index 0f523ff8..4434b350 100644 ---- a/tests/unittests/test_net.py -+++ b/tests/unittests/test_net.py -@@ -23,7 +23,6 @@ from cloudinit.net import ( - mask_and_ipv4_to_bcast_addr, - natural_sort_key, - netplan, -- network_manager, - network_state, - networkd, - renderers, -@@ -617,37 +616,6 @@ dns = none - ), - ), - ], -- "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 --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 -- --""".lstrip(), -- ), -- ], - }, - { - "in_data": { -@@ -1110,50 +1078,6 @@ NETWORK_CONFIGS = { - USERCTL=no""" - ), - }, -- "expected_network_manager": { -- "cloud-init-eth1.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth1 -- uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58 -- type=ethernet -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=CF:D6:AF:48:E8:80 -- -- """ -- ), -- "cloud-init-eth99.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth99 -- uuid=b1b88000-1f03-5360-8377-1a2205efffb4 -- type=ethernet -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=C0:D6:9F:2C:E8:80 -- -- [ipv4] -- method=auto -- may-fail=false -- address1=192.168.21.3/24 -- route1=0.0.0.0/0,65.61.151.37 -- dns=8.8.8.8;8.8.4.4; -- dns-search=barley.maas;sach.maas; -- -- """ -- ), -- }, - "yaml": textwrap.dedent( - """ - version: 1 -@@ -1959,29 +1883,6 @@ NETWORK_CONFIGS = { - """ - ), - }, -- "expected_network_manager": { -- "cloud-init-iface0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init iface0 -- uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -- type=ethernet -- interface-name=iface0 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- -- [ipv4] -- method=auto -- may-fail=false -- -- """ -- ), -- }, - "yaml_v2": textwrap.dedent( - """\ - version: 2 -@@ -2035,30 +1936,6 @@ NETWORK_CONFIGS = { - """ - ), - }, -- "expected_network_manager": { -- "cloud-init-iface0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init iface0 -- uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -- type=ethernet -- interface-name=iface0 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- wake-on-lan=64 -- -- [ipv4] -- method=auto -- may-fail=false -- -- """ -- ), -- }, - "yaml_v2": textwrap.dedent( - """\ - version: 2 -@@ -3092,8 +2969,8 @@ iface bond0 inet6 static - - to: 2001:67c:1562:8007::1/64 - via: 2001:67c:1562:8007::aac:40b2 - - metric: 10000 -- to: 3001:67c:15:8007::1/64 -- via: 3001:67c:15:8007::aac:40b2 -+ to: 3001:67c:1562:8007::1/64 -+ via: 3001:67c:1562:8007::aac:40b2 - """ - ), - "expected_netplan-v2": textwrap.dedent( -@@ -3125,8 +3002,8 @@ iface bond0 inet6 static - - to: 2001:67c:1562:8007::1/64 - via: 2001:67c:1562:8007::aac:40b2 - - metric: 10000 -- to: 3001:67c:15:8007::1/64 -- via: 3001:67c:15:8007::aac:40b2 -+ to: 3001:67c:1562:8007::1/64 -+ via: 3001:67c:1562:8007::aac:40b2 - ethernets: - eth0: - match: -@@ -3774,73 +3651,6 @@ iface bond0 inet6 static - """ - ), - }, -- "expected_network_manager": { -- "cloud-init-eth0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth0 -- uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -- type=ethernet -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=52:54:00:12:34:00 -- -- [ipv4] -- method=manual -- may-fail=false -- address1=192.168.1.2/24 -- -- """ -- ), -- "cloud-init-eth1.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth1 -- uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58 -- type=ethernet -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mtu=1480 -- mac-address=52:54:00:12:34:AA -- -- [ipv4] -- method=auto -- may-fail=true -- -- """ -- ), -- "cloud-init-eth2.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth2 -- uuid=5559a242-3421-5fdd-896e-9cb8313d5804 -- type=ethernet -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=52:54:00:12:34:FF -- -- [ipv4] -- method=auto -- may-fail=true -- -- """ -- ), -- }, - }, - "v2-dev-name-via-mac-lookup": { - "expected_sysconfig_rhel": { -@@ -4339,6 +4149,7 @@ class TestRhelSysConfigRendering(CiTestCase): - - with_logs = True - -+ nm_cfg_file = "/etc/NetworkManager/NetworkManager.conf" - scripts_dir = "/etc/sysconfig/network-scripts" - header = ( - "# Created by cloud-init on instance boot automatically, " -@@ -4913,6 +4724,78 @@ USERCTL=no - self._compare_files_to_expected(entry[self.expected_name], found) - self._assert_headers(found) - -+ def test_check_ifcfg_rh(self): -+ """ifcfg-rh plugin is added NetworkManager.conf if conf present.""" -+ render_dir = self.tmp_dir() -+ nm_cfg = subp.target_path(render_dir, path=self.nm_cfg_file) -+ util.ensure_dir(os.path.dirname(nm_cfg)) -+ -+ # write a template nm.conf, note plugins is a list here -+ with open(nm_cfg, "w") as fh: -+ fh.write("# test_check_ifcfg_rh\n[main]\nplugins=foo,bar\n") -+ self.assertTrue(os.path.exists(nm_cfg)) -+ -+ # render and read -+ entry = NETWORK_CONFIGS["small"] -+ found = self._render_and_read( -+ network_config=yaml.load(entry["yaml"]), dir=render_dir -+ ) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ self._assert_headers(found) -+ -+ # check ifcfg-rh is in the 'plugins' list -+ config = sysconfig.ConfigObj(nm_cfg) -+ self.assertIn("ifcfg-rh", config["main"]["plugins"]) -+ -+ def test_check_ifcfg_rh_plugins_string(self): -+ """ifcfg-rh plugin is append when plugins is a string.""" -+ render_dir = self.tmp_path("render") -+ os.makedirs(render_dir) -+ nm_cfg = subp.target_path(render_dir, path=self.nm_cfg_file) -+ util.ensure_dir(os.path.dirname(nm_cfg)) -+ -+ # write a template nm.conf, note plugins is a value here -+ util.write_file(nm_cfg, "# test_check_ifcfg_rh\n[main]\nplugins=foo\n") -+ -+ # render and read -+ entry = NETWORK_CONFIGS["small"] -+ found = self._render_and_read( -+ network_config=yaml.load(entry["yaml"]), dir=render_dir -+ ) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ self._assert_headers(found) -+ -+ # check raw content has plugin -+ nm_file_content = util.load_file(nm_cfg) -+ self.assertIn("ifcfg-rh", nm_file_content) -+ -+ # check ifcfg-rh is in the 'plugins' list -+ config = sysconfig.ConfigObj(nm_cfg) -+ self.assertIn("ifcfg-rh", config["main"]["plugins"]) -+ -+ def test_check_ifcfg_rh_plugins_no_plugins(self): -+ """enable_ifcfg_plugin creates plugins value if missing.""" -+ render_dir = self.tmp_path("render") -+ os.makedirs(render_dir) -+ nm_cfg = subp.target_path(render_dir, path=self.nm_cfg_file) -+ util.ensure_dir(os.path.dirname(nm_cfg)) -+ -+ # write a template nm.conf, note plugins is missing -+ util.write_file(nm_cfg, "# test_check_ifcfg_rh\n[main]\n") -+ self.assertTrue(os.path.exists(nm_cfg)) -+ -+ # render and read -+ entry = NETWORK_CONFIGS["small"] -+ found = self._render_and_read( -+ network_config=yaml.load(entry["yaml"]), dir=render_dir -+ ) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ self._assert_headers(found) -+ -+ # check ifcfg-rh is in the 'plugins' list -+ config = sysconfig.ConfigObj(nm_cfg) -+ self.assertIn("ifcfg-rh", config["main"]["plugins"]) -+ - 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) -@@ -5609,281 +5492,6 @@ STARTMODE=auto - self._assert_headers(found) - - --@mock.patch( -- "cloudinit.net.is_openvswitch_internal_interface", -- mock.Mock(return_value=False), --) --class TestNetworkManagerRendering(CiTestCase): -- -- with_logs = True -- -- scripts_dir = "/etc/NetworkManager/system-connections" -- -- expected_name = "expected_network_manager" -- -- def _get_renderer(self): -- return network_manager.Renderer() -- -- def _render_and_read(self, network_config=None, state=None, dir=None): -- if dir is None: -- dir = self.tmp_dir() -- -- if network_config: -- ns = network_state.parse_net_config_data(network_config) -- elif state: -- ns = state -- else: -- raise ValueError("Expected data or state, got neither") -- -- renderer = self._get_renderer() -- renderer.render_network_state(ns, target=dir) -- return dir2dict(dir) -- -- def _compare_files_to_expected(self, expected, found): -- orig_maxdiff = self.maxDiff -- expected_d = dict( -- (os.path.join(self.scripts_dir, k), v) for k, v in expected.items() -- ) -- -- try: -- self.maxDiff = None -- self.assertEqual(expected_d, found) -- finally: -- self.maxDiff = orig_maxdiff -- -- @mock.patch("cloudinit.net.util.get_cmdline", return_value="root=myroot") -- @mock.patch("cloudinit.net.sys_dev_path") -- @mock.patch("cloudinit.net.read_sys_net") -- @mock.patch("cloudinit.net.get_devicelist") -- def test_default_generation( -- self, -- mock_get_devicelist, -- mock_read_sys_net, -- mock_sys_dev_path, -- m_get_cmdline, -- ): -- tmp_dir = self.tmp_dir() -- _setup_test( -- tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path -- ) -- -- network_cfg = net.generate_fallback_config() -- ns = network_state.parse_net_config_data( -- network_cfg, skip_broken=False -- ) -- -- render_dir = os.path.join(tmp_dir, "render") -- os.makedirs(render_dir) -- -- renderer = self._get_renderer() -- renderer.render_network_state(ns, target=render_dir) -- -- found = dir2dict(render_dir) -- self._compare_files_to_expected( -- { -- "cloud-init-eth1000.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth1000 -- uuid=8c517500-0c95-5308-9c8a-3092eebc44eb -- type=ethernet -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=07:1C:C6:75:A4:BE -- -- [ipv4] -- method=auto -- may-fail=false -- -- """ -- ), -- }, -- found, -- ) -- -- def test_openstack_rendering_samples(self): -- for os_sample in OS_SAMPLES: -- render_dir = self.tmp_dir() -- ex_input = os_sample["in_data"] -- ex_mac_addrs = os_sample["in_macs"] -- network_cfg = openstack.convert_net_json( -- ex_input, known_macs=ex_mac_addrs -- ) -- ns = network_state.parse_net_config_data( -- network_cfg, skip_broken=False -- ) -- renderer = self._get_renderer() -- # render a multiple times to simulate reboots -- renderer.render_network_state(ns, target=render_dir) -- renderer.render_network_state(ns, target=render_dir) -- renderer.render_network_state(ns, target=render_dir) -- for fn, expected_content in os_sample.get(self.expected_name, []): -- with open(os.path.join(render_dir, fn)) as fh: -- self.assertEqual(expected_content, fh.read()) -- -- def test_network_config_v1_samples(self): -- ns = network_state.parse_net_config_data(CONFIG_V1_SIMPLE_SUBNET) -- render_dir = self.tmp_path("render") -- os.makedirs(render_dir) -- renderer = self._get_renderer() -- renderer.render_network_state(ns, target=render_dir) -- found = dir2dict(render_dir) -- self._compare_files_to_expected( -- { -- "cloud-init-interface0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init interface0 -- uuid=8b6862ed-dbd6-5830-93f7-a91451c13828 -- type=ethernet -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=52:54:00:12:34:00 -- -- [ipv4] -- method=manual -- may-fail=false -- address1=10.0.2.15/24 -- gateway=10.0.2.2 -- -- """ -- ), -- }, -- found, -- ) -- -- def test_config_with_explicit_loopback(self): -- render_dir = self.tmp_path("render") -- os.makedirs(render_dir) -- ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK) -- renderer = self._get_renderer() -- renderer.render_network_state(ns, target=render_dir) -- found = dir2dict(render_dir) -- self._compare_files_to_expected( -- { -- "cloud-init-eth0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth0 -- uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -- type=ethernet -- interface-name=eth0 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- -- [ipv4] -- method=auto -- may-fail=false -- -- """ -- ), -- }, -- found, -- ) -- -- def test_bond_config(self): -- entry = NETWORK_CONFIGS["bond"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_vlan_config(self): -- entry = NETWORK_CONFIGS["vlan"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_bridge_config(self): -- entry = NETWORK_CONFIGS["bridge"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_manual_config(self): -- entry = NETWORK_CONFIGS["manual"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_all_config(self): -- entry = NETWORK_CONFIGS["all"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- self.assertNotIn( -- "WARNING: Network config: ignoring eth0.101 device-level mtu", -- self.logs.getvalue(), -- ) -- -- def test_small_config(self): -- entry = NETWORK_CONFIGS["small"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_v4_and_v6_static_config(self): -- entry = NETWORK_CONFIGS["v4_and_v6_static"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- expected_msg = ( -- "WARNING: Network config: ignoring iface0 device-level mtu:8999" -- " because ipv4 subnet-level mtu:9000 provided." -- ) -- self.assertIn(expected_msg, self.logs.getvalue()) -- -- def test_dhcpv6_only_config(self): -- entry = NETWORK_CONFIGS["dhcpv6_only"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_simple_render_ipv6_slaac(self): -- entry = NETWORK_CONFIGS["ipv6_slaac"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_dhcpv6_stateless_config(self): -- entry = NETWORK_CONFIGS["dhcpv6_stateless"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_wakeonlan_disabled_config_v2(self): -- entry = NETWORK_CONFIGS["wakeonlan_disabled"] -- found = self._render_and_read( -- network_config=yaml.load(entry["yaml_v2"]) -- ) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_wakeonlan_enabled_config_v2(self): -- entry = NETWORK_CONFIGS["wakeonlan_enabled"] -- found = self._render_and_read( -- network_config=yaml.load(entry["yaml_v2"]) -- ) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_render_v4_and_v6(self): -- entry = NETWORK_CONFIGS["v4_and_v6"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- def test_render_v6_and_v4(self): -- entry = NETWORK_CONFIGS["v6_and_v4"] -- found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -- -- --@mock.patch( -- "cloudinit.net.is_openvswitch_internal_interface", -- mock.Mock(return_value=False), --) - class TestEniNetRendering(CiTestCase): - @mock.patch("cloudinit.net.util.get_cmdline", return_value="root=myroot") - @mock.patch("cloudinit.net.sys_dev_path") -@@ -7651,9 +7259,9 @@ class TestNetworkdRoundTrip(CiTestCase): - - class TestRenderersSelect: - @pytest.mark.parametrize( -- "renderer_selected,netplan,eni,sys,network_manager,networkd", -+ "renderer_selected,netplan,eni,nm,scfg,sys,networkd", - ( -- # -netplan -ifupdown -sys -network-manager -networkd raises error -+ # -netplan -ifupdown -nm -scfg -sys raises error - ( - net.RendererNotFoundError, - False, -@@ -7661,51 +7269,52 @@ class TestRenderersSelect: - False, - False, - False, -+ False, - ), -- # -netplan +ifupdown -sys -nm -networkd selects eni -- ("eni", False, True, False, False, False), -- # +netplan +ifupdown -sys -nm -networkd selects eni -- ("eni", True, True, False, False, False), -- # +netplan -ifupdown -sys -nm -networkd selects netplan -- ("netplan", True, False, False, False, False), -- # +netplan -ifupdown -sys -nm -networkd selects netplan -- ("netplan", True, False, False, False, False), -- # -netplan -ifupdown +sys -nm -networkd selects sysconfig -- ("sysconfig", False, False, True, False, False), -- # -netplan -ifupdown +sys +nm -networkd selects sysconfig -- ("sysconfig", False, False, True, True, False), -- # -netplan -ifupdown -sys +nm -networkd selects nm -- ("network-manager", False, False, False, True, False), -- # -netplan -ifupdown -sys +nm +networkd selects nm -- ("network-manager", False, False, False, True, True), -- # -netplan -ifupdown -sys -nm +networkd selects networkd -- ("networkd", False, False, False, False, True), -+ # -netplan +ifupdown -nm -scfg -sys selects eni -+ ("eni", False, True, False, False, False, False), -+ # +netplan +ifupdown -nm -scfg -sys selects eni -+ ("eni", True, True, False, False, False, False), -+ # +netplan -ifupdown -nm -scfg -sys selects netplan -+ ("netplan", True, False, False, False, False, False), -+ # Ubuntu with Network-Manager installed -+ # +netplan -ifupdown +nm -scfg -sys selects netplan -+ ("netplan", True, False, True, False, False, False), -+ # Centos/OpenSuse with Network-Manager installed selects sysconfig -+ # -netplan -ifupdown +nm -scfg +sys selects netplan -+ ("sysconfig", False, False, True, False, True, False), -+ # -netplan -ifupdown -nm -scfg -sys +networkd selects networkd -+ ("networkd", False, False, False, False, False, True), - ), - ) - @mock.patch("cloudinit.net.renderers.networkd.available") -- @mock.patch("cloudinit.net.renderers.network_manager.available") - @mock.patch("cloudinit.net.renderers.netplan.available") - @mock.patch("cloudinit.net.renderers.sysconfig.available") -+ @mock.patch("cloudinit.net.renderers.sysconfig.available_sysconfig") -+ @mock.patch("cloudinit.net.renderers.sysconfig.available_nm") - @mock.patch("cloudinit.net.renderers.eni.available") - def test_valid_renderer_from_defaults_depending_on_availability( - self, - m_eni_avail, -+ m_nm_avail, -+ m_scfg_avail, - m_sys_avail, - m_netplan_avail, -- m_network_manager_avail, - m_networkd_avail, - renderer_selected, - netplan, - eni, -+ nm, -+ scfg, - sys, -- network_manager, - networkd, - ): - """Assert proper renderer per DEFAULT_PRIORITY given availability.""" - m_eni_avail.return_value = eni # ifupdown pkg presence -+ m_nm_avail.return_value = nm # network-manager presence -+ m_scfg_avail.return_value = scfg # sysconfig presence - m_sys_avail.return_value = sys # sysconfig/ifup/down presence - m_netplan_avail.return_value = netplan # netplan presence -- m_network_manager_avail.return_value = network_manager # NM presence - m_networkd_avail.return_value = networkd # networkd presence - if isinstance(renderer_selected, str): - (renderer_name, _rnd_class) = renderers.select( -@@ -7763,7 +7372,7 @@ class TestNetRenderers(CiTestCase): - priority=["sysconfig", "eni"], - ) - -- @mock.patch("cloudinit.net.sysconfig.available") -+ @mock.patch("cloudinit.net.sysconfig.available_sysconfig") - @mock.patch("cloudinit.util.system_info") - def test_sysconfig_available_uses_variant_mapping(self, m_info, m_avail): - m_avail.return_value = True -diff --git a/tests/unittests/test_net_activators.py b/tests/unittests/test_net_activators.py -index afd9056a..b735ea9e 100644 ---- a/tests/unittests/test_net_activators.py -+++ b/tests/unittests/test_net_activators.py -@@ -139,6 +139,10 @@ NETPLAN_AVAILABLE_CALLS = [ - (("netplan",), {"search": ["/usr/sbin", "/sbin"], "target": None}), - ] - -+NETWORK_MANAGER_AVAILABLE_CALLS = [ -+ (("nmcli",), {"target": None}), -+] -+ - NETWORKD_AVAILABLE_CALLS = [ - (("ip",), {"search": ["/usr/sbin", "/bin"], "target": None}), - (("systemctl",), {"search": ["/usr/sbin", "/bin"], "target": None}), -@@ -150,6 +154,7 @@ NETWORKD_AVAILABLE_CALLS = [ - [ - (IfUpDownActivator, IF_UP_DOWN_AVAILABLE_CALLS), - (NetplanActivator, NETPLAN_AVAILABLE_CALLS), -+ (NetworkManagerActivator, NETWORK_MANAGER_AVAILABLE_CALLS), - (NetworkdActivator, NETWORKD_AVAILABLE_CALLS), - ], - ) -@@ -254,11 +259,9 @@ class TestActivatorsBringUp: - def test_bring_up_interface( - self, m_subp, activator, expected_call_list, available_mocks - ): -- index = 0 - activator.bring_up_interface("eth0") -- for call in m_subp.call_args_list: -- assert call == expected_call_list[index] -- index += 1 -+ assert len(m_subp.call_args_list) == 1 -+ assert m_subp.call_args_list[0] == expected_call_list[0] - - @patch("cloudinit.subp.subp", return_value=("", "")) - def test_bring_up_interfaces( diff --git a/SOURCES/0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch b/SOURCES/0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch new file mode 100644 index 0000000..40c2490 --- /dev/null +++ b/SOURCES/0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch @@ -0,0 +1,113 @@ +From c0df864e373e1e34bf23c4869acdf7d20aea7aaf Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Thu, 7 Dec 2023 02:39:51 +0530 +Subject: [PATCH] net/nm: check for presence of ifcfg files when nm connection + files are absent (#4645) + +On systems that use network manager to manage connections and activate network +interfaces, they may also use ifcfg files for configuring +interfaces using ifcfg-rh network manager plugin. When network manager is used +as the activator, we need to also check for the presence of ifcfg interface +config file when the network manager connection file is absent and if ifcfg-rh +plugin is present. +Hence, with this change, network manager activator first tries to use network +manager connection files to bring up or bring down the interface. If the +connection files are not present and if ifcfg-rh plugin is present, it tries to +use ifcfg files for the interface. If the plugin or the ifcfg files are not +present, the activator fails to activate or deactivate the interface and it +bails out with warning log. + +Fixes: GH-4640 + +Signed-off-by: Ani Sinha +(cherry picked from commit d1d5166895da471cff3606c70d4e8ab6eec1c006) +--- + cloudinit/net/activators.py | 7 +++++++ + cloudinit/net/network_manager.py | 33 ++++++++++++++++++++++++++++++-- + 2 files changed, 38 insertions(+), 2 deletions(-) + +diff --git a/cloudinit/net/activators.py b/cloudinit/net/activators.py +index e69da40d..dd858862 100644 +--- a/cloudinit/net/activators.py ++++ b/cloudinit/net/activators.py +@@ -117,6 +117,13 @@ class NetworkManagerActivator(NetworkActivator): + from cloudinit.net.network_manager import conn_filename + + filename = conn_filename(device_name) ++ if filename is None: ++ LOG.warning( ++ "Unable to find an interface config file. " ++ "Unable to bring up interface." ++ ) ++ return False ++ + cmd = ["nmcli", "connection", "load", filename] + if _alter_interface(cmd, device_name): + cmd = ["nmcli", "connection", "up", "filename", filename] +diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py +index 8a99eb3a..76a0ac15 100644 +--- a/cloudinit/net/network_manager.py ++++ b/cloudinit/net/network_manager.py +@@ -17,10 +17,12 @@ from typing import Optional + from cloudinit import subp, util + from cloudinit.net import is_ipv6_address, renderer, subnet_is_ipv6 + from cloudinit.net.network_state import NetworkState ++from cloudinit.net.sysconfig import available_nm_ifcfg_rh + + NM_RUN_DIR = "/etc/NetworkManager" + NM_LIB_DIR = "/usr/lib/NetworkManager" + NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf" ++IFCFG_CFG_FILE = "/etc/sysconfig/network-scripts" + NM_IPV6_ADDR_GEN_CONF = """# This is generated by cloud-init. Do not edit. + # + [.config] +@@ -442,7 +444,7 @@ class Renderer(renderer.Renderer): + for con_id, conn in self.connections.items(): + if not conn.valid(): + continue +- name = conn_filename(con_id, target) ++ name = nm_conn_filename(con_id, target) + util.write_file(name, conn.dump(), 0o600) + + # Select EUI64 to be used by default by NM for creating the address +@@ -452,12 +454,39 @@ class Renderer(renderer.Renderer): + ) + + +-def conn_filename(con_id, target=None): ++def nm_conn_filename(con_id, target=None): + target_con_dir = subp.target_path(target, NM_RUN_DIR) + con_file = f"cloud-init-{con_id}.nmconnection" + return f"{target_con_dir}/system-connections/{con_file}" + + ++def sysconfig_conn_filename(devname, target=None): ++ target_con_dir = subp.target_path(target, IFCFG_CFG_FILE) ++ con_file = f"ifcfg-{devname}" ++ return f"{target_con_dir}/{con_file}" ++ ++ ++def conn_filename(devname): ++ """ ++ This function returns the name of the interface config file. ++ It first checks for presence of network manager connection file. ++ If absent and ifcfg-rh plugin for network manager is available, ++ it returns the name of the ifcfg file if it is present. If the ++ plugin is not present or the plugin is present but ifcfg file is ++ not, it returns None. ++ This function is called from NetworkManagerActivator class in ++ activators.py. ++ """ ++ conn_file = nm_conn_filename(devname) ++ # If the network manager connection file is absent, also check for ++ # presence of ifcfg files for the same interface (if nm-ifcfg-rh plugin is ++ # present, network manager can handle ifcfg files). If both network manager ++ # connection file and ifcfg files are absent, return None. ++ if not os.path.isfile(conn_file) and available_nm_ifcfg_rh(): ++ conn_file = sysconfig_conn_filename(devname) ++ return conn_file if os.path.isfile(conn_file) else None ++ ++ + def cloud_init_nm_conf_filename(target=None): + target_con_dir = subp.target_path(target, NM_RUN_DIR) + conf_file = "30-cloud-init-ip6-addr-gen-mode.conf" diff --git a/SOURCES/0007-rhel-make-sure-previous-hostname-file-ends-with-a-ne.patch b/SOURCES/0007-rhel-make-sure-previous-hostname-file-ends-with-a-ne.patch deleted file mode 100644 index 7422b7e..0000000 --- a/SOURCES/0007-rhel-make-sure-previous-hostname-file-ends-with-a-ne.patch +++ /dev/null @@ -1,54 +0,0 @@ -From ac0cf308318d423162ce3b7be32dcbf88f20ff50 Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Tue, 4 Apr 2023 19:59:07 +0530 -Subject: [PATCH] rhel: make sure previous-hostname file ends with a new line - (#2108) - -cloud-init strips new line from "/etc/hostname" on rhel distro when processing -"/var/lib/cloud/data/previous-hostname". Although this does not pose a serious -issue, it is still better if the behavior is similar to other distros like -Ubuntu where /previous-hostname does end with a new line. Fix this issue by -using hostname parser in rhel similar to debian. - -Signed-off-by: Ani Sinha -(cherry picked from commit 6d42aa8e2c1a5454a658ab4e2b9cead2677c77cd) ---- - cloudinit/distros/rhel.py | 5 ++++- - tools/.github-cla-signers | 1 + - 2 files changed, 5 insertions(+), 1 deletion(-) - -diff --git a/cloudinit/distros/rhel.py b/cloudinit/distros/rhel.py -index df7dc3d6..9625709e 100644 ---- a/cloudinit/distros/rhel.py -+++ b/cloudinit/distros/rhel.py -@@ -13,6 +13,7 @@ from cloudinit import distros, helpers - from cloudinit import log as logging - from cloudinit import subp, util - from cloudinit.distros import rhel_util -+from cloudinit.distros.parsers.hostname import HostnameConf - from cloudinit.settings import PER_INSTANCE - - LOG = logging.getLogger(__name__) -@@ -111,7 +112,9 @@ class Distro(distros.Distro): - # systemd will never update previous-hostname for us, so - # we need to do it ourselves - if self.uses_systemd() and filename.endswith("/previous-hostname"): -- util.write_file(filename, hostname) -+ conf = HostnameConf("") -+ conf.set_hostname(hostname) -+ util.write_file(filename, str(conf), 0o644) - elif self.uses_systemd(): - subp.subp(["hostnamectl", "set-hostname", str(hostname)]) - else: -diff --git a/tools/.github-cla-signers b/tools/.github-cla-signers -index d8cca015..457dacf4 100644 ---- a/tools/.github-cla-signers -+++ b/tools/.github-cla-signers -@@ -9,6 +9,7 @@ andgein - andrew-lee-metaswitch - andrewbogott - andrewlukoshko -+ani-sinha - antonyc - aswinrajamannar - beantaxi diff --git a/SOURCES/0007-test-jsonschema-Pin-jsonschema-version-4781.patch b/SOURCES/0007-test-jsonschema-Pin-jsonschema-version-4781.patch new file mode 100644 index 0000000..ad7e5d6 --- /dev/null +++ b/SOURCES/0007-test-jsonschema-Pin-jsonschema-version-4781.patch @@ -0,0 +1,38 @@ +From e5258b60a3dbf44ef1faac91db2b45dab09de0b5 Mon Sep 17 00:00:00 2001 +From: Brett Holman +Date: Tue, 16 Jan 2024 12:43:17 -0700 +Subject: [PATCH] test(jsonschema): Pin jsonschema version (#4781) + +Release 4.21.0 broke tests + +(cherry picked from commit 034a5cdf10582da0492321f861b2b8b42182a54e) +--- + requirements.txt | 2 +- + test-requirements.txt | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/requirements.txt b/requirements.txt +index edec46a7..a095de18 100644 +--- a/requirements.txt ++++ b/requirements.txt +@@ -28,7 +28,7 @@ requests + jsonpatch + + # For validating cloud-config sections per schema definitions +-jsonschema ++jsonschema<=4.20.0 + + # Used by DataSourceVMware to inspect the host's network configuration during + # the "setup()" function. +diff --git a/test-requirements.txt b/test-requirements.txt +index 19488b94..46a98b4c 100644 +--- a/test-requirements.txt ++++ b/test-requirements.txt +@@ -9,6 +9,6 @@ pytest!=7.3.2 + pytest-cov + pytest-mock + setuptools +-jsonschema ++jsonschema<=4.20.0 + responses + passlib diff --git a/SOURCES/0008-Don-t-change-permissions-of-netrules-target-2076.patch b/SOURCES/0008-Don-t-change-permissions-of-netrules-target-2076.patch deleted file mode 100644 index d9bdf4f..0000000 --- a/SOURCES/0008-Don-t-change-permissions-of-netrules-target-2076.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 34ef256dc614c7dcf5b04a431d410030e333d82b Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Mon, 17 Apr 2023 10:20:16 +0200 -Subject: [PATCH] Don't change permissions of netrules target (#2076) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2182948 - -commit 56c88cafd1b3606e814069a79f4ec265fc427c87 -Author: James Falcon -Date: Thu Mar 23 10:21:56 2023 -0500 - - Don't change permissions of netrules target (#2076) - - Set permissions if file doesn't exist. Leave them if it does. - - LP: #2011783 - - Co-authored-by: Chad Smith - - Conflicts: - cloudinit/net/sysconfig.py: enable_ifcfg_rh missing upstream - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/net/eni.py | 4 +++- - cloudinit/net/sysconfig.py | 7 ++++++- - tests/unittests/distros/test_netconfig.py | 20 ++++++++++++++++++-- - 3 files changed, 27 insertions(+), 4 deletions(-) - -diff --git a/cloudinit/net/eni.py b/cloudinit/net/eni.py -index 53bd35ca..1de3bec2 100644 ---- a/cloudinit/net/eni.py -+++ b/cloudinit/net/eni.py -@@ -576,7 +576,9 @@ class Renderer(renderer.Renderer): - netrules = subp.target_path(target, self.netrules_path) - util.ensure_dir(os.path.dirname(netrules)) - util.write_file( -- netrules, self._render_persistent_net(network_state) -+ netrules, -+ content=self._render_persistent_net(network_state), -+ preserve_mode=True, - ) - - -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index 765c248a..e08c0c69 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -1034,7 +1034,12 @@ class Renderer(renderer.Renderer): - if self.netrules_path: - netrules_content = self._render_persistent_net(network_state) - netrules_path = subp.target_path(target, self.netrules_path) -- util.write_file(netrules_path, netrules_content, file_mode) -+ util.write_file( -+ netrules_path, -+ content=netrules_content, -+ mode=file_mode, -+ preserve_mode=True, -+ ) - if available_nm(target=target): - enable_ifcfg_rh(subp.target_path(target, path=NM_CFG_FILE)) - -diff --git a/tests/unittests/distros/test_netconfig.py b/tests/unittests/distros/test_netconfig.py -index e9fb0591..b1c89ce3 100644 ---- a/tests/unittests/distros/test_netconfig.py -+++ b/tests/unittests/distros/test_netconfig.py -@@ -458,8 +458,16 @@ class TestNetCfgDistroUbuntuEni(TestNetCfgDistroBase): - def eni_path(self): - return "/etc/network/interfaces.d/50-cloud-init.cfg" - -+ def rules_path(self): -+ return "/etc/udev/rules.d/70-persistent-net.rules" -+ - def _apply_and_verify_eni( -- self, apply_fn, config, expected_cfgs=None, bringup=False -+ self, -+ apply_fn, -+ config, -+ expected_cfgs=None, -+ bringup=False, -+ previous_files=(), - ): - if not expected_cfgs: - raise ValueError("expected_cfg must not be None") -@@ -467,7 +475,11 @@ class TestNetCfgDistroUbuntuEni(TestNetCfgDistroBase): - tmpd = None - with mock.patch("cloudinit.net.eni.available") as m_avail: - m_avail.return_value = True -+ path_modes = {} - with self.reRooted(tmpd) as tmpd: -+ for previous_path, content, mode in previous_files: -+ util.write_file(previous_path, content, mode=mode) -+ path_modes[previous_path] = mode - apply_fn(config, bringup) - - results = dir2dict(tmpd) -@@ -478,7 +490,9 @@ class TestNetCfgDistroUbuntuEni(TestNetCfgDistroBase): - print(results[cfgpath]) - print("----------") - self.assertEqual(expected, results[cfgpath]) -- self.assertEqual(0o644, get_mode(cfgpath, tmpd)) -+ self.assertEqual( -+ path_modes.get(cfgpath, 0o644), get_mode(cfgpath, tmpd) -+ ) - - def test_apply_network_config_and_bringup_filters_priority_eni_ub(self): - """Network activator search priority can be overridden from config.""" -@@ -527,11 +541,13 @@ class TestNetCfgDistroUbuntuEni(TestNetCfgDistroBase): - def test_apply_network_config_eni_ub(self): - expected_cfgs = { - self.eni_path(): V1_NET_CFG_OUTPUT, -+ self.rules_path(): "", - } - self._apply_and_verify_eni( - self.distro.apply_network_config, - V1_NET_CFG, - expected_cfgs=expected_cfgs.copy(), -+ previous_files=((self.rules_path(), "something", 0o660),), - ) - - def test_apply_network_config_ipv6_ub(self): diff --git a/SOURCES/0008-fix-clean-stop-warning-when-running-clean-command-47.patch b/SOURCES/0008-fix-clean-stop-warning-when-running-clean-command-47.patch new file mode 100644 index 0000000..72884d5 --- /dev/null +++ b/SOURCES/0008-fix-clean-stop-warning-when-running-clean-command-47.patch @@ -0,0 +1,121 @@ +From 9e8fbb736d5e8db8bcf0fbc35a76bdad9251990a Mon Sep 17 00:00:00 2001 +From: d1r3ct0r +Date: Sat, 20 Jan 2024 02:11:47 +0300 +Subject: [PATCH] fix(clean): stop warning when running clean command (#4761) + +When the clean command is run, runparts is called and README in +/etc/cloud/clean.d is not executable which leads to a warning. + +No longer deliver the README in our deb package, move content +to our online docs. Continue to deliver the /etc/cloud/clean.d +directory as it is used by installers like subiquity. + +Fixes: GH-4760 +(cherry picked from commit da08a260965e35fa63def1cd8b8b472f7c354ffe) + +There is a downstream only change that is squashed with the upstream commit. +The spec file under .distro/ has been updated so as to not include +/etc/cloud/clean.d/README file. Otherwise, we shall see errors like the +following during the build process: + +error: File not found: /builddir/build/.../etc/cloud/clean.d/README + +After a rebase, we can only maintain the downstream spec file change as +the rest of it is clean cherry-pick from upstream. + +X-downstream-only: true +Signed-off-by: Ani Sinha +--- + config/clean.d/README | 18 ------------------ + doc/rtd/reference/cli.rst | 27 +++++++++++++++++++++++++++ + packages/redhat/cloud-init.spec.in | 1 - + packages/suse/cloud-init.spec.in | 1 - + 4 files changed, 27 insertions(+), 20 deletions(-) + delete mode 100644 config/clean.d/README + +diff --git a/config/clean.d/README b/config/clean.d/README +deleted file mode 100644 +index 9b0feebe..00000000 +--- a/config/clean.d/README ++++ /dev/null +@@ -1,18 +0,0 @@ +--- cloud-init's clean.d run-parts directory -- +- +-This directory is provided for third party applications which need +-additional configuration artifact cleanup from the filesystem when +-the command `cloud-init clean` is invoked. +- +-The `cloud-init clean` operation is typically performed by image creators +-when preparing a golden image for clone and redeployment. The clean command +-removes any cloud-init semaphores, allowing cloud-init to treat the next +-boot of this image as the "first boot". When the image is next booted +-cloud-init will performing all initial configuration based on any valid +-datasource meta-data and user-data. +- +-Any executable scripts in this subdirectory will be invoked in lexicographical +-order with run-parts by the command: sudo cloud-init clean. +- +-Typical format of such scripts would be a ##- like the following: +- /etc/cloud/clean.d/99-live-installer +diff --git a/doc/rtd/reference/cli.rst b/doc/rtd/reference/cli.rst +index 04e05c55..c36775a8 100644 +--- a/doc/rtd/reference/cli.rst ++++ b/doc/rtd/reference/cli.rst +@@ -83,6 +83,33 @@ re-run all stages as it did on first boot. + config files for ssh daemon. Argument `network` removes all generated + config files for network. `all` removes config files of all types. + ++.. note:: ++ ++ Cloud-init provides the directory :file:`/etc/cloud/clean.d/` for third party ++ applications which need additional configuration artifact cleanup from ++ the fileystem when the `clean` command is invoked. ++ ++ The :command:`clean` operation is typically performed by image creators ++ when preparing a golden image for clone and redeployment. The clean command ++ removes any cloud-init semaphores, allowing cloud-init to treat the next ++ boot of this image as the "first boot". When the image is next booted ++ cloud-init will performing all initial configuration based on any valid ++ datasource meta-data and user-data. ++ ++ Any executable scripts in this subdirectory will be invoked in lexicographical ++ order with run-parts when running the :command:`clean` command. ++ ++ Typical format of such scripts would be a ##- like the following: ++ :file:`/etc/cloud/clean.d/99-live-installer` ++ ++ An example of a script is: ++ ++ .. code-block:: bash ++ ++ sudo rm -rf /var/lib/installer_imgs/ ++ sudo rm -rf /var/log/installer/ ++ ++ + .. _cli_collect_logs: + + :command:`collect-logs` +diff --git a/packages/redhat/cloud-init.spec.in b/packages/redhat/cloud-init.spec.in +index 97e95096..accfb1b6 100644 +--- a/packages/redhat/cloud-init.spec.in ++++ b/packages/redhat/cloud-init.spec.in +@@ -190,7 +190,6 @@ fi + # Configs + %config(noreplace) %{_sysconfdir}/cloud/cloud.cfg + %dir %{_sysconfdir}/cloud/clean.d +-%config(noreplace) %{_sysconfdir}/cloud/clean.d/README + %dir %{_sysconfdir}/cloud/cloud.cfg.d + %config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/*.cfg + %config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/README +diff --git a/packages/suse/cloud-init.spec.in b/packages/suse/cloud-init.spec.in +index 62a9129b..fae3c12b 100644 +--- a/packages/suse/cloud-init.spec.in ++++ b/packages/suse/cloud-init.spec.in +@@ -115,7 +115,6 @@ version_pys=$(cd "%{buildroot}" && find . -name version.py -type f) + + # Configs + %dir %{_sysconfdir}/cloud/clean.d +-%config(noreplace) %{_sysconfdir}/cloud/clean.d/README + %config(noreplace) %{_sysconfdir}/cloud/cloud.cfg + %dir %{_sysconfdir}/cloud/cloud.cfg.d + %config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/*.cfg diff --git a/SOURCES/0009-Make-user-vendor-data-sensitive-and-remove-log-permi.patch b/SOURCES/0009-Make-user-vendor-data-sensitive-and-remove-log-permi.patch deleted file mode 100644 index 570a42b..0000000 --- a/SOURCES/0009-Make-user-vendor-data-sensitive-and-remove-log-permi.patch +++ /dev/null @@ -1,295 +0,0 @@ -From d092efe0f437ad149f6d6e3a9f8b816c0f5c1c2a Mon Sep 17 00:00:00 2001 -From: James Falcon -Date: Wed, 26 Apr 2023 15:11:55 -0500 -Subject: [PATCH] Make user/vendor data sensitive and remove log permissions - (#2144) - -Because user data and vendor data may contain sensitive information, -this commit ensures that any user data or vendor data written to -instance-data.json gets redacted and is only available to root user. - -Also, modify the permissions of cloud-init.log to be 640, so that -sensitive data leaked to the log isn't world readable. -Additionally, remove the logging of user data and vendor data to -cloud-init.log from the Vultr datasource. - -LP: #2013967 -CVE: CVE-2023-1786 -(cherry picked from commit a378b7e4f47375458651c0972e7cd813f6fe0a6b) -Signed-off-by: Ani Sinha ---- - cloudinit/sources/DataSourceLXD.py | 9 ++++++--- - cloudinit/sources/DataSourceVultr.py | 14 ++++++-------- - cloudinit/sources/__init__.py | 28 +++++++++++++++++++++++++--- - cloudinit/stages.py | 4 +++- - tests/unittests/sources/test_init.py | 27 ++++++++++++++++++++++++++- - tests/unittests/test_stages.py | 18 +++++++++++------- - 6 files changed, 77 insertions(+), 23 deletions(-) - -diff --git a/cloudinit/sources/DataSourceLXD.py b/cloudinit/sources/DataSourceLXD.py -index ab440cc8..e4cae91a 100644 ---- a/cloudinit/sources/DataSourceLXD.py -+++ b/cloudinit/sources/DataSourceLXD.py -@@ -14,7 +14,7 @@ import stat - import time - from enum import Flag, auto - from json.decoder import JSONDecodeError --from typing import Any, Dict, List, Optional, Union, cast -+from typing import Any, Dict, List, Optional, Tuple, Union, cast - - import requests - from requests.adapters import HTTPAdapter -@@ -168,11 +168,14 @@ class DataSourceLXD(sources.DataSource): - _network_config: Union[Dict, str] = sources.UNSET - _crawled_metadata: Union[Dict, str] = sources.UNSET - -- sensitive_metadata_keys = ( -- "merged_cfg", -+ sensitive_metadata_keys: Tuple[ -+ str, ... -+ ] = sources.DataSource.sensitive_metadata_keys + ( - "user.meta-data", - "user.vendor-data", - "user.user-data", -+ "cloud-init.user-data", -+ "cloud-init.vendor-data", - ) - - skip_hotplug_detect = True -diff --git a/cloudinit/sources/DataSourceVultr.py b/cloudinit/sources/DataSourceVultr.py -index 9d7c84fb..660e9f14 100644 ---- a/cloudinit/sources/DataSourceVultr.py -+++ b/cloudinit/sources/DataSourceVultr.py -@@ -5,6 +5,8 @@ - # Vultr Metadata API: - # https://www.vultr.com/metadata/ - -+from typing import Tuple -+ - import cloudinit.sources.helpers.vultr as vultr - from cloudinit import log as log - from cloudinit import sources, util, version -@@ -28,6 +30,10 @@ class DataSourceVultr(sources.DataSource): - - dsname = "Vultr" - -+ sensitive_metadata_keys: Tuple[ -+ str, ... -+ ] = sources.DataSource.sensitive_metadata_keys + ("startup-script",) -+ - def __init__(self, sys_cfg, distro, paths): - super(DataSourceVultr, self).__init__(sys_cfg, distro, paths) - self.ds_cfg = util.mergemanydict( -@@ -54,13 +60,8 @@ class DataSourceVultr(sources.DataSource): - self.get_datasource_data(self.metadata) - - # Dump some data so diagnosing failures is manageable -- LOG.debug("Vultr Vendor Config:") -- LOG.debug(util.json_dumps(self.metadata["vendor-data"])) - LOG.debug("SUBID: %s", self.metadata["instance-id"]) - LOG.debug("Hostname: %s", self.metadata["local-hostname"]) -- if self.userdata_raw is not None: -- LOG.debug("User-Data:") -- LOG.debug(self.userdata_raw) - - return True - -@@ -146,7 +147,4 @@ if __name__ == "__main__": - config = md["vendor-data"] - sysinfo = vultr.get_sysinfo() - -- print(util.json_dumps(sysinfo)) -- print(util.json_dumps(config)) -- - # vi: ts=4 expandtab -diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py -index 565e1754..5c6ae8b1 100644 ---- a/cloudinit/sources/__init__.py -+++ b/cloudinit/sources/__init__.py -@@ -110,7 +110,10 @@ def process_instance_metadata(metadata, key_path="", sensitive_keys=()): - sub_key_path = key_path + "/" + key - else: - sub_key_path = key -- if key in sensitive_keys or sub_key_path in sensitive_keys: -+ if ( -+ key.lower() in sensitive_keys -+ or sub_key_path.lower() in sensitive_keys -+ ): - sens_keys.append(sub_key_path) - if isinstance(val, str) and val.startswith("ci-b64:"): - base64_encoded_keys.append(sub_key_path) -@@ -132,6 +135,12 @@ def redact_sensitive_keys(metadata, redact_value=REDACT_SENSITIVE_VALUE): - - Replace any keys values listed in 'sensitive_keys' with redact_value. - """ -+ # While 'sensitive_keys' should already sanitized to only include what -+ # is in metadata, it is possible keys will overlap. For example, if -+ # "merged_cfg" and "merged_cfg/ds/userdata" both match, it's possible that -+ # "merged_cfg" will get replaced first, meaning "merged_cfg/ds/userdata" -+ # no longer represents a valid key. -+ # Thus, we still need to do membership checks in this function. - if not metadata.get("sensitive_keys", []): - return metadata - md_copy = copy.deepcopy(metadata) -@@ -139,9 +148,14 @@ def redact_sensitive_keys(metadata, redact_value=REDACT_SENSITIVE_VALUE): - path_parts = key_path.split("/") - obj = md_copy - for path in path_parts: -- if isinstance(obj[path], dict) and path != path_parts[-1]: -+ if ( -+ path in obj -+ and isinstance(obj[path], dict) -+ and path != path_parts[-1] -+ ): - obj = obj[path] -- obj[path] = redact_value -+ if path in obj: -+ obj[path] = redact_value - return md_copy - - -@@ -249,6 +263,14 @@ class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta): - sensitive_metadata_keys: Tuple[str, ...] = ( - "merged_cfg", - "security-credentials", -+ "userdata", -+ "user-data", -+ "user_data", -+ "vendordata", -+ "vendor-data", -+ # Provide ds/vendor_data to avoid redacting top-level -+ # "vendor_data": {enabled: True} -+ "ds/vendor_data", - ) - - # True on datasources that may not see hotplugged devices reflected -diff --git a/cloudinit/stages.py b/cloudinit/stages.py -index a624a6fb..1326d205 100644 ---- a/cloudinit/stages.py -+++ b/cloudinit/stages.py -@@ -204,7 +204,9 @@ class Init: - log_file = util.get_cfg_option_str(self.cfg, "def_log_file") - log_file_mode = util.get_cfg_option_int(self.cfg, "def_log_file_mode") - if log_file: -- util.ensure_file(log_file, mode=0o640, preserve_mode=True) -+ # At this point the log file should have already been created -+ # in the setupLogging function of log.py -+ util.ensure_file(log_file, mode=0o640, preserve_mode=False) - perms = self.cfg.get("syslog_fix_perms") - if not perms: - perms = {} -diff --git a/tests/unittests/sources/test_init.py b/tests/unittests/sources/test_init.py -index 0447e02c..eb27198f 100644 ---- a/tests/unittests/sources/test_init.py -+++ b/tests/unittests/sources/test_init.py -@@ -458,12 +458,24 @@ class TestDataSource(CiTestCase): - "cred2": "othersekret", - } - }, -+ "someother": { -+ "nested": { -+ "userData": "HIDE ME", -+ } -+ }, -+ "VENDOR-DAta": "HIDE ME TOO", - }, - ) - self.assertCountEqual( - ( - "merged_cfg", - "security-credentials", -+ "userdata", -+ "user-data", -+ "user_data", -+ "vendordata", -+ "vendor-data", -+ "ds/vendor_data", - ), - datasource.sensitive_metadata_keys, - ) -@@ -490,7 +502,9 @@ class TestDataSource(CiTestCase): - "base64_encoded_keys": [], - "merged_cfg": REDACT_SENSITIVE_VALUE, - "sensitive_keys": [ -+ "ds/meta_data/VENDOR-DAta", - "ds/meta_data/some/security-credentials", -+ "ds/meta_data/someother/nested/userData", - "merged_cfg", - ], - "sys_info": sys_info, -@@ -500,6 +514,7 @@ class TestDataSource(CiTestCase): - "availability_zone": "myaz", - "cloud-name": "subclasscloudname", - "cloud_name": "subclasscloudname", -+ "cloud_id": "subclasscloudname", - "distro": "ubuntu", - "distro_release": "focal", - "distro_version": "20.04", -@@ -522,14 +537,18 @@ class TestDataSource(CiTestCase): - "ds": { - "_doc": EXPERIMENTAL_TEXT, - "meta_data": { -+ "VENDOR-DAta": REDACT_SENSITIVE_VALUE, - "availability_zone": "myaz", - "local-hostname": "test-subclass-hostname", - "region": "myregion", - "some": {"security-credentials": REDACT_SENSITIVE_VALUE}, -+ "someother": { -+ "nested": {"userData": REDACT_SENSITIVE_VALUE} -+ }, - }, - }, - } -- self.assertCountEqual(expected, redacted) -+ self.assertEqual(expected, redacted) - file_stat = os.stat(json_file) - self.assertEqual(0o644, stat.S_IMODE(file_stat.st_mode)) - -@@ -574,6 +593,12 @@ class TestDataSource(CiTestCase): - ( - "merged_cfg", - "security-credentials", -+ "userdata", -+ "user-data", -+ "user_data", -+ "vendordata", -+ "vendor-data", -+ "ds/vendor_data", - ), - datasource.sensitive_metadata_keys, - ) -diff --git a/tests/unittests/test_stages.py b/tests/unittests/test_stages.py -index 15a7e973..a61f9df9 100644 ---- a/tests/unittests/test_stages.py -+++ b/tests/unittests/test_stages.py -@@ -606,19 +606,23 @@ class TestInit_InitializeFilesystem: - # Assert we create it 0o640 by default if it doesn't already exist - assert 0o640 == stat.S_IMODE(log_file.stat().mode) - -- def test_existing_file_permissions_are_not_modified(self, init, tmpdir): -- """If the log file already exists, we should not modify its permissions -+ def test_existing_file_permissions(self, init, tmpdir): -+ """Test file permissions are set as expected. -+ -+ CIS Hardening requires 640 permissions. These permissions are -+ currently hardcoded on every boot, but if there's ever a reason -+ to change this, we need to then ensure that they -+ are *not* set every boot. - - See https://bugs.launchpad.net/cloud-init/+bug/1900837. - """ -- # Use a mode that will never be made the default so this test will -- # always be valid -- mode = 0o606 - log_file = tmpdir.join("cloud-init.log") - log_file.ensure() -- log_file.chmod(mode) -+ # Use a mode that will never be made the default so this test will -+ # always be valid -+ log_file.chmod(0o606) - init._cfg = {"def_log_file": str(log_file)} - - init._initialize_filesystem() - -- assert mode == stat.S_IMODE(log_file.stat().mode) -+ assert 0o640 == stat.S_IMODE(log_file.stat().mode) diff --git a/SOURCES/0010-Do-not-generate-dsa-and-ed25519-key-types-when-crypt.patch b/SOURCES/0010-Do-not-generate-dsa-and-ed25519-key-types-when-crypt.patch deleted file mode 100644 index d51a9dd..0000000 --- a/SOURCES/0010-Do-not-generate-dsa-and-ed25519-key-types-when-crypt.patch +++ /dev/null @@ -1,206 +0,0 @@ -From 6bf6ceab79df97eb1c90b4df61f654bc0b2f598c Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Tue, 2 May 2023 20:35:45 +0530 -Subject: [PATCH] Do not generate dsa and ed25519 key types when crypto FIPS - mode is enabled (#2142) - -DSA and ED25519 key types are not supported when FIPS is enabled in crypto. -Check if FIPS has been enabled on the system and if so, do not generate those -key types. Presently the check is only available on Linux systems. - -LP: 2017761 -RHBZ: 2187164 - -Signed-off-by: Ani Sinha -(cherry picked from commit c53f04aeb2acf9526a2ebf3d3320f149ac46caa6) ---- - cloudinit/config/cc_ssh.py | 21 +++++++++++++++- - cloudinit/util.py | 12 +++++++++ - tests/unittests/config/test_cc_ssh.py | 36 +++++++++++++++++++++------ - tests/unittests/test_util.py | 25 +++++++++++++++++++ - 4 files changed, 85 insertions(+), 9 deletions(-) - -diff --git a/cloudinit/config/cc_ssh.py b/cloudinit/config/cc_ssh.py -index 1ec889f3..5578654a 100644 ---- a/cloudinit/config/cc_ssh.py -+++ b/cloudinit/config/cc_ssh.py -@@ -172,6 +172,8 @@ meta: MetaSchema = { - __doc__ = get_meta_doc(meta) - - GENERATE_KEY_NAMES = ["rsa", "dsa", "ecdsa", "ed25519"] -+FIPS_UNSUPPORTED_KEY_NAMES = ["dsa", "ed25519"] -+ - pattern_unsupported_config_keys = re.compile( - "^(ecdsa-sk|ed25519-sk)_(private|public|certificate)$" - ) -@@ -259,9 +261,26 @@ def handle( - genkeys = util.get_cfg_option_list( - cfg, "ssh_genkeytypes", GENERATE_KEY_NAMES - ) -+ # remove keys that are not supported in fips mode if its enabled -+ key_names = ( -+ genkeys -+ if not util.fips_enabled() -+ else [ -+ names -+ for names in genkeys -+ if names not in FIPS_UNSUPPORTED_KEY_NAMES -+ ] -+ ) -+ skipped_keys = set(genkeys).difference(key_names) -+ if skipped_keys: -+ log.debug( -+ "skipping keys that are not supported in fips mode: %s", -+ ",".join(skipped_keys), -+ ) -+ - lang_c = os.environ.copy() - lang_c["LANG"] = "C" -- for keytype in genkeys: -+ for keytype in key_names: - keyfile = KEY_FILE_TPL % (keytype) - if os.path.exists(keyfile): - continue -diff --git a/cloudinit/util.py b/cloudinit/util.py -index 8ba3e2b6..4a8e3d3b 100644 ---- a/cloudinit/util.py -+++ b/cloudinit/util.py -@@ -1577,6 +1577,18 @@ def get_cmdline(): - return _get_cmdline() - - -+def fips_enabled() -> bool: -+ fips_proc = "/proc/sys/crypto/fips_enabled" -+ try: -+ contents = load_file(fips_proc).strip() -+ return contents == "1" -+ except (IOError, OSError): -+ # for BSD systems and Linux systems where the proc entry is not -+ # available, we assume FIPS is disabled to retain the old behavior -+ # for now. -+ return False -+ -+ - def pipe_in_out(in_fh, out_fh, chunk_size=1024, chunk_cb=None): - bytes_piped = 0 - while True: -diff --git a/tests/unittests/config/test_cc_ssh.py b/tests/unittests/config/test_cc_ssh.py -index 66368d0f..72941a95 100644 ---- a/tests/unittests/config/test_cc_ssh.py -+++ b/tests/unittests/config/test_cc_ssh.py -@@ -101,11 +101,16 @@ class TestHandleSsh: - expected_calls = [mock.call(set(keys), user)] + expected_calls - assert expected_calls == m_setup_keys.call_args_list - -+ @pytest.mark.parametrize("fips_enabled", (True, False)) - @mock.patch(MODPATH + "glob.glob") - @mock.patch(MODPATH + "ug_util.normalize_users_groups") - @mock.patch(MODPATH + "os.path.exists") -- def test_handle_no_cfg(self, m_path_exists, m_nug, m_glob, m_setup_keys): -+ @mock.patch(MODPATH + "util.fips_enabled") -+ def test_handle_no_cfg( -+ self, m_fips, m_path_exists, m_nug, m_glob, m_setup_keys, fips_enabled -+ ): - """Test handle with no config ignores generating existing keyfiles.""" -+ m_fips.return_value = fips_enabled - cfg = {} - keys = ["key1"] - m_glob.return_value = [] # Return no matching keys to prevent removal -@@ -118,12 +123,22 @@ class TestHandleSsh: - options = ssh_util.DISABLE_USER_OPTS.replace("$USER", "NONE") - options = options.replace("$DISABLE_USER", "root") - m_glob.assert_called_once_with("/etc/ssh/ssh_host_*key*") -- assert [ -- mock.call("/etc/ssh/ssh_host_rsa_key"), -- mock.call("/etc/ssh/ssh_host_dsa_key"), -- mock.call("/etc/ssh/ssh_host_ecdsa_key"), -- mock.call("/etc/ssh/ssh_host_ed25519_key"), -- ] in m_path_exists.call_args_list -+ m_fips.assert_called_once() -+ -+ if not m_fips(): -+ expected_calls = [ -+ mock.call("/etc/ssh/ssh_host_rsa_key"), -+ mock.call("/etc/ssh/ssh_host_dsa_key"), -+ mock.call("/etc/ssh/ssh_host_ecdsa_key"), -+ mock.call("/etc/ssh/ssh_host_ed25519_key"), -+ ] -+ else: -+ # Enabled fips doesn't generate dsa or ed25519 -+ expected_calls = [ -+ mock.call("/etc/ssh/ssh_host_rsa_key"), -+ mock.call("/etc/ssh/ssh_host_ecdsa_key"), -+ ] -+ assert expected_calls in m_path_exists.call_args_list - assert [ - mock.call(set(keys), "root", options=options) - ] == m_setup_keys.call_args_list -@@ -131,8 +146,9 @@ class TestHandleSsh: - @mock.patch(MODPATH + "glob.glob") - @mock.patch(MODPATH + "ug_util.normalize_users_groups") - @mock.patch(MODPATH + "os.path.exists") -+ @mock.patch(MODPATH + "util.fips_enabled", return_value=False) - def test_dont_allow_public_ssh_keys( -- self, m_path_exists, m_nug, m_glob, m_setup_keys -+ self, m_fips, m_path_exists, m_nug, m_glob, m_setup_keys - ): - """Test allow_public_ssh_keys=False ignores ssh public keys from - platform. -@@ -176,8 +192,10 @@ class TestHandleSsh: - @mock.patch(MODPATH + "glob.glob") - @mock.patch(MODPATH + "ug_util.normalize_users_groups") - @mock.patch(MODPATH + "os.path.exists") -+ @mock.patch(MODPATH + "util.fips_enabled", return_value=False) - def test_handle_default_root( - self, -+ m_fips, - m_path_exists, - m_nug, - m_glob, -@@ -241,8 +259,10 @@ class TestHandleSsh: - @mock.patch(MODPATH + "glob.glob") - @mock.patch(MODPATH + "ug_util.normalize_users_groups") - @mock.patch(MODPATH + "os.path.exists") -+ @mock.patch(MODPATH + "util.fips_enabled", return_value=False) - def test_handle_publish_hostkeys( - self, -+ m_fips, - m_path_exists, - m_nug, - m_glob, -diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py -index 07142a86..17182d06 100644 ---- a/tests/unittests/test_util.py -+++ b/tests/unittests/test_util.py -@@ -1945,6 +1945,31 @@ class TestGetCmdline(helpers.TestCase): - self.assertEqual("abcd 123", ret) - - -+class TestFipsEnabled: -+ @pytest.mark.parametrize( -+ "fips_enabled_content,expected", -+ ( -+ pytest.param(None, False, id="false_when_no_fips_enabled_file"), -+ pytest.param("0\n", False, id="false_when_fips_disabled"), -+ pytest.param("1\n", True, id="true_when_fips_enabled"), -+ pytest.param("1", True, id="true_when_fips_enabled_no_newline"), -+ ), -+ ) -+ @mock.patch(M_PATH + "load_file") -+ def test_fips_enabled_based_on_proc_crypto( -+ self, load_file, fips_enabled_content, expected, tmpdir -+ ): -+ def fake_load_file(path): -+ assert path == "/proc/sys/crypto/fips_enabled" -+ if fips_enabled_content is None: -+ raise IOError("No file exists Bob") -+ return fips_enabled_content -+ -+ load_file.side_effect = fake_load_file -+ -+ assert expected is util.fips_enabled() -+ -+ - class TestLoadYaml(helpers.CiTestCase): - mydefault = "7b03a8ebace993d806255121073fed52" - with_logs = True diff --git a/SOURCES/0011-Revert-Manual-revert-Use-Network-Manager-and-Netplan.patch b/SOURCES/0011-Revert-Manual-revert-Use-Network-Manager-and-Netplan.patch deleted file mode 100644 index bce0c00..0000000 --- a/SOURCES/0011-Revert-Manual-revert-Use-Network-Manager-and-Netplan.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0b0632f6c084a8ce95b53cb5125dc0f4107e6968 Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Thu, 4 May 2023 15:34:43 +0530 -Subject: [PATCH] Revert "Manual revert "Use Network-Manager and Netplan as - default renderers for RHEL and Fedora (#1465)"" - -This reverts commit ecae81f98ce230266eb99671b74534a4ede660f0. - -This is patch 1 of the two patches that re-enables NM renderer. This change -can be ignored while rebasing to latest upstream. - -X-downstream-only: true -Signed-off-by: Ani Sinha ---- - cloudinit/net/renderers.py | 1 + - config/cloud.cfg.tmpl | 3 +++ - doc/rtd/reference/network-config.rst | 16 ++++++++++++++-- - 3 files changed, 18 insertions(+), 2 deletions(-) - -diff --git a/cloudinit/net/renderers.py b/cloudinit/net/renderers.py -index c92b9dcf..022ff938 100644 ---- a/cloudinit/net/renderers.py -+++ b/cloudinit/net/renderers.py -@@ -28,6 +28,7 @@ DEFAULT_PRIORITY = [ - "eni", - "sysconfig", - "netplan", -+ "network-manager", - "freebsd", - "netbsd", - "openbsd", -diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl -index 12f32c51..7238c102 100644 ---- a/config/cloud.cfg.tmpl -+++ b/config/cloud.cfg.tmpl -@@ -381,6 +381,9 @@ system_info: - {% elif variant in ["dragonfly"] %} - network: - renderers: ['freebsd'] -+{% elif variant in ["fedora"] or is_rhel %} -+ network: -+ renderers: ['netplan', 'network-manager', 'networkd', 'sysconfig', 'eni'] - {% elif variant == "openmandriva" %} - network: - renderers: ['network-manager', 'networkd'] -diff --git a/doc/rtd/reference/network-config.rst b/doc/rtd/reference/network-config.rst -index bc52afa5..ea331f1c 100644 ---- a/doc/rtd/reference/network-config.rst -+++ b/doc/rtd/reference/network-config.rst -@@ -176,6 +176,16 @@ this state, ``cloud-init`` delegates rendering of the configuration to - distro-supported formats. The following ``renderers`` are supported in - ``cloud-init``: - -+NetworkManager -+-------------- -+ -+`NetworkManager`_ is the standard Linux network configuration tool suite. It -+supports a wide range of networking setups. Configuration is typically stored -+in :file:`/etc/NetworkManager`. -+ -+It is the default for a number of Linux distributions; notably Fedora, -+CentOS/RHEL, and their derivatives. -+ - ENI - --- - -@@ -213,6 +223,7 @@ preference) is as follows: - - ENI - - Sysconfig - - Netplan -+- NetworkManager - - FreeBSD - - NetBSD - - OpenBSD -@@ -223,6 +234,7 @@ preference) is as follows: - - - **ENI**: using ``ifup``, ``ifdown`` to manage device setup/teardown - - **Netplan**: using ``netplan apply`` to manage device setup/teardown -+- **NetworkManager**: using ``nmcli`` to manage device setup/teardown - - **Networkd**: using ``ip`` to manage device setup/teardown - - When applying the policy, ``cloud-init`` checks if the current instance has the -@@ -232,8 +244,8 @@ supplying an updated configuration in cloud-config. :: - - system_info: - network: -- renderers: ['netplan', 'eni', 'sysconfig', 'freebsd', 'netbsd', 'openbsd'] -- activators: ['eni', 'netplan', 'networkd'] -+ renderers: ['netplan', 'network-manager', 'eni', 'sysconfig', 'freebsd', 'netbsd', 'openbsd'] -+ activators: ['eni', 'netplan', 'network-manager', 'networkd'] - - Network configuration tools - =========================== diff --git a/SOURCES/0012-Revert-Revert-Add-native-NetworkManager-support-1224.patch b/SOURCES/0012-Revert-Revert-Add-native-NetworkManager-support-1224.patch deleted file mode 100644 index 2ae66c7..0000000 --- a/SOURCES/0012-Revert-Revert-Add-native-NetworkManager-support-1224.patch +++ /dev/null @@ -1,1391 +0,0 @@ -From 5822f72230a58d18dae8c3b76c02d4bf7a149e56 Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Thu, 4 May 2023 15:39:17 +0530 -Subject: [PATCH] Revert "Revert "Add native NetworkManager support (#1224)"" - -This reverts commit b1dd14ffafad2d2ca84326c525962b2ca086b292. - -This is patch 2 of the two patches that re-enables NM renderer. This change can -be ignored while rebasing to latest upstream. - -X-downstream-only: true -Signed-off-by: Ani Sinha ---- - cloudinit/cmd/devel/net_convert.py | 14 +- - cloudinit/net/activators.py | 25 +- - cloudinit/net/network_manager.py | 393 ++++++++++++++++ - cloudinit/net/renderers.py | 2 + - cloudinit/net/sysconfig.py | 42 +- - tests/unittests/test_net.py | 597 ++++++++++++++++++++----- - tests/unittests/test_net_activators.py | 11 +- - 7 files changed, 923 insertions(+), 161 deletions(-) - create mode 100644 cloudinit/net/network_manager.py - -diff --git a/cloudinit/cmd/devel/net_convert.py b/cloudinit/cmd/devel/net_convert.py -index 1a0a31ac..eee49860 100755 ---- a/cloudinit/cmd/devel/net_convert.py -+++ b/cloudinit/cmd/devel/net_convert.py -@@ -10,7 +10,14 @@ import sys - import yaml - - from cloudinit import distros, log, safeyaml --from cloudinit.net import eni, netplan, network_state, networkd, sysconfig -+from cloudinit.net import ( -+ eni, -+ netplan, -+ network_manager, -+ network_state, -+ networkd, -+ sysconfig, -+) - from cloudinit.sources import DataSourceAzure as azure - from cloudinit.sources.helpers import openstack - from cloudinit.sources.helpers.vmware.imc import guestcust_util -@@ -77,7 +84,7 @@ def get_parser(parser=None): - parser.add_argument( - "-O", - "--output-kind", -- choices=["eni", "netplan", "networkd", "sysconfig"], -+ choices=["eni", "netplan", "networkd", "sysconfig", "network-manager"], - required=True, - help="The network config format to emit", - ) -@@ -150,6 +157,9 @@ def handle_args(name, args): - elif args.output_kind == "sysconfig": - r_cls = sysconfig.Renderer - config = distro.renderer_configs.get("sysconfig") -+ elif args.output_kind == "network-manager": -+ r_cls = network_manager.Renderer -+ config = distro.renderer_configs.get("network-manager") - else: - raise RuntimeError("Invalid output_kind") - -diff --git a/cloudinit/net/activators.py b/cloudinit/net/activators.py -index d9a8c4d7..7d11a02c 100644 ---- a/cloudinit/net/activators.py -+++ b/cloudinit/net/activators.py -@@ -1,15 +1,14 @@ - # This file is part of cloud-init. See LICENSE file for license information. - import logging --import os - from abc import ABC, abstractmethod - from typing import Dict, Iterable, List, Optional, Type, Union - - from cloudinit import subp, util - from cloudinit.net.eni import available as eni_available - from cloudinit.net.netplan import available as netplan_available -+from cloudinit.net.network_manager import available as nm_available - from cloudinit.net.network_state import NetworkState - from cloudinit.net.networkd import available as networkd_available --from cloudinit.net.sysconfig import NM_CFG_FILE - - LOG = logging.getLogger(__name__) - -@@ -124,20 +123,24 @@ class IfUpDownActivator(NetworkActivator): - class NetworkManagerActivator(NetworkActivator): - @staticmethod - def available(target=None) -> bool: -- """Return true if network manager can be used on this system.""" -- config_present = os.path.isfile( -- subp.target_path(target, path=NM_CFG_FILE) -- ) -- nmcli_present = subp.which("nmcli", target=target) -- return config_present and bool(nmcli_present) -+ """Return true if NetworkManager can be used on this system.""" -+ return nm_available(target=target) - - @staticmethod - def bring_up_interface(device_name: str) -> bool: -- """Bring up interface using nmcli. -+ """Bring up connection using nmcli. - - Return True is successful, otherwise return False - """ -- cmd = ["nmcli", "connection", "up", "ifname", device_name] -+ from cloudinit.net.network_manager import conn_filename -+ -+ filename = conn_filename(device_name) -+ cmd = ["nmcli", "connection", "load", filename] -+ if _alter_interface(cmd, device_name): -+ cmd = ["nmcli", "connection", "up", "filename", filename] -+ else: -+ _alter_interface(["nmcli", "connection", "reload"], device_name) -+ cmd = ["nmcli", "connection", "up", "ifname", device_name] - return _alter_interface(cmd, device_name) - - @staticmethod -@@ -146,7 +149,7 @@ class NetworkManagerActivator(NetworkActivator): - - Return True is successful, otherwise return False - """ -- cmd = ["nmcli", "connection", "down", device_name] -+ cmd = ["nmcli", "device", "disconnect", device_name] - return _alter_interface(cmd, device_name) - - -diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py -new file mode 100644 -index 00000000..53763d15 ---- /dev/null -+++ b/cloudinit/net/network_manager.py -@@ -0,0 +1,393 @@ -+# Copyright 2022 Red Hat, Inc. -+# -+# Author: Lubomir Rintel -+# Fixes and suggestions contributed by James Falcon, Neal Gompa, -+# Zbigniew Jędrzejewski-Szmek and Emanuele Giuseppe Esposito. -+# -+# This file is part of cloud-init. See LICENSE file for license information. -+ -+import configparser -+import io -+import itertools -+import os -+import uuid -+from typing import Optional -+ -+from cloudinit import log as logging -+from cloudinit import subp, util -+from cloudinit.net import is_ipv6_address, renderer, subnet_is_ipv6 -+from cloudinit.net.network_state import NetworkState -+ -+NM_RUN_DIR = "/etc/NetworkManager" -+NM_LIB_DIR = "/usr/lib/NetworkManager" -+NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf" -+LOG = logging.getLogger(__name__) -+ -+ -+class NMConnection: -+ """Represents a NetworkManager connection profile.""" -+ -+ def __init__(self, con_id): -+ """ -+ Initializes the connection with some very basic properties, -+ notably the UUID so that the connection can be referred to. -+ """ -+ -+ # Chosen by fair dice roll -+ CI_NM_UUID = uuid.UUID("a3924cb8-09e0-43e9-890b-77972a800108") -+ -+ self.config = configparser.ConfigParser() -+ # Identity option name mapping, to achieve case sensitivity -+ self.config.optionxform = str -+ -+ self.config["connection"] = { -+ "id": f"cloud-init {con_id}", -+ "uuid": str(uuid.uuid5(CI_NM_UUID, con_id)), -+ } -+ -+ # This is not actually used anywhere, but may be useful in future -+ self.config["user"] = { -+ "org.freedesktop.NetworkManager.origin": "cloud-init" -+ } -+ -+ def _set_default(self, section, option, value): -+ """ -+ Sets a property unless it's already set, ensuring the section -+ exists. -+ """ -+ -+ if not self.config.has_section(section): -+ self.config[section] = {} -+ if not self.config.has_option(section, option): -+ self.config[section][option] = value -+ -+ def _set_ip_method(self, family, subnet_type): -+ """ -+ Ensures there's appropriate [ipv4]/[ipv6] for given family -+ appropriate for given configuration type -+ """ -+ -+ method_map = { -+ "static": "manual", -+ "dhcp6": "auto", -+ "ipv6_slaac": "auto", -+ "ipv6_dhcpv6-stateless": "auto", -+ "ipv6_dhcpv6-stateful": "auto", -+ "dhcp4": "auto", -+ "dhcp": "auto", -+ } -+ -+ # Ensure we got an [ipvX] section -+ self._set_default(family, "method", "disabled") -+ -+ try: -+ method = method_map[subnet_type] -+ except KeyError: -+ # What else can we do -+ method = "auto" -+ self.config[family]["may-fail"] = "true" -+ -+ # Make sure we don't "downgrade" the method in case -+ # we got conflicting subnets (e.g. static along with dhcp) -+ if self.config[family]["method"] == "dhcp": -+ return -+ if self.config[family]["method"] == "auto" and method == "manual": -+ return -+ -+ self.config[family]["method"] = method -+ self._set_default(family, "may-fail", "false") -+ -+ def _add_numbered(self, section, key_prefix, value): -+ """ -+ Adds a numbered property, such as address or route, ensuring -+ the appropriate value gets used for . -+ """ -+ -+ for index in itertools.count(1): -+ key = f"{key_prefix}{index}" -+ if not self.config.has_option(section, key): -+ self.config[section][key] = value -+ break -+ -+ def _add_address(self, family, subnet): -+ """ -+ Adds an ipv[46]address property. -+ """ -+ -+ value = subnet["address"] + "/" + str(subnet["prefix"]) -+ self._add_numbered(family, "address", value) -+ -+ def _add_route(self, family, route): -+ """ -+ Adds a ipv[46].route property. -+ """ -+ -+ value = route["network"] + "/" + str(route["prefix"]) -+ if "gateway" in route: -+ value = value + "," + route["gateway"] -+ self._add_numbered(family, "route", value) -+ -+ def _add_nameserver(self, dns): -+ """ -+ Extends the ipv[46].dns property with a name server. -+ """ -+ -+ # FIXME: the subnet contains IPv4 and IPv6 name server mixed -+ # together. We might be getting an IPv6 name server while -+ # we're dealing with an IPv4 subnet. Sort this out by figuring -+ # out the correct family and making sure a valid section exist. -+ family = "ipv6" if is_ipv6_address(dns) else "ipv4" -+ self._set_default(family, "method", "disabled") -+ -+ self._set_default(family, "dns", "") -+ self.config[family]["dns"] = self.config[family]["dns"] + dns + ";" -+ -+ def _add_dns_search(self, family, dns_search): -+ """ -+ Extends the ipv[46].dns-search property with a name server. -+ """ -+ -+ self._set_default(family, "dns-search", "") -+ self.config[family]["dns-search"] = ( -+ self.config[family]["dns-search"] + ";".join(dns_search) + ";" -+ ) -+ -+ def con_uuid(self): -+ """ -+ Returns the connection UUID -+ """ -+ return self.config["connection"]["uuid"] -+ -+ def valid(self): -+ """ -+ Can this be serialized into a meaningful connection profile? -+ """ -+ return self.config.has_option("connection", "type") -+ -+ @staticmethod -+ def mac_addr(addr): -+ """ -+ Sanitize a MAC address. -+ """ -+ return addr.replace("-", ":").upper() -+ -+ def render_interface(self, iface, renderer): -+ """ -+ Integrate information from network state interface information -+ into the connection. Most of the work is done here. -+ """ -+ -+ # Initialize type & connectivity -+ _type_map = { -+ "physical": "ethernet", -+ "vlan": "vlan", -+ "bond": "bond", -+ "bridge": "bridge", -+ "infiniband": "infiniband", -+ "loopback": None, -+ } -+ -+ if_type = _type_map[iface["type"]] -+ if if_type is None: -+ return -+ if "bond-master" in iface: -+ slave_type = "bond" -+ else: -+ slave_type = None -+ -+ self.config["connection"]["type"] = if_type -+ if slave_type is not None: -+ self.config["connection"]["slave-type"] = slave_type -+ self.config["connection"]["master"] = renderer.con_ref( -+ iface[slave_type + "-master"] -+ ) -+ -+ # Add type specific-section -+ self.config[if_type] = {} -+ -+ # These are the interface properties that map nicely -+ # to NetworkManager properties -+ _prop_map = { -+ "bond": { -+ "mode": "bond-mode", -+ "miimon": "bond_miimon", -+ "xmit_hash_policy": "bond-xmit-hash-policy", -+ "num_grat_arp": "bond-num-grat-arp", -+ "downdelay": "bond-downdelay", -+ "updelay": "bond-updelay", -+ "fail_over_mac": "bond-fail-over-mac", -+ "primary_reselect": "bond-primary-reselect", -+ "primary": "bond-primary", -+ }, -+ "bridge": { -+ "stp": "bridge_stp", -+ "priority": "bridge_bridgeprio", -+ }, -+ "vlan": { -+ "id": "vlan_id", -+ }, -+ "ethernet": {}, -+ "infiniband": {}, -+ } -+ -+ device_mtu = iface["mtu"] -+ ipv4_mtu = None -+ -+ # Deal with Layer 3 configuration -+ for subnet in iface["subnets"]: -+ family = "ipv6" if subnet_is_ipv6(subnet) else "ipv4" -+ -+ self._set_ip_method(family, subnet["type"]) -+ if "address" in subnet: -+ self._add_address(family, subnet) -+ if "gateway" in subnet: -+ self.config[family]["gateway"] = subnet["gateway"] -+ for route in subnet["routes"]: -+ self._add_route(family, route) -+ if "dns_nameservers" in subnet: -+ for nameserver in subnet["dns_nameservers"]: -+ self._add_nameserver(nameserver) -+ if "dns_search" in subnet: -+ self._add_dns_search(family, subnet["dns_search"]) -+ if family == "ipv4" and "mtu" in subnet: -+ ipv4_mtu = subnet["mtu"] -+ -+ if ipv4_mtu is None: -+ ipv4_mtu = device_mtu -+ if not ipv4_mtu == device_mtu: -+ LOG.warning( -+ "Network config: ignoring %s device-level mtu:%s" -+ " because ipv4 subnet-level mtu:%s provided.", -+ iface["name"], -+ device_mtu, -+ ipv4_mtu, -+ ) -+ -+ # Parse type-specific properties -+ for nm_prop, key in _prop_map[if_type].items(): -+ if key not in iface: -+ continue -+ if iface[key] is None: -+ continue -+ if isinstance(iface[key], bool): -+ self.config[if_type][nm_prop] = ( -+ "true" if iface[key] else "false" -+ ) -+ else: -+ self.config[if_type][nm_prop] = str(iface[key]) -+ -+ # These ones need special treatment -+ if if_type == "ethernet": -+ if iface["wakeonlan"] is True: -+ # NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC -+ self.config["ethernet"]["wake-on-lan"] = str(0x40) -+ if ipv4_mtu is not None: -+ self.config["ethernet"]["mtu"] = str(ipv4_mtu) -+ if iface["mac_address"] is not None: -+ self.config["ethernet"]["mac-address"] = self.mac_addr( -+ iface["mac_address"] -+ ) -+ if if_type == "vlan" and "vlan-raw-device" in iface: -+ self.config["vlan"]["parent"] = renderer.con_ref( -+ iface["vlan-raw-device"] -+ ) -+ if if_type == "bridge": -+ # Bridge is ass-backwards compared to bond -+ for port in iface["bridge_ports"]: -+ port = renderer.get_conn(port) -+ port._set_default("connection", "slave-type", "bridge") -+ port._set_default("connection", "master", self.con_uuid()) -+ if iface["mac_address"] is not None: -+ self.config["bridge"]["mac-address"] = self.mac_addr( -+ iface["mac_address"] -+ ) -+ if if_type == "infiniband" and ipv4_mtu is not None: -+ self.config["infiniband"]["transport-mode"] = "datagram" -+ self.config["infiniband"]["mtu"] = str(ipv4_mtu) -+ if iface["mac_address"] is not None: -+ self.config["infiniband"]["mac-address"] = self.mac_addr( -+ iface["mac_address"] -+ ) -+ -+ # Finish up -+ if if_type == "bridge" or not self.config.has_option( -+ if_type, "mac-address" -+ ): -+ self.config["connection"]["interface-name"] = iface["name"] -+ -+ def dump(self): -+ """ -+ Stringify. -+ """ -+ -+ buf = io.StringIO() -+ self.config.write(buf, space_around_delimiters=False) -+ header = "# Generated by cloud-init. Changes will be lost.\n\n" -+ return header + buf.getvalue() -+ -+ -+class Renderer(renderer.Renderer): -+ """Renders network information in a NetworkManager keyfile format.""" -+ -+ def __init__(self, config=None): -+ self.connections = {} -+ -+ def get_conn(self, con_id): -+ return self.connections[con_id] -+ -+ def con_ref(self, con_id): -+ if con_id in self.connections: -+ return self.connections[con_id].con_uuid() -+ else: -+ # Well, what can we do... -+ return con_id -+ -+ def render_network_state( -+ self, -+ network_state: NetworkState, -+ templates: Optional[dict] = None, -+ target=None, -+ ) -> None: -+ # First pass makes sure there's NMConnections for all known -+ # 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"]) -+ -+ # Now render the actual interface configuration -+ for iface in network_state.iter_interfaces(): -+ conn = self.connections[iface["name"]] -+ conn.render_interface(iface, self) -+ -+ # And finally write the files -+ for con_id, conn in self.connections.items(): -+ if not conn.valid(): -+ continue -+ name = conn_filename(con_id, target) -+ util.write_file(name, conn.dump(), 0o600) -+ -+ -+def conn_filename(con_id, target=None): -+ target_con_dir = subp.target_path(target, NM_RUN_DIR) -+ con_file = f"cloud-init-{con_id}.nmconnection" -+ return f"{target_con_dir}/system-connections/{con_file}" -+ -+ -+def available(target=None): -+ # TODO: Move `uses_systemd` to a more appropriate location -+ # It is imported here to avoid circular import -+ from cloudinit.distros import uses_systemd -+ -+ config_present = os.path.isfile(subp.target_path(target, path=NM_CFG_FILE)) -+ nmcli_present = subp.which("nmcli", target=target) -+ service_active = True -+ if uses_systemd(): -+ try: -+ subp.subp(["systemctl", "is-enabled", "NetworkManager.service"]) -+ except subp.ProcessExecutionError: -+ service_active = False -+ -+ return config_present and bool(nmcli_present) and service_active -+ -+ -+# vi: ts=4 expandtab -diff --git a/cloudinit/net/renderers.py b/cloudinit/net/renderers.py -index 022ff938..fcf7feba 100644 ---- a/cloudinit/net/renderers.py -+++ b/cloudinit/net/renderers.py -@@ -8,6 +8,7 @@ from cloudinit.net import ( - freebsd, - netbsd, - netplan, -+ network_manager, - networkd, - openbsd, - renderer, -@@ -19,6 +20,7 @@ NAME_TO_RENDERER = { - "freebsd": freebsd, - "netbsd": netbsd, - "netplan": netplan, -+ "network-manager": network_manager, - "networkd": networkd, - "openbsd": openbsd, - "sysconfig": sysconfig, -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index e08c0c69..b8786fb7 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -6,8 +6,6 @@ import os - import re - from typing import Mapping, Optional - --from configobj import ConfigObj -- - from cloudinit import log as logging - from cloudinit import subp, util - from cloudinit.distros.parsers import networkmanager_conf, resolv_conf -@@ -37,7 +35,7 @@ KNOWN_DISTROS = [ - "TencentOS", - "virtuozzo", - ] --NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf" -+ - - def _make_header(sep="#"): - lines = [ -@@ -68,26 +66,7 @@ def _quote_value(value): - return value - - -- --def enable_ifcfg_rh(path): -- """Add ifcfg-rh to NetworkManager.cfg plugins if main section is present""" -- config = ConfigObj(path) -- if "main" in config: -- if "plugins" in config["main"]: -- if "ifcfg-rh" in config["main"]["plugins"]: -- return -- else: -- config["main"]["plugins"] = [] -- -- if isinstance(config["main"]["plugins"], list): -- config["main"]["plugins"].append("ifcfg-rh") -- else: -- config["main"]["plugins"] = [config["main"]["plugins"], "ifcfg-rh"] -- config.write() -- LOG.debug("Enabled ifcfg-rh NetworkManager plugins") -- -- --class ConfigMap(object): -+class ConfigMap: - """Sysconfig like dictionary object.""" - - # Why does redhat prefer yes/no to true/false?? -@@ -1040,8 +1019,6 @@ class Renderer(renderer.Renderer): - mode=file_mode, - preserve_mode=True, - ) -- if available_nm(target=target): -- enable_ifcfg_rh(subp.target_path(target, path=NM_CFG_FILE)) - - sysconfig_path = subp.target_path(target, templates.get("control")) - # Distros configuring /etc/sysconfig/network as a file e.g. Centos -@@ -1080,14 +1057,9 @@ def _supported_vlan_names(rdev, vid): - - - def available(target=None): -- sysconfig = available_sysconfig(target=target) -- nm = available_nm(target=target) -- return util.system_info()["variant"] in KNOWN_DISTROS and any( -- [nm, sysconfig] -- ) -- -+ if not util.system_info()["variant"] in KNOWN_DISTROS: -+ return False - --def available_sysconfig(target=None): - expected = ["ifup", "ifdown"] - search = ["/sbin", "/usr/sbin"] - for p in expected: -@@ -1104,10 +1076,4 @@ def available_sysconfig(target=None): - return False - - --def available_nm(target=None): -- if not os.path.isfile(subp.target_path(target, path=NM_CFG_FILE)): -- return False -- return True -- -- - # vi: ts=4 expandtab -diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index 4434b350..0f523ff8 100644 ---- a/tests/unittests/test_net.py -+++ b/tests/unittests/test_net.py -@@ -23,6 +23,7 @@ from cloudinit.net import ( - mask_and_ipv4_to_bcast_addr, - natural_sort_key, - netplan, -+ network_manager, - network_state, - networkd, - renderers, -@@ -616,6 +617,37 @@ dns = none - ), - ), - ], -+ "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 -+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 -+ -+""".lstrip(), -+ ), -+ ], - }, - { - "in_data": { -@@ -1078,6 +1110,50 @@ NETWORK_CONFIGS = { - USERCTL=no""" - ), - }, -+ "expected_network_manager": { -+ "cloud-init-eth1.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth1 -+ uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58 -+ type=ethernet -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=CF:D6:AF:48:E8:80 -+ -+ """ -+ ), -+ "cloud-init-eth99.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth99 -+ uuid=b1b88000-1f03-5360-8377-1a2205efffb4 -+ type=ethernet -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=C0:D6:9F:2C:E8:80 -+ -+ [ipv4] -+ method=auto -+ may-fail=false -+ address1=192.168.21.3/24 -+ route1=0.0.0.0/0,65.61.151.37 -+ dns=8.8.8.8;8.8.4.4; -+ dns-search=barley.maas;sach.maas; -+ -+ """ -+ ), -+ }, - "yaml": textwrap.dedent( - """ - version: 1 -@@ -1883,6 +1959,29 @@ NETWORK_CONFIGS = { - """ - ), - }, -+ "expected_network_manager": { -+ "cloud-init-iface0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init iface0 -+ uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ type=ethernet -+ interface-name=iface0 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ -+ [ipv4] -+ method=auto -+ may-fail=false -+ -+ """ -+ ), -+ }, - "yaml_v2": textwrap.dedent( - """\ - version: 2 -@@ -1936,6 +2035,30 @@ NETWORK_CONFIGS = { - """ - ), - }, -+ "expected_network_manager": { -+ "cloud-init-iface0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init iface0 -+ uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ type=ethernet -+ interface-name=iface0 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ wake-on-lan=64 -+ -+ [ipv4] -+ method=auto -+ may-fail=false -+ -+ """ -+ ), -+ }, - "yaml_v2": textwrap.dedent( - """\ - version: 2 -@@ -2969,8 +3092,8 @@ iface bond0 inet6 static - - to: 2001:67c:1562:8007::1/64 - via: 2001:67c:1562:8007::aac:40b2 - - metric: 10000 -- to: 3001:67c:1562:8007::1/64 -- via: 3001:67c:1562:8007::aac:40b2 -+ to: 3001:67c:15:8007::1/64 -+ via: 3001:67c:15:8007::aac:40b2 - """ - ), - "expected_netplan-v2": textwrap.dedent( -@@ -3002,8 +3125,8 @@ iface bond0 inet6 static - - to: 2001:67c:1562:8007::1/64 - via: 2001:67c:1562:8007::aac:40b2 - - metric: 10000 -- to: 3001:67c:1562:8007::1/64 -- via: 3001:67c:1562:8007::aac:40b2 -+ to: 3001:67c:15:8007::1/64 -+ via: 3001:67c:15:8007::aac:40b2 - ethernets: - eth0: - match: -@@ -3651,6 +3774,73 @@ iface bond0 inet6 static - """ - ), - }, -+ "expected_network_manager": { -+ "cloud-init-eth0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth0 -+ uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -+ type=ethernet -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=52:54:00:12:34:00 -+ -+ [ipv4] -+ method=manual -+ may-fail=false -+ address1=192.168.1.2/24 -+ -+ """ -+ ), -+ "cloud-init-eth1.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth1 -+ uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58 -+ type=ethernet -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mtu=1480 -+ mac-address=52:54:00:12:34:AA -+ -+ [ipv4] -+ method=auto -+ may-fail=true -+ -+ """ -+ ), -+ "cloud-init-eth2.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth2 -+ uuid=5559a242-3421-5fdd-896e-9cb8313d5804 -+ type=ethernet -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=52:54:00:12:34:FF -+ -+ [ipv4] -+ method=auto -+ may-fail=true -+ -+ """ -+ ), -+ }, - }, - "v2-dev-name-via-mac-lookup": { - "expected_sysconfig_rhel": { -@@ -4149,7 +4339,6 @@ class TestRhelSysConfigRendering(CiTestCase): - - with_logs = True - -- nm_cfg_file = "/etc/NetworkManager/NetworkManager.conf" - scripts_dir = "/etc/sysconfig/network-scripts" - header = ( - "# Created by cloud-init on instance boot automatically, " -@@ -4724,78 +4913,6 @@ USERCTL=no - self._compare_files_to_expected(entry[self.expected_name], found) - self._assert_headers(found) - -- def test_check_ifcfg_rh(self): -- """ifcfg-rh plugin is added NetworkManager.conf if conf present.""" -- render_dir = self.tmp_dir() -- nm_cfg = subp.target_path(render_dir, path=self.nm_cfg_file) -- util.ensure_dir(os.path.dirname(nm_cfg)) -- -- # write a template nm.conf, note plugins is a list here -- with open(nm_cfg, "w") as fh: -- fh.write("# test_check_ifcfg_rh\n[main]\nplugins=foo,bar\n") -- self.assertTrue(os.path.exists(nm_cfg)) -- -- # render and read -- entry = NETWORK_CONFIGS["small"] -- found = self._render_and_read( -- network_config=yaml.load(entry["yaml"]), dir=render_dir -- ) -- self._compare_files_to_expected(entry[self.expected_name], found) -- self._assert_headers(found) -- -- # check ifcfg-rh is in the 'plugins' list -- config = sysconfig.ConfigObj(nm_cfg) -- self.assertIn("ifcfg-rh", config["main"]["plugins"]) -- -- def test_check_ifcfg_rh_plugins_string(self): -- """ifcfg-rh plugin is append when plugins is a string.""" -- render_dir = self.tmp_path("render") -- os.makedirs(render_dir) -- nm_cfg = subp.target_path(render_dir, path=self.nm_cfg_file) -- util.ensure_dir(os.path.dirname(nm_cfg)) -- -- # write a template nm.conf, note plugins is a value here -- util.write_file(nm_cfg, "# test_check_ifcfg_rh\n[main]\nplugins=foo\n") -- -- # render and read -- entry = NETWORK_CONFIGS["small"] -- found = self._render_and_read( -- network_config=yaml.load(entry["yaml"]), dir=render_dir -- ) -- self._compare_files_to_expected(entry[self.expected_name], found) -- self._assert_headers(found) -- -- # check raw content has plugin -- nm_file_content = util.load_file(nm_cfg) -- self.assertIn("ifcfg-rh", nm_file_content) -- -- # check ifcfg-rh is in the 'plugins' list -- config = sysconfig.ConfigObj(nm_cfg) -- self.assertIn("ifcfg-rh", config["main"]["plugins"]) -- -- def test_check_ifcfg_rh_plugins_no_plugins(self): -- """enable_ifcfg_plugin creates plugins value if missing.""" -- render_dir = self.tmp_path("render") -- os.makedirs(render_dir) -- nm_cfg = subp.target_path(render_dir, path=self.nm_cfg_file) -- util.ensure_dir(os.path.dirname(nm_cfg)) -- -- # write a template nm.conf, note plugins is missing -- util.write_file(nm_cfg, "# test_check_ifcfg_rh\n[main]\n") -- self.assertTrue(os.path.exists(nm_cfg)) -- -- # render and read -- entry = NETWORK_CONFIGS["small"] -- found = self._render_and_read( -- network_config=yaml.load(entry["yaml"]), dir=render_dir -- ) -- self._compare_files_to_expected(entry[self.expected_name], found) -- self._assert_headers(found) -- -- # check ifcfg-rh is in the 'plugins' list -- config = sysconfig.ConfigObj(nm_cfg) -- self.assertIn("ifcfg-rh", config["main"]["plugins"]) -- - 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) -@@ -5492,6 +5609,281 @@ STARTMODE=auto - self._assert_headers(found) - - -+@mock.patch( -+ "cloudinit.net.is_openvswitch_internal_interface", -+ mock.Mock(return_value=False), -+) -+class TestNetworkManagerRendering(CiTestCase): -+ -+ with_logs = True -+ -+ scripts_dir = "/etc/NetworkManager/system-connections" -+ -+ expected_name = "expected_network_manager" -+ -+ def _get_renderer(self): -+ return network_manager.Renderer() -+ -+ def _render_and_read(self, network_config=None, state=None, dir=None): -+ if dir is None: -+ dir = self.tmp_dir() -+ -+ if network_config: -+ ns = network_state.parse_net_config_data(network_config) -+ elif state: -+ ns = state -+ else: -+ raise ValueError("Expected data or state, got neither") -+ -+ renderer = self._get_renderer() -+ renderer.render_network_state(ns, target=dir) -+ return dir2dict(dir) -+ -+ def _compare_files_to_expected(self, expected, found): -+ orig_maxdiff = self.maxDiff -+ expected_d = dict( -+ (os.path.join(self.scripts_dir, k), v) for k, v in expected.items() -+ ) -+ -+ try: -+ self.maxDiff = None -+ self.assertEqual(expected_d, found) -+ finally: -+ self.maxDiff = orig_maxdiff -+ -+ @mock.patch("cloudinit.net.util.get_cmdline", return_value="root=myroot") -+ @mock.patch("cloudinit.net.sys_dev_path") -+ @mock.patch("cloudinit.net.read_sys_net") -+ @mock.patch("cloudinit.net.get_devicelist") -+ def test_default_generation( -+ self, -+ mock_get_devicelist, -+ mock_read_sys_net, -+ mock_sys_dev_path, -+ m_get_cmdline, -+ ): -+ tmp_dir = self.tmp_dir() -+ _setup_test( -+ tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path -+ ) -+ -+ network_cfg = net.generate_fallback_config() -+ ns = network_state.parse_net_config_data( -+ network_cfg, skip_broken=False -+ ) -+ -+ render_dir = os.path.join(tmp_dir, "render") -+ os.makedirs(render_dir) -+ -+ renderer = self._get_renderer() -+ renderer.render_network_state(ns, target=render_dir) -+ -+ found = dir2dict(render_dir) -+ self._compare_files_to_expected( -+ { -+ "cloud-init-eth1000.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth1000 -+ uuid=8c517500-0c95-5308-9c8a-3092eebc44eb -+ type=ethernet -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=07:1C:C6:75:A4:BE -+ -+ [ipv4] -+ method=auto -+ may-fail=false -+ -+ """ -+ ), -+ }, -+ found, -+ ) -+ -+ def test_openstack_rendering_samples(self): -+ for os_sample in OS_SAMPLES: -+ render_dir = self.tmp_dir() -+ ex_input = os_sample["in_data"] -+ ex_mac_addrs = os_sample["in_macs"] -+ network_cfg = openstack.convert_net_json( -+ ex_input, known_macs=ex_mac_addrs -+ ) -+ ns = network_state.parse_net_config_data( -+ network_cfg, skip_broken=False -+ ) -+ renderer = self._get_renderer() -+ # render a multiple times to simulate reboots -+ renderer.render_network_state(ns, target=render_dir) -+ renderer.render_network_state(ns, target=render_dir) -+ renderer.render_network_state(ns, target=render_dir) -+ for fn, expected_content in os_sample.get(self.expected_name, []): -+ with open(os.path.join(render_dir, fn)) as fh: -+ self.assertEqual(expected_content, fh.read()) -+ -+ def test_network_config_v1_samples(self): -+ ns = network_state.parse_net_config_data(CONFIG_V1_SIMPLE_SUBNET) -+ render_dir = self.tmp_path("render") -+ os.makedirs(render_dir) -+ renderer = self._get_renderer() -+ renderer.render_network_state(ns, target=render_dir) -+ found = dir2dict(render_dir) -+ self._compare_files_to_expected( -+ { -+ "cloud-init-interface0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init interface0 -+ uuid=8b6862ed-dbd6-5830-93f7-a91451c13828 -+ type=ethernet -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=52:54:00:12:34:00 -+ -+ [ipv4] -+ method=manual -+ may-fail=false -+ address1=10.0.2.15/24 -+ gateway=10.0.2.2 -+ -+ """ -+ ), -+ }, -+ found, -+ ) -+ -+ def test_config_with_explicit_loopback(self): -+ render_dir = self.tmp_path("render") -+ os.makedirs(render_dir) -+ ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK) -+ renderer = self._get_renderer() -+ renderer.render_network_state(ns, target=render_dir) -+ found = dir2dict(render_dir) -+ self._compare_files_to_expected( -+ { -+ "cloud-init-eth0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth0 -+ uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -+ type=ethernet -+ interface-name=eth0 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ -+ [ipv4] -+ method=auto -+ may-fail=false -+ -+ """ -+ ), -+ }, -+ found, -+ ) -+ -+ def test_bond_config(self): -+ entry = NETWORK_CONFIGS["bond"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_vlan_config(self): -+ entry = NETWORK_CONFIGS["vlan"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_bridge_config(self): -+ entry = NETWORK_CONFIGS["bridge"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_manual_config(self): -+ entry = NETWORK_CONFIGS["manual"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_all_config(self): -+ entry = NETWORK_CONFIGS["all"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ self.assertNotIn( -+ "WARNING: Network config: ignoring eth0.101 device-level mtu", -+ self.logs.getvalue(), -+ ) -+ -+ def test_small_config(self): -+ entry = NETWORK_CONFIGS["small"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_v4_and_v6_static_config(self): -+ entry = NETWORK_CONFIGS["v4_and_v6_static"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ expected_msg = ( -+ "WARNING: Network config: ignoring iface0 device-level mtu:8999" -+ " because ipv4 subnet-level mtu:9000 provided." -+ ) -+ self.assertIn(expected_msg, self.logs.getvalue()) -+ -+ def test_dhcpv6_only_config(self): -+ entry = NETWORK_CONFIGS["dhcpv6_only"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_simple_render_ipv6_slaac(self): -+ entry = NETWORK_CONFIGS["ipv6_slaac"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_dhcpv6_stateless_config(self): -+ entry = NETWORK_CONFIGS["dhcpv6_stateless"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_wakeonlan_disabled_config_v2(self): -+ entry = NETWORK_CONFIGS["wakeonlan_disabled"] -+ found = self._render_and_read( -+ network_config=yaml.load(entry["yaml_v2"]) -+ ) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_wakeonlan_enabled_config_v2(self): -+ entry = NETWORK_CONFIGS["wakeonlan_enabled"] -+ found = self._render_and_read( -+ network_config=yaml.load(entry["yaml_v2"]) -+ ) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_render_v4_and_v6(self): -+ entry = NETWORK_CONFIGS["v4_and_v6"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ def test_render_v6_and_v4(self): -+ entry = NETWORK_CONFIGS["v6_and_v4"] -+ found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -+ self._compare_files_to_expected(entry[self.expected_name], found) -+ -+ -+@mock.patch( -+ "cloudinit.net.is_openvswitch_internal_interface", -+ mock.Mock(return_value=False), -+) - class TestEniNetRendering(CiTestCase): - @mock.patch("cloudinit.net.util.get_cmdline", return_value="root=myroot") - @mock.patch("cloudinit.net.sys_dev_path") -@@ -7259,9 +7651,9 @@ class TestNetworkdRoundTrip(CiTestCase): - - class TestRenderersSelect: - @pytest.mark.parametrize( -- "renderer_selected,netplan,eni,nm,scfg,sys,networkd", -+ "renderer_selected,netplan,eni,sys,network_manager,networkd", - ( -- # -netplan -ifupdown -nm -scfg -sys raises error -+ # -netplan -ifupdown -sys -network-manager -networkd raises error - ( - net.RendererNotFoundError, - False, -@@ -7269,52 +7661,51 @@ class TestRenderersSelect: - False, - False, - False, -- False, - ), -- # -netplan +ifupdown -nm -scfg -sys selects eni -- ("eni", False, True, False, False, False, False), -- # +netplan +ifupdown -nm -scfg -sys selects eni -- ("eni", True, True, False, False, False, False), -- # +netplan -ifupdown -nm -scfg -sys selects netplan -- ("netplan", True, False, False, False, False, False), -- # Ubuntu with Network-Manager installed -- # +netplan -ifupdown +nm -scfg -sys selects netplan -- ("netplan", True, False, True, False, False, False), -- # Centos/OpenSuse with Network-Manager installed selects sysconfig -- # -netplan -ifupdown +nm -scfg +sys selects netplan -- ("sysconfig", False, False, True, False, True, False), -- # -netplan -ifupdown -nm -scfg -sys +networkd selects networkd -- ("networkd", False, False, False, False, False, True), -+ # -netplan +ifupdown -sys -nm -networkd selects eni -+ ("eni", False, True, False, False, False), -+ # +netplan +ifupdown -sys -nm -networkd selects eni -+ ("eni", True, True, False, False, False), -+ # +netplan -ifupdown -sys -nm -networkd selects netplan -+ ("netplan", True, False, False, False, False), -+ # +netplan -ifupdown -sys -nm -networkd selects netplan -+ ("netplan", True, False, False, False, False), -+ # -netplan -ifupdown +sys -nm -networkd selects sysconfig -+ ("sysconfig", False, False, True, False, False), -+ # -netplan -ifupdown +sys +nm -networkd selects sysconfig -+ ("sysconfig", False, False, True, True, False), -+ # -netplan -ifupdown -sys +nm -networkd selects nm -+ ("network-manager", False, False, False, True, False), -+ # -netplan -ifupdown -sys +nm +networkd selects nm -+ ("network-manager", False, False, False, True, True), -+ # -netplan -ifupdown -sys -nm +networkd selects networkd -+ ("networkd", False, False, False, False, True), - ), - ) - @mock.patch("cloudinit.net.renderers.networkd.available") -+ @mock.patch("cloudinit.net.renderers.network_manager.available") - @mock.patch("cloudinit.net.renderers.netplan.available") - @mock.patch("cloudinit.net.renderers.sysconfig.available") -- @mock.patch("cloudinit.net.renderers.sysconfig.available_sysconfig") -- @mock.patch("cloudinit.net.renderers.sysconfig.available_nm") - @mock.patch("cloudinit.net.renderers.eni.available") - def test_valid_renderer_from_defaults_depending_on_availability( - self, - m_eni_avail, -- m_nm_avail, -- m_scfg_avail, - m_sys_avail, - m_netplan_avail, -+ m_network_manager_avail, - m_networkd_avail, - renderer_selected, - netplan, - eni, -- nm, -- scfg, - sys, -+ network_manager, - networkd, - ): - """Assert proper renderer per DEFAULT_PRIORITY given availability.""" - m_eni_avail.return_value = eni # ifupdown pkg presence -- m_nm_avail.return_value = nm # network-manager presence -- m_scfg_avail.return_value = scfg # sysconfig presence - m_sys_avail.return_value = sys # sysconfig/ifup/down presence - m_netplan_avail.return_value = netplan # netplan presence -+ m_network_manager_avail.return_value = network_manager # NM presence - m_networkd_avail.return_value = networkd # networkd presence - if isinstance(renderer_selected, str): - (renderer_name, _rnd_class) = renderers.select( -@@ -7372,7 +7763,7 @@ class TestNetRenderers(CiTestCase): - priority=["sysconfig", "eni"], - ) - -- @mock.patch("cloudinit.net.sysconfig.available_sysconfig") -+ @mock.patch("cloudinit.net.sysconfig.available") - @mock.patch("cloudinit.util.system_info") - def test_sysconfig_available_uses_variant_mapping(self, m_info, m_avail): - m_avail.return_value = True -diff --git a/tests/unittests/test_net_activators.py b/tests/unittests/test_net_activators.py -index b735ea9e..afd9056a 100644 ---- a/tests/unittests/test_net_activators.py -+++ b/tests/unittests/test_net_activators.py -@@ -139,10 +139,6 @@ NETPLAN_AVAILABLE_CALLS = [ - (("netplan",), {"search": ["/usr/sbin", "/sbin"], "target": None}), - ] - --NETWORK_MANAGER_AVAILABLE_CALLS = [ -- (("nmcli",), {"target": None}), --] -- - NETWORKD_AVAILABLE_CALLS = [ - (("ip",), {"search": ["/usr/sbin", "/bin"], "target": None}), - (("systemctl",), {"search": ["/usr/sbin", "/bin"], "target": None}), -@@ -154,7 +150,6 @@ NETWORKD_AVAILABLE_CALLS = [ - [ - (IfUpDownActivator, IF_UP_DOWN_AVAILABLE_CALLS), - (NetplanActivator, NETPLAN_AVAILABLE_CALLS), -- (NetworkManagerActivator, NETWORK_MANAGER_AVAILABLE_CALLS), - (NetworkdActivator, NETWORKD_AVAILABLE_CALLS), - ], - ) -@@ -259,9 +254,11 @@ class TestActivatorsBringUp: - def test_bring_up_interface( - self, m_subp, activator, expected_call_list, available_mocks - ): -+ index = 0 - activator.bring_up_interface("eth0") -- assert len(m_subp.call_args_list) == 1 -- assert m_subp.call_args_list[0] == expected_call_list[0] -+ for call in m_subp.call_args_list: -+ assert call == expected_call_list[index] -+ index += 1 - - @patch("cloudinit.subp.subp", return_value=("", "")) - def test_bring_up_interfaces( diff --git a/SOURCES/0013-net-sysconfig-do-not-use-the-highest-autoconnect-pri.patch b/SOURCES/0013-net-sysconfig-do-not-use-the-highest-autoconnect-pri.patch deleted file mode 100644 index cb9b594..0000000 --- a/SOURCES/0013-net-sysconfig-do-not-use-the-highest-autoconnect-pri.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0a2c6b6118ffaf29694b3a51aff3a33298419c50 Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Mon, 15 May 2023 19:15:12 +0530 -Subject: [PATCH] net/sysconfig: do not use the highest autoconnect priority - -Using the highest priority is a very big hammer that we may not want to use. We -may want users to override the cloud init generated ifcfg files for custom -configuration of interfaces. If cloud init uses the highest priority, nothing -can beat it. Hence lower the priority to 120 allowing values from 121 to 999 -to be used by users if they want to use a custom interface nm keyfile. - -X-downstream-only: true - -Suggested-by: thaller@redhat.com -fixes: c589da20eb92231 ("Setting highest autoconnect priority for network-scripts") -Signed-off-by: Ani Sinha ---- - cloudinit/net/sysconfig.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index b8786fb7..1fe82412 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -317,7 +317,7 @@ class Renderer(renderer.Renderer): - "ONBOOT": True, - "USERCTL": False, - "BOOTPROTO": "none", -- "AUTOCONNECT_PRIORITY": 999 -+ "AUTOCONNECT_PRIORITY": 120, - }, - "suse": {"BOOTPROTO": "static", "STARTMODE": "auto"}, - } diff --git a/SOURCES/0014-net-sysconfig-cosmetic-fix-tox-formatting.patch b/SOURCES/0014-net-sysconfig-cosmetic-fix-tox-formatting.patch deleted file mode 100644 index 4af002f..0000000 --- a/SOURCES/0014-net-sysconfig-cosmetic-fix-tox-formatting.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 603ad38bca7735eeb72217b4f169a4b4c42ac092 Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Tue, 16 May 2023 16:08:21 +0530 -Subject: [PATCH] net/sysconfig: cosmetic - fix tox formatting - -recommended cloud-init code formatting was not enforced with an older downstream -only change. This change fixes the formatting issue so that tox -e do_format -does not complain. Changes are cosmetic. - -X-downstream-only: true - -fixes: b3b96bff187e9d ("Do not write NM_CONTROLLED=no in generated interface config files") -Signed-off-by: Ani Sinha ---- - cloudinit/net/sysconfig.py | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index 1fe82412..fcce3e99 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -1025,15 +1025,15 @@ class Renderer(renderer.Renderer): - if sysconfig_path.endswith("network"): - util.ensure_dir(os.path.dirname(sysconfig_path)) - netcfg = [] -- for line in util.load_file(sysconfig_path, quiet=True).split('\n'): -- if 'cloud-init' in line: -+ for line in util.load_file(sysconfig_path, quiet=True).split("\n"): -+ if "cloud-init" in line: - break -- if not line.startswith(('NETWORKING=', -- 'IPV6_AUTOCONF=', -- 'NETWORKING_IPV6=')): -+ if not line.startswith( -+ ("NETWORKING=", "IPV6_AUTOCONF=", "NETWORKING_IPV6=") -+ ): - netcfg.append(line) - # Now generate the cloud-init portion of sysconfig/network -- netcfg.extend([_make_header(), 'NETWORKING=yes']) -+ netcfg.extend([_make_header(), "NETWORKING=yes"]) - if network_state.use_ipv6: - netcfg.append("NETWORKING_IPV6=yes") - netcfg.append("IPV6_AUTOCONF=no") diff --git a/SOURCES/0015-nm-generate-ipv6-stateful-dhcp-config-at-par-with-sy.patch b/SOURCES/0015-nm-generate-ipv6-stateful-dhcp-config-at-par-with-sy.patch deleted file mode 100644 index 31e95a8..0000000 --- a/SOURCES/0015-nm-generate-ipv6-stateful-dhcp-config-at-par-with-sy.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 58d7574bca2b00d05d090c180f1345a2408cc700 Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Mon, 22 May 2023 21:30:01 +0530 -Subject: [PATCH] nm: generate ipv6 stateful dhcp config at par with sysconfig - (#4115) - -The sysconfig renderer sets the following in the ifcfg file for IPV6 stateful -DHCP configuration: - - BOOTPROTO = "dhcp" - DHCPV6C = True - IPV6INIT = True - IPV6_AUTOCONF = False - -This should result in - [ipv6] - method=dhcp - -in the network manager generated keyfile as DHCPV6C is set and -IPV6_AUTOCONF is not set. Unfortunately the network manager renderer -deviates from this and generates: - [ipv6] - method=auto - -in it's rendered keyfile. This change fixes this deviation and sets the -IPV6 dhcp stateful configuration in alignment with what is generated by the -sysconfig renderer. - -RHBZ: 2207716 - -Signed-off-by: Ani Sinha -(cherry picked from commit ea573ba6fc25fe49a6a1a322eeb5259b6238d78b) ---- - cloudinit/net/network_manager.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py -index 53763d15..744c0cbb 100644 ---- a/cloudinit/net/network_manager.py -+++ b/cloudinit/net/network_manager.py -@@ -72,7 +72,7 @@ class NMConnection: - "dhcp6": "auto", - "ipv6_slaac": "auto", - "ipv6_dhcpv6-stateless": "auto", -- "ipv6_dhcpv6-stateful": "auto", -+ "ipv6_dhcpv6-stateful": "dhcp", - "dhcp4": "auto", - "dhcp": "auto", - } diff --git a/SOURCES/0016-network_manager-add-a-method-for-ipv6-static-IP-conf.patch b/SOURCES/0016-network_manager-add-a-method-for-ipv6-static-IP-conf.patch deleted file mode 100644 index be26e61..0000000 --- a/SOURCES/0016-network_manager-add-a-method-for-ipv6-static-IP-conf.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 018aa09f049791755dd746b533abb2464b08a92d Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Mon, 22 May 2023 21:33:53 +0530 -Subject: [PATCH] network_manager: add a method for ipv6 static IP - configuration (#4127) - -The static IP configuration for IPv6 in the method_map is missing for -network manager renderer. This is causing cloud-init to generate a keyfile with -IPv6 method as "auto" instead of "manual". This fixes this issue. - -fixes: #4126 -RHBZ: 2196284 - -Signed-off-by: Ani Sinha -(cherry picked from commit 5d440856cb6d2b4c908015fe4eb7227615c17c8b) ---- - cloudinit/net/network_manager.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py -index 744c0cbb..2752f52f 100644 ---- a/cloudinit/net/network_manager.py -+++ b/cloudinit/net/network_manager.py -@@ -69,6 +69,7 @@ class NMConnection: - - method_map = { - "static": "manual", -+ "static6": "manual", - "dhcp6": "auto", - "ipv6_slaac": "auto", - "ipv6_dhcpv6-stateless": "auto", diff --git a/SOURCES/0017-net-sysconfig-enable-sysconfig-renderer-if-network-m.patch b/SOURCES/0017-net-sysconfig-enable-sysconfig-renderer-if-network-m.patch deleted file mode 100644 index ba373ba..0000000 --- a/SOURCES/0017-net-sysconfig-enable-sysconfig-renderer-if-network-m.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 19adc5a0939fc1804b180333af5486e69d6af0ac Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Mon, 22 May 2023 22:06:28 +0530 -Subject: [PATCH] net/sysconfig: enable sysconfig renderer if network manager - has ifcfg-rh plugin (#4132) - -Some distributions like RHEL does not have ifup and ifdown -scripts that traditionally handled ifcfg-eth* files. Instead RHEL -uses network manager with ifcfg-rh plugin to handle ifcfg -scripts. Therefore, the sysconfig should check for the -existence of ifcfg-rh plugin in addition to checking for the -existence of ifup and ifdown scripts in order to determine if it -can handle ifcfg files. If either the plugin or ifup/ifdown scripts -are present, sysconfig renderer can be enabled. - -fixes: #4131 -RHBZ: 2194050 - -Signed-off-by: Ani Sinha -(cherry picked from commit 009dbf85a72a9077b2267d377b2ff46639fb3def) ---- - cloudinit/net/sysconfig.py | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index fcce3e99..f2c7c92c 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -1,6 +1,7 @@ - # This file is part of cloud-init. See LICENSE file for license information. - - import copy -+import glob - import io - import os - import re -@@ -1059,7 +1060,25 @@ def _supported_vlan_names(rdev, vid): - def available(target=None): - if not util.system_info()["variant"] in KNOWN_DISTROS: - return False -+ if available_sysconfig(target): -+ return True -+ if available_nm_ifcfg_rh(target): -+ return True -+ return False -+ -+ -+def available_nm_ifcfg_rh(target=None): -+ # The ifcfg-rh plugin of NetworkManager is installed. -+ # NetworkManager can handle the ifcfg files. -+ return glob.glob( -+ subp.target_path( -+ target, -+ "usr/lib*/NetworkManager/*/libnm-settings-plugin-ifcfg-rh.so", -+ ) -+ ) -+ - -+def available_sysconfig(target=None): - expected = ["ifup", "ifdown"] - search = ["/sbin", "/usr/sbin"] - for p in expected: diff --git a/SOURCES/0018-network-manager-Set-higher-autoconnect-priority-for-.patch b/SOURCES/0018-network-manager-Set-higher-autoconnect-priority-for-.patch deleted file mode 100644 index 84deac5..0000000 --- a/SOURCES/0018-network-manager-Set-higher-autoconnect-priority-for-.patch +++ /dev/null @@ -1,401 +0,0 @@ -From f0cf9e52fd084c23f0552456e3b780b5c9c3313a Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Tue, 23 May 2023 20:38:31 +0530 -Subject: [PATCH] network-manager: Set higher autoconnect priority for nm - keyfiles (#3671) - -cloud init generated keyfiles by network manager renderer for network -interfaces can sometimes conflict with existing keyfiles that are left as an -artifact of an upgrade process or are old user generated keyfiles. When two -such keyfiles are present, the existing keyfile can take precedence over the -cloud init generated keyfile making the later ineffective. Removing the old -keyfile blindly by cloud init would also not be correct since there would be -no way to enforce a different interface configuration if one needs it. - -This change adds an autoconnect-priority value for cloud init generated keyfile -so that the cloud init configuration takes precedence over the existing old -keyfile configuration in the default case. The priority values range from 0 -to 999. We set a value of 120 so that it would be high enough in the default -case and result in cloud init keyfile to take precedence but not too high so -that if the user generated keyfile needs to take precedence, the user can do -so by using a higher value than the one used by cloud init key file, between -the values 121 and 999. - -RHBZ: 2196231 - -Signed-off-by: Ani Sinha -(cherry picked from commit f663e94ac50bc518e694cbd167fdab216fcff029) ---- - cloudinit/net/network_manager.py | 1 + - tests/unittests/cmd/devel/test_net_convert.py | 1 + - .../cloud-init-encc000.2653.nmconnection | 1 + - .../cloud-init-encc000.nmconnection | 1 + - .../cloud-init-zz-all-en.nmconnection | 1 + - .../cloud-init-zz-all-eth.nmconnection | 1 + - tests/unittests/test_net.py | 36 +++++++++++++++++++ - 7 files changed, 42 insertions(+) - -diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py -index 2752f52f..ca216928 100644 ---- a/cloudinit/net/network_manager.py -+++ b/cloudinit/net/network_manager.py -@@ -43,6 +43,7 @@ class NMConnection: - self.config["connection"] = { - "id": f"cloud-init {con_id}", - "uuid": str(uuid.uuid5(CI_NM_UUID, con_id)), -+ "autoconnect-priority": "120", - } - - # This is not actually used anywhere, but may be useful in future -diff --git a/tests/unittests/cmd/devel/test_net_convert.py b/tests/unittests/cmd/devel/test_net_convert.py -index 100aa8de..71654750 100644 ---- a/tests/unittests/cmd/devel/test_net_convert.py -+++ b/tests/unittests/cmd/devel/test_net_convert.py -@@ -74,6 +74,7 @@ SAMPLE_NETWORK_MANAGER_CONTENT = """\ - [connection] - id=cloud-init eth0 - uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -+autoconnect-priority=120 - type=ethernet - interface-name=eth0 - -diff --git a/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-encc000.2653.nmconnection b/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-encc000.2653.nmconnection -index 80483d4f..f44485d2 100644 ---- a/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-encc000.2653.nmconnection -+++ b/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-encc000.2653.nmconnection -@@ -3,6 +3,7 @@ - [connection] - id=cloud-init encc000.2653 - uuid=116aaf19-aabc-50ea-b480-e9aee18bda59 -+autoconnect-priority=120 - type=vlan - interface-name=encc000.2653 - -diff --git a/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-encc000.nmconnection b/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-encc000.nmconnection -index 3368388d..fbdfbc65 100644 ---- a/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-encc000.nmconnection -+++ b/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-encc000.nmconnection -@@ -3,6 +3,7 @@ - [connection] - id=cloud-init encc000 - uuid=f869ebd3-f175-5747-bf02-d0d44d687248 -+autoconnect-priority=120 - type=ethernet - interface-name=encc000 - -diff --git a/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-zz-all-en.nmconnection b/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-zz-all-en.nmconnection -index 16120bc1..dce56c7d 100644 ---- a/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-zz-all-en.nmconnection -+++ b/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-zz-all-en.nmconnection -@@ -3,6 +3,7 @@ - [connection] - id=cloud-init zz-all-en - uuid=159daec9-cba3-5101-85e7-46d831857f43 -+autoconnect-priority=120 - type=ethernet - interface-name=zz-all-en - -diff --git a/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-zz-all-eth.nmconnection b/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-zz-all-eth.nmconnection -index df44d546..ee436bf2 100644 ---- a/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-zz-all-eth.nmconnection -+++ b/tests/unittests/net/artifacts/no_matching_mac/etc/NetworkManager/system-connections/cloud-init-zz-all-eth.nmconnection -@@ -3,6 +3,7 @@ - [connection] - id=cloud-init zz-all-eth - uuid=23a83d8a-d7db-5133-a77b-e68a6ac61ec9 -+autoconnect-priority=120 - type=ethernet - interface-name=zz-all-eth - -diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index 0f523ff8..7abe61b9 100644 ---- a/tests/unittests/test_net.py -+++ b/tests/unittests/test_net.py -@@ -631,6 +631,7 @@ dns = none - [connection] - id=cloud-init eth0 - uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -+autoconnect-priority=120 - type=ethernet - - [user] -@@ -1118,6 +1119,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init eth1 - uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58 -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -1135,6 +1137,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init eth99 - uuid=b1b88000-1f03-5360-8377-1a2205efffb4 -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -1234,6 +1237,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init iface0 - uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ autoconnect-priority=120 - type=ethernet - interface-name=iface0 - -@@ -1364,6 +1368,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init iface0 - uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ autoconnect-priority=120 - type=ethernet - interface-name=iface0 - -@@ -1404,6 +1409,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init iface0 - uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ autoconnect-priority=120 - type=ethernet - interface-name=iface0 - -@@ -1504,6 +1510,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init iface0 - uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ autoconnect-priority=120 - type=ethernet - interface-name=iface0 - -@@ -1734,6 +1741,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init iface0 - uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ autoconnect-priority=120 - type=ethernet - interface-name=iface0 - -@@ -1845,6 +1853,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init iface0 - uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ autoconnect-priority=120 - type=ethernet - interface-name=iface0 - -@@ -1967,6 +1976,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init iface0 - uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ autoconnect-priority=120 - type=ethernet - interface-name=iface0 - -@@ -2043,6 +2053,7 @@ NETWORK_CONFIGS = { - [connection] - id=cloud-init iface0 - uuid=8ddfba48-857c-5e86-ac09-1b43eae0bf70 -+ autoconnect-priority=120 - type=ethernet - interface-name=iface0 - -@@ -2507,6 +2518,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init eth3 - uuid=b7e95dda-7746-5bf8-bf33-6e5f3c926790 -+ autoconnect-priority=120 - type=ethernet - slave-type=bridge - master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -@@ -2526,6 +2538,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init eth5 - uuid=5fda13c7-9942-5e90-a41b-1d043bd725dc -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -2547,6 +2560,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init ib0 - uuid=11a1dda7-78b4-5529-beba-d9b5f549ad7b -+ autoconnect-priority=120 - type=infiniband - - [user] -@@ -2571,6 +2585,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init bond0.200 - uuid=88984a9c-ff22-5233-9267-86315e0acaa7 -+ autoconnect-priority=120 - type=vlan - interface-name=bond0.200 - -@@ -2594,6 +2609,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init eth0 - uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -2611,6 +2627,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init eth4 - uuid=e27e4959-fb50-5580-b9a4-2073554627b9 -+ autoconnect-priority=120 - type=ethernet - slave-type=bridge - master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -@@ -2630,6 +2647,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init eth1 - uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58 -+ autoconnect-priority=120 - type=ethernet - slave-type=bond - master=54317911-f840-516b-a10d-82cb4c1f075c -@@ -2649,6 +2667,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init br0 - uuid=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -+ autoconnect-priority=120 - type=bridge - interface-name=br0 - -@@ -2680,6 +2699,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init eth0.101 - uuid=b5acec5e-db80-5935-8b02-0d5619fc42bf -+ autoconnect-priority=120 - type=vlan - interface-name=eth0.101 - -@@ -2708,6 +2728,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init bond0 - uuid=54317911-f840-516b-a10d-82cb4c1f075c -+ autoconnect-priority=120 - type=bond - interface-name=bond0 - -@@ -2732,6 +2753,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - [connection] - id=cloud-init eth2 - uuid=5559a242-3421-5fdd-896e-9cb8313d5804 -+ autoconnect-priority=120 - type=ethernet - slave-type=bond - master=54317911-f840-516b-a10d-82cb4c1f075c -@@ -3257,6 +3279,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init bond0s0 - uuid=09d0b5b9-67e7-5577-a1af-74d1cf17a71e -+ autoconnect-priority=120 - type=ethernet - slave-type=bond - master=54317911-f840-516b-a10d-82cb4c1f075c -@@ -3276,6 +3299,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init bond0s1 - uuid=4d9aca96-b515-5630-ad83-d13daac7f9d0 -+ autoconnect-priority=120 - type=ethernet - slave-type=bond - master=54317911-f840-516b-a10d-82cb4c1f075c -@@ -3295,6 +3319,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init bond0 - uuid=54317911-f840-516b-a10d-82cb4c1f075c -+ autoconnect-priority=120 - type=bond - interface-name=bond0 - -@@ -3421,6 +3446,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init en0.99 - uuid=f594e2ed-f107-51df-b225-1dc530a5356b -+ autoconnect-priority=120 - type=vlan - interface-name=en0.99 - -@@ -3453,6 +3479,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init en0 - uuid=e0ca478b-8d84-52ab-8fae-628482c629b5 -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -3580,6 +3607,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init br0 - uuid=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -+ autoconnect-priority=120 - type=bridge - interface-name=br0 - -@@ -3604,6 +3632,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init eth0 - uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -+ autoconnect-priority=120 - type=ethernet - slave-type=bridge - master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -@@ -3628,6 +3657,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init eth1 - uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58 -+ autoconnect-priority=120 - type=ethernet - slave-type=bridge - master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -@@ -3782,6 +3812,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init eth0 - uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -3804,6 +3835,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init eth1 - uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58 -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -3826,6 +3858,7 @@ iface bond0 inet6 static - [connection] - id=cloud-init eth2 - uuid=5559a242-3421-5fdd-896e-9cb8313d5804 -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -5688,6 +5721,7 @@ class TestNetworkManagerRendering(CiTestCase): - [connection] - id=cloud-init eth1000 - uuid=8c517500-0c95-5308-9c8a-3092eebc44eb -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -5742,6 +5776,7 @@ class TestNetworkManagerRendering(CiTestCase): - [connection] - id=cloud-init interface0 - uuid=8b6862ed-dbd6-5830-93f7-a91451c13828 -+ autoconnect-priority=120 - type=ethernet - - [user] -@@ -5778,6 +5813,7 @@ class TestNetworkManagerRendering(CiTestCase): - [connection] - id=cloud-init eth0 - uuid=1dd9a779-d327-56e1-8454-c65e2556c12c -+ autoconnect-priority=120 - type=ethernet - interface-name=eth0 - diff --git a/SOURCES/0019-Set-default-renderer-as-sysconfig-for-c9s-RHEL-9.patch b/SOURCES/0019-Set-default-renderer-as-sysconfig-for-c9s-RHEL-9.patch deleted file mode 100644 index 82c2353..0000000 --- a/SOURCES/0019-Set-default-renderer-as-sysconfig-for-c9s-RHEL-9.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 5394e28e896e9d18db6d359190bfb58dcbdb2646 Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Tue, 23 May 2023 21:15:30 +0530 -Subject: [PATCH] Set default renderer as sysconfig for c9s/RHEL 9 - -Currently, network manager is disabled on c9s and RHEL 9 and therefore -sysconfig is used as the primary renderer for network configuration on those -distribution flavors. We do not want to change this for c9s or RHEL 9 even when -network-manager renderer is re-enabled. NM was re-enabled with the following -commit: -5822f72230a58d ("Revert "Revert "Add native NetworkManager support (#1224)""") - -This change bumps up the priority for sysconfig renderer so that it is used as -the primary renderer on c9s/RHEL 9 and other downstream distributions derived -from them. For c10s or RHEL 10, we might revert this change so that -network-manager again becomes the primary renderer for those distributions. - -X-downstream-only: true - -fixes: 0b0632f6c0 ("Revert "Manual revert "Use Network-Manager and Netplan as default renderers for RHEL and Fedora (#1465)") -fixes: 7703aa98b89 ("Use Network-Manager and Netplan as default renderers for RHEL and Fedora (#1465)") - -RHBZ:2209349 - -Signed-off-by: Ani Sinha ---- - config/cloud.cfg.tmpl | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl -index 7238c102..22c6654c 100644 ---- a/config/cloud.cfg.tmpl -+++ b/config/cloud.cfg.tmpl -@@ -383,7 +383,7 @@ system_info: - renderers: ['freebsd'] - {% elif variant in ["fedora"] or is_rhel %} - network: -- renderers: ['netplan', 'network-manager', 'networkd', 'sysconfig', 'eni'] -+ renderers: ['sysconfig', 'eni', 'netplan', 'network-manager', 'networkd'] - {% elif variant == "openmandriva" %} - network: - renderers: ['network-manager', 'networkd'] diff --git a/SOURCES/0020-Revert-Set-default-renderer-as-sysconfig-for-c9s-RHE.patch b/SOURCES/0020-Revert-Set-default-renderer-as-sysconfig-for-c9s-RHE.patch deleted file mode 100644 index b4c93c1..0000000 --- a/SOURCES/0020-Revert-Set-default-renderer-as-sysconfig-for-c9s-RHE.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 86dd9b0e215a40e60a6c48401a9c04215e10cdea Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Thu, 8 Jun 2023 10:19:49 +0530 -Subject: [PATCH] Revert "Set default renderer as sysconfig for c9s/RHEL 9" - -This reverts commit 5394e28e896e9d18db6d359190bfb58dcbdb2646. - -Revert this downstream-only patch and replace it with the upstream patch. ---- - config/cloud.cfg.tmpl | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl -index 22c6654c..7238c102 100644 ---- a/config/cloud.cfg.tmpl -+++ b/config/cloud.cfg.tmpl -@@ -383,7 +383,7 @@ system_info: - renderers: ['freebsd'] - {% elif variant in ["fedora"] or is_rhel %} - network: -- renderers: ['sysconfig', 'eni', 'netplan', 'network-manager', 'networkd'] -+ renderers: ['netplan', 'network-manager', 'networkd', 'sysconfig', 'eni'] - {% elif variant == "openmandriva" %} - network: - renderers: ['network-manager', 'networkd'] diff --git a/SOURCES/0021-Set-default-renderer-as-sysconfig-for-centos-rhel-41.patch b/SOURCES/0021-Set-default-renderer-as-sysconfig-for-centos-rhel-41.patch deleted file mode 100644 index 46f0f79..0000000 --- a/SOURCES/0021-Set-default-renderer-as-sysconfig-for-centos-rhel-41.patch +++ /dev/null @@ -1,35 +0,0 @@ -From fd4f6d94e09ed97a4dd6aba3284d9156c16c483b Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Thu, 8 Jun 2023 03:29:13 +0530 -Subject: [PATCH] Set default renderer as sysconfig for centos/rhel (#4165) - -Currently, network manager is disabled on c9s and therefore sysconfig is used as the primary renderer for network configuration. We do not want to change this for c9s even when network-manager renderer is re-enabled as it would mean a big behaviour change for cloud-init in the centos 9 stream. - -This change bumps up the priority for sysconfig renderer so that it is used as the primary renderer on c9s and other downstream distributions derived from it. In the next major centos stream release, we may use network manager as the default renderer and make changes accordingly. - -RHBZ: 2209349 - -Signed-off-by: Ani Sinha -(cherry picked from commit a1f375095bd0ac8628c4fdc79538dc177bb9ff99) ---- - config/cloud.cfg.tmpl | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl -index 7238c102..020340f9 100644 ---- a/config/cloud.cfg.tmpl -+++ b/config/cloud.cfg.tmpl -@@ -381,9 +381,12 @@ system_info: - {% elif variant in ["dragonfly"] %} - network: - renderers: ['freebsd'] --{% elif variant in ["fedora"] or is_rhel %} -+{% elif variant in ["fedora"] %} - network: - renderers: ['netplan', 'network-manager', 'networkd', 'sysconfig', 'eni'] -+{% elif is_rhel %} -+ network: -+ renderers: ['sysconfig', 'eni', 'netplan', 'network-manager', 'networkd' ] - {% elif variant == "openmandriva" %} - network: - renderers: ['network-manager', 'networkd'] diff --git a/SOURCES/0023-test-fixes-remove-NM_CONTROLLED-no-from-tests.patch b/SOURCES/0023-test-fixes-remove-NM_CONTROLLED-no-from-tests.patch deleted file mode 100644 index f9d3362..0000000 --- a/SOURCES/0023-test-fixes-remove-NM_CONTROLLED-no-from-tests.patch +++ /dev/null @@ -1,283 +0,0 @@ -From 9eb7ef217eb03131904fb6e0c692130126334f52 Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Fri, 23 Jun 2023 16:54:24 +0530 -Subject: [PATCH] test fixes: remove NM_CONTROLLED=no from tests - -X-downstream-only: true -fixes: b3b96bff187e9 ("Do not write NM_CONTROLLED=no in generated interface config files") - -Signed-off-by: Ani Sinha ---- - tests/unittests/cmd/devel/test_net_convert.py | 1 - - tests/unittests/distros/test_netconfig.py | 8 ------- - tests/unittests/test_net.py | 23 ------------------- - 3 files changed, 32 deletions(-) - -diff --git a/tests/unittests/cmd/devel/test_net_convert.py b/tests/unittests/cmd/devel/test_net_convert.py -index 43e879f7..082e9656 100644 ---- a/tests/unittests/cmd/devel/test_net_convert.py -+++ b/tests/unittests/cmd/devel/test_net_convert.py -@@ -63,7 +63,6 @@ SAMPLE_SYSCONFIG_CONTENT = """\ - AUTOCONNECT_PRIORITY=120 - BOOTPROTO=dhcp - DEVICE=eth0 --NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -diff --git a/tests/unittests/distros/test_netconfig.py b/tests/unittests/distros/test_netconfig.py -index eaf723c8..7ac8182a 100644 ---- a/tests/unittests/distros/test_netconfig.py -+++ b/tests/unittests/distros/test_netconfig.py -@@ -724,7 +724,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): - GATEWAY=192.168.1.254 - IPADDR=192.168.1.5 - NETMASK=255.255.255.0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -735,7 +734,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): - AUTOCONNECT_PRIORITY=120 - BOOTPROTO=dhcp - DEVICE=eth1 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -767,7 +765,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): - IPV6_AUTOCONF=no - IPV6_DEFAULTGW=2607:f0d0:1002:0011::1 - IPV6_FORCE_ACCEPT_RA=no -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -778,7 +775,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): - AUTOCONNECT_PRIORITY=120 - BOOTPROTO=dhcp - DEVICE=eth1 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -826,7 +822,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): - HWADDR=00:16:3e:60:7c:df - IPADDR=192.10.1.2 - NETMASK=255.255.255.0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -839,7 +834,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): - DEVICE=infra0 - IPADDR=10.0.1.2 - NETMASK=255.255.0.0 -- NM_CONTROLLED=no - ONBOOT=yes - PHYSDEV=eth0 - USERCTL=no -@@ -876,7 +870,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): - DEVICE=eth0 - IPADDR=192.10.1.2 - NETMASK=255.255.255.0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -889,7 +882,6 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): - DEVICE=eth0.1001 - IPADDR=10.0.1.2 - NETMASK=255.255.0.0 -- NM_CONTROLLED=no - ONBOOT=yes - PHYSDEV=eth0 - USERCTL=no -diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index 1261840b..fd656a57 100644 ---- a/tests/unittests/test_net.py -+++ b/tests/unittests/test_net.py -@@ -1502,7 +1502,6 @@ NETWORK_CONFIGS = { - DHCPV6C=yes - IPV6INIT=yes - DEVICE=iface0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -1594,7 +1593,6 @@ NETWORK_CONFIGS = { - IPV6INIT=yes - IPV6_FORCE_ACCEPT_RA=yes - DEVICE=iface0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -1671,7 +1669,6 @@ NETWORK_CONFIGS = { - IPV6INIT=yes - IPV6_FORCE_ACCEPT_RA=no - DEVICE=iface0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -1736,7 +1733,6 @@ NETWORK_CONFIGS = { - IPV6_AUTOCONF=yes - IPV6INIT=yes - DEVICE=iface0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -1792,7 +1788,6 @@ NETWORK_CONFIGS = { - IPV6_AUTOCONF=no - IPV6_FORCE_ACCEPT_RA=no - DEVICE=iface0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -1850,7 +1845,6 @@ NETWORK_CONFIGS = { - IPV6_AUTOCONF=yes - IPV6INIT=yes - DEVICE=iface0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -1933,7 +1927,6 @@ NETWORK_CONFIGS = { - IPV6_AUTOCONF=no - IPV6_FORCE_ACCEPT_RA=yes - DEVICE=iface0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -1975,7 +1968,6 @@ NETWORK_CONFIGS = { - AUTOCONNECT_PRIORITY=120 - BOOTPROTO=dhcp - DEVICE=iface0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -2053,7 +2045,6 @@ NETWORK_CONFIGS = { - BOOTPROTO=dhcp - DEVICE=iface0 - ETHTOOL_OPTS="wol g" -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -2530,7 +2521,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - IPADDR=192.168.200.7 - MTU=9000 - NETMASK=255.255.255.0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=InfiniBand - USERCTL=no""" -@@ -3609,7 +3599,6 @@ iface bond0 inet6 static - IPV6INIT=yes - IPV6_AUTOCONF=no - IPV6_FORCE_ACCEPT_RA=no -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -3626,7 +3615,6 @@ iface bond0 inet6 static - IPV6INIT=yes - IPV6_AUTOCONF=no - IPV6_FORCE_ACCEPT_RA=no -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -3920,7 +3908,6 @@ iface bond0 inet6 static - BOOTPROTO=none - DEVICE=eth0 - HWADDR=cf:d6:af:48:e8:80 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no""" -@@ -4759,7 +4746,6 @@ HWADDR=fa:16:3e:25:b4:59 - IPADDR=51.68.89.122 - MTU=1500 - NETMASK=255.255.240.0 --NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -4774,7 +4760,6 @@ DEVICE=eth1 - DHCLIENT_SET_DEFAULT_ROUTE=no - HWADDR=fa:16:3e:b1:ca:29 - MTU=9000 --NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -5027,7 +5012,6 @@ USERCTL=no - IPV6_FORCE_ACCEPT_RA=no - IPV6_DEFAULTGW=2001:db8::1 - NETMASK=255.255.255.0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -5060,7 +5044,6 @@ USERCTL=no - AUTOCONNECT_PRIORITY=120 - BOOTPROTO=none - DEVICE=eno1 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -5074,7 +5057,6 @@ USERCTL=no - IPADDR=192.6.1.9 - MTU=1495 - NETMASK=255.255.255.0 -- NM_CONTROLLED=no - ONBOOT=yes - PHYSDEV=eno1 - USERCTL=no -@@ -5111,7 +5093,6 @@ USERCTL=no - IPADDR=10.101.8.65 - MTU=1334 - NETMASK=255.255.255.192 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Bond - USERCTL=no -@@ -5124,7 +5105,6 @@ USERCTL=no - BOOTPROTO=none - DEVICE=enp0s0 - MASTER=bond0 -- NM_CONTROLLED=no - ONBOOT=yes - SLAVE=yes - TYPE=Bond -@@ -5138,7 +5118,6 @@ USERCTL=no - BOOTPROTO=none - DEVICE=enp0s1 - MASTER=bond0 -- NM_CONTROLLED=no - ONBOOT=yes - SLAVE=yes - TYPE=Bond -@@ -5170,7 +5149,6 @@ USERCTL=no - DEVICE=eno1 - HWADDR=07-1c-c6-75-a4-be - METRIC=100 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no -@@ -5262,7 +5240,6 @@ USERCTL=no - IPV6_FORCE_ACCEPT_RA=no - MTU=1400 - NETMASK=255.255.248.0 -- NM_CONTROLLED=no - ONBOOT=yes - TYPE=Ethernet - USERCTL=no diff --git a/SOURCES/0024-Revert-limit-permissions-on-def_log_file.patch b/SOURCES/0024-Revert-limit-permissions-on-def_log_file.patch deleted file mode 100644 index 1b0e024..0000000 --- a/SOURCES/0024-Revert-limit-permissions-on-def_log_file.patch +++ /dev/null @@ -1,58 +0,0 @@ -From d39cd4de3ce41b1a1727185f2e57ec27190c23cb Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Tue, 4 Jul 2023 13:58:27 +0530 -Subject: [PATCH] Revert "limit permissions on def_log_file" - -This reverts commit dfff374f66904e84fb07ca157ba010fac6b5f1de. - -This commit seems useless and does not effectively change permission of the -log file. Remove it. ---- - cloudinit/settings.py | 1 - - cloudinit/stages.py | 1 - - doc/examples/cloud-config.txt | 4 ---- - 3 files changed, 6 deletions(-) - -diff --git a/cloudinit/settings.py b/cloudinit/settings.py -index 3d541141..edbb217d 100644 ---- a/cloudinit/settings.py -+++ b/cloudinit/settings.py -@@ -52,7 +52,6 @@ CFG_BUILTIN = { - "None", - ], - "def_log_file": "/var/log/cloud-init.log", -- "def_log_file_mode": 0o600, - "log_cfgs": [], - "mount_default_fields": [None, None, "auto", "defaults,nofail", "0", "2"], - "syslog_fix_perms": [], -diff --git a/cloudinit/stages.py b/cloudinit/stages.py -index 1326d205..21f30a1f 100644 ---- a/cloudinit/stages.py -+++ b/cloudinit/stages.py -@@ -202,7 +202,6 @@ class Init: - def _initialize_filesystem(self): - util.ensure_dirs(self._initial_subdirs()) - log_file = util.get_cfg_option_str(self.cfg, "def_log_file") -- log_file_mode = util.get_cfg_option_int(self.cfg, "def_log_file_mode") - if log_file: - # At this point the log file should have already been created - # in the setupLogging function of log.py -diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt -index b6d16c9c..15d788f3 100644 ---- a/doc/examples/cloud-config.txt -+++ b/doc/examples/cloud-config.txt -@@ -383,14 +383,10 @@ timezone: US/Eastern - # if syslog_fix_perms is a list, it will iterate through and use the - # first pair that does not raise error. - # --# 'def_log_file' will be created with mode 'def_log_file_mode', which --# is specified as a numeric value and defaults to 0600. --# - # the default values are '/var/log/cloud-init.log' and 'syslog:adm' - # the value of 'def_log_file' should match what is configured in logging - # if either is empty, then no change of ownership will be done - def_log_file: /var/log/my-logging-file.log --def_log_file_mode: 0600 - syslog_fix_perms: syslog:root - - # you can set passwords for a user or multiple users diff --git a/SOURCES/0025-test-fixes-changes-to-apply-RHEL-specific-config-set.patch b/SOURCES/0025-test-fixes-changes-to-apply-RHEL-specific-config-set.patch deleted file mode 100644 index aaefb26..0000000 --- a/SOURCES/0025-test-fixes-changes-to-apply-RHEL-specific-config-set.patch +++ /dev/null @@ -1,43 +0,0 @@ -From f1ccdbdb6c662ce67b4af74e0433a59f099d784a Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Fri, 23 Jun 2023 17:54:04 +0530 -Subject: [PATCH] test fixes: changes to apply RHEL specific config settings to - tests - -X-downstream-only: true -fixes: c4d66915520554adedff9b ("Add initial redhat changes") -fixes: dfff374f66904e84fb07ca ("limit permissions on def_log_file") - -Signed-off-by: Ani Sinha ---- - tests/unittests/cmd/test_main.py | 15 +++++++++------ - 1 file changed, 9 insertions(+), 6 deletions(-) - -diff --git a/tests/unittests/cmd/test_main.py b/tests/unittests/cmd/test_main.py -index e9ad0bb8..5d61aa2c 100644 ---- a/tests/unittests/cmd/test_main.py -+++ b/tests/unittests/cmd/test_main.py -@@ -119,14 +119,17 @@ class TestMain(FilesystemMockingTestCase): - { - "def_log_file": "/var/log/cloud-init.log", - "log_cfgs": [], -- "syslog_fix_perms": [ -- "syslog:adm", -- "root:adm", -- "root:wheel", -- "root:root", -- ], - "vendor_data": {"enabled": True, "prefix": []}, - "vendor_data2": {"enabled": True, "prefix": []}, -+ "syslog_fix_perms": [], -+ "mount_default_fields": [ -+ None, -+ None, -+ "auto", -+ "defaults,nofail", -+ "0", -+ "2", -+ ], - } - ) - updated_cfg.pop("system_info") diff --git a/SOURCES/0026-Enable-SUSE-based-distros-for-ca-handling-2036.patch b/SOURCES/0026-Enable-SUSE-based-distros-for-ca-handling-2036.patch deleted file mode 100644 index 2b2ca7d..0000000 --- a/SOURCES/0026-Enable-SUSE-based-distros-for-ca-handling-2036.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 7a530e186e791858bf70accd2fab80dd9b43ee7e Mon Sep 17 00:00:00 2001 -From: Robert Schweikert -Date: Thu, 23 Feb 2023 16:43:56 -0500 -Subject: [PATCH] Enable SUSE based distros for ca handling (#2036) - -CA handling in the configuration module was previously not supported -for SUSE based distros. Enable this functionality by creating the -necessary configuration settings. - -Secondly update the test such that it does not bleed through to the -test system. - -(cherry picked from commit 46fcd03187d70f405c748f7a6cfdb02ecb8c6ee7) -Signed-off-by: Ani Sinha ---- - cloudinit/config/cc_ca_certs.py | 31 +++++++++++++++++++++- - tests/unittests/config/test_cc_ca_certs.py | 2 ++ - 2 files changed, 32 insertions(+), 1 deletion(-) - -diff --git a/cloudinit/config/cc_ca_certs.py b/cloudinit/config/cc_ca_certs.py -index 169b0e18..51b8577c 100644 ---- a/cloudinit/config/cc_ca_certs.py -+++ b/cloudinit/config/cc_ca_certs.py -@@ -32,8 +32,25 @@ DISTRO_OVERRIDES = { - "ca_cert_config": None, - "ca_cert_update_cmd": ["update-ca-trust"], - }, -+ "opensuse": { -+ "ca_cert_path": "/etc/pki/trust/", -+ "ca_cert_local_path": "/usr/share/pki/trust/", -+ "ca_cert_filename": "anchors/cloud-init-ca-cert-{cert_index}.crt", -+ "ca_cert_config": None, -+ "ca_cert_update_cmd": ["update-ca-certificates"], -+ }, - } - -+for distro in ( -+ "opensuse-microos", -+ "opensuse-tumbleweed", -+ "opensuse-leap", -+ "sle_hpc", -+ "sle-micro", -+ "sles", -+): -+ DISTRO_OVERRIDES[distro] = DISTRO_OVERRIDES["opensuse"] -+ - MODULE_DESCRIPTION = """\ - This module adds CA certificates to the system's CA store and updates any - related files using the appropriate OS-specific utility. The default CA -@@ -48,7 +65,19 @@ configuration option ``remove_defaults``. - Alpine Linux requires the ca-certificates package to be installed in - order to provide the ``update-ca-certificates`` command. - """ --distros = ["alpine", "debian", "rhel", "ubuntu"] -+distros = [ -+ "alpine", -+ "debian", -+ "rhel", -+ "opensuse", -+ "opensuse-microos", -+ "opensuse-tumbleweed", -+ "opensuse-leap", -+ "sle_hpc", -+ "sle-micro", -+ "sles", -+ "ubuntu", -+] - - meta: MetaSchema = { - "id": "cc_ca_certs", -diff --git a/tests/unittests/config/test_cc_ca_certs.py b/tests/unittests/config/test_cc_ca_certs.py -index 19e5d422..6db17485 100644 ---- a/tests/unittests/config/test_cc_ca_certs.py -+++ b/tests/unittests/config/test_cc_ca_certs.py -@@ -311,6 +311,7 @@ class TestRemoveDefaultCaCerts(TestCase): - "cloud_dir": tmpdir, - } - ) -+ self.add_patch("cloudinit.config.cc_ca_certs.os.stat", "m_stat") - - def test_commands(self): - ca_certs_content = "# line1\nline2\nline3\n" -@@ -318,6 +319,7 @@ class TestRemoveDefaultCaCerts(TestCase): - "# line1\n# Modified by cloud-init to deselect certs due to" - " user-data\n!line2\n!line3\n" - ) -+ self.m_stat.return_value.st_size = 1 - - for distro_name in cc_ca_certs.distros: - conf = cc_ca_certs._distro_ca_certs_configs(distro_name) diff --git a/SOURCES/0027-Handle-non-existent-ca-cert-config-situation-2073.patch b/SOURCES/0027-Handle-non-existent-ca-cert-config-situation-2073.patch deleted file mode 100644 index ecdf8ca..0000000 --- a/SOURCES/0027-Handle-non-existent-ca-cert-config-situation-2073.patch +++ /dev/null @@ -1,85 +0,0 @@ -From add770c442088c0915bdefad2a7438f9a38596c5 Mon Sep 17 00:00:00 2001 -From: Shreenidhi Shedi <53473811+sshedi@users.noreply.github.com> -Date: Fri, 17 Mar 2023 03:01:22 +0530 -Subject: [PATCH] Handle non existent ca-cert-config situation (#2073) - -Currently if a cert file doesn't exist, cc_ca_certs module crashes -This fix makes it possible to handle it gracefully. - -Also, out_lines variable may not be available if os.stat returns 0. -This issue is also taken care of. - -Added tests for the same. - -(cherry picked from commit 3634678465e7b8f8608bcb9a1f5773ae7837cbe9) -Signed-off-by: Ani Sinha ---- - cloudinit/config/cc_ca_certs.py | 19 +++++++++++++------ - tests/unittests/config/test_cc_ca_certs.py | 12 ++++++++++++ - 2 files changed, 25 insertions(+), 6 deletions(-) - -diff --git a/cloudinit/config/cc_ca_certs.py b/cloudinit/config/cc_ca_certs.py -index 51b8577c..4dc08681 100644 ---- a/cloudinit/config/cc_ca_certs.py -+++ b/cloudinit/config/cc_ca_certs.py -@@ -177,14 +177,20 @@ def disable_system_ca_certs(distro_cfg): - - @param distro_cfg: A hash providing _distro_ca_certs_configs function. - """ -- if distro_cfg["ca_cert_config"] is None: -+ -+ ca_cert_cfg_fn = distro_cfg["ca_cert_config"] -+ -+ if not ca_cert_cfg_fn or not os.path.exists(ca_cert_cfg_fn): - return -+ - header_comment = ( - "# Modified by cloud-init to deselect certs due to user-data" - ) -+ - added_header = False -- if os.stat(distro_cfg["ca_cert_config"]).st_size != 0: -- orig = util.load_file(distro_cfg["ca_cert_config"]) -+ -+ if os.stat(ca_cert_cfg_fn).st_size: -+ orig = util.load_file(ca_cert_cfg_fn) - out_lines = [] - for line in orig.splitlines(): - if line == header_comment: -@@ -197,9 +203,10 @@ def disable_system_ca_certs(distro_cfg): - out_lines.append(header_comment) - added_header = True - out_lines.append("!" + line) -- util.write_file( -- distro_cfg["ca_cert_config"], "\n".join(out_lines) + "\n", omode="wb" -- ) -+ -+ util.write_file( -+ ca_cert_cfg_fn, "\n".join(out_lines) + "\n", omode="wb" -+ ) - - - def remove_default_ca_certs(distro_cfg): -diff --git a/tests/unittests/config/test_cc_ca_certs.py b/tests/unittests/config/test_cc_ca_certs.py -index 6db17485..5f1894e7 100644 ---- a/tests/unittests/config/test_cc_ca_certs.py -+++ b/tests/unittests/config/test_cc_ca_certs.py -@@ -365,6 +365,18 @@ class TestRemoveDefaultCaCerts(TestCase): - else: - assert mock_subp.call_count == 0 - -+ def test_non_existent_cert_cfg(self): -+ self.m_stat.return_value.st_size = 0 -+ -+ for distro_name in cc_ca_certs.distros: -+ conf = cc_ca_certs._distro_ca_certs_configs(distro_name) -+ with ExitStack() as mocks: -+ mocks.enter_context( -+ mock.patch.object(util, "delete_dir_contents") -+ ) -+ mocks.enter_context(mock.patch.object(subp, "subp")) -+ cc_ca_certs.disable_default_ca_certs(distro_name, conf) -+ - - class TestCACertsSchema: - """Directly test schema rather than through handle.""" diff --git a/SOURCES/0028-logging-keep-current-file-mode-of-log-file-if-its-st.patch b/SOURCES/0028-logging-keep-current-file-mode-of-log-file-if-its-st.patch deleted file mode 100644 index 9de8369..0000000 --- a/SOURCES/0028-logging-keep-current-file-mode-of-log-file-if-its-st.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 1cecfe4bc3d7e4806d1890615a119e478decd5fd Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Thu, 20 Jul 2023 23:56:01 +0530 -Subject: [PATCH] logging: keep current file mode of log file if its stricter - than the new mode (#4250) - -By default, the cloud init log file is created with mode 0o644 with -`preserve_mode` parameter of `write_file()` set to False. This means that when -an existing log file is found, its mode will be unconditionally reset to the -mode 0o644. It is possible that this might cause the change of the mode of the -log file from the current more stricter mode to a less strict mode -(when the new mode 0o644 is less strict than the existing mode of the file). - -In order to mitigate the above issue, check the current mode of the log file -and if the current mode is stricter than the default new mode 0o644, then -preserve the current mode of the file. - -Fixes GH-4243 - -Signed-off-by: Ani Sinha -(cherry picked from commit a0e4ec15a1adffabd1c539879514eae4807c834c) - - Conflicts: - tests/unittests/test_util.py ---- - cloudinit/stages.py | 15 ++++++++++++++- - cloudinit/util.py | 23 +++++++++++++++++++++++ - tests/unittests/test_stages.py | 23 ++++++++++++++++------- - tests/unittests/test_util.py | 24 ++++++++++++++++++++++++ - 4 files changed, 77 insertions(+), 8 deletions(-) - -diff --git a/cloudinit/stages.py b/cloudinit/stages.py -index 21f30a1f..979179af 100644 ---- a/cloudinit/stages.py -+++ b/cloudinit/stages.py -@@ -200,12 +200,25 @@ class Init: - self._initialize_filesystem() - - def _initialize_filesystem(self): -+ mode = 0o640 -+ fmode = None -+ - util.ensure_dirs(self._initial_subdirs()) - log_file = util.get_cfg_option_str(self.cfg, "def_log_file") - if log_file: - # At this point the log file should have already been created - # in the setupLogging function of log.py -- util.ensure_file(log_file, mode=0o640, preserve_mode=False) -+ -+ try: -+ fmode = util.get_permissions(log_file) -+ except OSError: -+ pass -+ -+ # if existing file mode fmode is stricter, do not change it. -+ if fmode and util.compare_permission(fmode, mode) < 0: -+ mode = fmode -+ -+ util.ensure_file(log_file, mode, preserve_mode=False) - perms = self.cfg.get("syslog_fix_perms") - if not perms: - perms = {} -diff --git a/cloudinit/util.py b/cloudinit/util.py -index 4a8e3d3b..af617e73 100644 ---- a/cloudinit/util.py -+++ b/cloudinit/util.py -@@ -2099,6 +2099,29 @@ def safe_int(possible_int): - return None - - -+def compare_permission(mode1, mode2): -+ """Compare two file modes in octal. -+ -+ If mode1 is less restrictive than mode2 return 1 -+ If mode1 is more restrictive than mode2 return -1 -+ If mode1 is same as mode2, return 0 -+ -+ The comparison starts from the permission of the -+ set of users in "others" and then works up to the -+ permission of "user" set. -+ """ -+ # Convert modes to octal and reverse the last 3 digits -+ # so 0o640 would be become 0o046 -+ mode1_oct = oct(mode1)[2:].rjust(3, "0") -+ mode2_oct = oct(mode2)[2:].rjust(3, "0") -+ m1 = int(mode1_oct[:-3] + mode1_oct[-3:][::-1], 8) -+ m2 = int(mode2_oct[:-3] + mode2_oct[-3:][::-1], 8) -+ -+ # Then do a traditional cmp() -+ # https://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons -+ return (m1 > m2) - (m1 < m2) -+ -+ - def chmod(path, mode): - real_mode = safe_int(mode) - if path and real_mode: -diff --git a/tests/unittests/test_stages.py b/tests/unittests/test_stages.py -index a61f9df9..831ea9f2 100644 ---- a/tests/unittests/test_stages.py -+++ b/tests/unittests/test_stages.py -@@ -606,13 +606,22 @@ class TestInit_InitializeFilesystem: - # Assert we create it 0o640 by default if it doesn't already exist - assert 0o640 == stat.S_IMODE(log_file.stat().mode) - -- def test_existing_file_permissions(self, init, tmpdir): -+ @pytest.mark.parametrize( -+ "set_perms,expected_perms", -+ [ -+ (0o640, 0o640), -+ (0o606, 0o640), -+ (0o600, 0o600), -+ ], -+ ) -+ def test_existing_file_permissions( -+ self, init, tmpdir, set_perms, expected_perms -+ ): - """Test file permissions are set as expected. - -- CIS Hardening requires 640 permissions. These permissions are -- currently hardcoded on every boot, but if there's ever a reason -- to change this, we need to then ensure that they -- are *not* set every boot. -+ CIS Hardening requires 640 permissions. If the file has looser -+ permissions, then hard code 640. If the file has tighter -+ permissions, then leave them as they are - - See https://bugs.launchpad.net/cloud-init/+bug/1900837. - """ -@@ -620,9 +629,9 @@ class TestInit_InitializeFilesystem: - log_file.ensure() - # Use a mode that will never be made the default so this test will - # always be valid -- log_file.chmod(0o606) -+ log_file.chmod(set_perms) - init._cfg = {"def_log_file": str(log_file)} - - init._initialize_filesystem() - -- assert 0o640 == stat.S_IMODE(log_file.stat().mode) -+ assert expected_perms == stat.S_IMODE(log_file.stat().mode) -diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py -index 17182d06..289a4234 100644 ---- a/tests/unittests/test_util.py -+++ b/tests/unittests/test_util.py -@@ -3051,3 +3051,27 @@ class TestVersion: - ) - def test_from_str(self, str_ver, cls_ver): - assert util.Version.from_str(str_ver) == cls_ver -+ -+ -+class TestComparePermissions: -+ @pytest.mark.parametrize( -+ "perm1,perm2,expected", -+ [ -+ (0o777, 0o777, 0), -+ (0o000, 0o000, 0), -+ (0o421, 0o421, 0), -+ (0o1640, 0o1640, 0), -+ (0o1407, 0o1600, 1), -+ (0o1600, 0o1407, -1), -+ (0o407, 0o600, 1), -+ (0o600, 0o407, -1), -+ (0o007, 0o700, 1), -+ (0o700, 0o007, -1), -+ (0o077, 0o100, 1), -+ (0o644, 0o640, 1), -+ (0o640, 0o600, 1), -+ (0o600, 0o400, 1), -+ ], -+ ) -+ def test_compare_permissions(self, perm1, perm2, expected): -+ assert util.compare_permission(perm1, perm2) == expected diff --git a/SOURCES/0029-DS-VMware-modify-a-few-log-level-4284.patch b/SOURCES/0029-DS-VMware-modify-a-few-log-level-4284.patch deleted file mode 100644 index f8d2e74..0000000 --- a/SOURCES/0029-DS-VMware-modify-a-few-log-level-4284.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 25ac8bb44af554a040f0dfa9b52e9241a33a4845 Mon Sep 17 00:00:00 2001 -From: PengpengSun <40026211+PengpengSun@users.noreply.github.com> -Date: Tue, 25 Jul 2023 05:21:46 +0800 -Subject: [PATCH] DS VMware: modify a few log level (#4284) - -Multiple ip addresses are common scenario for modern Linux, so set -debug log level for such cases. - -(cherry picked from commit 4a6a9d3f6c8fe213c51f6c1336f1dd378bf4bdca) -Signed-off-by: Ani Sinha ---- - cloudinit/sources/DataSourceVMware.py | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/cloudinit/sources/DataSourceVMware.py b/cloudinit/sources/DataSourceVMware.py -index 07a80222..bc3b5a5f 100644 ---- a/cloudinit/sources/DataSourceVMware.py -+++ b/cloudinit/sources/DataSourceVMware.py -@@ -1,6 +1,6 @@ - # Cloud-Init DataSource for VMware - # --# Copyright (c) 2018-2022 VMware, Inc. All Rights Reserved. -+# Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. - # - # Authors: Anish Swaminathan - # Andrew Kutz -@@ -719,7 +719,7 @@ def get_default_ip_addrs(): - af_inet4 = addr4_fams.get(netifaces.AF_INET) - if af_inet4: - if len(af_inet4) > 1: -- LOG.warning( -+ LOG.debug( - "device %s has more than one ipv4 address: %s", - dev4, - af_inet4, -@@ -737,7 +737,7 @@ def get_default_ip_addrs(): - af_inet6 = addr6_fams.get(netifaces.AF_INET6) - if af_inet6: - if len(af_inet6) > 1: -- LOG.warning( -+ LOG.debug( - "device %s has more than one ipv6 address: %s", - dev6, - af_inet6, -@@ -752,7 +752,7 @@ def get_default_ip_addrs(): - af_inet6 = addr4_fams.get(netifaces.AF_INET6) - if af_inet6: - if len(af_inet6) > 1: -- LOG.warning( -+ LOG.debug( - "device %s has more than one ipv6 address: %s", - dev4, - af_inet6, -@@ -767,7 +767,7 @@ def get_default_ip_addrs(): - af_inet4 = addr6_fams.get(netifaces.AF_INET) - if af_inet4: - if len(af_inet4) > 1: -- LOG.warning( -+ LOG.debug( - "device %s has more than one ipv4 address: %s", - dev6, - af_inet4, diff --git a/SOURCES/0030-NM-renderer-set-default-IPv6-addr-gen-mode-for-all-i.patch b/SOURCES/0030-NM-renderer-set-default-IPv6-addr-gen-mode-for-all-i.patch deleted file mode 100644 index 680622b..0000000 --- a/SOURCES/0030-NM-renderer-set-default-IPv6-addr-gen-mode-for-all-i.patch +++ /dev/null @@ -1,283 +0,0 @@ -From c720ab9703752535767691a31e4720e11674bb1f Mon Sep 17 00:00:00 2001 -From: Ani Sinha -Date: Fri, 4 Aug 2023 08:58:26 +0530 -Subject: [PATCH] NM renderer: set default IPv6 addr-gen-mode for all - interfaces to eui64 (#4291) - -By default, NetworkManager renderer in cloud-init does not set any specific -method for IPV6 addr-gen-mode in the keyfiles it writes. Hence, implicitly the -mode is set to `eui64` in the absence of any global addr-gen-mode option in -NetworkManager configuration. -Later when other interfaces get added via D-Bus API or by using nmcli commands -without explictly setting an addr-gen-mode, NM auto generates new profiles for -those interfaces with addr-gen-mode set to `stable-privacy`. This introduces -inconsistency of configurations between interfaces based on how they were -added. This can cause problems for the customers. - -In this change, cloud-init overrides NetworkManager's preferred default of -`stable-privacy` to use EUI64 using a drop in NetworkManager configuration -file. This setting can be overriden by using global-connection-defaults -setting in /etc/NetworkManager/NetworkManager.conf file. - -RHBZ: 2188388 - -Signed-off-by: Ani Sinha -(cherry picked from commit d41264cb4297a4b143a23f3677d33b81fbfc6e8e) - -Conflicts: - tests/unittests/test_net.py ---- - cloudinit/net/network_manager.py | 21 ++++++++ - tests/unittests/test_net.py | 91 +++++++++++++++++++++++++------- - 2 files changed, 94 insertions(+), 18 deletions(-) - -diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py -index ca216928..8047f796 100644 ---- a/cloudinit/net/network_manager.py -+++ b/cloudinit/net/network_manager.py -@@ -21,6 +21,15 @@ from cloudinit.net.network_state import NetworkState - NM_RUN_DIR = "/etc/NetworkManager" - NM_LIB_DIR = "/usr/lib/NetworkManager" - NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf" -+NM_IPV6_ADDR_GEN_CONF = """# This is generated by cloud-init. Do not edit. -+# -+[.config] -+ enable=nm-version-min:1.40 -+[connection.30-cloud-init-ip6-addr-gen-mode] -+ # Select EUI64 to be used if the profile does not specify it. -+ ipv6.addr-gen-mode=0 -+ -+""" - LOG = logging.getLogger(__name__) - - -@@ -368,6 +377,12 @@ class Renderer(renderer.Renderer): - name = conn_filename(con_id, target) - util.write_file(name, conn.dump(), 0o600) - -+ # Select EUI64 to be used by default by NM for creating the address -+ # for use with RFC4862 IPv6 Stateless Address Autoconfiguration. -+ util.write_file( -+ cloud_init_nm_conf_filename(target), NM_IPV6_ADDR_GEN_CONF, 0o600 -+ ) -+ - - def conn_filename(con_id, target=None): - target_con_dir = subp.target_path(target, NM_RUN_DIR) -@@ -375,6 +390,12 @@ def conn_filename(con_id, target=None): - return f"{target_con_dir}/system-connections/{con_file}" - - -+def cloud_init_nm_conf_filename(target=None): -+ target_con_dir = subp.target_path(target, NM_RUN_DIR) -+ conf_file = "30-cloud-init-ip6-addr-gen-mode.conf" -+ return f"{target_con_dir}/conf.d/{conf_file}" -+ -+ - def available(target=None): - # TODO: Move `uses_systemd` to a more appropriate location - # It is imported here to avoid circular import -diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index fd656a57..d49da696 100644 ---- a/tests/unittests/test_net.py -+++ b/tests/unittests/test_net.py -@@ -5679,9 +5679,25 @@ class TestNetworkManagerRendering(CiTestCase): - with_logs = True - - scripts_dir = "/etc/NetworkManager/system-connections" -+ conf_dir = "/etc/NetworkManager/conf.d" - - expected_name = "expected_network_manager" - -+ expected_conf_d = { -+ "30-cloud-init-ip6-addr-gen-mode.conf": textwrap.dedent( -+ """\ -+ # This is generated by cloud-init. Do not edit. -+ # -+ [.config] -+ enable=nm-version-min:1.40 -+ [connection.30-cloud-init-ip6-addr-gen-mode] -+ # Select EUI64 to be used if the profile does not specify it. -+ ipv6.addr-gen-mode=0 -+ -+ """ -+ ), -+ } -+ - def _get_renderer(self): - return network_manager.Renderer() - -@@ -5700,11 +5716,19 @@ class TestNetworkManagerRendering(CiTestCase): - renderer.render_network_state(ns, target=dir) - return dir2dict(dir) - -- def _compare_files_to_expected(self, expected, found): -+ def _compare_files_to_expected( -+ self, expected_scripts, expected_conf, found -+ ): - orig_maxdiff = self.maxDiff -- expected_d = dict( -- (os.path.join(self.scripts_dir, k), v) for k, v in expected.items() -+ conf_d = dict( -+ (os.path.join(self.conf_dir, k), v) -+ for k, v in expected_conf.items() -+ ) -+ scripts_d = dict( -+ (os.path.join(self.scripts_dir, k), v) -+ for k, v in expected_scripts.items() - ) -+ expected_d = {**conf_d, **scripts_d} - - try: - self.maxDiff = None -@@ -5765,6 +5789,7 @@ class TestNetworkManagerRendering(CiTestCase): - """ - ), - }, -+ self.expected_conf_d, - found, - ) - -@@ -5820,8 +5845,9 @@ class TestNetworkManagerRendering(CiTestCase): - gateway=10.0.2.2 - - """ -- ), -+ ) - }, -+ self.expected_conf_d, - found, - ) - -@@ -5857,33 +5883,44 @@ class TestNetworkManagerRendering(CiTestCase): - """ - ), - }, -+ self.expected_conf_d, - found, - ) - - def test_bond_config(self): - entry = NETWORK_CONFIGS["bond"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_vlan_config(self): - entry = NETWORK_CONFIGS["vlan"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_bridge_config(self): - entry = NETWORK_CONFIGS["bridge"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_manual_config(self): - entry = NETWORK_CONFIGS["manual"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_all_config(self): - entry = NETWORK_CONFIGS["all"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - self.assertNotIn( - "WARNING: Network config: ignoring eth0.101 device-level mtu", - self.logs.getvalue(), -@@ -5892,12 +5929,16 @@ class TestNetworkManagerRendering(CiTestCase): - def test_small_config(self): - entry = NETWORK_CONFIGS["small"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_v4_and_v6_static_config(self): - entry = NETWORK_CONFIGS["v4_and_v6_static"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - expected_msg = ( - "WARNING: Network config: ignoring iface0 device-level mtu:8999" - " because ipv4 subnet-level mtu:9000 provided." -@@ -5907,41 +5948,55 @@ class TestNetworkManagerRendering(CiTestCase): - def test_dhcpv6_only_config(self): - entry = NETWORK_CONFIGS["dhcpv6_only"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_simple_render_ipv6_slaac(self): - entry = NETWORK_CONFIGS["ipv6_slaac"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_dhcpv6_stateless_config(self): - entry = NETWORK_CONFIGS["dhcpv6_stateless"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_wakeonlan_disabled_config_v2(self): - entry = NETWORK_CONFIGS["wakeonlan_disabled"] - found = self._render_and_read( - network_config=yaml.load(entry["yaml_v2"]) - ) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_wakeonlan_enabled_config_v2(self): - entry = NETWORK_CONFIGS["wakeonlan_enabled"] - found = self._render_and_read( - network_config=yaml.load(entry["yaml_v2"]) - ) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_render_v4_and_v6(self): - entry = NETWORK_CONFIGS["v4_and_v6"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - def test_render_v6_and_v4(self): - entry = NETWORK_CONFIGS["v6_and_v4"] - found = self._render_and_read(network_config=yaml.load(entry["yaml"])) -- self._compare_files_to_expected(entry[self.expected_name], found) -+ self._compare_files_to_expected( -+ entry[self.expected_name], self.expected_conf_d, found -+ ) - - - @mock.patch( diff --git a/SOURCES/ci-Pin-pythes-8.0.0.patch b/SOURCES/ci-Pin-pythes-8.0.0.patch new file mode 100644 index 0000000..cdb8413 --- /dev/null +++ b/SOURCES/ci-Pin-pythes-8.0.0.patch @@ -0,0 +1,44 @@ +From 7f3b0ff968409a880596e04aece4e4c504fb9c64 Mon Sep 17 00:00:00 2001 +From: Brett Holman +Date: Mon, 29 Jan 2024 12:03:36 -0700 +Subject: [PATCH] ci: Pin pytest<8.0.0. (#4816) + +The latest pytest release broke some tests in non-obvious ways. Pin +the version for now so that CI passes. + +(cherry picked from commit 7c96c9cd9318e816ce4564b58a2c98271363c447) +Signed-off-by: Ani Sinha +--- + integration-requirements.txt | 2 +- + test-requirements.txt | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/integration-requirements.txt b/integration-requirements.txt +index 1f8b54a5..c0792d63 100644 +--- a/integration-requirements.txt ++++ b/integration-requirements.txt +@@ -7,7 +7,7 @@ pycloudlib>=5.10.0,<1!6 + # test/unittests/conftest.py to be loaded by our integration-tests tox env + # resulting in an unmet dependency issue: + # https://github.com/pytest-dev/pytest/issues/11104 +-pytest!=7.3.2 ++pytest!=7.3.2,<8.0.0 + + packaging + passlib +diff --git a/test-requirements.txt b/test-requirements.txt +index 46a98b4c..3d2480fd 100644 +--- a/test-requirements.txt ++++ b/test-requirements.txt +@@ -4,7 +4,7 @@ + # test/unittests/conftest.py to be loaded by our integration-tests tox env + # resulting in an unmet dependency issue: + # https://github.com/pytest-dev/pytest/issues/11104 +-pytest!=7.3.2 ++pytest!=7.3.2,<8.0.0 + + pytest-cov + pytest-mock +-- +2.39.3 + diff --git a/SOURCES/ci-Revert-Use-grep-for-faster-parsing-of-cloud-config-i.patch b/SOURCES/ci-Revert-Use-grep-for-faster-parsing-of-cloud-config-i.patch new file mode 100644 index 0000000..850913f --- /dev/null +++ b/SOURCES/ci-Revert-Use-grep-for-faster-parsing-of-cloud-config-i.patch @@ -0,0 +1,242 @@ +From 72b2deeafd9276d15f20831f01b2f8c44616f33d Mon Sep 17 00:00:00 2001 +From: Brett Holman +Date: Tue, 23 Jan 2024 11:47:35 -0700 +Subject: [PATCH] Revert "Use grep for faster parsing of cloud config in + ds-identify (#4327)" + +RH-Author: Ani Sinha +RH-MergeRequest: 67: Revert "Use grep for faster parsing of cloud config in ds-identify (#4327)" +RH-Jira: RHEL-22255 +RH-Acked-by: Emanuele Giuseppe Esposito +RH-Acked-by: Miroslav Rezanina +RH-Commit: [1/1] 5997598254cd16ea7f26d87212b0f09920fcdf50 (anisinha/cloud-init) + +This reverts commit 816e05d4830f5e789f1f85ef926e2849156bff3a. + +Reopens LP: 2030729 +Fixes GH-4794 + +(cherry picked from commit 8ff94fe9493ad88344eb8bbf2f023c6ba2db5206) +Signed-off-by: Ani Sinha +--- + tests/unittests/test_ds_identify.py | 146 +--------------------------- + tools/ds-identify | 31 +++--- + 2 files changed, 15 insertions(+), 162 deletions(-) + +diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py +index ca206fb5..ba0bf779 100644 +--- a/tests/unittests/test_ds_identify.py ++++ b/tests/unittests/test_ds_identify.py +@@ -57,146 +57,6 @@ BLKID_UEFI_UBUNTU = [ + ] + + +-DEFAULT_CLOUD_CONFIG = """\ +-# The top level settings are used as module +-# and base configuration. +-# A set of users which may be applied and/or used by various modules +-# when a 'default' entry is found it will reference the 'default_user' +-# from the distro configuration specified below +-users: +- - default +- +-# If this is set, 'root' will not be able to ssh in and they +-# will get a message to login instead as the default $user +-disable_root: true +- +-# This will cause the set+update hostname module to not operate (if true) +-preserve_hostname: false +- +-# If you use datasource_list array, keep array items in a single line. +-# If you use multi line array, ds-identify script won't read array items. +-# Example datasource config +-# datasource: +-# Ec2: +-# metadata_urls: [ 'blah.com' ] +-# timeout: 5 # (defaults to 50 seconds) +-# max_wait: 10 # (defaults to 120 seconds) +- +-# The modules that run in the 'init' stage +-cloud_init_modules: +- - migrator +- - seed_random +- - bootcmd +- - write-files +- - growpart +- - resizefs +- - disk_setup +- - mounts +- - set_hostname +- - update_hostname +- - update_etc_hosts +- - ca-certs +- - rsyslog +- - users-groups +- - ssh +- +-# The modules that run in the 'config' stage +-cloud_config_modules: +- - wireguard +- - snap +- - ubuntu_autoinstall +- - ssh-import-id +- - keyboard +- - locale +- - set-passwords +- - grub-dpkg +- - apt-pipelining +- - apt-configure +- - ubuntu-advantage +- - ntp +- - timezone +- - disable-ec2-metadata +- - runcmd +- - byobu +- +-# The modules that run in the 'final' stage +-cloud_final_modules: +- - package-update-upgrade-install +- - fan +- - landscape +- - lxd +- - ubuntu-drivers +- - write-files-deferred +- - puppet +- - chef +- - ansible +- - mcollective +- - salt-minion +- - reset_rmc +- - refresh_rmc_and_interface +- - rightscale_userdata +- - scripts-vendor +- - scripts-per-once +- - scripts-per-boot +- - scripts-per-instance +- - scripts-user +- - ssh-authkey-fingerprints +- - keys-to-console +- - install-hotplug +- - phone-home +- - final-message +- - power-state-change +- +-# System and/or distro specific settings +-# (not accessible to handlers/transforms) +-system_info: +- # This will affect which distro class gets used +- distro: ubuntu +- # Default user name + that default users groups (if added/used) +- default_user: +- name: ubuntu +- lock_passwd: True +- gecos: Ubuntu +- groups: [adm, audio, cdrom, floppy, lxd, netdev, plugdev, sudo, video] +- sudo: ["ALL=(ALL) NOPASSWD:ALL"] +- shell: /bin/bash +- network: +- renderers: ['netplan', 'eni', 'sysconfig'] +- activators: ['netplan', 'eni', 'network-manager', 'networkd'] +- # Automatically discover the best ntp_client +- ntp_client: auto +- # Other config here will be given to the distro class and/or path classes +- paths: +- cloud_dir: /var/lib/cloud/ +- templates_dir: /etc/cloud/templates/ +- package_mirrors: +- - arches: [i386, amd64] +- failsafe: +- primary: http://archive.ubuntu.com/ubuntu +- security: http://security.ubuntu.com/ubuntu +- search: +- primary: +- - http://%(ec2_region)s.ec2.archive.ubuntu.com/ubuntu/ +- - http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/ +- - http://%(region)s.clouds.archive.ubuntu.com/ubuntu/ +- security: [] +- - arches: [arm64, armel, armhf] +- failsafe: +- primary: http://ports.ubuntu.com/ubuntu-ports +- security: http://ports.ubuntu.com/ubuntu-ports +- search: +- primary: +- - http://%(ec2_region)s.ec2.ports.ubuntu.com/ubuntu-ports/ +- - http://%(availability_zone)s.clouds.ports.ubuntu.com/ubuntu-ports/ +- - http://%(region)s.clouds.ports.ubuntu.com/ubuntu-ports/ +- security: [] +- - arches: [default] +- failsafe: +- primary: http://ports.ubuntu.com/ubuntu-ports +- security: http://ports.ubuntu.com/ubuntu-ports +- ssh_svcname: ssh +-""" +- + POLICY_FOUND_ONLY = "search,found=all,maybe=none,notfound=disabled" + POLICY_FOUND_OR_MAYBE = "search,found=all,maybe=all,notfound=disabled" + DI_DEFAULT_POLICY = "search,found=all,maybe=all,notfound=disabled" +@@ -279,10 +139,6 @@ class DsIdentifyBase(CiTestCase): + if files is None: + files = {} + +- cloudcfg = "etc/cloud/cloud.cfg" +- if cloudcfg not in files: +- files[cloudcfg] = DEFAULT_CLOUD_CONFIG +- + if rootd is None: + rootd = self.tmp_dir() + +@@ -1305,7 +1161,7 @@ VALID_CFG = { + # Also include a datasource list of more than just + # [NoCloud, None], because that would automatically select + # NoCloud without checking +- "etc/cloud/cloud.cfg": dedent( ++ "/etc/cloud/cloud.cfg": dedent( + """\ + datasource_list: [ Azure, Openstack, NoCloud, None ] + datasource: +diff --git a/tools/ds-identify b/tools/ds-identify +index 7a537278..ec2cc18a 100755 +--- a/tools/ds-identify ++++ b/tools/ds-identify +@@ -777,24 +777,21 @@ check_config() { + if [ "$1" = "$files" -a ! -f "$1" ]; then + return 1 + fi +- local line="" ret="" found=0 found_fn="" oifs="$IFS" out="" +- out=$(grep "$key\"\?:" "$@" 2>/dev/null) +- IFS=${CR} +- for line in $out; do +- # drop '# comment' +- line=${line%%#*} +- # if more than one file was 'grep'ed, then grep will output filename: +- # but if only one file, line will not be prefixed. +- if [ $# -eq 1 ]; then +- found_fn="$1" +- else +- found_fn="${line%%:*}" +- line=${line#*:} +- fi +- ret=${line#*: }; +- found=$((found+1)) ++ local fname="" line="" ret="" found=0 found_fn="" ++ # shellcheck disable=2094 ++ for fname in "$@"; do ++ [ -f "$fname" ] || continue ++ while read line; do ++ line=${line%%#*} ++ case "$line" in ++ $key:\ *|"${key}":) ++ ret=${line#*:}; ++ ret=${ret# }; ++ found=$((found+1)) ++ found_fn="$fname";; ++ esac ++ done <"$fname" + done +- IFS="$oifs" + if [ $found -ne 0 ]; then + _RET="$ret" + _RET_fname="$found_fn" +-- +2.39.3 + diff --git a/SOURCES/ci-fix-Add-types-to-network-v1-schema-4841.patch b/SOURCES/ci-fix-Add-types-to-network-v1-schema-4841.patch new file mode 100644 index 0000000..48224c6 --- /dev/null +++ b/SOURCES/ci-fix-Add-types-to-network-v1-schema-4841.patch @@ -0,0 +1,110 @@ +From 2f7f3dc6237ea70825dcb70f71d9718f631a9d95 Mon Sep 17 00:00:00 2001 +From: James Falcon +Date: Tue, 6 Feb 2024 09:24:37 -0600 +Subject: [PATCH] fix: Add types to network v1 schema (#4841) + +RH-Author: Cathy Avery +RH-MergeRequest: 69: fix: Add types to network v1 schema (#4841) +RH-Jira: RHEL-21324 +RH-Acked-by: Ani Sinha +RH-Acked-by: Emanuele Giuseppe Esposito +RH-Commit: [1/1] 59b2b4b07dd9eed956943a22b90af487f18b4cbd (cavery/cloud-init-c-9-s) + +Conflicts: +No log argument as we are not including commit e168b4a1383b6eae9c1dc81411d7684fcbbf7df9 + +Even though it has conflicted with our documentation, we have allowed +nameserver address to a be a string, mtu to be empty, and nameserver +search to be missing. Since we have allowed these, expand our schema +and documentation accordingly. + +Fixes GH-4710 + +(cherry picked from commit b08193b376552ede5d162d8283310adc783d81bf) +Signed-off-by: Cathy Avery +--- + .../config/schemas/schema-network-config-v1.json | 13 +++++++++---- + doc/rtd/reference/network-config-format-v1.rst | 4 ++-- + tests/unittests/config/test_schema.py | 13 +++++++++++++ + 3 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/cloudinit/config/schemas/schema-network-config-v1.json b/cloudinit/config/schemas/schema-network-config-v1.json +index c77885ec..56dc27c9 100644 +--- a/cloudinit/config/schemas/schema-network-config-v1.json ++++ b/cloudinit/config/schemas/schema-network-config-v1.json +@@ -24,7 +24,10 @@ + "description": "The lowercase MAC address of the physical device." + }, + "mtu": { +- "type": "integer", ++ "type": [ ++ "integer", ++ "null" ++ ], + "description": "The MTU size in bytes. The ``mtu`` key represents a device's Maximum Transmission Unit, which is the largest size packet or frame, specified in octets (eight-bit bytes), that can be sent in a packet- or frame-based network. Specifying ``mtu`` is optional. Values too small or too large for a device may be ignored by that device." + }, + "subnets": { +@@ -384,8 +387,7 @@ + "additionalProperties": false, + "required": [ + "type", +- "address", +- "search" ++ "address" + ], + "properties": { + "type": { +@@ -396,7 +398,10 @@ + }, + "address": { + "description": "List of IPv4 or IPv6 address of nameservers.", +- "type": "array", ++ "type": [ ++ "array", ++ "string" ++ ], + "items": { + "type": "string" + } +diff --git a/doc/rtd/reference/network-config-format-v1.rst b/doc/rtd/reference/network-config-format-v1.rst +index d267eb94..42f2dc22 100644 +--- a/doc/rtd/reference/network-config-format-v1.rst ++++ b/doc/rtd/reference/network-config-format-v1.rst +@@ -252,8 +252,8 @@ Users can specify a ``nameserver`` type. Nameserver dictionaries include + the following keys: + + - ``address``: List of IPv4 or IPv6 address of nameservers. +-- ``search``: List of hostnames to include in the :file:`resolv.conf` search +- path. ++- ``search``: Optional. List of hostnames to include in the :file:`resolv.conf` ++ search path. + - ``interface``: Optional. Ties the nameserver definition to the specified + interface. The value specified here must match the ``name`` of an interface + defined in this config. If unspecified, this nameserver will be considered +diff --git a/tests/unittests/config/test_schema.py b/tests/unittests/config/test_schema.py +index 28f0b39d..52667332 100644 +--- a/tests/unittests/config/test_schema.py ++++ b/tests/unittests/config/test_schema.py +@@ -2048,6 +2048,19 @@ class TestNetworkSchema: + does_not_raise(), + id="bond_with_all_known_properties", + ), ++ pytest.param( ++ { ++ "network": { ++ "version": 1, ++ "config": [ ++ {"type": "physical", "name": "eth0", "mtu": None}, ++ {"type": "nameserver", "address": "8.8.8.8"}, ++ ], ++ } ++ }, ++ does_not_raise(), ++ id="GH-4710_mtu_none_and_str_address", ++ ), + ), + ) + def test_network_schema(self, src_config, expectation): +-- +2.39.3 + diff --git a/SPECS/cloud-init.spec b/SPECS/cloud-init.spec index 1a9c25d..7717f68 100644 --- a/SPECS/cloud-init.spec +++ b/SPECS/cloud-init.spec @@ -1,6 +1,6 @@ Name: cloud-init -Version: 23.1.1 -Release: 11%{?dist} +Version: 23.4 +Release: 6%{?dist} Summary: Cloud instance init scripts License: ASL 2.0 or GPLv3 URL: http://launchpad.net/cloud-init @@ -10,34 +10,17 @@ Source1: cloud-init-tmpfiles.conf # Source-git patches Patch1: 0001-Add-initial-redhat-changes.patch Patch2: 0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch -Patch3: 0003-Setting-highest-autoconnect-priority-for-network-scr.patch -Patch4: 0004-limit-permissions-on-def_log_file.patch -Patch5: 0005-Manual-revert-Use-Network-Manager-and-Netplan-as-def.patch -Patch6: 0006-Revert-Add-native-NetworkManager-support-1224.patch -Patch7: 0007-rhel-make-sure-previous-hostname-file-ends-with-a-ne.patch -Patch8: 0008-Don-t-change-permissions-of-netrules-target-2076.patch -Patch9: 0009-Make-user-vendor-data-sensitive-and-remove-log-permi.patch -Patch10: 0010-Do-not-generate-dsa-and-ed25519-key-types-when-crypt.patch -Patch11: 0011-Revert-Manual-revert-Use-Network-Manager-and-Netplan.patch -Patch12: 0012-Revert-Revert-Add-native-NetworkManager-support-1224.patch -Patch13: 0013-net-sysconfig-do-not-use-the-highest-autoconnect-pri.patch -Patch14: 0014-net-sysconfig-cosmetic-fix-tox-formatting.patch -Patch15: 0015-nm-generate-ipv6-stateful-dhcp-config-at-par-with-sy.patch -Patch16: 0016-network_manager-add-a-method-for-ipv6-static-IP-conf.patch -Patch17: 0017-net-sysconfig-enable-sysconfig-renderer-if-network-m.patch -Patch18: 0018-network-manager-Set-higher-autoconnect-priority-for-.patch -Patch19: 0019-Set-default-renderer-as-sysconfig-for-c9s-RHEL-9.patch -Patch20: 0020-Revert-Set-default-renderer-as-sysconfig-for-c9s-RHE.patch -Patch21: 0021-Set-default-renderer-as-sysconfig-for-centos-rhel-41.patch -Patch22: 0022-test-fixes-update-tests-to-reflect-AUTOCONNECT_PRIOR.patch -Patch23: 0023-test-fixes-remove-NM_CONTROLLED-no-from-tests.patch -Patch24: 0024-Revert-limit-permissions-on-def_log_file.patch -Patch25: 0025-test-fixes-changes-to-apply-RHEL-specific-config-set.patch -Patch26: 0026-Enable-SUSE-based-distros-for-ca-handling-2036.patch -Patch27: 0027-Handle-non-existent-ca-cert-config-situation-2073.patch -Patch28: 0028-logging-keep-current-file-mode-of-log-file-if-its-st.patch -Patch29: 0029-DS-VMware-modify-a-few-log-level-4284.patch -Patch30: 0030-NM-renderer-set-default-IPv6-addr-gen-mode-for-all-i.patch +Patch3: 0003-Setting-autoconnect-priority-setting-for-network-scr.patch +Patch4: 0004-net-network_manager-do-not-set-may-fail-to-False-for.patch +Patch5: 0005-net-allow-dhcp6-configuration-from-generate_fallback.patch +Patch6: 0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch +Patch7: 0007-test-jsonschema-Pin-jsonschema-version-4781.patch +Patch8: 0008-fix-clean-stop-warning-when-running-clean-command-47.patch +# For RHEL-22255 - [Azure][RHEL-9] cloud-init-23.4 cannot read "- Azure" datasource_list format +Patch9: ci-Revert-Use-grep-for-faster-parsing-of-cloud-config-i.patch +Patch10: ci-Pin-pythes-8.0.0.patch +# For RHEL-21324 - [rhel-9] The schema WARNING info for network-config.json is not suitable in cloud-init-23.4 +Patch11: ci-fix-Add-types-to-network-v1-schema-4841.patch BuildArch: noarch @@ -113,7 +96,7 @@ sed -i -e 's|#!/usr/bin/env python|#!/usr/bin/env python3|' \ %py3_install -- %if 0%{?fedora} -python3 tools/render-cloudcfg --variant fedora > $RPM_BUILD_ROOT/%{_sysconfdir}/cloud/cloud.cfg +python3 tools/render-template --variant fedora > $RPM_BUILD_ROOT/%{_sysconfdir}/cloud/cloud.cfg %endif sed -i "s,@@PACKAGED_VERSION@@,%{version}-%{release}," $RPM_BUILD_ROOT/%{python3_sitelib}/cloudinit/version.py @@ -128,12 +111,8 @@ cp -p %{SOURCE1} $RPM_BUILD_ROOT/%{_tmpfilesdir}/%{name}.conf mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d cp -p tools/21-cloudinit.conf $RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf -# Make installed NetworkManager hook name less generic -mv $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/hook-network-manager \ - $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/cloud-init-azure-hook - [ ! -d $RPM_BUILD_ROOT%{_systemdgeneratordir} ] && mkdir -p $RPM_BUILD_ROOT%{_systemdgeneratordir} -python3 tools/render-cloudcfg --variant rhel systemd/cloud-init-generator.tmpl > $RPM_BUILD_ROOT%{_systemdgeneratordir}/cloud-init-generator +python3 tools/render-template --variant rhel systemd/cloud-init-generator.tmpl > $RPM_BUILD_ROOT%{_systemdgeneratordir}/cloud-init-generator chmod 755 $RPM_BUILD_ROOT%{_systemdgeneratordir}/cloud-init-generator # installing man pages @@ -209,16 +188,19 @@ fi %postun %systemd_postun cloud-config.service cloud-config.target cloud-final.service cloud-init.service cloud-init.target cloud-init-local.service -if [ -f /etc/ssh/sshd_config.d/50-cloud-init.conf ] ; then - echo "/etc/ssh/sshd_config.d/50-cloud-init.conf not removed" -fi +if [ $1 -eq 0 ] ; then + # warn during package removal not upgrade + if [ -f /etc/ssh/sshd_config.d/50-cloud-init.conf ] ; then + echo "/etc/ssh/sshd_config.d/50-cloud-init.conf not removed" + fi -if [ -f /etc/NetworkManager/conf.d/99-cloud-init.conf ] ; then - echo "/etc/NetworkManager/conf.d/99-cloud-init.conf not removed" -fi + if [ -f /etc/NetworkManager/conf.d/99-cloud-init.conf ] ; then + echo "/etc/NetworkManager/conf.d/99-cloud-init.conf not removed" + fi -if [ -f /etc/NetworkManager/conf.d/30-cloud-init-ip6-addr-gen-mode.conf ] ; then - echo "/etc/NetworkManager/conf.d/30-cloud-init-ip6-addr-gen-mode.conf not removed" + if [ -f /etc/NetworkManager/conf.d/30-cloud-init-ip6-addr-gen-mode.conf ] ; then + echo "/etc/NetworkManager/conf.d/30-cloud-init-ip6-addr-gen-mode.conf not removed" + fi fi %files @@ -227,7 +209,6 @@ fi %dir %{_sysconfdir}/cloud/cloud.cfg.d %config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/*.cfg %doc %{_sysconfdir}/cloud/cloud.cfg.d/README -%doc %{_sysconfdir}/cloud/clean.d/README %dir %{_sysconfdir}/cloud/templates %config(noreplace) %{_sysconfdir}/cloud/templates/* %{_unitdir}/cloud-config.service @@ -246,8 +227,6 @@ fi %{_mandir}/man1/* %dir %verify(not mode) /run/cloud-init %dir /var/lib/cloud -/etc/NetworkManager/dispatcher.d/cloud-init-azure-hook -/etc/dhcp/dhclient-exit-hooks.d/hook-dhclient %{_udevrulesdir}/66-azure-ephemeral.rules %{_datadir}/bash-completion/completions/cloud-init %{_bindir}/cloud-id @@ -258,6 +237,37 @@ fi %config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf %changelog +* Mon Feb 26 2024 Miroslav Rezanina - 23.4-6 +- ci-fix-Add-types-to-network-v1-schema-4841.patch [RHEL-21324] +- Resolves: RHEL-21324 + ([rhel-9] The schema WARNING info for network-config.json is not suitable in cloud-init-23.4) + +* Mon Feb 19 2024 Miroslav Rezanina - 23.4-5 +- ci-Revert-Use-grep-for-faster-parsing-of-cloud-config-i.patch [RHEL-22255] +- Resolves: RHEL-22255 + ([Azure][RHEL-9] cloud-init-23.4 cannot read "- Azure" datasource_list format) + +* Mon Jan 29 2024 Camilla Conte - 23.4-4 +- 0008-fix-clean-stop-warning-when-running-clean-command-47.patch [RHEL-21531] +- Resolves: RHEL-21531 + +* Wed Jan 17 2024 Camilla Conte - 23.4-3 +- 0004-net-network_manager-do-not-set-may-fail-to-False-for.patch [RHEL-21629] +- 0005-net-allow-dhcp6-configuration-from-generate_fallback.patch [RHEL-21629] +- Resolves: RHEL-21629 +- 0006-net-nm-check-for-presence-of-ifcfg-files-when-nm-con.patch [RHEL-17609] +- Resolves: RHEL-17609 +- 0007-test-jsonschema-Pin-jsonschema-version-4781.patch + +* Wed Jan 10 2024 Camilla Conte - 23.4-2 +- 0003-Setting-autoconnect-priority-setting-for-network-scr.patch [RHEL-18313] +- Resolves: RHEL-18313 + +* Fri Sep 15 2023 Camilla Conte - 23.1.1-12 +- Resolves: RHEL-2323 +- 0031-net-fix-ipv6_dhcpv6_stateful-stateless-slaac-configu.patch [bz#2227767] +- Resolves: bz#2227767 + * Thu Aug 17 2023 Miroslav Rezanina - 23.1.1-11 - Resolves: bz#2232296