From fb9276ff27a8f09685feca2d3fadb17e80c71a1a Mon Sep 17 00:00:00 2001 From: Camilla Conte Date: Thu, 30 Mar 2023 12:02:04 +0000 Subject: [PATCH] * Thu Mar 30 2023 Camilla Conte - 23.1.1-1 - Rebase to 23.1.1 [bz#2172811] - Resolves: bz#2172811 --- 0001-Add-initial-redhat-changes.patch | 647 +---- ...CONTROLLED-no-in-generated-interface.patch | 71 +- ...v-to-the-default-mount-configuration.patch | 42 - ...autoconnect-priority-for-network-scr.patch | 14 +- ...04-limit-permissions-on-def_log_file.patch | 31 +- ...e-Network-Manager-and-Netplan-as-def.patch | 95 + ...d-native-NetworkManager-support-1224.patch | 1073 +------- ...emove-ssh_genkeytypes-in-settings.py.patch | 65 - README.rst | 18 - ...d-native-NetworkManager-support-1224.patch | 2299 ----------------- ...rhel-custom-files-with-upstream-1431.patch | 256 -- ...-to-resize-encrypted-partitions-1316.patch | 516 ---- ...eady-before-cloud-init-service-runs-.patch | 36 - ci-Honor-system-locale-for-RHEL-1355.patch | 135 - ci-Remove-rhel-specific-files.patch | 370 --- ...tting-highest-autoconnect-priority-f.patch | 37 - ...ighest-autoconnect-priority-for-netw.patch | 37 - ...rk-Manager-and-Netplan-as-default-re.patch | 75 - ...t-EC2-tags-in-instance-metadata-1309.patch | 165 -- ...ger-and-Netplan-as-default-renderers.patch | 109 - ...do-not-write-localhost-when-no-hostn.patch | 801 ------ ...ignore-var-lib-cloud-data-set-hostna.patch | 77 - ...ake-sure-centos-settings-are-identic.patch | 139 - ...-adjust-udev-rules-default-path-1513.patch | 57 - cloud-init.spec | 63 +- sources | 2 +- 26 files changed, 310 insertions(+), 6920 deletions(-) delete mode 100644 0003-Adding-_netdev-to-the-default-mount-configuration.patch rename 0004-Setting-highest-autoconnect-priority-for-network-scr.patch => 0003-Setting-highest-autoconnect-priority-for-network-scr.patch (80%) rename 0005-limit-permissions-on-def_log_file.patch => 0004-limit-permissions-on-def_log_file.patch (75%) create mode 100644 0005-Manual-revert-Use-Network-Manager-and-Netplan-as-def.patch rename ci-Revert-Add-native-NetworkManager-support-1224.patch => 0006-Revert-Add-native-NetworkManager-support-1224.patch (60%) delete mode 100644 0006-rhel-cloud.cfg-remove-ssh_genkeytypes-in-settings.py.patch delete mode 100644 README.rst delete mode 100644 ci-Add-native-NetworkManager-support-1224.patch delete mode 100644 ci-Align-rhel-custom-files-with-upstream-1431.patch delete mode 100644 ci-Allow-growpart-to-resize-encrypted-partitions-1316.patch delete mode 100644 ci-Ensure-network-ready-before-cloud-init-service-runs-.patch delete mode 100644 ci-Honor-system-locale-for-RHEL-1355.patch delete mode 100644 ci-Remove-rhel-specific-files.patch delete mode 100644 ci-Revert-Revert-Setting-highest-autoconnect-priority-f.patch delete mode 100644 ci-Revert-Setting-highest-autoconnect-priority-for-netw.patch delete mode 100644 ci-Revert-Use-Network-Manager-and-Netplan-as-default-re.patch delete mode 100644 ci-Support-EC2-tags-in-instance-metadata-1309.patch delete mode 100644 ci-Use-Network-Manager-and-Netplan-as-default-renderers.patch delete mode 100644 ci-cc_set_hostname-do-not-write-localhost-when-no-hostn.patch delete mode 100644 ci-cc_set_hostname-ignore-var-lib-cloud-data-set-hostna.patch delete mode 100644 ci-cloud.cfg.tmpl-make-sure-centos-settings-are-identic.patch delete mode 100644 ci-setup.py-adjust-udev-rules-default-path-1513.patch diff --git a/0001-Add-initial-redhat-changes.patch b/0001-Add-initial-redhat-changes.patch index d9ae844..9ba25e6 100644 --- a/0001-Add-initial-redhat-changes.patch +++ b/0001-Add-initial-redhat-changes.patch @@ -1,621 +1,64 @@ -From 7daf47d1ee60a132244f2a9ec4e89ad496c32c3e Mon Sep 17 00:00:00 2001 +From c4d66915520554adedff9be7396f877cd1a5525c Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito -Date: Mon, 28 Mar 2022 14:08:05 +0200 -Subject: Add initial redhat setup +Date: Mon, 6 Mar 2023 16:37:20 +0100 +Subject: [PATCH 1/6] Add initial redhat changes -Merged patches (22.1): -- 70f80f82 Use _systemdgeneratordir macro for cloud-init-generator handling -- 0f74e7b8 Add dhcp-client as a dependency -- 791eb2b6 Report full specific version with "cloud-init --version" -- 865805d6 source-git: Use dynamic SRPM_NAME -- 45ddc666 add the drop-in also in the %files section of cloud-init.spec -- 08d939b2 Add gdisk and openssl as deps to fix UEFI / Azure initialization -- 0531cd68 Add netifaces package as a Requires in cloud-init.spec.template +Adding minimal set of changes necessary for successful build of the package +on RHEL/CentOS 9 Stream koji. + +Merged patches (23.1.1): +724a80ac Add TargetRelease +967a4405b rhel/cloud.cfg: remove ssh_genkeytypes in settings.py and set in cloud.cfg +^ Merged since it removes hunks added in this commit itself + +Discarded because not needed anymore (packit): +e3fd7ce12 Configure Packit to ignore the .gitignore file +e18654e9 Fixes for packit support + +Discarded because file does not exist anymore and templates are aligned with upstream: +3576b12460bf18557857ee25df6bf530dab66612 Adding _netdev to the default mount configuration +8092b57ab245856ff1fdde1469960608a489c95e Remove rhel specific files + +Added the following entry to %files to keep track of the new README file in config/clean.d/README +%doc %{_sysconfdir}/cloud/clean.d/README + +ignored +c75e509b0 Revert "Revert "Setting highest autoconnect priority for network-scripts"" +0eba5c619 Revert "Setting highest autoconnect priority for network-scripts" + +ignored +ba19343c0d9807d0c68a2d8e4ab274f3ca884247 Add Gitlab CI +fe09305a5479a4814d6c46df07a906bafa29d637 Delete .gitlab-ci.yml Conflicts: -- .gitignore -- cloudinit/config/cc_chef.py = use double quotes instead of single quotes -- cloudinit/settings.py = use rhel settings -- cloudinit/sources/DataSourceAzure.py = remove temporary_hostname and helper -- requirements.txt = just add netifaces and not jsonschema dep -- setup.py = use double quotes instead of single quotes +missing rhel/ static files and "" instead of '' in setup.py Signed-off-by: Emanuele Giuseppe Esposito - -Merged patches (RHEL-9/21.1): -- 5688a1d0 Removing python-nose and python-tox as dependency -- 237d57f9 Removing mock dependency -- d1c2f496 Removing python-jsonschema dependency -- 0d1cd14c Don't override default network configuration - -Merged patches (21.1): -- 915d30ad Change gating file to correct rhel version -- 311f318d Removing net-tools dependency -- 74731806 Adding man pages to Red Hat spec file -- 758d333d Removing blocking test from yaml configuration file -- c7e7c59c Changing permission of cloud-init-generator to 755 -- 8b85abbb Installing man pages in the correct place with correct permissions -- c6808d8d Fix unit failure of cloud-final.service if NetworkManager was not present. -- 11866ef6 Report full specific version with "cloud-init --version" - -Rebase notes (18.5): -- added bash_completition file -- added cloud-id file - -Merged patches (20.3): -- 01900d0 changing ds-identify patch from /usr/lib to /usr/libexec -- 7f47ca3 Render the generator from template instead of cp - -Merged patches (19.4): -- 4ab5a61 Fix for network configuration not persisting after reboot -- 84cf125 Removing cloud-user from wheel -- 31290ab Adding gating tests for Azure, ESXi and AWS - -Merged patches (18.5): -- 2d6b469 add power-state-change module to cloud_final_modules -- 764159f Adding systemd mount options to wait for cloud-init -- da4d99e Adding disk_setup to rhel/cloud.cfg -- f5c6832 Enable cloud-init by default on vmware - -Conflicts: -cloudinit/config/cc_chef.py: -- Updated header documentation text -- Replacing double quotes by simple quotes - -setup.py: -- Adding missing cmdclass info - -Signed-off-by: Eduardo Otubo - -Changes: -- move redhat to .distro to use new build script structure -- Fixing changelog for RHEL 9 - -Merged patches (21.1): -- 69bd7f71 DataSourceAzure.py: use hostnamectl to set hostname -- 0407867e Remove race condition between cloud-init and NetworkManager - -Signed-off-by: Miroslav Rezanina --- - .distro/.gitignore | 1 + - .distro/Makefile | 74 ++++ - .distro/Makefile.common | 20 + - .distro/cloud-init-tmpfiles.conf | 1 + - .distro/cloud-init.spec.template | 505 ++++++++++++++++++++++++++ - .distro/gating.yaml | 8 + - .distro/rpmbuild/BUILD/.gitignore | 3 + - .distro/rpmbuild/RPMS/.gitignore | 3 + - .distro/rpmbuild/SOURCES/.gitignore | 3 + - .distro/rpmbuild/SPECS/.gitignore | 3 + - .distro/rpmbuild/SRPMS/.gitignore | 3 + - .distro/scripts/frh.py | 27 ++ - .distro/scripts/git-backport-diff | 327 +++++++++++++++++ - .distro/scripts/git-compile-check | 215 +++++++++++ - .distro/scripts/process-patches.sh | 88 +++++ - .distro/scripts/tarball_checksum.sh | 3 + - .gitignore | 1 + - cloudinit/config/cc_chef.py | 65 +++- - cloudinit/settings.py | 21 +- - requirements.txt | 3 - - rhel/README.rhel | 5 + - rhel/cloud-init-tmpfiles.conf | 1 + - rhel/cloud.cfg | 69 ++++ - rhel/systemd/cloud-config.service | 18 + - rhel/systemd/cloud-config.target | 11 + - rhel/systemd/cloud-final.service | 24 ++ - rhel/systemd/cloud-init-local.service | 31 ++ - rhel/systemd/cloud-init.service | 26 ++ - rhel/systemd/cloud-init.target | 7 + - setup.py | 28 +- - tools/read-version | 28 +- - 31 files changed, 1557 insertions(+), 65 deletions(-) - create mode 100644 .distro/.gitignore - create mode 100644 .distro/Makefile - create mode 100644 .distro/Makefile.common - create mode 100644 .distro/cloud-init-tmpfiles.conf - create mode 100644 .distro/cloud-init.spec.template - create mode 100644 .distro/gating.yaml - create mode 100644 .distro/rpmbuild/BUILD/.gitignore - create mode 100644 .distro/rpmbuild/RPMS/.gitignore - create mode 100644 .distro/rpmbuild/SOURCES/.gitignore - create mode 100644 .distro/rpmbuild/SPECS/.gitignore - create mode 100644 .distro/rpmbuild/SRPMS/.gitignore - create mode 100755 .distro/scripts/frh.py - create mode 100755 .distro/scripts/git-backport-diff - create mode 100755 .distro/scripts/git-compile-check - create mode 100755 .distro/scripts/process-patches.sh - create mode 100755 .distro/scripts/tarball_checksum.sh - create mode 100644 rhel/README.rhel - create mode 100644 rhel/cloud-init-tmpfiles.conf - create mode 100644 rhel/cloud.cfg - create mode 100644 rhel/systemd/cloud-config.service - create mode 100644 rhel/systemd/cloud-config.target - create mode 100644 rhel/systemd/cloud-final.service - create mode 100644 rhel/systemd/cloud-init-local.service - create mode 100644 rhel/systemd/cloud-init.service - create mode 100644 rhel/systemd/cloud-init.target + cloudinit/settings.py | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) -diff --git a/cloudinit/config/cc_chef.py b/cloudinit/config/cc_chef.py -index fdb3a6e3..d028c548 100644 ---- a/cloudinit/config/cc_chef.py -+++ b/cloudinit/config/cc_chef.py -@@ -6,7 +6,70 @@ - # - # This file is part of cloud-init. See LICENSE file for license information. - --"""Chef: module that configures, starts and installs chef.""" -+""" -+Chef -+---- -+**Summary:** module that configures, starts and installs chef. -+ -+This module enables chef to be installed (from packages or -+from gems, or from omnibus). Before this occurs chef configurations are -+written to disk (validation.pem, client.pem, firstboot.json, client.rb), -+and needed chef folders/directories are created (/etc/chef and /var/log/chef -+and so-on). Then once installing proceeds correctly if configured chef will -+be started (in daemon mode or in non-daemon mode) and then once that has -+finished (if ran in non-daemon mode this will be when chef finishes -+converging, if ran in daemon mode then no further actions are possible since -+chef will have forked into its own process) then a post run function can -+run that can do finishing activities (such as removing the validation pem -+file). -+ -+**Internal name:** ``cc_chef`` -+ -+**Module frequency:** per always -+ -+**Supported distros:** all -+ -+**Config keys**:: -+ -+ chef: -+ directories: (defaulting to /etc/chef, /var/log/chef, /var/lib/chef, -+ /var/cache/chef, /var/backups/chef, /run/chef) -+ validation_cert: (optional string to be written to file validation_key) -+ special value 'system' means set use existing file -+ validation_key: (optional the path for validation_cert. default -+ /etc/chef/validation.pem) -+ firstboot_path: (path to write run_list and initial_attributes keys that -+ should also be present in this configuration, defaults -+ to /etc/chef/firstboot.json) -+ exec: boolean to run or not run chef (defaults to false, unless -+ a gem installed is requested -+ where this will then default -+ to true) -+ -+ chef.rb template keys (if falsey, then will be skipped and not -+ written to /etc/chef/client.rb) -+ -+ chef: -+ client_key: -+ encrypted_data_bag_secret: -+ environment: -+ file_backup_path: -+ file_cache_path: -+ json_attribs: -+ log_level: -+ log_location: -+ node_name: -+ omnibus_url: -+ omnibus_url_retries: -+ omnibus_version: -+ pid_file: -+ server_url: -+ show_time: -+ ssl_verify_mode: -+ validation_cert: -+ validation_key: -+ validation_name: -+""" - - import itertools - import json diff --git a/cloudinit/settings.py b/cloudinit/settings.py -index ecc1403b..a780e21e 100644 +index 8684d0039..edbb217d3 100644 --- a/cloudinit/settings.py +++ b/cloudinit/settings.py -@@ -48,16 +48,19 @@ CFG_BUILTIN = { - # At the end to act as a 'catch' when none of the above work... - "None", +@@ -53,13 +53,14 @@ CFG_BUILTIN = { ], -- "def_log_file": "/var/log/cloud-init.log", -- "log_cfgs": [], + "def_log_file": "/var/log/cloud-init.log", + "log_cfgs": [], - "syslog_fix_perms": ["syslog:adm", "root:adm", "root:wheel", "root:root"], -- "system_info": { -- "paths": { -- "cloud_dir": "/var/lib/cloud", -- "templates_dir": "/etc/cloud/templates/", -+ 'def_log_file': '/var/log/cloud-init.log', -+ 'log_cfgs': [], -+ 'mount_default_fields': [None, None, 'auto', 'defaults,nofail', '0', '2'], -+ 'ssh_deletekeys': False, -+ 'ssh_genkeytypes': [], -+ 'syslog_fix_perms': [], -+ 'system_info': { -+ 'paths': { -+ 'cloud_dir': '/var/lib/cloud', -+ 'templates_dir': '/etc/cloud/templates/', ++ "mount_default_fields": [None, None, "auto", "defaults,nofail", "0", "2"], ++ "syslog_fix_perms": [], + "system_info": { + "paths": { + "cloud_dir": "/var/lib/cloud", + "templates_dir": "/etc/cloud/templates/", }, - "distro": "ubuntu", -- "network": {"renderers": None}, -+ 'distro': 'rhel', -+ 'network': {'renderers': None}, ++ "distro": "rhel", + "network": {"renderers": None}, }, "vendor_data": {"enabled": True, "prefix": []}, - "vendor_data2": {"enabled": True, "prefix": []}, -diff --git a/requirements.txt b/requirements.txt -index c4adc455..f77f1d73 100644 ---- a/requirements.txt -+++ b/requirements.txt -@@ -30,9 +30,6 @@ requests - # For patching pieces of cloud-config together - jsonpatch - --# For validating cloud-config sections per schema definitions --jsonschema -- - # Used by DataSourceVMware to inspect the host's network configuration during - # the "setup()" function. - # -diff --git a/rhel/README.rhel b/rhel/README.rhel -new file mode 100644 -index 00000000..aa29630d ---- /dev/null -+++ b/rhel/README.rhel -@@ -0,0 +1,5 @@ -+The following cloud-init modules are currently unsupported on this OS: -+ - apt_update_upgrade ('apt_update', 'apt_upgrade', 'apt_mirror', 'apt_preserve_sources_list', 'apt_old_mirror', 'apt_sources', 'debconf_selections', 'packages' options) -+ - byobu ('byobu_by_default' option) -+ - chef -+ - grub_dpkg -diff --git a/rhel/cloud-init-tmpfiles.conf b/rhel/cloud-init-tmpfiles.conf -new file mode 100644 -index 00000000..0c6d2a3b ---- /dev/null -+++ b/rhel/cloud-init-tmpfiles.conf -@@ -0,0 +1 @@ -+d /run/cloud-init 0700 root root - - -diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg -new file mode 100644 -index 00000000..9ecba215 ---- /dev/null -+++ b/rhel/cloud.cfg -@@ -0,0 +1,69 @@ -+users: -+ - default -+ -+disable_root: 1 -+ssh_pwauth: 0 -+ -+mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service', '0', '2'] -+resize_rootfs_tmp: /dev -+ssh_deletekeys: 1 -+ssh_genkeytypes: ~ -+syslog_fix_perms: ~ -+disable_vmware_customization: false -+ -+cloud_init_modules: -+ - disk_setup -+ - migrator -+ - bootcmd -+ - write-files -+ - growpart -+ - resizefs -+ - set_hostname -+ - update_hostname -+ - update_etc_hosts -+ - rsyslog -+ - users-groups -+ - ssh -+ -+cloud_config_modules: -+ - mounts -+ - locale -+ - set-passwords -+ - rh_subscription -+ - yum-add-repo -+ - package-update-upgrade-install -+ - timezone -+ - puppet -+ - chef -+ - salt-minion -+ - mcollective -+ - disable-ec2-metadata -+ - runcmd -+ -+cloud_final_modules: -+ - rightscale_userdata -+ - scripts-per-once -+ - scripts-per-boot -+ - scripts-per-instance -+ - scripts-user -+ - ssh-authkey-fingerprints -+ - keys-to-console -+ - phone-home -+ - final-message -+ - power-state-change -+ -+system_info: -+ default_user: -+ name: cloud-user -+ lock_passwd: true -+ gecos: Cloud User -+ groups: [adm, systemd-journal] -+ sudo: ["ALL=(ALL) NOPASSWD:ALL"] -+ shell: /bin/bash -+ distro: rhel -+ paths: -+ cloud_dir: /var/lib/cloud -+ templates_dir: /etc/cloud/templates -+ ssh_svcname: sshd -+ -+# vim:syntax=yaml -diff --git a/rhel/systemd/cloud-config.service b/rhel/systemd/cloud-config.service -new file mode 100644 -index 00000000..f3dcd4be ---- /dev/null -+++ b/rhel/systemd/cloud-config.service -@@ -0,0 +1,18 @@ -+[Unit] -+Description=Apply the settings specified in cloud-config -+After=network-online.target cloud-config.target -+Wants=network-online.target cloud-config.target -+ConditionPathExists=!/etc/cloud/cloud-init.disabled -+ConditionKernelCommandLine=!cloud-init=disabled -+ -+[Service] -+Type=oneshot -+ExecStart=/usr/bin/cloud-init modules --mode=config -+RemainAfterExit=yes -+TimeoutSec=0 -+ -+# Output needs to appear in instance console output -+StandardOutput=journal+console -+ -+[Install] -+WantedBy=cloud-init.target -diff --git a/rhel/systemd/cloud-config.target b/rhel/systemd/cloud-config.target -new file mode 100644 -index 00000000..ae9b7d02 ---- /dev/null -+++ b/rhel/systemd/cloud-config.target -@@ -0,0 +1,11 @@ -+# cloud-init normally emits a "cloud-config" upstart event to inform third -+# parties that cloud-config is available, which does us no good when we're -+# using systemd. cloud-config.target serves as this synchronization point -+# instead. Services that would "start on cloud-config" with upstart can -+# instead use "After=cloud-config.target" and "Wants=cloud-config.target" -+# as appropriate. -+ -+[Unit] -+Description=Cloud-config availability -+Wants=cloud-init-local.service cloud-init.service -+After=cloud-init-local.service cloud-init.service -diff --git a/rhel/systemd/cloud-final.service b/rhel/systemd/cloud-final.service -new file mode 100644 -index 00000000..e281c0cf ---- /dev/null -+++ b/rhel/systemd/cloud-final.service -@@ -0,0 +1,24 @@ -+[Unit] -+Description=Execute cloud user/final scripts -+After=network-online.target cloud-config.service rc-local.service -+Wants=network-online.target cloud-config.service -+ConditionPathExists=!/etc/cloud/cloud-init.disabled -+ConditionKernelCommandLine=!cloud-init=disabled -+ -+[Service] -+Type=oneshot -+ExecStart=/usr/bin/cloud-init modules --mode=final -+RemainAfterExit=yes -+TimeoutSec=0 -+KillMode=process -+# Restart NetworkManager if it is present and running. -+ExecStartPost=/bin/sh -c 'u=NetworkManager.service; \ -+ out=$(systemctl show --property=SubState $u) || exit; \ -+ [ "$out" = "SubState=running" ] || exit 0; \ -+ systemctl reload-or-try-restart $u' -+ -+# Output needs to appear in instance console output -+StandardOutput=journal+console -+ -+[Install] -+WantedBy=cloud-init.target -diff --git a/rhel/systemd/cloud-init-local.service b/rhel/systemd/cloud-init-local.service -new file mode 100644 -index 00000000..8f9f6c9f ---- /dev/null -+++ b/rhel/systemd/cloud-init-local.service -@@ -0,0 +1,31 @@ -+[Unit] -+Description=Initial cloud-init job (pre-networking) -+DefaultDependencies=no -+Wants=network-pre.target -+After=systemd-remount-fs.service -+Requires=dbus.socket -+After=dbus.socket -+Before=NetworkManager.service network.service -+Before=network-pre.target -+Before=shutdown.target -+Before=firewalld.target -+Conflicts=shutdown.target -+RequiresMountsFor=/var/lib/cloud -+ConditionPathExists=!/etc/cloud/cloud-init.disabled -+ConditionKernelCommandLine=!cloud-init=disabled -+ -+[Service] -+Type=oneshot -+ExecStartPre=/bin/mkdir -p /run/cloud-init -+ExecStartPre=/sbin/restorecon /run/cloud-init -+ExecStartPre=/usr/bin/touch /run/cloud-init/enabled -+ExecStart=/usr/bin/cloud-init init --local -+ExecStart=/bin/touch /run/cloud-init/network-config-ready -+RemainAfterExit=yes -+TimeoutSec=0 -+ -+# Output needs to appear in instance console output -+StandardOutput=journal+console -+ -+[Install] -+WantedBy=cloud-init.target -diff --git a/rhel/systemd/cloud-init.service b/rhel/systemd/cloud-init.service -new file mode 100644 -index 00000000..0b3d796d ---- /dev/null -+++ b/rhel/systemd/cloud-init.service -@@ -0,0 +1,26 @@ -+[Unit] -+Description=Initial cloud-init job (metadata service crawler) -+Wants=cloud-init-local.service -+Wants=sshd-keygen.service -+Wants=sshd.service -+After=cloud-init-local.service -+After=NetworkManager.service network.service -+After=NetworkManager-wait-online.service -+Before=network-online.target -+Before=sshd-keygen.service -+Before=sshd.service -+Before=systemd-user-sessions.service -+ConditionPathExists=!/etc/cloud/cloud-init.disabled -+ConditionKernelCommandLine=!cloud-init=disabled -+ -+[Service] -+Type=oneshot -+ExecStart=/usr/bin/cloud-init init -+RemainAfterExit=yes -+TimeoutSec=0 -+ -+# Output needs to appear in instance console output -+StandardOutput=journal+console -+ -+[Install] -+WantedBy=cloud-init.target -diff --git a/rhel/systemd/cloud-init.target b/rhel/systemd/cloud-init.target -new file mode 100644 -index 00000000..083c3b6f ---- /dev/null -+++ b/rhel/systemd/cloud-init.target -@@ -0,0 +1,7 @@ -+# cloud-init target is enabled by cloud-init-generator -+# To disable it you can either: -+# a.) boot with kernel cmdline of 'cloud-init=disabled' -+# b.) touch a file /etc/cloud/cloud-init.disabled -+[Unit] -+Description=Cloud-init target -+After=multi-user.target -diff --git a/setup.py b/setup.py -index a9132d2c..3c377eaa 100755 ---- a/setup.py -+++ b/setup.py -@@ -139,21 +139,6 @@ INITSYS_FILES = { - "sysvinit_deb": [f for f in glob("sysvinit/debian/*") if is_f(f)], - "sysvinit_openrc": [f for f in glob("sysvinit/gentoo/*") if is_f(f)], - "sysvinit_suse": [f for f in glob("sysvinit/suse/*") if is_f(f)], -- "systemd": [ -- render_tmpl(f) -- for f in ( -- glob("systemd/*.tmpl") -- + glob("systemd/*.service") -- + glob("systemd/*.socket") -- + glob("systemd/*.target") -- ) -- if (is_f(f) and not is_generator(f)) -- ], -- "systemd.generators": [ -- render_tmpl(f, mode=0o755) -- for f in glob("systemd/*") -- if is_f(f) and is_generator(f) -- ], - "upstart": [f for f in glob("upstart/*") if is_f(f)], - } - INITSYS_ROOTS = { -@@ -163,10 +148,6 @@ INITSYS_ROOTS = { - "sysvinit_deb": "etc/init.d", - "sysvinit_openrc": "etc/init.d", - "sysvinit_suse": "etc/init.d", -- "systemd": pkg_config_read("systemd", "systemdsystemunitdir"), -- "systemd.generators": pkg_config_read( -- "systemd", "systemdsystemgeneratordir" -- ), - "upstart": "etc/init/", - } - INITSYS_TYPES = sorted([f.partition(".")[0] for f in INITSYS_ROOTS.keys()]) -@@ -281,15 +262,13 @@ data_files = [ - ( - USR_LIB_EXEC + "/cloud-init", - [ -- "tools/ds-identify", - "tools/hook-hotplug", - "tools/uncloud-init", - "tools/write-ssh-key-fingerprints", - ], - ), - ( -- USR + "/share/bash-completion/completions", -- ["bash_completion/cloud-init"], -+ ETC + "/bash_completion.d", ["bash_completion/cloud-init"], - ), - (USR + "/share/doc/cloud-init", [f for f in glob("doc/*") if is_f(f)]), - ( -@@ -308,8 +287,7 @@ if not platform.system().endswith("BSD"): - ETC + "/NetworkManager/dispatcher.d/", - ["tools/hook-network-manager"], - ), -- (ETC + "/dhcp/dhclient-exit-hooks.d/", ["tools/hook-dhclient"]), -- (LIB + "/udev/rules.d", [f for f in glob("udev/*.rules")]), -+ ("/usr/lib/udev/rules.d", [f for f in glob("udev/*.rules")]), - ( - ETC + "/systemd/system/sshd-keygen@.service.d/", - ["systemd/disable-sshd-keygen-if-cloud-init-active.conf"], -@@ -339,8 +317,6 @@ setuptools.setup( - scripts=["tools/cloud-init-per"], - license="Dual-licensed under GPLv3 or Apache 2.0", - data_files=data_files, -- install_requires=requirements, -- cmdclass=cmdclass, - entry_points={ - "console_scripts": [ - "cloud-init = cloudinit.cmd.main:main", -diff --git a/tools/read-version b/tools/read-version -index 02c90643..79755f78 100755 ---- a/tools/read-version -+++ b/tools/read-version -@@ -71,32 +71,8 @@ version_long = None - is_release_branch_ci = ( - os.environ.get("TRAVIS_PULL_REQUEST_BRANCH", "").startswith("upstream/") - ) --if is_gitdir(_tdir) and which("git") and not is_release_branch_ci: -- flags = [] -- if use_tags: -- flags = ['--tags'] -- cmd = ['git', 'describe', '--abbrev=8', '--match=[0-9]*'] + flags -- -- try: -- version = tiny_p(cmd).strip() -- except RuntimeError: -- version = None -- -- if version is None or not version.startswith(src_version): -- sys.stderr.write("git describe version (%s) differs from " -- "cloudinit.version (%s)\n" % (version, src_version)) -- sys.stderr.write( -- "Please get the latest upstream tags.\n" -- "As an example, this can be done with the following:\n" -- "$ git remote add upstream https://git.launchpad.net/cloud-init\n" -- "$ git fetch upstream --tags\n" -- ) -- sys.exit(1) -- -- version_long = tiny_p(cmd + ["--long"]).strip() --else: -- version = src_version -- version_long = None -+version = src_version -+version_long = None - - # version is X.Y.Z[+xxx.gHASH] - # version_long is None or X.Y.Z-xxx-gHASH -- -2.31.1 +2.39.2 diff --git a/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch b/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch index a686f6d..8b4d554 100644 --- a/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch +++ b/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch @@ -1,7 +1,8 @@ -From c521ec2ce5b1d9a7322ce152011b8792f121bf5c Mon Sep 17 00:00:00 2001 +From b3b96bff187e9d0bfcbfefd5fca05c61bd50d368 Mon Sep 17 00:00:00 2001 From: Eduardo Otubo Date: Fri, 7 May 2021 13:36:06 +0200 -Subject: Do not write NM_CONTROLLED=no in generated interface config files +Subject: [PATCH 2/6] Do not write NM_CONTROLLED=no in generated interface + config files Conflicts 20.3: - Not appplying patch on cloudinit/net/sysconfig.py since it now has a @@ -20,10 +21,10 @@ Signed-off-by: Ryan McCabe 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index ba85c4f6..d8c53312 100644 +index d4daa78f0..a7dbe55b4 100644 --- a/cloudinit/net/sysconfig.py +++ b/cloudinit/net/sysconfig.py -@@ -336,7 +336,6 @@ class Renderer(renderer.Renderer): +@@ -316,7 +316,6 @@ class Renderer(renderer.Renderer): "rhel": { "ONBOOT": True, "USERCTL": False, @@ -31,7 +32,7 @@ index ba85c4f6..d8c53312 100644 "BOOTPROTO": "none", }, "suse": {"BOOTPROTO": "static", "STARTMODE": "auto"}, -@@ -1039,7 +1038,16 @@ class Renderer(renderer.Renderer): +@@ -1019,7 +1018,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)) @@ -50,10 +51,10 @@ index ba85c4f6..d8c53312 100644 netcfg.append("NETWORKING_IPV6=yes") netcfg.append("IPV6_AUTOCONF=no") diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index 47e4ba00..591241b3 100644 +index 056aaeb6f..0f523ff84 100644 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py -@@ -579,7 +579,6 @@ GATEWAY=172.19.3.254 +@@ -585,7 +585,6 @@ GATEWAY=172.19.3.254 HWADDR=fa:16:3e:ed:9a:59 IPADDR=172.19.1.34 NETMASK=255.255.252.0 @@ -61,7 +62,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -712,7 +711,6 @@ IPADDR=172.19.1.34 +@@ -749,7 +748,6 @@ IPADDR=172.19.1.34 IPADDR1=10.0.0.10 NETMASK=255.255.252.0 NETMASK1=255.255.255.0 @@ -69,7 +70,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -874,7 +872,6 @@ IPV6_AUTOCONF=no +@@ -911,7 +909,6 @@ IPV6_AUTOCONF=no IPV6_DEFAULTGW=2001:DB8::1 IPV6_FORCE_ACCEPT_RA=no NETMASK=255.255.252.0 @@ -77,7 +78,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -1053,7 +1050,6 @@ NETWORK_CONFIGS = { +@@ -1090,7 +1087,6 @@ NETWORK_CONFIGS = { BOOTPROTO=none DEVICE=eth1 HWADDR=cf:d6:af:48:e8:80 @@ -85,7 +86,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -1072,7 +1068,6 @@ NETWORK_CONFIGS = { +@@ -1109,7 +1105,6 @@ NETWORK_CONFIGS = { IPADDR=192.168.21.3 NETMASK=255.255.255.0 METRIC=10000 @@ -93,7 +94,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -1244,7 +1239,6 @@ NETWORK_CONFIGS = { +@@ -1353,7 +1348,6 @@ NETWORK_CONFIGS = { IPV6_AUTOCONF=no IPV6_FORCE_ACCEPT_RA=no NETMASK=255.255.255.0 @@ -101,7 +102,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -2093,7 +2087,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2377,7 +2371,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 @@ -109,7 +110,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Bond USERCTL=no""" -@@ -2103,7 +2096,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2387,7 +2380,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 @@ -117,7 +118,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes PHYSDEV=bond0 USERCTL=no -@@ -2123,7 +2115,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2407,7 +2399,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 @@ -125,7 +126,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes PRIO=22 STP=no -@@ -2135,7 +2126,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2419,7 +2410,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 @@ -133,7 +134,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -2154,7 +2144,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2438,7 +2428,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 @@ -141,7 +142,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes PHYSDEV=eth0 USERCTL=no -@@ -2166,7 +2155,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2450,7 +2439,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 @@ -149,7 +150,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes SLAVE=yes TYPE=Ethernet -@@ -2178,7 +2166,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2462,7 +2450,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 @@ -157,7 +158,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes SLAVE=yes TYPE=Ethernet -@@ -2190,7 +2177,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2474,7 +2461,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 @@ -165,7 +166,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -2201,7 +2187,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2485,7 +2471,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 @@ -173,7 +174,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -2212,7 +2197,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true +@@ -2496,7 +2481,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 @@ -181,7 +182,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=no TYPE=Ethernet USERCTL=no""" -@@ -2689,7 +2673,6 @@ iface bond0 inet6 static +@@ -3220,7 +3204,6 @@ iface bond0 inet6 static MTU=9000 NETMASK=255.255.255.0 NETMASK1=255.255.255.0 @@ -189,7 +190,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Bond USERCTL=no -@@ -2701,7 +2684,6 @@ iface bond0 inet6 static +@@ -3232,7 +3215,6 @@ iface bond0 inet6 static DEVICE=bond0s0 HWADDR=aa:bb:cc:dd:e8:00 MASTER=bond0 @@ -197,7 +198,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes SLAVE=yes TYPE=Ethernet -@@ -2729,7 +2711,6 @@ iface bond0 inet6 static +@@ -3260,7 +3242,6 @@ iface bond0 inet6 static DEVICE=bond0s1 HWADDR=aa:bb:cc:dd:e8:01 MASTER=bond0 @@ -205,7 +206,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes SLAVE=yes TYPE=Ethernet -@@ -2794,7 +2775,6 @@ iface bond0 inet6 static +@@ -3406,7 +3387,6 @@ iface bond0 inet6 static BOOTPROTO=none DEVICE=en0 HWADDR=aa:bb:cc:dd:e8:00 @@ -213,7 +214,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no""" -@@ -2815,7 +2795,6 @@ iface bond0 inet6 static +@@ -3427,7 +3407,6 @@ iface bond0 inet6 static MTU=2222 NETMASK=255.255.255.0 NETMASK1=255.255.255.0 @@ -221,7 +222,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes PHYSDEV=en0 USERCTL=no -@@ -2890,7 +2869,6 @@ iface bond0 inet6 static +@@ -3553,7 +3532,6 @@ iface bond0 inet6 static DEVICE=br0 IPADDR=192.168.2.2 NETMASK=255.255.255.0 @@ -229,7 +230,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes PRIO=22 STP=no -@@ -3032,7 +3010,6 @@ iface bond0 inet6 static +@@ -3769,7 +3747,6 @@ iface bond0 inet6 static HWADDR=52:54:00:12:34:00 IPADDR=192.168.1.2 NETMASK=255.255.255.0 @@ -237,7 +238,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=no TYPE=Ethernet USERCTL=no -@@ -3044,7 +3021,6 @@ iface bond0 inet6 static +@@ -3781,7 +3758,6 @@ iface bond0 inet6 static DEVICE=eth1 HWADDR=52:54:00:12:34:aa MTU=1480 @@ -245,7 +246,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -3055,7 +3031,6 @@ iface bond0 inet6 static +@@ -3792,7 +3768,6 @@ iface bond0 inet6 static BOOTPROTO=none DEVICE=eth2 HWADDR=52:54:00:12:34:ff @@ -253,7 +254,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=no TYPE=Ethernet USERCTL=no -@@ -3628,7 +3603,6 @@ class TestRhelSysConfigRendering(CiTestCase): +@@ -4469,7 +4444,6 @@ class TestRhelSysConfigRendering(CiTestCase): BOOTPROTO=dhcp DEVICE=eth1000 HWADDR=07-1c-c6-75-a4-be @@ -261,7 +262,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -3840,7 +3814,6 @@ GATEWAY=10.0.2.2 +@@ -4681,7 +4655,6 @@ GATEWAY=10.0.2.2 HWADDR=52:54:00:12:34:00 IPADDR=10.0.2.15 NETMASK=255.255.255.0 @@ -269,7 +270,7 @@ index 47e4ba00..591241b3 100644 ONBOOT=yes TYPE=Ethernet USERCTL=no -@@ -3910,7 +3883,6 @@ USERCTL=no +@@ -4751,7 +4724,6 @@ USERCTL=no # BOOTPROTO=dhcp DEVICE=eth0 @@ -278,5 +279,5 @@ index 47e4ba00..591241b3 100644 TYPE=Ethernet USERCTL=no -- -2.31.1 +2.39.2 diff --git a/0003-Adding-_netdev-to-the-default-mount-configuration.patch b/0003-Adding-_netdev-to-the-default-mount-configuration.patch deleted file mode 100644 index 0f57fed..0000000 --- a/0003-Adding-_netdev-to-the-default-mount-configuration.patch +++ /dev/null @@ -1,42 +0,0 @@ -From b952fa472be3f417e0d857c8647a1b930624c247 Mon Sep 17 00:00:00 2001 -From: Eduardo Otubo -Date: Fri, 25 Feb 2022 05:05:17 -0500 -Subject: Adding _netdev to the default mount configuration - -RH-Author: Eduardo Otubo -RH-MergeRequest: 21: Adding _netdev to the default mount configuration -RH-Commit: [1/1] 250860a24db396a5088d207d6526a0028ac73eb3 (otubo/cloud-init-src) -RH-Bugzilla: 1998445 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Emanuele Giuseppe Esposito - -Adding _netdev option also to the default configuration for RHEL. - -rhbz: 1998445 -x-downstream-only: yes - -Signed-off-by: Eduardo Otubo - -patch_name: ci-Adding-_netdev-to-the-default-mount-configuration.patch -present_in_specfile: true -location_in_specfile: 29 ---- - rhel/cloud.cfg | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg -index 9ecba215..1ec1a6c6 100644 ---- a/rhel/cloud.cfg -+++ b/rhel/cloud.cfg -@@ -4,7 +4,7 @@ users: - disable_root: 1 - ssh_pwauth: 0 - --mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service', '0', '2'] -+mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service,_netdev', '0', '2'] - resize_rootfs_tmp: /dev - ssh_deletekeys: 1 - ssh_genkeytypes: ~ --- -2.31.1 - diff --git a/0004-Setting-highest-autoconnect-priority-for-network-scr.patch b/0003-Setting-highest-autoconnect-priority-for-network-scr.patch similarity index 80% rename from 0004-Setting-highest-autoconnect-priority-for-network-scr.patch rename to 0003-Setting-highest-autoconnect-priority-for-network-scr.patch index 690a02f..75327e6 100644 --- a/0004-Setting-highest-autoconnect-priority-for-network-scr.patch +++ b/0003-Setting-highest-autoconnect-priority-for-network-scr.patch @@ -1,7 +1,7 @@ -From a14df44ffdc880ae16c691901e2671458ab234ff Mon Sep 17 00:00:00 2001 +From c589da20eb92231ef08e10c9724e3e6c663e6ce2 Mon Sep 17 00:00:00 2001 From: Eduardo Otubo Date: Thu, 17 Feb 2022 15:32:35 +0100 -Subject: Setting highest autoconnect priority for network-scripts +Subject: [PATCH 3/6] Setting highest autoconnect priority for network-scripts RH-Author: Eduardo Otubo RH-MergeRequest: 22: Setting highest autoconnect priority for network-scripts @@ -24,19 +24,15 @@ rhbz: 2036060 x-downstream-only: yes Signed-off-by: Eduardo Otubo - -patch_name: ci-Setting-highest-autoconnect-priority-for-network-scr.patch -present_in_specfile: true -location_in_specfile: 30 --- cloudinit/net/sysconfig.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index d8c53312..b50035b5 100644 +index a7dbe55b4..4262cd489 100644 --- a/cloudinit/net/sysconfig.py +++ b/cloudinit/net/sysconfig.py -@@ -337,6 +337,7 @@ class Renderer(renderer.Renderer): +@@ -317,6 +317,7 @@ class Renderer(renderer.Renderer): "ONBOOT": True, "USERCTL": False, "BOOTPROTO": "none", @@ -45,5 +41,5 @@ index d8c53312..b50035b5 100644 "suse": {"BOOTPROTO": "static", "STARTMODE": "auto"}, } -- -2.31.1 +2.39.2 diff --git a/0005-limit-permissions-on-def_log_file.patch b/0004-limit-permissions-on-def_log_file.patch similarity index 75% rename from 0005-limit-permissions-on-def_log_file.patch rename to 0004-limit-permissions-on-def_log_file.patch index ed1072e..b2b76c6 100644 --- a/0005-limit-permissions-on-def_log_file.patch +++ b/0004-limit-permissions-on-def_log_file.patch @@ -1,7 +1,7 @@ -From 40ad855b883050069393b9c00db2a6d222d949db Mon Sep 17 00:00:00 2001 +From dfff374f66904e84fb07ca157ba010fac6b5f1de Mon Sep 17 00:00:00 2001 From: Eduardo Otubo Date: Fri, 7 May 2021 13:36:08 +0200 -Subject: limit permissions on def_log_file +Subject: [PATCH 4/6] 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. @@ -13,7 +13,10 @@ 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 + @@ -22,22 +25,22 @@ Signed-off-by: Eduardo Otubo 3 files changed, 6 insertions(+) diff --git a/cloudinit/settings.py b/cloudinit/settings.py -index a780e21e..aa2d6b95 100644 +index edbb217d3..3d5411412 100644 --- a/cloudinit/settings.py +++ b/cloudinit/settings.py -@@ -49,6 +49,7 @@ CFG_BUILTIN = { +@@ -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'], - 'ssh_deletekeys': False, + "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 3f17294b..61db1dbd 100644 +index 9494a0bfa..a624a6fb2 100644 --- a/cloudinit/stages.py +++ b/cloudinit/stages.py -@@ -205,6 +205,7 @@ class Init(object): +@@ -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") @@ -46,10 +49,10 @@ index 3f17294b..61db1dbd 100644 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 a2b4a3fa..0ccf3147 100644 +index 15d788f38..b6d16c9c3 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt -@@ -414,10 +414,14 @@ timezone: US/Eastern +@@ -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. # @@ -65,5 +68,5 @@ index a2b4a3fa..0ccf3147 100644 # you can set passwords for a user or multiple users -- -2.31.1 +2.39.2 diff --git a/0005-Manual-revert-Use-Network-Manager-and-Netplan-as-def.patch b/0005-Manual-revert-Use-Network-Manager-and-Netplan-as-def.patch new file mode 100644 index 0000000..f0aa07d --- /dev/null +++ b/0005-Manual-revert-Use-Network-Manager-and-Netplan-as-def.patch @@ -0,0 +1,95 @@ +From ecae81f98ce230266eb99671b74534a4ede660f0 Mon Sep 17 00:00:00 2001 +From: Emanuele Giuseppe Esposito +Date: Fri, 10 Mar 2023 11:51:48 +0100 +Subject: [PATCH 5/6] 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 fcf7febad..b241683f9 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 7238c1021..12f32c516 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 ea331f1cb..bc52afa5f 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 + =========================== +-- +2.39.2 + diff --git a/ci-Revert-Add-native-NetworkManager-support-1224.patch b/0006-Revert-Add-native-NetworkManager-support-1224.patch similarity index 60% rename from ci-Revert-Add-native-NetworkManager-support-1224.patch rename to 0006-Revert-Add-native-NetworkManager-support-1224.patch index 981473c..49a5926 100644 --- a/ci-Revert-Add-native-NetworkManager-support-1224.patch +++ b/0006-Revert-Add-native-NetworkManager-support-1224.patch @@ -1,38 +1,28 @@ -From 35bd50e66f636a3f3923b6980bdee3ba33f7457d Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Mon, 8 Aug 2022 10:01:16 +0200 -Subject: [PATCH 1/3] Revert "Add native NetworkManager support (#1224)" +From b1dd14ffafad2d2ca84326c525962b2ca086b292 Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Wed, 22 Mar 2023 16:31:58 +0530 +Subject: [PATCH 6/6] Revert "Add native NetworkManager support (#1224)" -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 31: Revert "Revert "Setting highest autoconnect priority for network-scripts"" -RH-Commit: [1/3] 38dcbc9ec19412601e96305fcac09642c89d73b8 (eesposit/cloud-init-centos-) -RH-Bugzilla: 2107463 2104389 2117532 2098501 -RH-Acked-by: Eduardo Otubo -RH-Acked-by: Vitaly Kuznetsov -RH-Acked-by: Mohamed Gamal Morsy +This reverts commit feda344e6cf9d37b09bc13cf333a717d1654c26c. -NM is still not stable, revert it for now. - -This reverts commit 588deeb5b3f87ffe40d9ecaf6da3639176f806c4. - -Signed-off-by: Emanuele Giuseppe Esposito +Signed-off-by: Ani Sinha --- - cloudinit/cmd/devel/net_convert.py | 14 +- - cloudinit/net/activators.py | 25 +- - cloudinit/net/network_manager.py | 377 ------- - cloudinit/net/renderers.py | 3 - - cloudinit/net/sysconfig.py | 37 +- - tests/unittests/test_net.py | 1268 +++--------------------- - tests/unittests/test_net_activators.py | 93 +- - 7 files changed, 193 insertions(+), 1624 deletions(-) + 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 647fe07b..18b1e7ff 100755 +index eee498601..1a0a31acf 100755 --- a/cloudinit/cmd/devel/net_convert.py +++ b/cloudinit/cmd/devel/net_convert.py -@@ -7,14 +7,7 @@ import os - import sys +@@ -10,14 +10,7 @@ import sys + import yaml from cloudinit import distros, log, safeyaml -from cloudinit.net import ( @@ -45,9 +35,9 @@ index 647fe07b..18b1e7ff 100755 -) +from cloudinit.net import eni, netplan, network_state, networkd, sysconfig from cloudinit.sources import DataSourceAzure as azure - from cloudinit.sources import DataSourceOVF as ovf from cloudinit.sources.helpers import openstack -@@ -81,7 +74,7 @@ def get_parser(parser=None): + from cloudinit.sources.helpers.vmware.imc import guestcust_util +@@ -84,7 +77,7 @@ def get_parser(parser=None): parser.add_argument( "-O", "--output-kind", @@ -56,7 +46,7 @@ index 647fe07b..18b1e7ff 100755 required=True, help="The network config format to emit", ) -@@ -155,9 +148,6 @@ def handle_args(name, args): +@@ -157,9 +150,6 @@ def handle_args(name, args): elif args.output_kind == "sysconfig": r_cls = sysconfig.Renderer config = distro.renderer_configs.get("sysconfig") @@ -67,7 +57,7 @@ index 647fe07b..18b1e7ff 100755 raise RuntimeError("Invalid output_kind") diff --git a/cloudinit/net/activators.py b/cloudinit/net/activators.py -index edbc0c06..e80c26df 100644 +index 7d11a02c7..d9a8c4d76 100644 --- a/cloudinit/net/activators.py +++ b/cloudinit/net/activators.py @@ -1,14 +1,15 @@ @@ -75,7 +65,7 @@ index edbc0c06..e80c26df 100644 import logging +import os from abc import ABC, abstractmethod - from typing import Iterable, List, Type + from typing import Dict, Iterable, List, Optional, Type, Union from cloudinit import subp, util from cloudinit.net.eni import available as eni_available @@ -131,10 +121,10 @@ index edbc0c06..e80c26df 100644 diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py deleted file mode 100644 -index 79b0fe0b..00000000 +index 53763d15e..000000000 --- a/cloudinit/net/network_manager.py +++ /dev/null -@@ -1,377 +0,0 @@ +@@ -1,393 +0,0 @@ -# Copyright 2022 Red Hat, Inc. -# -# Author: Lubomir Rintel @@ -148,15 +138,16 @@ index 79b0fe0b..00000000 -import itertools -import os -import uuid +-from typing import Optional - -from cloudinit import log as logging -from cloudinit import subp, util -- --from . import renderer --from .network_state import is_ipv6_addr, subnet_is_ipv6 +-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__) - - @@ -205,7 +196,7 @@ index 79b0fe0b..00000000 - - method_map = { - "static": "manual", -- "dhcp6": "dhcp", +- "dhcp6": "auto", - "ipv6_slaac": "auto", - "ipv6_dhcpv6-stateless": "auto", - "ipv6_dhcpv6-stateful": "auto", @@ -232,8 +223,6 @@ index 79b0fe0b..00000000 - - self.config[family]["method"] = method - self._set_default(family, "may-fail", "false") -- if family == "ipv6": -- self._set_default(family, "addr-gen-mode", "stable-privacy") - - def _add_numbered(self, section, key_prefix, value): - """ @@ -274,7 +263,7 @@ index 79b0fe0b..00000000 - # 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_addr(dns) else "ipv4" +- family = "ipv6" if is_ipv6_address(dns) else "ipv4" - self._set_default(family, "method", "disabled") - - self._set_default(family, "dns", "") @@ -480,7 +469,12 @@ index 79b0fe0b..00000000 - # Well, what can we do... - return con_id - -- def render_network_state(self, network_state, templates=None, target=None): +- 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 @@ -507,16 +501,28 @@ index 79b0fe0b..00000000 - - -def available(target=None): -- target_nm_dir = subp.target_path(target, NM_LIB_DIR) -- return os.path.exists(target_nm_dir) +- # 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 7edc34b5..c755f04c 100644 +index b241683f9..c92b9dcf9 100644 --- a/cloudinit/net/renderers.py +++ b/cloudinit/net/renderers.py -@@ -8,7 +8,6 @@ from . import ( +@@ -8,7 +8,6 @@ from cloudinit.net import ( freebsd, netbsd, netplan, @@ -532,31 +538,34 @@ index 7edc34b5..c755f04c 100644 "networkd": networkd, "openbsd": openbsd, "sysconfig": sysconfig, -@@ -30,7 +28,6 @@ DEFAULT_PRIORITY = [ - "eni", - "sysconfig", - "netplan", -- "network-manager", - "freebsd", - "netbsd", - "openbsd", diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index dc401d78..d8c53312 100644 +index 4262cd489..765c248ae 100644 --- a/cloudinit/net/sysconfig.py +++ b/cloudinit/net/sysconfig.py -@@ -5,6 +5,8 @@ import io - import os +@@ -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 -@@ -64,6 +66,24 @@ def _quote_value(value): +@@ -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) @@ -575,10 +584,11 @@ index dc401d78..d8c53312 100644 + LOG.debug("Enabled ifcfg-rh NetworkManager plugins") + + - class ConfigMap(object): ++class ConfigMap(object): """Sysconfig like dictionary object.""" -@@ -1011,6 +1031,8 @@ class Renderer(renderer.Renderer): + # 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) @@ -587,7 +597,7 @@ index dc401d78..d8c53312 100644 sysconfig_path = subp.target_path(target, templates.get("control")) # Distros configuring /etc/sysconfig/network as a file e.g. Centos -@@ -1049,9 +1071,14 @@ def _supported_vlan_names(rdev, vid): +@@ -1052,9 +1075,14 @@ def _supported_vlan_names(rdev, vid): def available(target=None): @@ -604,7 +614,7 @@ index dc401d78..d8c53312 100644 expected = ["ifup", "ifdown"] search = ["/sbin", "/usr/sbin"] for p in expected: -@@ -1068,4 +1095,10 @@ def available(target=None): +@@ -1071,4 +1099,10 @@ def available(target=None): return False @@ -616,18 +626,18 @@ index dc401d78..d8c53312 100644 + # vi: ts=4 expandtab diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py -index ef21ad76..591241b3 100644 +index 0f523ff84..4434b350b 100644 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py -@@ -21,7 +21,6 @@ from cloudinit.net import ( - interface_has_own_mac, +@@ -23,7 +23,6 @@ from cloudinit.net import ( + mask_and_ipv4_to_bcast_addr, natural_sort_key, netplan, - network_manager, network_state, networkd, renderers, -@@ -612,37 +611,6 @@ dns = none +@@ -617,37 +616,6 @@ dns = none ), ), ], @@ -665,7 +675,7 @@ index ef21ad76..591241b3 100644 }, { "in_data": { -@@ -1105,50 +1073,6 @@ NETWORK_CONFIGS = { +@@ -1110,50 +1078,6 @@ NETWORK_CONFIGS = { USERCTL=no""" ), }, @@ -716,208 +726,7 @@ index ef21ad76..591241b3 100644 "yaml": textwrap.dedent( """ version: 1 -@@ -1221,34 +1145,6 @@ NETWORK_CONFIGS = { - STARTMODE=auto""" - ) - }, -- "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 -- -- [ipv6] -- method=dhcp -- may-fail=false -- addr-gen-mode=stable-privacy -- -- """ -- ), -- }, - "yaml": textwrap.dedent( - """\ - version: 1 -@@ -1351,37 +1247,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] -- mtu=9000 -- -- [ipv4] -- method=manual -- may-fail=false -- address1=192.168.14.2/24 -- -- [ipv6] -- method=manual -- may-fail=false -- addr-gen-mode=stable-privacy -- address1=2001:1::1/64 -- -- """ -- ), -- }, - }, - "v6_and_v4": { - "expected_sysconfig_opensuse": { -@@ -1392,34 +1257,6 @@ NETWORK_CONFIGS = { - STARTMODE=auto""" - ) - }, -- "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] -- -- [ipv6] -- method=dhcp -- may-fail=false -- addr-gen-mode=stable-privacy -- -- [ipv4] -- method=auto -- may-fail=false -- -- """ -- ), -- }, - "yaml": textwrap.dedent( - """\ - version: 1 -@@ -1493,30 +1330,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] -- -- [ipv6] -- method=dhcp -- may-fail=false -- addr-gen-mode=stable-privacy -- -- """ -- ), -- }, - }, - "dhcpv6_accept_ra": { - "expected_eni": textwrap.dedent( -@@ -1724,30 +1537,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] -- -- [ipv6] -- method=auto -- may-fail=false -- addr-gen-mode=stable-privacy -- -- """ -- ), -- }, - }, - "static6": { - "yaml": textwrap.dedent( -@@ -1836,30 +1625,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] -- -- [ipv6] -- method=auto -- may-fail=false -- addr-gen-mode=stable-privacy -- -- """ -- ), -- }, - }, - "dhcpv6_stateful": { - "expected_eni": textwrap.dedent( -@@ -1959,29 +1724,6 @@ NETWORK_CONFIGS = { +@@ -1959,29 +1883,6 @@ NETWORK_CONFIGS = { """ ), }, @@ -947,7 +756,7 @@ index ef21ad76..591241b3 100644 "yaml_v2": textwrap.dedent( """\ version: 2 -@@ -2035,30 +1777,6 @@ NETWORK_CONFIGS = { +@@ -2035,30 +1936,6 @@ NETWORK_CONFIGS = { """ ), }, @@ -978,304 +787,7 @@ index ef21ad76..591241b3 100644 "yaml_v2": textwrap.dedent( """\ version: 2 -@@ -2497,254 +2215,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - USERCTL=no""" - ), - }, -- "expected_network_manager": { -- "cloud-init-eth3.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth3 -- uuid=b7e95dda-7746-5bf8-bf33-6e5f3c926790 -- type=ethernet -- slave-type=bridge -- master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=66:BB:9F:2C:E8:80 -- -- """ -- ), -- "cloud-init-eth5.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth5 -- uuid=5fda13c7-9942-5e90-a41b-1d043bd725dc -- type=ethernet -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=98:BB:9F:2C:E8:8A -- -- [ipv4] -- method=auto -- may-fail=false -- -- """ -- ), -- "cloud-init-ib0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init ib0 -- uuid=11a1dda7-78b4-5529-beba-d9b5f549ad7b -- type=infiniband -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [infiniband] -- transport-mode=datagram -- mtu=9000 -- mac-address=A0:00:02:20:FE:80:00:00:00:00:00:00:EC:0D:9A:03:00:15:E2:C1 -- -- [ipv4] -- method=manual -- may-fail=false -- address1=192.168.200.7/24 -- -- """ -- ), -- "cloud-init-bond0.200.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init bond0.200 -- uuid=88984a9c-ff22-5233-9267-86315e0acaa7 -- type=vlan -- interface-name=bond0.200 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [vlan] -- id=200 -- parent=54317911-f840-516b-a10d-82cb4c1f075c -- -- [ipv4] -- method=auto -- may-fail=false -- -- """ -- ), -- "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=C0:D6:9F:2C:E8:80 -- -- """ -- ), -- "cloud-init-eth4.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth4 -- uuid=e27e4959-fb50-5580-b9a4-2073554627b9 -- type=ethernet -- slave-type=bridge -- master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=98:BB:9F:2C:E8:80 -- -- """ -- ), -- "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 -- slave-type=bond -- master=54317911-f840-516b-a10d-82cb4c1f075c -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=AA:D6:9F:2C:E8:80 -- -- """ -- ), -- "cloud-init-br0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init br0 -- uuid=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -- type=bridge -- interface-name=br0 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [bridge] -- stp=false -- priority=22 -- mac-address=BB:BB:BB:BB:BB:AA -- -- [ipv4] -- method=manual -- may-fail=false -- address1=192.168.14.2/24 -- -- [ipv6] -- method=manual -- may-fail=false -- addr-gen-mode=stable-privacy -- address1=2001:1::1/64 -- route1=::/0,2001:4800:78ff:1b::1 -- -- """ -- ), -- "cloud-init-eth0.101.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init eth0.101 -- uuid=b5acec5e-db80-5935-8b02-0d5619fc42bf -- type=vlan -- interface-name=eth0.101 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [vlan] -- id=101 -- parent=1dd9a779-d327-56e1-8454-c65e2556c12c -- -- [ipv4] -- method=manual -- may-fail=false -- address1=192.168.0.2/24 -- gateway=192.168.0.1 -- dns=192.168.0.10;10.23.23.134; -- dns-search=barley.maas;sacchromyces.maas;brettanomyces.maas; -- address2=192.168.2.10/24 -- -- """ -- ), -- "cloud-init-bond0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init bond0 -- uuid=54317911-f840-516b-a10d-82cb4c1f075c -- type=bond -- interface-name=bond0 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [bond] -- mode=active-backup -- miimon=100 -- xmit_hash_policy=layer3+4 -- -- [ipv6] -- method=dhcp -- may-fail=false -- addr-gen-mode=stable-privacy -- -- """ -- ), -- "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 -- slave-type=bond -- master=54317911-f840-516b-a10d-82cb4c1f075c -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=C0:BB:9F:2C:E8:80 -- -- """ -- ), -- }, - "yaml": textwrap.dedent( - """ - version: 1 -@@ -2933,10 +2403,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - - type: static - address: 2001:1::1/92 - routes: -- - gateway: 2001:67c:1562::1 -+ - gateway: 2001:67c:1562:1 - network: 2001:67c:1 - netmask: "ffff:ffff::" -- - gateway: 3001:67c:15::1 -+ - gateway: 3001:67c:1562:1 - network: 3001:67c:1 - netmask: "ffff:ffff::" - metric: 10000 -@@ -2981,10 +2451,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - - to: 10.1.3.0/24 - via: 192.168.0.3 - - to: 2001:67c:1/32 -- via: 2001:67c:1562::1 -+ via: 2001:67c:1562:1 - - metric: 10000 - to: 3001:67c:1/32 -- via: 3001:67c:15::1 -+ via: 3001:67c:1562:1 - """ - ), - "expected_eni": textwrap.dedent( -@@ -3044,11 +2514,11 @@ iface bond0 inet static - # control-alias bond0 - iface bond0 inet6 static - address 2001:1::1/92 -- post-up route add -A inet6 2001:67c:1/32 gw 2001:67c:1562::1 || true -- pre-down route del -A inet6 2001:67c:1/32 gw 2001:67c:1562::1 || true -- post-up route add -A inet6 3001:67c:1/32 gw 3001:67c:15::1 metric 10000 \ -+ post-up route add -A inet6 2001:67c:1/32 gw 2001:67c:1562:1 || true -+ pre-down route del -A inet6 2001:67c:1/32 gw 2001:67c:1562:1 || true -+ post-up route add -A inet6 3001:67c:1/32 gw 3001:67c:1562:1 metric 10000 \ - || true -- pre-down route del -A inet6 3001:67c:1/32 gw 3001:67c:15::1 metric 10000 \ -+ pre-down route del -A inet6 3001:67c:1/32 gw 3001:67c:1562:1 metric 10000 \ - || true - """ - ), -@@ -3091,8 +2561,8 @@ iface bond0 inet6 static +@@ -3092,8 +2969,8 @@ iface bond0 inet6 static - to: 2001:67c:1562:8007::1/64 via: 2001:67c:1562:8007::aac:40b2 - metric: 10000 @@ -1286,7 +798,7 @@ index ef21ad76..591241b3 100644 """ ), "expected_netplan-v2": textwrap.dedent( -@@ -3124,8 +2594,8 @@ iface bond0 inet6 static +@@ -3125,8 +3002,8 @@ iface bond0 inet6 static - to: 2001:67c:1562:8007::1/64 via: 2001:67c:1562:8007::aac:40b2 - metric: 10000 @@ -1297,249 +809,7 @@ index ef21ad76..591241b3 100644 ethernets: eth0: match: -@@ -3224,8 +2694,8 @@ iface bond0 inet6 static - """\ - # Created by cloud-init on instance boot automatically, do not edit. - # -- 2001:67c:1/32 via 2001:67c:1562::1 dev bond0 -- 3001:67c:1/32 via 3001:67c:15::1 metric 10000 dev bond0 -+ 2001:67c:1/32 via 2001:67c:1562:1 dev bond0 -+ 3001:67c:1/32 via 3001:67c:1562:1 metric 10000 dev bond0 - """ - ), - "route-bond0": textwrap.dedent( -@@ -3248,88 +2718,6 @@ iface bond0 inet6 static - """ - ), - }, -- "expected_network_manager": { -- "cloud-init-bond0s0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init bond0s0 -- uuid=09d0b5b9-67e7-5577-a1af-74d1cf17a71e -- type=ethernet -- slave-type=bond -- master=54317911-f840-516b-a10d-82cb4c1f075c -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=AA:BB:CC:DD:E8:00 -- -- """ -- ), -- "cloud-init-bond0s1.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init bond0s1 -- uuid=4d9aca96-b515-5630-ad83-d13daac7f9d0 -- type=ethernet -- slave-type=bond -- master=54317911-f840-516b-a10d-82cb4c1f075c -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=AA:BB:CC:DD:E8:01 -- -- """ -- ), -- "cloud-init-bond0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init bond0 -- uuid=54317911-f840-516b-a10d-82cb4c1f075c -- type=bond -- interface-name=bond0 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [bond] -- mode=active-backup -- miimon=100 -- xmit_hash_policy=layer3+4 -- num_grat_arp=5 -- downdelay=10 -- updelay=20 -- fail_over_mac=active -- primary_reselect=always -- primary=bond0s0 -- -- [ipv4] -- method=manual -- may-fail=false -- address1=192.168.0.2/24 -- gateway=192.168.0.1 -- route1=10.1.3.0/24,192.168.0.3 -- address2=192.168.1.2/24 -- -- [ipv6] -- method=manual -- may-fail=false -- addr-gen-mode=stable-privacy -- address1=2001:1::1/92 -- route1=2001:67c:1/32,2001:67c:1562::1 -- route2=3001:67c:1/32,3001:67c:15::1 -- -- """ -- ), -- }, - }, - "vlan": { - "yaml": textwrap.dedent( -@@ -3413,58 +2801,6 @@ iface bond0 inet6 static - VLAN=yes""" - ), - }, -- "expected_network_manager": { -- "cloud-init-en0.99.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init en0.99 -- uuid=f594e2ed-f107-51df-b225-1dc530a5356b -- type=vlan -- interface-name=en0.99 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [vlan] -- id=99 -- parent=e0ca478b-8d84-52ab-8fae-628482c629b5 -- -- [ipv4] -- method=manual -- may-fail=false -- address1=192.168.2.2/24 -- address2=192.168.1.2/24 -- gateway=192.168.1.1 -- -- [ipv6] -- method=manual -- may-fail=false -- addr-gen-mode=stable-privacy -- address1=2001:1::bbbb/96 -- route1=::/0,2001:1::1 -- -- """ -- ), -- "cloud-init-en0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init en0 -- uuid=e0ca478b-8d84-52ab-8fae-628482c629b5 -- type=ethernet -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=AA:BB:CC:DD:E8:00 -- -- """ -- ), -- }, - }, - "bridge": { - "yaml": textwrap.dedent( -@@ -3573,82 +2909,6 @@ iface bond0 inet6 static - """ - ), - }, -- "expected_network_manager": { -- "cloud-init-br0.nmconnection": textwrap.dedent( -- """\ -- # Generated by cloud-init. Changes will be lost. -- -- [connection] -- id=cloud-init br0 -- uuid=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -- type=bridge -- interface-name=br0 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [bridge] -- stp=false -- priority=22 -- -- [ipv4] -- method=manual -- may-fail=false -- address1=192.168.2.2/24 -- -- """ -- ), -- "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 -- slave-type=bridge -- master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=52:54:00:12:34:00 -- -- [ipv6] -- method=manual -- may-fail=false -- addr-gen-mode=stable-privacy -- address1=2001:1::100/96 -- -- """ -- ), -- "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 -- slave-type=bridge -- master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -- -- [user] -- org.freedesktop.NetworkManager.origin=cloud-init -- -- [ethernet] -- mac-address=52:54:00:12:34:01 -- -- [ipv6] -- method=manual -- may-fail=false -- addr-gen-mode=stable-privacy -- address1=2001:1::101/96 -- -- """ -- ), -- }, - }, - "manual": { - "yaml": textwrap.dedent( -@@ -3777,92 +3037,25 @@ iface bond0 inet6 static +@@ -3774,73 +3651,6 @@ iface bond0 inet6 static """ ), }, @@ -1552,12 +822,10 @@ index ef21ad76..591241b3 100644 - 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 - @@ -1612,44 +880,10 @@ index ef21ad76..591241b3 100644 - """ - ), - }, -- }, --} -- -- --CONFIG_V1_EXPLICIT_LOOPBACK = { -- "version": 1, -- "config": [ -- { -- "name": "eth0", -- "type": "physical", -- "subnets": [{"control": "auto", "type": "dhcp"}], -- }, -- { -- "name": "lo", -- "type": "loopback", -- "subnets": [{"control": "auto", "type": "loopback"}], -- }, -- ], --} -+CONFIG_V1_EXPLICIT_LOOPBACK = { -+ "version": 1, -+ "config": [ -+ { -+ "name": "eth0", -+ "type": "physical", -+ "subnets": [{"control": "auto", "type": "dhcp"}], -+ }, -+ { -+ "name": "lo", -+ "type": "loopback", -+ "subnets": [{"control": "auto", "type": "loopback"}], -+ }, -+ ], -+} - - - CONFIG_V1_SIMPLE_SUBNET = { -@@ -4304,6 +3497,7 @@ class TestRhelSysConfigRendering(CiTestCase): + }, + "v2-dev-name-via-mac-lookup": { + "expected_sysconfig_rhel": { +@@ -4339,6 +4149,7 @@ class TestRhelSysConfigRendering(CiTestCase): with_logs = True @@ -1657,7 +891,7 @@ index ef21ad76..591241b3 100644 scripts_dir = "/etc/sysconfig/network-scripts" header = ( "# Created by cloud-init on instance boot automatically, " -@@ -4878,6 +4072,78 @@ USERCTL=no +@@ -4913,6 +4724,78 @@ USERCTL=no self._compare_files_to_expected(entry[self.expected_name], found) self._assert_headers(found) @@ -1736,7 +970,7 @@ index ef21ad76..591241b3 100644 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) -@@ -5433,281 +4699,6 @@ STARTMODE=auto +@@ -5609,281 +5492,6 @@ STARTMODE=auto self._assert_headers(found) @@ -2018,7 +1252,7 @@ index ef21ad76..591241b3 100644 class TestEniNetRendering(CiTestCase): @mock.patch("cloudinit.net.util.get_cmdline", return_value="root=myroot") @mock.patch("cloudinit.net.sys_dev_path") -@@ -7145,9 +6136,9 @@ class TestNetworkdRoundTrip(CiTestCase): +@@ -7651,9 +7259,9 @@ class TestNetworkdRoundTrip(CiTestCase): class TestRenderersSelect: @pytest.mark.parametrize( @@ -2030,7 +1264,7 @@ index ef21ad76..591241b3 100644 ( net.RendererNotFoundError, False, -@@ -7155,51 +6146,52 @@ class TestRenderersSelect: +@@ -7661,51 +7269,52 @@ class TestRenderersSelect: False, False, False, @@ -2105,7 +1339,7 @@ index ef21ad76..591241b3 100644 m_networkd_avail.return_value = networkd # networkd presence if isinstance(renderer_selected, str): (renderer_name, _rnd_class) = renderers.select( -@@ -7257,7 +6249,7 @@ class TestNetRenderers(CiTestCase): +@@ -7763,7 +7372,7 @@ class TestNetRenderers(CiTestCase): priority=["sysconfig", "eni"], ) @@ -2115,35 +1349,10 @@ index ef21ad76..591241b3 100644 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 4525c49c..3c29e2f7 100644 +index afd9056af..b735ea9ed 100644 --- a/tests/unittests/test_net_activators.py +++ b/tests/unittests/test_net_activators.py -@@ -41,20 +41,18 @@ NETPLAN_CALL_LIST = [ - - @pytest.fixture - def available_mocks(): -- mocks = namedtuple("Mocks", "m_which, m_file, m_exists") -+ mocks = namedtuple("Mocks", "m_which, m_file") - with patch("cloudinit.subp.which", return_value=True) as m_which: - with patch("os.path.isfile", return_value=True) as m_file: -- with patch("os.path.exists", return_value=True) as m_exists: -- yield mocks(m_which, m_file, m_exists) -+ yield mocks(m_which, m_file) - - - @pytest.fixture - def unavailable_mocks(): -- mocks = namedtuple("Mocks", "m_which, m_file, m_exists") -+ mocks = namedtuple("Mocks", "m_which, m_file") - with patch("cloudinit.subp.which", return_value=False) as m_which: - with patch("os.path.isfile", return_value=False) as m_file: -- with patch("os.path.exists", return_value=False) as m_exists: -- yield mocks(m_which, m_file, m_exists) -+ yield mocks(m_which, m_file) - - - class TestSearchAndSelect: -@@ -115,6 +113,10 @@ NETPLAN_AVAILABLE_CALLS = [ +@@ -139,6 +139,10 @@ NETPLAN_AVAILABLE_CALLS = [ (("netplan",), {"search": ["/usr/sbin", "/sbin"], "target": None}), ] @@ -2154,7 +1363,7 @@ index 4525c49c..3c29e2f7 100644 NETWORKD_AVAILABLE_CALLS = [ (("ip",), {"search": ["/usr/sbin", "/bin"], "target": None}), (("systemctl",), {"search": ["/usr/sbin", "/bin"], "target": None}), -@@ -126,6 +128,7 @@ NETWORKD_AVAILABLE_CALLS = [ +@@ -150,6 +154,7 @@ NETWORKD_AVAILABLE_CALLS = [ [ (IfUpDownActivator, IF_UP_DOWN_AVAILABLE_CALLS), (NetplanActivator, NETPLAN_AVAILABLE_CALLS), @@ -2162,82 +1371,7 @@ index 4525c49c..3c29e2f7 100644 (NetworkdActivator, NETWORKD_AVAILABLE_CALLS), ], ) -@@ -141,72 +144,8 @@ IF_UP_DOWN_BRING_UP_CALL_LIST = [ - ] - - NETWORK_MANAGER_BRING_UP_CALL_LIST = [ -- ( -- ( -- [ -- "nmcli", -- "connection", -- "load", -- "".join( -- [ -- "/etc/NetworkManager/system-connections", -- "/cloud-init-eth0.nmconnection", -- ] -- ), -- ], -- ), -- {}, -- ), -- ( -- ( -- [ -- "nmcli", -- "connection", -- "up", -- "filename", -- "".join( -- [ -- "/etc/NetworkManager/system-connections", -- "/cloud-init-eth0.nmconnection", -- ] -- ), -- ], -- ), -- {}, -- ), -- ( -- ( -- [ -- "nmcli", -- "connection", -- "load", -- "".join( -- [ -- "/etc/NetworkManager/system-connections", -- "/cloud-init-eth1.nmconnection", -- ] -- ), -- ], -- ), -- {}, -- ), -- ( -- ( -- [ -- "nmcli", -- "connection", -- "up", -- "filename", -- "".join( -- [ -- "/etc/NetworkManager/system-connections", -- "/cloud-init-eth1.nmconnection", -- ] -- ), -- ], -- ), -- {}, -- ), -+ ((["nmcli", "connection", "up", "ifname", "eth0"],), {}), -+ ((["nmcli", "connection", "up", "ifname", "eth1"],), {}), - ] - - NETWORKD_BRING_UP_CALL_LIST = [ -@@ -230,11 +169,9 @@ class TestActivatorsBringUp: +@@ -254,11 +259,9 @@ class TestActivatorsBringUp: def test_bring_up_interface( self, m_subp, activator, expected_call_list, available_mocks ): @@ -2251,17 +1385,6 @@ index 4525c49c..3c29e2f7 100644 @patch("cloudinit.subp.subp", return_value=("", "")) def test_bring_up_interfaces( -@@ -271,8 +208,8 @@ IF_UP_DOWN_BRING_DOWN_CALL_LIST = [ - ] - - NETWORK_MANAGER_BRING_DOWN_CALL_LIST = [ -- ((["nmcli", "device", "disconnect", "eth0"],), {}), -- ((["nmcli", "device", "disconnect", "eth1"],), {}), -+ ((["nmcli", "connection", "down", "eth0"],), {}), -+ ((["nmcli", "connection", "down", "eth1"],), {}), - ] - - NETWORKD_BRING_DOWN_CALL_LIST = [ -- -2.31.1 +2.39.2 diff --git a/0006-rhel-cloud.cfg-remove-ssh_genkeytypes-in-settings.py.patch b/0006-rhel-cloud.cfg-remove-ssh_genkeytypes-in-settings.py.patch deleted file mode 100644 index fb05778..0000000 --- a/0006-rhel-cloud.cfg-remove-ssh_genkeytypes-in-settings.py.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 00f1f910d8d166ebe2913c12549f212c2d666c11 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Thu, 20 May 2021 08:53:55 +0200 -Subject: rhel/cloud.cfg: remove ssh_genkeytypes in settings.py and set in - cloud.cfg - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 10: rhel/cloud.cfg: remove ssh_genkeytypes in settings.py and set in cloud.cfg -RH-Commit: [1/1] 6da989423b9b6e017afbac2f1af3649b0487310f -RH-Bugzilla: 1957532 -RH-Acked-by: Eduardo Otubo -RH-Acked-by: Cathy Avery -RH-Acked-by: Vitaly Kuznetsov -RH-Acked-by: Mohamed Gamal Morsy - -Currently genkeytypes in cloud.cfg is set to None, so together with -ssh_deletekeys=1 cloudinit on first boot it will just delete the existing -keys and not generate new ones. - -Just removing that property in cloud.cfg is not enough, because -settings.py provides another empty default value that will be used -instead, resulting to no key generated even when the property is not defined. - -Removing genkeytypes also in settings.py will default to GENERATE_KEY_NAMES, -but since we want only 'rsa', 'ecdsa' and 'ed25519', add back genkeytypes in -cloud.cfg with the above defaults. - -Also remove ssh_deletekeys in settings.py as we always need -to 1 (and it also defaults to 1). - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/settings.py | 2 -- - rhel/cloud.cfg | 2 +- - 2 files changed, 1 insertion(+), 3 deletions(-) - -diff --git a/cloudinit/settings.py b/cloudinit/settings.py -index aa2d6b95..38a90b70 100644 ---- a/cloudinit/settings.py -+++ b/cloudinit/settings.py -@@ -52,8 +52,6 @@ CFG_BUILTIN = { - 'def_log_file_mode': 0o600, - 'log_cfgs': [], - 'mount_default_fields': [None, None, 'auto', 'defaults,nofail', '0', '2'], -- 'ssh_deletekeys': False, -- 'ssh_genkeytypes': [], - 'syslog_fix_perms': [], - 'system_info': { - 'paths': { -diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg -index 1ec1a6c6..75d5c84b 100644 ---- a/rhel/cloud.cfg -+++ b/rhel/cloud.cfg -@@ -7,7 +7,7 @@ ssh_pwauth: 0 - mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service,_netdev', '0', '2'] - resize_rootfs_tmp: /dev - ssh_deletekeys: 1 --ssh_genkeytypes: ~ -+ssh_genkeytypes: ['rsa', 'ecdsa', 'ed25519'] - syslog_fix_perms: ~ - disable_vmware_customization: false - --- -2.31.1 - diff --git a/README.rst b/README.rst deleted file mode 100644 index fbd67ca..0000000 --- a/README.rst +++ /dev/null @@ -1,18 +0,0 @@ -=================== -cloud-init development -=================== - -cloud-init is maintained in a `source tree`_ rather than directly in dist-git -using packit service that provides way to develope using regular source code -structure and provides way to generate SRPM and build using koji service. - -Developers deliver all changes to source-git using merge request. Only maintainers -will be pushing changes sent to source-git to dist-git. - -Each release in dist-git is tagged in the source repository so you can easily -check out the source tree for a build. The tags are in the format -name-version-release, but note release doesn't contain the dist tag since the -source can be built in different build roots (Fedora, CentOS, etc.) - -.. _source tree: https://gitlab.com/redhat/centos-stream/src/cloud-init - diff --git a/ci-Add-native-NetworkManager-support-1224.patch b/ci-Add-native-NetworkManager-support-1224.patch deleted file mode 100644 index 8bcbcc7..0000000 --- a/ci-Add-native-NetworkManager-support-1224.patch +++ /dev/null @@ -1,2299 +0,0 @@ -From f0ae77cbf4a5e269da54fc2783a2a836023bbd86 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Mon, 2 May 2022 14:42:52 +0200 -Subject: [PATCH 1/5] Add native NetworkManager support (#1224) - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 24: Add native NetworkManager support (#1224) -RH-Commit: [1/3] 65231ba68460c505646807faf186c704d67678b5 (eesposit/cloud-init-centos-) -RH-Bugzilla: 2056964 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Vitaly Kuznetsov - -commit feda344e6cf9d37b09bc13cf333a717d1654c26c -Author: Lubomir Rintel -Date: Fri Feb 25 23:33:20 2022 +0100 - - Add native NetworkManager support (#1224) - - Fedora currently relies on sysconfig/ifcfg renderer. This is not too great, - because Fedora (also RHEL since version 8) dropped support for the legacy - network service that uses ifcfg files long ago. - - In turn, Fedora ended up patching cloud-init downstream to utilize - NetworkManager's ifcfg compatibility mode [1]. This seems to have worked - for a while, nevertheless the NetworkManager's ifcfg backend is reaching - the end of its useful life too [2]. - - [1] https://src.fedoraproject.org/rpms/cloud-init/blob/rawhide/f/cloud-init-21.3-nm-controlled.patch - [2] https://fedoraproject.org/wiki/Changes/NoIfcfgFiles - - Let's not mangle things downstream and make vanilla cloud-init work great - on Fedora instead. - - This also means that the sysconfig compatibility with - Network Manager was removed. - - Firstly, this relies upon the fact that you can get ifcfg support by adding - it to NetworkManager.conf. That is not guaranteed and certainly will not - be case in future. - - Secondly, cloud-init always generates configuration with - NM_CONTROLLED=no, so the generated ifcfg files are no good for - NetworkManager. Fedora patches around this by just removing those lines - in their cloud-init package. - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/cmd/devel/net_convert.py | 14 +- - cloudinit/net/activators.py | 25 +- - cloudinit/net/network_manager.py | 377 +++++++ - cloudinit/net/renderers.py | 3 + - cloudinit/net/sysconfig.py | 37 +- - tests/unittests/test_net.py | 1270 +++++++++++++++++++++--- - tests/unittests/test_net_activators.py | 93 +- - 7 files changed, 1625 insertions(+), 194 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 18b1e7ff..647fe07b 100755 ---- a/cloudinit/cmd/devel/net_convert.py -+++ b/cloudinit/cmd/devel/net_convert.py -@@ -7,7 +7,14 @@ import os - import sys - - 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 import DataSourceOVF as ovf - from cloudinit.sources.helpers import openstack -@@ -74,7 +81,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", - ) -@@ -148,6 +155,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 e80c26df..edbc0c06 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 Iterable, List, Type - - 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..79b0fe0b ---- /dev/null -+++ b/cloudinit/net/network_manager.py -@@ -0,0 +1,377 @@ -+# 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 cloudinit import log as logging -+from cloudinit import subp, util -+ -+from . import renderer -+from .network_state import is_ipv6_addr, subnet_is_ipv6 -+ -+NM_RUN_DIR = "/etc/NetworkManager" -+NM_LIB_DIR = "/usr/lib/NetworkManager" -+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": "dhcp", -+ "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") -+ if family == "ipv6": -+ self._set_default(family, "addr-gen-mode", "stable-privacy") -+ -+ 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_addr(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, templates=None, target=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): -+ target_nm_dir = subp.target_path(target, NM_LIB_DIR) -+ return os.path.exists(target_nm_dir) -+ -+ -+# vi: ts=4 expandtab -diff --git a/cloudinit/net/renderers.py b/cloudinit/net/renderers.py -index c755f04c..7edc34b5 100644 ---- a/cloudinit/net/renderers.py -+++ b/cloudinit/net/renderers.py -@@ -8,6 +8,7 @@ from . 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, -@@ -28,6 +30,7 @@ DEFAULT_PRIORITY = [ - "eni", - "sysconfig", - "netplan", -+ "network-manager", - "freebsd", - "netbsd", - "openbsd", -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index b50035b5..2a45a4fa 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -5,8 +5,6 @@ import io - import os - import re - --from configobj import ConfigObj -- - from cloudinit import log as logging - from cloudinit import subp, util - from cloudinit.distros.parsers import networkmanager_conf, resolv_conf -@@ -66,24 +64,6 @@ 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): - """Sysconfig like dictionary object.""" - -@@ -1032,8 +1012,6 @@ 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 -@@ -1072,14 +1050,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: -@@ -1096,10 +1069,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 591241b3..ef21ad76 100644 ---- a/tests/unittests/test_net.py -+++ b/tests/unittests/test_net.py -@@ -21,6 +21,7 @@ from cloudinit.net import ( - interface_has_own_mac, - natural_sort_key, - netplan, -+ network_manager, - network_state, - networkd, - renderers, -@@ -611,6 +612,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": { -@@ -1073,6 +1105,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 -@@ -1145,6 +1221,34 @@ NETWORK_CONFIGS = { - STARTMODE=auto""" - ) - }, -+ "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 -+ -+ [ipv6] -+ method=dhcp -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ -+ """ -+ ), -+ }, - "yaml": textwrap.dedent( - """\ - version: 1 -@@ -1247,6 +1351,37 @@ 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] -+ mtu=9000 -+ -+ [ipv4] -+ method=manual -+ may-fail=false -+ address1=192.168.14.2/24 -+ -+ [ipv6] -+ method=manual -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ address1=2001:1::1/64 -+ -+ """ -+ ), -+ }, - }, - "v6_and_v4": { - "expected_sysconfig_opensuse": { -@@ -1257,6 +1392,34 @@ NETWORK_CONFIGS = { - STARTMODE=auto""" - ) - }, -+ "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] -+ -+ [ipv6] -+ method=dhcp -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ -+ [ipv4] -+ method=auto -+ may-fail=false -+ -+ """ -+ ), -+ }, - "yaml": textwrap.dedent( - """\ - version: 1 -@@ -1330,6 +1493,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] -+ -+ [ipv6] -+ method=dhcp -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ -+ """ -+ ), -+ }, - }, - "dhcpv6_accept_ra": { - "expected_eni": textwrap.dedent( -@@ -1537,6 +1724,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] -+ -+ [ipv6] -+ method=auto -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ -+ """ -+ ), -+ }, - }, - "static6": { - "yaml": textwrap.dedent( -@@ -1625,6 +1836,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] -+ -+ [ipv6] -+ method=auto -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ -+ """ -+ ), -+ }, - }, - "dhcpv6_stateful": { - "expected_eni": textwrap.dedent( -@@ -1724,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 -@@ -1777,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 -@@ -2215,6 +2497,254 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - USERCTL=no""" - ), - }, -+ "expected_network_manager": { -+ "cloud-init-eth3.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth3 -+ uuid=b7e95dda-7746-5bf8-bf33-6e5f3c926790 -+ type=ethernet -+ slave-type=bridge -+ master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=66:BB:9F:2C:E8:80 -+ -+ """ -+ ), -+ "cloud-init-eth5.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth5 -+ uuid=5fda13c7-9942-5e90-a41b-1d043bd725dc -+ type=ethernet -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=98:BB:9F:2C:E8:8A -+ -+ [ipv4] -+ method=auto -+ may-fail=false -+ -+ """ -+ ), -+ "cloud-init-ib0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init ib0 -+ uuid=11a1dda7-78b4-5529-beba-d9b5f549ad7b -+ type=infiniband -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [infiniband] -+ transport-mode=datagram -+ mtu=9000 -+ mac-address=A0:00:02:20:FE:80:00:00:00:00:00:00:EC:0D:9A:03:00:15:E2:C1 -+ -+ [ipv4] -+ method=manual -+ may-fail=false -+ address1=192.168.200.7/24 -+ -+ """ -+ ), -+ "cloud-init-bond0.200.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init bond0.200 -+ uuid=88984a9c-ff22-5233-9267-86315e0acaa7 -+ type=vlan -+ interface-name=bond0.200 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [vlan] -+ id=200 -+ parent=54317911-f840-516b-a10d-82cb4c1f075c -+ -+ [ipv4] -+ method=auto -+ may-fail=false -+ -+ """ -+ ), -+ "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=C0:D6:9F:2C:E8:80 -+ -+ """ -+ ), -+ "cloud-init-eth4.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth4 -+ uuid=e27e4959-fb50-5580-b9a4-2073554627b9 -+ type=ethernet -+ slave-type=bridge -+ master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=98:BB:9F:2C:E8:80 -+ -+ """ -+ ), -+ "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 -+ slave-type=bond -+ master=54317911-f840-516b-a10d-82cb4c1f075c -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=AA:D6:9F:2C:E8:80 -+ -+ """ -+ ), -+ "cloud-init-br0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init br0 -+ uuid=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -+ type=bridge -+ interface-name=br0 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [bridge] -+ stp=false -+ priority=22 -+ mac-address=BB:BB:BB:BB:BB:AA -+ -+ [ipv4] -+ method=manual -+ may-fail=false -+ address1=192.168.14.2/24 -+ -+ [ipv6] -+ method=manual -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ address1=2001:1::1/64 -+ route1=::/0,2001:4800:78ff:1b::1 -+ -+ """ -+ ), -+ "cloud-init-eth0.101.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init eth0.101 -+ uuid=b5acec5e-db80-5935-8b02-0d5619fc42bf -+ type=vlan -+ interface-name=eth0.101 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [vlan] -+ id=101 -+ parent=1dd9a779-d327-56e1-8454-c65e2556c12c -+ -+ [ipv4] -+ method=manual -+ may-fail=false -+ address1=192.168.0.2/24 -+ gateway=192.168.0.1 -+ dns=192.168.0.10;10.23.23.134; -+ dns-search=barley.maas;sacchromyces.maas;brettanomyces.maas; -+ address2=192.168.2.10/24 -+ -+ """ -+ ), -+ "cloud-init-bond0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init bond0 -+ uuid=54317911-f840-516b-a10d-82cb4c1f075c -+ type=bond -+ interface-name=bond0 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [bond] -+ mode=active-backup -+ miimon=100 -+ xmit_hash_policy=layer3+4 -+ -+ [ipv6] -+ method=dhcp -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ -+ """ -+ ), -+ "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 -+ slave-type=bond -+ master=54317911-f840-516b-a10d-82cb4c1f075c -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=C0:BB:9F:2C:E8:80 -+ -+ """ -+ ), -+ }, - "yaml": textwrap.dedent( - """ - version: 1 -@@ -2403,10 +2933,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - - type: static - address: 2001:1::1/92 - routes: -- - gateway: 2001:67c:1562:1 -+ - gateway: 2001:67c:1562::1 - network: 2001:67c:1 - netmask: "ffff:ffff::" -- - gateway: 3001:67c:1562:1 -+ - gateway: 3001:67c:15::1 - network: 3001:67c:1 - netmask: "ffff:ffff::" - metric: 10000 -@@ -2451,10 +2981,10 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true - - to: 10.1.3.0/24 - via: 192.168.0.3 - - to: 2001:67c:1/32 -- via: 2001:67c:1562:1 -+ via: 2001:67c:1562::1 - - metric: 10000 - to: 3001:67c:1/32 -- via: 3001:67c:1562:1 -+ via: 3001:67c:15::1 - """ - ), - "expected_eni": textwrap.dedent( -@@ -2514,11 +3044,11 @@ iface bond0 inet static - # control-alias bond0 - iface bond0 inet6 static - address 2001:1::1/92 -- post-up route add -A inet6 2001:67c:1/32 gw 2001:67c:1562:1 || true -- pre-down route del -A inet6 2001:67c:1/32 gw 2001:67c:1562:1 || true -- post-up route add -A inet6 3001:67c:1/32 gw 3001:67c:1562:1 metric 10000 \ -+ post-up route add -A inet6 2001:67c:1/32 gw 2001:67c:1562::1 || true -+ pre-down route del -A inet6 2001:67c:1/32 gw 2001:67c:1562::1 || true -+ post-up route add -A inet6 3001:67c:1/32 gw 3001:67c:15::1 metric 10000 \ - || true -- pre-down route del -A inet6 3001:67c:1/32 gw 3001:67c:1562:1 metric 10000 \ -+ pre-down route del -A inet6 3001:67c:1/32 gw 3001:67c:15::1 metric 10000 \ - || true - """ - ), -@@ -2561,8 +3091,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( -@@ -2594,8 +3124,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: -@@ -2694,8 +3224,8 @@ iface bond0 inet6 static - """\ - # Created by cloud-init on instance boot automatically, do not edit. - # -- 2001:67c:1/32 via 2001:67c:1562:1 dev bond0 -- 3001:67c:1/32 via 3001:67c:1562:1 metric 10000 dev bond0 -+ 2001:67c:1/32 via 2001:67c:1562::1 dev bond0 -+ 3001:67c:1/32 via 3001:67c:15::1 metric 10000 dev bond0 - """ - ), - "route-bond0": textwrap.dedent( -@@ -2718,6 +3248,88 @@ iface bond0 inet6 static - """ - ), - }, -+ "expected_network_manager": { -+ "cloud-init-bond0s0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init bond0s0 -+ uuid=09d0b5b9-67e7-5577-a1af-74d1cf17a71e -+ type=ethernet -+ slave-type=bond -+ master=54317911-f840-516b-a10d-82cb4c1f075c -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=AA:BB:CC:DD:E8:00 -+ -+ """ -+ ), -+ "cloud-init-bond0s1.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init bond0s1 -+ uuid=4d9aca96-b515-5630-ad83-d13daac7f9d0 -+ type=ethernet -+ slave-type=bond -+ master=54317911-f840-516b-a10d-82cb4c1f075c -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=AA:BB:CC:DD:E8:01 -+ -+ """ -+ ), -+ "cloud-init-bond0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init bond0 -+ uuid=54317911-f840-516b-a10d-82cb4c1f075c -+ type=bond -+ interface-name=bond0 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [bond] -+ mode=active-backup -+ miimon=100 -+ xmit_hash_policy=layer3+4 -+ num_grat_arp=5 -+ downdelay=10 -+ updelay=20 -+ fail_over_mac=active -+ primary_reselect=always -+ primary=bond0s0 -+ -+ [ipv4] -+ method=manual -+ may-fail=false -+ address1=192.168.0.2/24 -+ gateway=192.168.0.1 -+ route1=10.1.3.0/24,192.168.0.3 -+ address2=192.168.1.2/24 -+ -+ [ipv6] -+ method=manual -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ address1=2001:1::1/92 -+ route1=2001:67c:1/32,2001:67c:1562::1 -+ route2=3001:67c:1/32,3001:67c:15::1 -+ -+ """ -+ ), -+ }, - }, - "vlan": { - "yaml": textwrap.dedent( -@@ -2801,6 +3413,58 @@ iface bond0 inet6 static - VLAN=yes""" - ), - }, -+ "expected_network_manager": { -+ "cloud-init-en0.99.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init en0.99 -+ uuid=f594e2ed-f107-51df-b225-1dc530a5356b -+ type=vlan -+ interface-name=en0.99 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [vlan] -+ id=99 -+ parent=e0ca478b-8d84-52ab-8fae-628482c629b5 -+ -+ [ipv4] -+ method=manual -+ may-fail=false -+ address1=192.168.2.2/24 -+ address2=192.168.1.2/24 -+ gateway=192.168.1.1 -+ -+ [ipv6] -+ method=manual -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ address1=2001:1::bbbb/96 -+ route1=::/0,2001:1::1 -+ -+ """ -+ ), -+ "cloud-init-en0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init en0 -+ uuid=e0ca478b-8d84-52ab-8fae-628482c629b5 -+ type=ethernet -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=AA:BB:CC:DD:E8:00 -+ -+ """ -+ ), -+ }, - }, - "bridge": { - "yaml": textwrap.dedent( -@@ -2909,6 +3573,82 @@ iface bond0 inet6 static - """ - ), - }, -+ "expected_network_manager": { -+ "cloud-init-br0.nmconnection": textwrap.dedent( -+ """\ -+ # Generated by cloud-init. Changes will be lost. -+ -+ [connection] -+ id=cloud-init br0 -+ uuid=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -+ type=bridge -+ interface-name=br0 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [bridge] -+ stp=false -+ priority=22 -+ -+ [ipv4] -+ method=manual -+ may-fail=false -+ address1=192.168.2.2/24 -+ -+ """ -+ ), -+ "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 -+ slave-type=bridge -+ master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=52:54:00:12:34:00 -+ -+ [ipv6] -+ method=manual -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ address1=2001:1::100/96 -+ -+ """ -+ ), -+ "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 -+ slave-type=bridge -+ master=dee46ce4-af7a-5e7c-aa08-b25533ae9213 -+ -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init -+ -+ [ethernet] -+ mac-address=52:54:00:12:34:01 -+ -+ [ipv6] -+ method=manual -+ may-fail=false -+ addr-gen-mode=stable-privacy -+ address1=2001:1::101/96 -+ -+ """ -+ ), -+ }, - }, - "manual": { - "yaml": textwrap.dedent( -@@ -3037,28 +3777,95 @@ 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 - --CONFIG_V1_EXPLICIT_LOOPBACK = { -- "version": 1, -- "config": [ -- { -- "name": "eth0", -- "type": "physical", -- "subnets": [{"control": "auto", "type": "dhcp"}], -- }, -- { -- "name": "lo", -- "type": "loopback", -- "subnets": [{"control": "auto", "type": "loopback"}], -- }, -- ], --} -+ [user] -+ org.freedesktop.NetworkManager.origin=cloud-init - -+ [ethernet] -+ mac-address=52:54:00:12:34:00 - --CONFIG_V1_SIMPLE_SUBNET = { -+ [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 -+ -+ """ -+ ), -+ }, -+ }, -+} -+ -+ -+CONFIG_V1_EXPLICIT_LOOPBACK = { -+ "version": 1, -+ "config": [ -+ { -+ "name": "eth0", -+ "type": "physical", -+ "subnets": [{"control": "auto", "type": "dhcp"}], -+ }, -+ { -+ "name": "lo", -+ "type": "loopback", -+ "subnets": [{"control": "auto", "type": "loopback"}], -+ }, -+ ], -+} -+ -+ -+CONFIG_V1_SIMPLE_SUBNET = { - "version": 1, - "config": [ - { -@@ -3497,7 +4304,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, " -@@ -4072,78 +4878,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) -@@ -4699,6 +5433,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") -@@ -6136,9 +7145,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, -@@ -6146,52 +7155,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( -@@ -6249,7 +7257,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 3c29e2f7..4525c49c 100644 ---- a/tests/unittests/test_net_activators.py -+++ b/tests/unittests/test_net_activators.py -@@ -41,18 +41,20 @@ NETPLAN_CALL_LIST = [ - - @pytest.fixture - def available_mocks(): -- mocks = namedtuple("Mocks", "m_which, m_file") -+ mocks = namedtuple("Mocks", "m_which, m_file, m_exists") - with patch("cloudinit.subp.which", return_value=True) as m_which: - with patch("os.path.isfile", return_value=True) as m_file: -- yield mocks(m_which, m_file) -+ with patch("os.path.exists", return_value=True) as m_exists: -+ yield mocks(m_which, m_file, m_exists) - - - @pytest.fixture - def unavailable_mocks(): -- mocks = namedtuple("Mocks", "m_which, m_file") -+ mocks = namedtuple("Mocks", "m_which, m_file, m_exists") - with patch("cloudinit.subp.which", return_value=False) as m_which: - with patch("os.path.isfile", return_value=False) as m_file: -- yield mocks(m_which, m_file) -+ with patch("os.path.exists", return_value=False) as m_exists: -+ yield mocks(m_which, m_file, m_exists) - - - class TestSearchAndSelect: -@@ -113,10 +115,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}), -@@ -128,7 +126,6 @@ NETWORKD_AVAILABLE_CALLS = [ - [ - (IfUpDownActivator, IF_UP_DOWN_AVAILABLE_CALLS), - (NetplanActivator, NETPLAN_AVAILABLE_CALLS), -- (NetworkManagerActivator, NETWORK_MANAGER_AVAILABLE_CALLS), - (NetworkdActivator, NETWORKD_AVAILABLE_CALLS), - ], - ) -@@ -144,8 +141,72 @@ IF_UP_DOWN_BRING_UP_CALL_LIST = [ - ] - - NETWORK_MANAGER_BRING_UP_CALL_LIST = [ -- ((["nmcli", "connection", "up", "ifname", "eth0"],), {}), -- ((["nmcli", "connection", "up", "ifname", "eth1"],), {}), -+ ( -+ ( -+ [ -+ "nmcli", -+ "connection", -+ "load", -+ "".join( -+ [ -+ "/etc/NetworkManager/system-connections", -+ "/cloud-init-eth0.nmconnection", -+ ] -+ ), -+ ], -+ ), -+ {}, -+ ), -+ ( -+ ( -+ [ -+ "nmcli", -+ "connection", -+ "up", -+ "filename", -+ "".join( -+ [ -+ "/etc/NetworkManager/system-connections", -+ "/cloud-init-eth0.nmconnection", -+ ] -+ ), -+ ], -+ ), -+ {}, -+ ), -+ ( -+ ( -+ [ -+ "nmcli", -+ "connection", -+ "load", -+ "".join( -+ [ -+ "/etc/NetworkManager/system-connections", -+ "/cloud-init-eth1.nmconnection", -+ ] -+ ), -+ ], -+ ), -+ {}, -+ ), -+ ( -+ ( -+ [ -+ "nmcli", -+ "connection", -+ "up", -+ "filename", -+ "".join( -+ [ -+ "/etc/NetworkManager/system-connections", -+ "/cloud-init-eth1.nmconnection", -+ ] -+ ), -+ ], -+ ), -+ {}, -+ ), - ] - - NETWORKD_BRING_UP_CALL_LIST = [ -@@ -169,9 +230,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( -@@ -208,8 +271,8 @@ IF_UP_DOWN_BRING_DOWN_CALL_LIST = [ - ] - - NETWORK_MANAGER_BRING_DOWN_CALL_LIST = [ -- ((["nmcli", "connection", "down", "eth0"],), {}), -- ((["nmcli", "connection", "down", "eth1"],), {}), -+ ((["nmcli", "device", "disconnect", "eth0"],), {}), -+ ((["nmcli", "device", "disconnect", "eth1"],), {}), - ] - - NETWORKD_BRING_DOWN_CALL_LIST = [ --- -2.31.1 - diff --git a/ci-Align-rhel-custom-files-with-upstream-1431.patch b/ci-Align-rhel-custom-files-with-upstream-1431.patch deleted file mode 100644 index ec79047..0000000 --- a/ci-Align-rhel-custom-files-with-upstream-1431.patch +++ /dev/null @@ -1,256 +0,0 @@ -From 8e599c618ba33f7ed572f752fc9201ca44e41868 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Wed, 18 May 2022 16:21:45 +0200 -Subject: [PATCH 4/5] Align rhel custom files with upstream (#1431) - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 26: Align rhel custom files with upstream (#1431) -RH-Commit: [1/2] edac80c4fa3a11d093ee0e7260796566a7eb141e (eesposit/cloud-init-centos-) -RH-Bugzilla: 2088448 -RH-Acked-by: Vitaly Kuznetsov -RH-Acked-by: Miroslav Rezanina - -commit 9624758f91b61f4711e8d7b5c83075b5d23e0c43 -Author: Emanuele Giuseppe Esposito -Date: Wed May 18 15:18:04 2022 +0200 - - Align rhel custom files with upstream (#1431) - - So far RHEL had its own custom .service and cloud.cfg files, - that diverged from upstream. We always replaced the generated files - with the ones we had. - - This caused only confusion and made it harder to rebase and backport - patches targeting these files. - At the same time, we are going to delete our custom downstream-only files - and use the ones generated by .tmpl. - - The mapping is: - config/cloud.cfg.tmpl -> rhel/cloud.cfg - systemd/* -> rhel/systemd/* - - Such rhel-specific files are open and available in the Centos repo: - https://gitlab.com/redhat/centos-stream/src/cloud-init - - With this commit, we are also introducing modules in cloud.cfg that - were not in the default rhel cfg file, even though they should already - have been there with previous rebases and releases. - Anyways such modules support rhel as distro, and - therefore should cause no harm. - - Signed-off-by: Emanuele Giuseppe Esposito - - RHBZ: 2082071 - -Signed-off-by: Emanuele Giuseppe Esposito ---- - config/cloud.cfg.tmpl | 23 +++++++++++++++++++++++ - systemd/cloud-config.service.tmpl | 4 ++++ - systemd/cloud-final.service.tmpl | 13 +++++++++++++ - systemd/cloud-init-local.service.tmpl | 22 +++++++++++++++++++++- - systemd/cloud-init.service.tmpl | 6 +++++- - tests/unittests/test_render_cloudcfg.py | 1 + - 6 files changed, 67 insertions(+), 2 deletions(-) - -diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl -index 86beee3c..f4d2fd14 100644 ---- a/config/cloud.cfg.tmpl -+++ b/config/cloud.cfg.tmpl -@@ -34,7 +34,11 @@ disable_root: true - - {% if variant in ["almalinux", "alpine", "amazon", "centos", "cloudlinux", "eurolinux", - "fedora", "miraclelinux", "openEuler", "rhel", "rocky", "virtuozzo"] %} -+{% if variant == "rhel" %} -+mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service,_netdev', '0', '2'] -+{% else %} - mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2'] -+{% endif %} - {% if variant == "amazon" %} - resize_rootfs: noblock - {% endif %} -@@ -66,6 +70,14 @@ network: - config: disabled - {% endif %} - -+{% if variant == "rhel" %} -+# Default redhat settings: -+ssh_deletekeys: true -+ssh_genkeytypes: ['rsa', 'ecdsa', 'ed25519'] -+syslog_fix_perms: ~ -+disable_vmware_customization: false -+{% endif %} -+ - # The modules that run in the 'init' stage - cloud_init_modules: - - migrator -@@ -107,10 +119,15 @@ cloud_config_modules: - {% endif %} - {% if variant not in ["photon"] %} - - ssh-import-id -+{% if variant not in ["rhel"] %} - - keyboard -+{% endif %} - - locale - {% endif %} - - set-passwords -+{% if variant in ["rhel"] %} -+ - rh_subscription -+{% endif %} - {% if variant in ["rhel", "fedora", "photon"] %} - {% if variant not in ["photon"] %} - - spacewalk -@@ -239,6 +256,10 @@ system_info: - name: ec2-user - lock_passwd: True - gecos: EC2 Default User -+{% elif variant == "rhel" %} -+ name: cloud-user -+ lock_passwd: true -+ gecos: Cloud User - {% else %} - name: {{ variant }} - lock_passwd: True -@@ -254,6 +275,8 @@ system_info: - groups: [adm, sudo] - {% elif variant == "arch" %} - groups: [wheel, users] -+{% elif variant == "rhel" %} -+ groups: [adm, systemd-journal] - {% else %} - groups: [wheel, adm, systemd-journal] - {% endif %} -diff --git a/systemd/cloud-config.service.tmpl b/systemd/cloud-config.service.tmpl -index 9d928ca2..d5568a6e 100644 ---- a/systemd/cloud-config.service.tmpl -+++ b/systemd/cloud-config.service.tmpl -@@ -4,6 +4,10 @@ Description=Apply the settings specified in cloud-config - After=network-online.target cloud-config.target - After=snapd.seeded.service - Wants=network-online.target cloud-config.target -+{% if variant == "rhel" %} -+ConditionPathExists=!/etc/cloud/cloud-init.disabled -+ConditionKernelCommandLine=!cloud-init=disabled -+{% endif %} - - [Service] - Type=oneshot -diff --git a/systemd/cloud-final.service.tmpl b/systemd/cloud-final.service.tmpl -index 8207b18c..85f423ac 100644 ---- a/systemd/cloud-final.service.tmpl -+++ b/systemd/cloud-final.service.tmpl -@@ -7,6 +7,10 @@ After=multi-user.target - Before=apt-daily.service - {% endif %} - Wants=network-online.target cloud-config.service -+{% if variant == "rhel" %} -+ConditionPathExists=!/etc/cloud/cloud-init.disabled -+ConditionKernelCommandLine=!cloud-init=disabled -+{% endif %} - - - [Service] -@@ -15,7 +19,16 @@ ExecStart=/usr/bin/cloud-init modules --mode=final - RemainAfterExit=yes - TimeoutSec=0 - KillMode=process -+{% if variant == "rhel" %} -+# Restart NetworkManager if it is present and running. -+ExecStartPost=/bin/sh -c 'u=NetworkManager.service; \ -+ out=$(systemctl show --property=SubState $u) || exit; \ -+ [ "$out" = "SubState=running" ] || exit 0; \ -+ systemctl reload-or-try-restart $u' -+{% else %} - TasksMax=infinity -+{% endif %} -+ - - # Output needs to appear in instance console output - StandardOutput=journal+console -diff --git a/systemd/cloud-init-local.service.tmpl b/systemd/cloud-init-local.service.tmpl -index 7166f640..a6b82650 100644 ---- a/systemd/cloud-init-local.service.tmpl -+++ b/systemd/cloud-init-local.service.tmpl -@@ -1,23 +1,43 @@ - ## template:jinja - [Unit] - Description=Initial cloud-init job (pre-networking) --{% if variant in ["ubuntu", "unknown", "debian"] %} -+{% if variant in ["ubuntu", "unknown", "debian", "rhel" ] %} - DefaultDependencies=no - {% endif %} - Wants=network-pre.target - After=hv_kvp_daemon.service - After=systemd-remount-fs.service -+{% if variant == "rhel" %} -+Requires=dbus.socket -+After=dbus.socket -+{% endif %} - Before=NetworkManager.service -+{% if variant == "rhel" %} -+Before=network.service -+{% endif %} - Before=network-pre.target - Before=shutdown.target -+{% if variant == "rhel" %} -+Before=firewalld.target -+Conflicts=shutdown.target -+{% endif %} - {% if variant in ["ubuntu", "unknown", "debian"] %} - Before=sysinit.target - Conflicts=shutdown.target - {% endif %} - RequiresMountsFor=/var/lib/cloud -+{% if variant == "rhel" %} -+ConditionPathExists=!/etc/cloud/cloud-init.disabled -+ConditionKernelCommandLine=!cloud-init=disabled -+{% endif %} - - [Service] - Type=oneshot -+{% if variant == "rhel" %} -+ExecStartPre=/bin/mkdir -p /run/cloud-init -+ExecStartPre=/sbin/restorecon /run/cloud-init -+ExecStartPre=/usr/bin/touch /run/cloud-init/enabled -+{% endif %} - ExecStart=/usr/bin/cloud-init init --local - ExecStart=/bin/touch /run/cloud-init/network-config-ready - RemainAfterExit=yes -diff --git a/systemd/cloud-init.service.tmpl b/systemd/cloud-init.service.tmpl -index e71e5679..c170aef7 100644 ---- a/systemd/cloud-init.service.tmpl -+++ b/systemd/cloud-init.service.tmpl -@@ -1,7 +1,7 @@ - ## template:jinja - [Unit] - Description=Initial cloud-init job (metadata service crawler) --{% if variant not in ["photon"] %} -+{% if variant not in ["photon", "rhel"] %} - DefaultDependencies=no - {% endif %} - Wants=cloud-init-local.service -@@ -36,6 +36,10 @@ Before=shutdown.target - Conflicts=shutdown.target - {% endif %} - Before=systemd-user-sessions.service -+{% if variant == "rhel" %} -+ConditionPathExists=!/etc/cloud/cloud-init.disabled -+ConditionKernelCommandLine=!cloud-init=disabled -+{% endif %} - - [Service] - Type=oneshot -diff --git a/tests/unittests/test_render_cloudcfg.py b/tests/unittests/test_render_cloudcfg.py -index 30fbd1a4..9f95d448 100644 ---- a/tests/unittests/test_render_cloudcfg.py -+++ b/tests/unittests/test_render_cloudcfg.py -@@ -68,6 +68,7 @@ class TestRenderCloudCfg: - default_user_exceptions = { - "amazon": "ec2-user", - "debian": "ubuntu", -+ "rhel": "cloud-user", - "unknown": "ubuntu", - } - default_user = system_cfg["system_info"]["default_user"]["name"] --- -2.31.1 - diff --git a/ci-Allow-growpart-to-resize-encrypted-partitions-1316.patch b/ci-Allow-growpart-to-resize-encrypted-partitions-1316.patch deleted file mode 100644 index 93d922f..0000000 --- a/ci-Allow-growpart-to-resize-encrypted-partitions-1316.patch +++ /dev/null @@ -1,516 +0,0 @@ -From 1176a788c23697099093b4d8a9a21f10f71ebb12 Mon Sep 17 00:00:00 2001 -From: Vitaly Kuznetsov -Date: Wed, 1 Feb 2023 10:47:07 +0100 -Subject: [PATCH] Allow growpart to resize encrypted partitions (#1316) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2166245 - -commit d95a331d1035d52443c470e0c00765a2c2b271cc -Author: James Falcon -Date: Tue Apr 26 19:03:13 2022 -0500 - - Allow growpart to resize encrypted partitions (#1316) - - Adds the ability for growpart to resize a LUKS formatted partition. - This involves resizing the underlying partition as well as the - filesystem. 'cryptsetup' is used for resizing. - - This relies on a file present at /cc_growpart_keydata containing - json formatted 'key' and 'slot' keys, with the key being - base64 encoded. After resize, cloud-init will destroy - the luks slot used for resizing and remove the key file. - -Conflicts: - cloudinit/config/cc_growpart.py (includes only) - -Signed-off-by: Vitaly Kuznetsov ---- - cloudinit/config/cc_growpart.py | 171 +++++++++++++++- - test-requirements.txt | 1 + - tests/unittests/config/test_cc_growpart.py | 228 +++++++++++++++++++++ - tox.ini | 1 + - 4 files changed, 400 insertions(+), 1 deletion(-) - -diff --git a/cloudinit/config/cc_growpart.py b/cloudinit/config/cc_growpart.py -index 43334caa..bdf17aba 100644 ---- a/cloudinit/config/cc_growpart.py -+++ b/cloudinit/config/cc_growpart.py -@@ -64,10 +64,16 @@ growpart is:: - ignore_growroot_disabled: - """ - -+import base64 -+import copy -+import json - import os - import os.path - import re - import stat -+from contextlib import suppress -+from pathlib import Path -+from typing import Tuple - - from cloudinit import log as logging - from cloudinit import subp, temp_utils, util -@@ -81,6 +87,8 @@ DEFAULT_CONFIG = { - "ignore_growroot_disabled": False, - } - -+KEYDATA_PATH = Path("/cc_growpart_keydata") -+ - - class RESIZE(object): - SKIPPED = "SKIPPED" -@@ -289,10 +297,128 @@ def devent2dev(devent): - return dev - - -+def get_mapped_device(blockdev): -+ """Returns underlying block device for a mapped device. -+ -+ If it is mapped, blockdev will usually take the form of -+ /dev/mapper/some_name -+ -+ If blockdev is a symlink pointing to a /dev/dm-* device, return -+ the device pointed to. Otherwise, return None. -+ """ -+ realpath = os.path.realpath(blockdev) -+ if realpath.startswith("/dev/dm-"): -+ LOG.debug("%s is a mapped device pointing to %s", blockdev, realpath) -+ return realpath -+ return None -+ -+ -+def is_encrypted(blockdev, partition) -> bool: -+ """ -+ Check if a device is an encrypted device. blockdev should have -+ a /dev/dm-* path whereas partition is something like /dev/sda1. -+ """ -+ if not subp.which("cryptsetup"): -+ LOG.debug("cryptsetup not found. Assuming no encrypted partitions") -+ return False -+ try: -+ subp.subp(["cryptsetup", "status", blockdev]) -+ except subp.ProcessExecutionError as e: -+ if e.exit_code == 4: -+ LOG.debug("Determined that %s is not encrypted", blockdev) -+ else: -+ LOG.warning( -+ "Received unexpected exit code %s from " -+ "cryptsetup status. Assuming no encrypted partitions.", -+ e.exit_code, -+ ) -+ return False -+ with suppress(subp.ProcessExecutionError): -+ subp.subp(["cryptsetup", "isLuks", partition]) -+ LOG.debug("Determined that %s is encrypted", blockdev) -+ return True -+ return False -+ -+ -+def get_underlying_partition(blockdev): -+ command = ["dmsetup", "deps", "--options=devname", blockdev] -+ dep: str = subp.subp(command)[0] # type: ignore -+ # Returned result should look something like: -+ # 1 dependencies : (vdb1) -+ if not dep.startswith("1 depend"): -+ raise RuntimeError( -+ f"Expecting '1 dependencies' from 'dmsetup'. Received: {dep}" -+ ) -+ try: -+ return f'/dev/{dep.split(": (")[1].split(")")[0]}' -+ except IndexError as e: -+ raise RuntimeError( -+ f"Ran `{command}`, but received unexpected stdout: `{dep}`" -+ ) from e -+ -+ -+def resize_encrypted(blockdev, partition) -> Tuple[str, str]: -+ """Use 'cryptsetup resize' to resize LUKS volume. -+ -+ The loaded keyfile is json formatted with 'key' and 'slot' keys. -+ key is base64 encoded. Example: -+ {"key":"XFmCwX2FHIQp0LBWaLEMiHIyfxt1SGm16VvUAVledlY=","slot":5} -+ """ -+ if not KEYDATA_PATH.exists(): -+ return (RESIZE.SKIPPED, "No encryption keyfile found") -+ try: -+ with KEYDATA_PATH.open() as f: -+ keydata = json.load(f) -+ key = keydata["key"] -+ decoded_key = base64.b64decode(key) -+ slot = keydata["slot"] -+ except Exception as e: -+ raise RuntimeError( -+ "Could not load encryption key. This is expected if " -+ "the volume has been previously resized." -+ ) from e -+ -+ try: -+ subp.subp( -+ ["cryptsetup", "--key-file", "-", "resize", blockdev], -+ data=decoded_key, -+ ) -+ finally: -+ try: -+ subp.subp( -+ [ -+ "cryptsetup", -+ "luksKillSlot", -+ "--batch-mode", -+ partition, -+ str(slot), -+ ] -+ ) -+ except subp.ProcessExecutionError as e: -+ LOG.warning( -+ "Failed to kill luks slot after resizing encrypted volume: %s", -+ e, -+ ) -+ try: -+ KEYDATA_PATH.unlink() -+ except Exception: -+ util.logexc( -+ LOG, "Failed to remove keyfile after resizing encrypted volume" -+ ) -+ -+ return ( -+ RESIZE.CHANGED, -+ f"Successfully resized encrypted volume '{blockdev}'", -+ ) -+ -+ - def resize_devices(resizer, devices): - # returns a tuple of tuples containing (entry-in-devices, action, message) -+ devices = copy.copy(devices) - info = [] -- for devent in devices: -+ -+ while devices: -+ devent = devices.pop(0) - try: - blockdev = devent2dev(devent) - except ValueError as e: -@@ -329,6 +455,49 @@ def resize_devices(resizer, devices): - ) - continue - -+ underlying_blockdev = get_mapped_device(blockdev) -+ if underlying_blockdev: -+ try: -+ # We need to resize the underlying partition first -+ partition = get_underlying_partition(blockdev) -+ if is_encrypted(underlying_blockdev, partition): -+ if partition not in [x[0] for x in info]: -+ # We shouldn't attempt to resize this mapped partition -+ # until the underlying partition is resized, so re-add -+ # our device to the beginning of the list we're -+ # iterating over, then add our underlying partition -+ # so it can get processed first -+ devices.insert(0, devent) -+ devices.insert(0, partition) -+ continue -+ status, message = resize_encrypted(blockdev, partition) -+ info.append( -+ ( -+ devent, -+ status, -+ message, -+ ) -+ ) -+ else: -+ info.append( -+ ( -+ devent, -+ RESIZE.SKIPPED, -+ f"Resizing mapped device ({blockdev}) skipped " -+ "as it is not encrypted.", -+ ) -+ ) -+ except Exception as e: -+ info.append( -+ ( -+ devent, -+ RESIZE.FAILED, -+ f"Resizing encrypted device ({blockdev}) failed: {e}", -+ ) -+ ) -+ # At this point, we WON'T resize a non-encrypted mapped device -+ # though we should probably grow the ability to -+ continue - try: - (disk, ptnum) = device_part_info(blockdev) - except (TypeError, ValueError) as e: -diff --git a/test-requirements.txt b/test-requirements.txt -index 06dfbbec..7160416a 100644 ---- a/test-requirements.txt -+++ b/test-requirements.txt -@@ -2,6 +2,7 @@ - httpretty>=0.7.1 - pytest - pytest-cov -+pytest-mock - - # Only really needed on older versions of python - setuptools -diff --git a/tests/unittests/config/test_cc_growpart.py b/tests/unittests/config/test_cc_growpart.py -index ba66f136..7d4e2629 100644 ---- a/tests/unittests/config/test_cc_growpart.py -+++ b/tests/unittests/config/test_cc_growpart.py -@@ -8,6 +8,7 @@ import shutil - import stat - import unittest - from contextlib import ExitStack -+from itertools import chain - from unittest import mock - - from cloudinit import cloud, subp, temp_utils -@@ -342,6 +343,233 @@ class TestResize(unittest.TestCase): - os.stat = real_stat - - -+class TestEncrypted: -+ """Attempt end-to-end scenarios using encrypted devices. -+ -+ Things are mocked such that: -+ - "/fake_encrypted" is mounted onto "/dev/mapper/fake" -+ - "/dev/mapper/fake" is a LUKS device and symlinked to /dev/dm-1 -+ - The partition backing "/dev/mapper/fake" is "/dev/vdx1" -+ - "/" is not encrypted and mounted onto "/dev/vdz1" -+ -+ Note that we don't (yet) support non-encrypted mapped drives, such -+ as LVM volumes. If our mount point is /dev/mapper/*, then we will -+ not resize it if it is not encrypted. -+ """ -+ -+ def _subp_side_effect(self, value, good=True, **kwargs): -+ if value[0] == "dmsetup": -+ return ("1 dependencies : (vdx1)",) -+ return mock.Mock() -+ -+ def _device_part_info_side_effect(self, value): -+ if value.startswith("/dev/mapper/"): -+ raise TypeError(f"{value} not a partition") -+ return (1024, 1024) -+ -+ def _devent2dev_side_effect(self, value): -+ if value == "/fake_encrypted": -+ return "/dev/mapper/fake" -+ elif value == "/": -+ return "/dev/vdz" -+ elif value.startswith("/dev"): -+ return value -+ raise Exception(f"unexpected value {value}") -+ -+ def _realpath_side_effect(self, value): -+ return "/dev/dm-1" if value.startswith("/dev/mapper") else value -+ -+ def assert_resize_and_cleanup(self): -+ all_subp_args = list( -+ chain(*[args[0][0] for args in self.m_subp.call_args_list]) -+ ) -+ assert "resize" in all_subp_args -+ assert "luksKillSlot" in all_subp_args -+ self.m_unlink.assert_called_once() -+ -+ def assert_no_resize_or_cleanup(self): -+ all_subp_args = list( -+ chain(*[args[0][0] for args in self.m_subp.call_args_list]) -+ ) -+ assert "resize" not in all_subp_args -+ assert "luksKillSlot" not in all_subp_args -+ self.m_unlink.assert_not_called() -+ -+ @pytest.fixture -+ def common_mocks(self, mocker): -+ # These are all "happy path" mocks which will get overridden -+ # when needed -+ mocker.patch( -+ "cloudinit.config.cc_growpart.device_part_info", -+ side_effect=self._device_part_info_side_effect, -+ ) -+ mocker.patch("os.stat") -+ mocker.patch("stat.S_ISBLK") -+ mocker.patch("stat.S_ISCHR") -+ mocker.patch( -+ "cloudinit.config.cc_growpart.devent2dev", -+ side_effect=self._devent2dev_side_effect, -+ ) -+ mocker.patch( -+ "os.path.realpath", side_effect=self._realpath_side_effect -+ ) -+ # Only place subp.which is used in cc_growpart is for cryptsetup -+ mocker.patch( -+ "cloudinit.config.cc_growpart.subp.which", -+ return_value="/usr/sbin/cryptsetup", -+ ) -+ self.m_subp = mocker.patch( -+ "cloudinit.config.cc_growpart.subp.subp", -+ side_effect=self._subp_side_effect, -+ ) -+ mocker.patch( -+ "pathlib.Path.open", -+ new_callable=mock.mock_open, -+ read_data=( -+ '{"key":"XFmCwX2FHIQp0LBWaLEMiHIyfxt1SGm16VvUAVledlY=",' -+ '"slot":5}' -+ ), -+ ) -+ mocker.patch("pathlib.Path.exists", return_value=True) -+ self.m_unlink = mocker.patch("pathlib.Path.unlink", autospec=True) -+ -+ self.resizer = mock.Mock() -+ self.resizer.resize = mock.Mock(return_value=(1024, 1024)) -+ -+ def test_resize_when_encrypted(self, common_mocks, caplog): -+ info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"]) -+ assert len(info) == 2 -+ assert info[0][0] == "/dev/vdx1" -+ assert info[0][2].startswith("no change necessary") -+ assert info[1][0] == "/fake_encrypted" -+ assert ( -+ info[1][2] -+ == "Successfully resized encrypted volume '/dev/mapper/fake'" -+ ) -+ assert ( -+ "/dev/mapper/fake is a mapped device pointing to /dev/dm-1" -+ in caplog.text -+ ) -+ assert "Determined that /dev/dm-1 is encrypted" in caplog.text -+ -+ self.assert_resize_and_cleanup() -+ -+ def test_resize_when_unencrypted(self, common_mocks): -+ info = cc_growpart.resize_devices(self.resizer, ["/"]) -+ assert len(info) == 1 -+ assert info[0][0] == "/" -+ assert "encrypted" not in info[0][2] -+ self.assert_no_resize_or_cleanup() -+ -+ def test_encrypted_but_cryptsetup_not_found( -+ self, common_mocks, mocker, caplog -+ ): -+ mocker.patch( -+ "cloudinit.config.cc_growpart.subp.which", -+ return_value=None, -+ ) -+ info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"]) -+ -+ assert len(info) == 1 -+ assert "skipped as it is not encrypted" in info[0][2] -+ assert "cryptsetup not found" in caplog.text -+ self.assert_no_resize_or_cleanup() -+ -+ def test_dmsetup_not_found(self, common_mocks, mocker, caplog): -+ def _subp_side_effect(value, **kwargs): -+ if value[0] == "dmsetup": -+ raise subp.ProcessExecutionError() -+ -+ mocker.patch( -+ "cloudinit.config.cc_growpart.subp.subp", -+ side_effect=_subp_side_effect, -+ ) -+ info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"]) -+ assert len(info) == 1 -+ assert info[0][0] == "/fake_encrypted" -+ assert info[0][1] == "FAILED" -+ assert ( -+ "Resizing encrypted device (/dev/mapper/fake) failed" in info[0][2] -+ ) -+ self.assert_no_resize_or_cleanup() -+ -+ def test_unparsable_dmsetup(self, common_mocks, mocker, caplog): -+ def _subp_side_effect(value, **kwargs): -+ if value[0] == "dmsetup": -+ return ("2 dependencies",) -+ return mock.Mock() -+ -+ mocker.patch( -+ "cloudinit.config.cc_growpart.subp.subp", -+ side_effect=_subp_side_effect, -+ ) -+ info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"]) -+ assert len(info) == 1 -+ assert info[0][0] == "/fake_encrypted" -+ assert info[0][1] == "FAILED" -+ assert ( -+ "Resizing encrypted device (/dev/mapper/fake) failed" in info[0][2] -+ ) -+ self.assert_no_resize_or_cleanup() -+ -+ def test_missing_keydata(self, common_mocks, mocker, caplog): -+ # Note that this will be standard behavior after first boot -+ # on a system with an encrypted root partition -+ mocker.patch("pathlib.Path.open", side_effect=FileNotFoundError()) -+ info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"]) -+ assert len(info) == 2 -+ assert info[0][0] == "/dev/vdx1" -+ assert info[0][2].startswith("no change necessary") -+ assert info[1][0] == "/fake_encrypted" -+ assert info[1][1] == "FAILED" -+ assert ( -+ info[1][2] -+ == "Resizing encrypted device (/dev/mapper/fake) failed: Could " -+ "not load encryption key. This is expected if the volume has " -+ "been previously resized." -+ ) -+ self.assert_no_resize_or_cleanup() -+ -+ def test_resize_failed(self, common_mocks, mocker, caplog): -+ def _subp_side_effect(value, **kwargs): -+ if value[0] == "dmsetup": -+ return ("1 dependencies : (vdx1)",) -+ elif value[0] == "cryptsetup" and "resize" in value: -+ raise subp.ProcessExecutionError() -+ return mock.Mock() -+ -+ self.m_subp = mocker.patch( -+ "cloudinit.config.cc_growpart.subp.subp", -+ side_effect=_subp_side_effect, -+ ) -+ -+ info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"]) -+ assert len(info) == 2 -+ assert info[0][0] == "/dev/vdx1" -+ assert info[0][2].startswith("no change necessary") -+ assert info[1][0] == "/fake_encrypted" -+ assert info[1][1] == "FAILED" -+ assert ( -+ "Resizing encrypted device (/dev/mapper/fake) failed" in info[1][2] -+ ) -+ # Assert we still cleanup -+ all_subp_args = list( -+ chain(*[args[0][0] for args in self.m_subp.call_args_list]) -+ ) -+ assert "luksKillSlot" in all_subp_args -+ self.m_unlink.assert_called_once() -+ -+ def test_resize_skipped(self, common_mocks, mocker, caplog): -+ mocker.patch("pathlib.Path.exists", return_value=False) -+ info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"]) -+ assert len(info) == 2 -+ assert info[1] == ( -+ "/fake_encrypted", -+ "SKIPPED", -+ "No encryption keyfile found", -+ ) -+ -+ - def simple_device_part_info(devpath): - # simple stupid return (/dev/vda, 1) for /dev/vda - ret = re.search("([^0-9]*)([0-9]*)$", devpath) -diff --git a/tox.ini b/tox.ini -index c494cb94..04a206f2 100644 ---- a/tox.ini -+++ b/tox.ini -@@ -108,6 +108,7 @@ deps = - # test-requirements - pytest==3.3.2 - pytest-cov==2.5.1 -+ pytest-mock==1.7.1 - # Needed by pytest and default causes failures - attrs==17.4.0 - --- -2.39.1 - diff --git a/ci-Ensure-network-ready-before-cloud-init-service-runs-.patch b/ci-Ensure-network-ready-before-cloud-init-service-runs-.patch deleted file mode 100644 index cd93ee6..0000000 --- a/ci-Ensure-network-ready-before-cloud-init-service-runs-.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 14d1952c17637b80923d1bfaf3b6b5f8cf032147 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Wed, 14 Dec 2022 09:31:51 +0100 -Subject: [PATCH] Ensure network ready before cloud-init service runs on RHEL - (#1893) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2152100 - -commit 6e725f36647407d201af0603d7db11fc96a93d4d -Author: James Falcon -Date: Tue Dec 13 10:55:23 2022 -0600 - - Ensure network ready before cloud-init service runs on RHEL (#1893) - - LP: #1998655 - -Signed-off-by: Emanuele Giuseppe Esposito ---- - systemd/cloud-init.service.tmpl | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/systemd/cloud-init.service.tmpl b/systemd/cloud-init.service.tmpl -index c170aef7..fc984d5c 100644 ---- a/systemd/cloud-init.service.tmpl -+++ b/systemd/cloud-init.service.tmpl -@@ -16,6 +16,7 @@ After=networking.service - "miraclelinux", "openEuler", "rhel", "rocky", "virtuozzo"] %} - After=network.service - After=NetworkManager.service -+After=NetworkManager-wait-online.service - {% endif %} - {% if variant in ["suse"] %} - After=wicked.service --- -2.38.1 - diff --git a/ci-Honor-system-locale-for-RHEL-1355.patch b/ci-Honor-system-locale-for-RHEL-1355.patch deleted file mode 100644 index c362160..0000000 --- a/ci-Honor-system-locale-for-RHEL-1355.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 53e3f8ab9008fec8400f96918c2129f7defe6a70 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Fri, 10 Jun 2022 20:51:55 +0200 -Subject: [PATCH 1/3] Honor system locale for RHEL (#1355) - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 29: Honor system locale for RHEL (#1355) -RH-Commit: [1/1] d571126fe6add8dc34a22c869d4e1a07a7373d8d (eesposit/cloud-init-centos-) -RH-Bugzilla: 2061604 -RH-Acked-by: Mohamed Gamal Morsy -RH-Acked-by: Vitaly Kuznetsov - -commit 58da7d856274e9ca2b507128d6f186e0e6abfe06 -Author: Wei Shi -Date: Wed Mar 30 23:55:30 2022 +0800 - - Honor system locale for RHEL (#1355) - - Make sure to use system locale as default on RHEL if locale is not - set in cloud-config. - - RHEL has a pre-installed cloud image using C.UTF-8 for system locale - just like ubuntu-minimal cloud image, without this patch, locale - module will set it to en_US.UTF-8 from ds default value during config - stage. - - Authored-by: Wei Shi - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/distros/rhel.py | 32 +++++++++++++++++++++++++ - tests/unittests/distros/test_generic.py | 10 ++++---- - tools/.github-cla-signers | 1 + - 3 files changed, 39 insertions(+), 4 deletions(-) - -diff --git a/cloudinit/distros/rhel.py b/cloudinit/distros/rhel.py -index 84744ece..320f4ba1 100644 ---- a/cloudinit/distros/rhel.py -+++ b/cloudinit/distros/rhel.py -@@ -7,6 +7,7 @@ - # Author: Joshua Harlow - # - # This file is part of cloud-init. See LICENSE file for license information. -+import os - - from cloudinit import distros, helpers - from cloudinit import log as logging -@@ -57,11 +58,25 @@ class Distro(distros.Distro): - # should only happen say once per instance...) - self._runner = helpers.Runners(paths) - self.osfamily = "redhat" -+ self.default_locale = "en_US.UTF-8" -+ self.system_locale = None - cfg["ssh_svcname"] = "sshd" - - def install_packages(self, pkglist): - self.package_command("install", pkgs=pkglist) - -+ def get_locale(self): -+ """Return the default locale if set, else use system locale""" -+ -+ # read system locale value -+ if not self.system_locale: -+ self.system_locale = self._read_system_locale() -+ -+ # Return system_locale setting if valid, else use default locale -+ return ( -+ self.system_locale if self.system_locale else self.default_locale -+ ) -+ - def apply_locale(self, locale, out_fn=None): - if self.uses_systemd(): - if not out_fn: -@@ -75,6 +90,23 @@ class Distro(distros.Distro): - } - rhel_util.update_sysconfig_file(out_fn, locale_cfg) - -+ def _read_system_locale(self, keyname="LANG"): -+ """Read system default locale setting, if present""" -+ if self.uses_systemd(): -+ locale_fn = self.systemd_locale_conf_fn -+ else: -+ locale_fn = self.locale_conf_fn -+ -+ if not locale_fn: -+ raise ValueError("Invalid path: %s" % locale_fn) -+ -+ if os.path.exists(locale_fn): -+ (_exists, contents) = rhel_util.read_sysconfig_file(locale_fn) -+ if keyname in contents: -+ return contents[keyname] -+ else: -+ return None -+ - def _write_hostname(self, hostname, filename): - # systemd will never update previous-hostname for us, so - # we need to do it ourselves -diff --git a/tests/unittests/distros/test_generic.py b/tests/unittests/distros/test_generic.py -index 93c5395c..fedc7300 100644 ---- a/tests/unittests/distros/test_generic.py -+++ b/tests/unittests/distros/test_generic.py -@@ -187,12 +187,14 @@ class TestGenericDistro(helpers.FilesystemMockingTestCase): - locale = d.get_locale() - self.assertEqual("C.UTF-8", locale) - -- def test_get_locale_rhel(self): -- """Test rhel distro returns NotImplementedError exception""" -+ @mock.patch("cloudinit.distros.rhel.Distro._read_system_locale") -+ def test_get_locale_rhel(self, m_locale): -+ """Test rhel distro returns locale set to C.UTF-8""" -+ m_locale.return_value = "C.UTF-8" - cls = distros.fetch("rhel") - d = cls("rhel", {}, None) -- with self.assertRaises(NotImplementedError): -- d.get_locale() -+ locale = d.get_locale() -+ self.assertEqual("C.UTF-8", locale) - - def test_expire_passwd_uses_chpasswd(self): - """Test ubuntu.expire_passwd uses the passwd command.""" -diff --git a/tools/.github-cla-signers b/tools/.github-cla-signers -index 9f71ea0c..9eb2ae38 100644 ---- a/tools/.github-cla-signers -+++ b/tools/.github-cla-signers -@@ -70,6 +70,7 @@ renanrodrigo - rhansen - riedel - sarahwzadara -+shi2wei3 - slingamn - slyon - smoser --- -2.35.1 - diff --git a/ci-Remove-rhel-specific-files.patch b/ci-Remove-rhel-specific-files.patch deleted file mode 100644 index efce1f5..0000000 --- a/ci-Remove-rhel-specific-files.patch +++ /dev/null @@ -1,370 +0,0 @@ -From 0ae221fe8f29555370520d05f6558eb75fe3cd42 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Thu, 5 May 2022 11:31:33 +0200 -Subject: [PATCH 5/5] Remove rhel specific files - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 26: Align rhel custom files with upstream (#1431) -RH-Commit: [2/2] 0b9687ebab4f4039d5bbe05c00806ec7923e898d (eesposit/cloud-init-centos-) -RH-Bugzilla: 2088448 -RH-Acked-by: Vitaly Kuznetsov -RH-Acked-by: Miroslav Rezanina - -Remove all files in rhel/ directory and related commands that copy -and replace them with the generated ones. - -Also adjust setup.py, align it with upstream: -- by default, after rhel 8.3 ds-identify is in /usr/libexec, so no need to move it manually -- bash-completions work also in /usr/share, as upstream -- udev also works in /lib/udev - -Also remove rhel/README since it is outdated (chef is used in cloud.cfg) and cloud-init-tmpfiles.conf, -as it exists also in .distro. - -X-downstream-only: yes - -Signed-off-by: Emanuele Giuseppe Esposito ---- - rhel/README.rhel | 5 -- - rhel/cloud-init-tmpfiles.conf | 1 - - rhel/cloud.cfg | 69 --------------------------- - rhel/systemd/cloud-config.service | 18 ------- - rhel/systemd/cloud-config.target | 11 ----- - rhel/systemd/cloud-final.service | 24 ---------- - rhel/systemd/cloud-init-local.service | 31 ------------ - rhel/systemd/cloud-init.service | 26 ---------- - rhel/systemd/cloud-init.target | 7 --- - setup.py | 28 ++++++++++- - 11 files changed, 31 insertions(+), 210 deletions(-) - delete mode 100644 rhel/README.rhel - delete mode 100644 rhel/cloud-init-tmpfiles.conf - delete mode 100644 rhel/cloud.cfg - delete mode 100644 rhel/systemd/cloud-config.service - delete mode 100644 rhel/systemd/cloud-config.target - delete mode 100644 rhel/systemd/cloud-final.service - delete mode 100644 rhel/systemd/cloud-init-local.service - delete mode 100644 rhel/systemd/cloud-init.service - delete mode 100644 rhel/systemd/cloud-init.target - -diff --git a/rhel/README.rhel b/rhel/README.rhel -deleted file mode 100644 -index aa29630d..00000000 ---- a/rhel/README.rhel -+++ /dev/null -@@ -1,5 +0,0 @@ --The following cloud-init modules are currently unsupported on this OS: -- - apt_update_upgrade ('apt_update', 'apt_upgrade', 'apt_mirror', 'apt_preserve_sources_list', 'apt_old_mirror', 'apt_sources', 'debconf_selections', 'packages' options) -- - byobu ('byobu_by_default' option) -- - chef -- - grub_dpkg -diff --git a/rhel/cloud-init-tmpfiles.conf b/rhel/cloud-init-tmpfiles.conf -deleted file mode 100644 -index 0c6d2a3b..00000000 ---- a/rhel/cloud-init-tmpfiles.conf -+++ /dev/null -@@ -1 +0,0 @@ --d /run/cloud-init 0700 root root - - -diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg -deleted file mode 100644 -index 75d5c84b..00000000 ---- a/rhel/cloud.cfg -+++ /dev/null -@@ -1,69 +0,0 @@ --users: -- - default -- --disable_root: 1 --ssh_pwauth: 0 -- --mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service,_netdev', '0', '2'] --resize_rootfs_tmp: /dev --ssh_deletekeys: 1 --ssh_genkeytypes: ['rsa', 'ecdsa', 'ed25519'] --syslog_fix_perms: ~ --disable_vmware_customization: false -- --cloud_init_modules: -- - disk_setup -- - migrator -- - bootcmd -- - write-files -- - growpart -- - resizefs -- - set_hostname -- - update_hostname -- - update_etc_hosts -- - rsyslog -- - users-groups -- - ssh -- --cloud_config_modules: -- - mounts -- - locale -- - set-passwords -- - rh_subscription -- - yum-add-repo -- - package-update-upgrade-install -- - timezone -- - puppet -- - chef -- - salt-minion -- - mcollective -- - disable-ec2-metadata -- - runcmd -- --cloud_final_modules: -- - rightscale_userdata -- - scripts-per-once -- - scripts-per-boot -- - scripts-per-instance -- - scripts-user -- - ssh-authkey-fingerprints -- - keys-to-console -- - phone-home -- - final-message -- - power-state-change -- --system_info: -- default_user: -- name: cloud-user -- lock_passwd: true -- gecos: Cloud User -- groups: [adm, systemd-journal] -- sudo: ["ALL=(ALL) NOPASSWD:ALL"] -- shell: /bin/bash -- distro: rhel -- paths: -- cloud_dir: /var/lib/cloud -- templates_dir: /etc/cloud/templates -- ssh_svcname: sshd -- --# vim:syntax=yaml -diff --git a/rhel/systemd/cloud-config.service b/rhel/systemd/cloud-config.service -deleted file mode 100644 -index f3dcd4be..00000000 ---- a/rhel/systemd/cloud-config.service -+++ /dev/null -@@ -1,18 +0,0 @@ --[Unit] --Description=Apply the settings specified in cloud-config --After=network-online.target cloud-config.target --Wants=network-online.target cloud-config.target --ConditionPathExists=!/etc/cloud/cloud-init.disabled --ConditionKernelCommandLine=!cloud-init=disabled -- --[Service] --Type=oneshot --ExecStart=/usr/bin/cloud-init modules --mode=config --RemainAfterExit=yes --TimeoutSec=0 -- --# Output needs to appear in instance console output --StandardOutput=journal+console -- --[Install] --WantedBy=cloud-init.target -diff --git a/rhel/systemd/cloud-config.target b/rhel/systemd/cloud-config.target -deleted file mode 100644 -index ae9b7d02..00000000 ---- a/rhel/systemd/cloud-config.target -+++ /dev/null -@@ -1,11 +0,0 @@ --# cloud-init normally emits a "cloud-config" upstart event to inform third --# parties that cloud-config is available, which does us no good when we're --# using systemd. cloud-config.target serves as this synchronization point --# instead. Services that would "start on cloud-config" with upstart can --# instead use "After=cloud-config.target" and "Wants=cloud-config.target" --# as appropriate. -- --[Unit] --Description=Cloud-config availability --Wants=cloud-init-local.service cloud-init.service --After=cloud-init-local.service cloud-init.service -diff --git a/rhel/systemd/cloud-final.service b/rhel/systemd/cloud-final.service -deleted file mode 100644 -index e281c0cf..00000000 ---- a/rhel/systemd/cloud-final.service -+++ /dev/null -@@ -1,24 +0,0 @@ --[Unit] --Description=Execute cloud user/final scripts --After=network-online.target cloud-config.service rc-local.service --Wants=network-online.target cloud-config.service --ConditionPathExists=!/etc/cloud/cloud-init.disabled --ConditionKernelCommandLine=!cloud-init=disabled -- --[Service] --Type=oneshot --ExecStart=/usr/bin/cloud-init modules --mode=final --RemainAfterExit=yes --TimeoutSec=0 --KillMode=process --# Restart NetworkManager if it is present and running. --ExecStartPost=/bin/sh -c 'u=NetworkManager.service; \ -- out=$(systemctl show --property=SubState $u) || exit; \ -- [ "$out" = "SubState=running" ] || exit 0; \ -- systemctl reload-or-try-restart $u' -- --# Output needs to appear in instance console output --StandardOutput=journal+console -- --[Install] --WantedBy=cloud-init.target -diff --git a/rhel/systemd/cloud-init-local.service b/rhel/systemd/cloud-init-local.service -deleted file mode 100644 -index 8f9f6c9f..00000000 ---- a/rhel/systemd/cloud-init-local.service -+++ /dev/null -@@ -1,31 +0,0 @@ --[Unit] --Description=Initial cloud-init job (pre-networking) --DefaultDependencies=no --Wants=network-pre.target --After=systemd-remount-fs.service --Requires=dbus.socket --After=dbus.socket --Before=NetworkManager.service network.service --Before=network-pre.target --Before=shutdown.target --Before=firewalld.target --Conflicts=shutdown.target --RequiresMountsFor=/var/lib/cloud --ConditionPathExists=!/etc/cloud/cloud-init.disabled --ConditionKernelCommandLine=!cloud-init=disabled -- --[Service] --Type=oneshot --ExecStartPre=/bin/mkdir -p /run/cloud-init --ExecStartPre=/sbin/restorecon /run/cloud-init --ExecStartPre=/usr/bin/touch /run/cloud-init/enabled --ExecStart=/usr/bin/cloud-init init --local --ExecStart=/bin/touch /run/cloud-init/network-config-ready --RemainAfterExit=yes --TimeoutSec=0 -- --# Output needs to appear in instance console output --StandardOutput=journal+console -- --[Install] --WantedBy=cloud-init.target -diff --git a/rhel/systemd/cloud-init.service b/rhel/systemd/cloud-init.service -deleted file mode 100644 -index 0b3d796d..00000000 ---- a/rhel/systemd/cloud-init.service -+++ /dev/null -@@ -1,26 +0,0 @@ --[Unit] --Description=Initial cloud-init job (metadata service crawler) --Wants=cloud-init-local.service --Wants=sshd-keygen.service --Wants=sshd.service --After=cloud-init-local.service --After=NetworkManager.service network.service --After=NetworkManager-wait-online.service --Before=network-online.target --Before=sshd-keygen.service --Before=sshd.service --Before=systemd-user-sessions.service --ConditionPathExists=!/etc/cloud/cloud-init.disabled --ConditionKernelCommandLine=!cloud-init=disabled -- --[Service] --Type=oneshot --ExecStart=/usr/bin/cloud-init init --RemainAfterExit=yes --TimeoutSec=0 -- --# Output needs to appear in instance console output --StandardOutput=journal+console -- --[Install] --WantedBy=cloud-init.target -diff --git a/rhel/systemd/cloud-init.target b/rhel/systemd/cloud-init.target -deleted file mode 100644 -index 083c3b6f..00000000 ---- a/rhel/systemd/cloud-init.target -+++ /dev/null -@@ -1,7 +0,0 @@ --# cloud-init target is enabled by cloud-init-generator --# To disable it you can either: --# a.) boot with kernel cmdline of 'cloud-init=disabled' --# b.) touch a file /etc/cloud/cloud-init.disabled --[Unit] --Description=Cloud-init target --After=multi-user.target -diff --git a/setup.py b/setup.py -index 3c377eaa..a9132d2c 100755 ---- a/setup.py -+++ b/setup.py -@@ -139,6 +139,21 @@ INITSYS_FILES = { - "sysvinit_deb": [f for f in glob("sysvinit/debian/*") if is_f(f)], - "sysvinit_openrc": [f for f in glob("sysvinit/gentoo/*") if is_f(f)], - "sysvinit_suse": [f for f in glob("sysvinit/suse/*") if is_f(f)], -+ "systemd": [ -+ render_tmpl(f) -+ for f in ( -+ glob("systemd/*.tmpl") -+ + glob("systemd/*.service") -+ + glob("systemd/*.socket") -+ + glob("systemd/*.target") -+ ) -+ if (is_f(f) and not is_generator(f)) -+ ], -+ "systemd.generators": [ -+ render_tmpl(f, mode=0o755) -+ for f in glob("systemd/*") -+ if is_f(f) and is_generator(f) -+ ], - "upstart": [f for f in glob("upstart/*") if is_f(f)], - } - INITSYS_ROOTS = { -@@ -148,6 +163,10 @@ INITSYS_ROOTS = { - "sysvinit_deb": "etc/init.d", - "sysvinit_openrc": "etc/init.d", - "sysvinit_suse": "etc/init.d", -+ "systemd": pkg_config_read("systemd", "systemdsystemunitdir"), -+ "systemd.generators": pkg_config_read( -+ "systemd", "systemdsystemgeneratordir" -+ ), - "upstart": "etc/init/", - } - INITSYS_TYPES = sorted([f.partition(".")[0] for f in INITSYS_ROOTS.keys()]) -@@ -262,13 +281,15 @@ data_files = [ - ( - USR_LIB_EXEC + "/cloud-init", - [ -+ "tools/ds-identify", - "tools/hook-hotplug", - "tools/uncloud-init", - "tools/write-ssh-key-fingerprints", - ], - ), - ( -- ETC + "/bash_completion.d", ["bash_completion/cloud-init"], -+ USR + "/share/bash-completion/completions", -+ ["bash_completion/cloud-init"], - ), - (USR + "/share/doc/cloud-init", [f for f in glob("doc/*") if is_f(f)]), - ( -@@ -287,7 +308,8 @@ if not platform.system().endswith("BSD"): - ETC + "/NetworkManager/dispatcher.d/", - ["tools/hook-network-manager"], - ), -- ("/usr/lib/udev/rules.d", [f for f in glob("udev/*.rules")]), -+ (ETC + "/dhcp/dhclient-exit-hooks.d/", ["tools/hook-dhclient"]), -+ (LIB + "/udev/rules.d", [f for f in glob("udev/*.rules")]), - ( - ETC + "/systemd/system/sshd-keygen@.service.d/", - ["systemd/disable-sshd-keygen-if-cloud-init-active.conf"], -@@ -317,6 +339,8 @@ setuptools.setup( - scripts=["tools/cloud-init-per"], - license="Dual-licensed under GPLv3 or Apache 2.0", - data_files=data_files, -+ install_requires=requirements, -+ cmdclass=cmdclass, - entry_points={ - "console_scripts": [ - "cloud-init = cloudinit.cmd.main:main", --- -2.31.1 - diff --git a/ci-Revert-Revert-Setting-highest-autoconnect-priority-f.patch b/ci-Revert-Revert-Setting-highest-autoconnect-priority-f.patch deleted file mode 100644 index d919da9..0000000 --- a/ci-Revert-Revert-Setting-highest-autoconnect-priority-f.patch +++ /dev/null @@ -1,37 +0,0 @@ -From c843f5cf7152846da3422185a6ad344dd47604e6 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Mon, 8 Aug 2022 10:02:48 +0200 -Subject: [PATCH 3/3] Revert "Revert "Setting highest autoconnect priority for - network-scripts"" - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 31: Revert "Revert "Setting highest autoconnect priority for network-scripts"" -RH-Commit: [3/3] 09b83fb559675a2fcd4fc5394b251f034b92c1bc (eesposit/cloud-init-centos-) -RH-Bugzilla: 2107463 2104389 2117532 2098501 -RH-Acked-by: Eduardo Otubo -RH-Acked-by: Vitaly Kuznetsov -RH-Acked-by: Mohamed Gamal Morsy - -Reverting NM means we also need to restore this patch -This reverts commit 0eba5c6194017ef493a735cb24757c57d8af7b59. - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/net/sysconfig.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index d8c53312..b50035b5 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -337,6 +337,7 @@ class Renderer(renderer.Renderer): - "ONBOOT": True, - "USERCTL": False, - "BOOTPROTO": "none", -+ "AUTOCONNECT_PRIORITY": 999 - }, - "suse": {"BOOTPROTO": "static", "STARTMODE": "auto"}, - } --- -2.31.1 - diff --git a/ci-Revert-Setting-highest-autoconnect-priority-for-netw.patch b/ci-Revert-Setting-highest-autoconnect-priority-for-netw.patch deleted file mode 100644 index bd183a4..0000000 --- a/ci-Revert-Setting-highest-autoconnect-priority-for-netw.patch +++ /dev/null @@ -1,37 +0,0 @@ -From e5e2ba9e21ac40ec7b8fe1c1dcf501eaeb9f66bf Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Mon, 2 May 2022 14:43:17 +0200 -Subject: [PATCH 3/5] Revert "Setting highest autoconnect priority for - network-scripts" - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 24: Add native NetworkManager support (#1224) -RH-Commit: [3/3] 06c87581fc42b6827ad9df600f3dd76d51ced0d0 (eesposit/cloud-init-centos-) -RH-Bugzilla: 2056964 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Vitaly Kuznetsov - -This reverts commit 0ef0c86350aa5f800f8393a432f431e2818c8938, -since it was a temporary downstream-only patch while we waited for -"Add native NetworkManager support (#1224)". - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/net/sysconfig.py | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py -index 2a45a4fa..dc401d78 100644 ---- a/cloudinit/net/sysconfig.py -+++ b/cloudinit/net/sysconfig.py -@@ -317,7 +317,6 @@ class Renderer(renderer.Renderer): - "ONBOOT": True, - "USERCTL": False, - "BOOTPROTO": "none", -- "AUTOCONNECT_PRIORITY": 999 - }, - "suse": {"BOOTPROTO": "static", "STARTMODE": "auto"}, - } --- -2.31.1 - diff --git a/ci-Revert-Use-Network-Manager-and-Netplan-as-default-re.patch b/ci-Revert-Use-Network-Manager-and-Netplan-as-default-re.patch deleted file mode 100644 index 28c4151..0000000 --- a/ci-Revert-Use-Network-Manager-and-Netplan-as-default-re.patch +++ /dev/null @@ -1,75 +0,0 @@ -From c063021168dee7937281decd8f9b601f49a7d0f3 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Mon, 8 Aug 2022 10:02:17 +0200 -Subject: [PATCH 2/3] Revert "Use Network-Manager and Netplan as default - renderers for RHEL and Fedora (#1465)" - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 31: Revert "Revert "Setting highest autoconnect priority for network-scripts"" -RH-Commit: [2/3] bd662b768dc694c748cab9e36bc5ff0eb009e128 (eesposit/cloud-init-centos-) -RH-Bugzilla: 2107463 2104389 2117532 2098501 -RH-Acked-by: Eduardo Otubo -RH-Acked-by: Vitaly Kuznetsov -RH-Acked-by: Mohamed Gamal Morsy - -As NM is reverted, remove also documentation and any trace of it. -This reverts commit bbd9f47a7988e15a2823b065cd539d7c9562d77e. - -Signed-off-by: Emanuele Giuseppe Esposito ---- - config/cloud.cfg.tmpl | 3 --- - doc/rtd/topics/network-config.rst | 12 +----------- - 2 files changed, 1 insertion(+), 14 deletions(-) - -diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl -index f4d2fd14..80ab4f96 100644 ---- a/config/cloud.cfg.tmpl -+++ b/config/cloud.cfg.tmpl -@@ -353,7 +353,4 @@ system_info: - {% elif variant in ["dragonfly"] %} - network: - renderers: ['freebsd'] --{% elif variant in ["rhel", "fedora"] %} -- network: -- renderers: ['netplan', 'network-manager', 'networkd', 'sysconfig', 'eni'] - {% endif %} -diff --git a/doc/rtd/topics/network-config.rst b/doc/rtd/topics/network-config.rst -index f503caab..c461a3fe 100644 ---- a/doc/rtd/topics/network-config.rst -+++ b/doc/rtd/topics/network-config.rst -@@ -188,15 +188,6 @@ generated configuration into an internal network configuration state. From - 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 ``/etc/NetworkManager``. -- --It is the default for a number of Linux distributions, notably Fedora; --CentOS/RHEL; and derivatives. -- - - **ENI** - - /etc/network/interfaces or ``ENI`` is supported by the ``ifupdown`` package -@@ -224,7 +215,6 @@ is as follows: - - ENI - - Sysconfig - - Netplan --- NetworkManager - - When applying the policy, `Cloud-init`_ checks if the current instance has the - correct binaries and paths to support the renderer. The first renderer that -@@ -233,7 +223,7 @@ supplying an updated configuration in cloud-config. :: - - system_info: - network: -- renderers: ['netplan', 'network-manager', 'eni', 'sysconfig', 'freebsd', 'netbsd', 'openbsd'] -+ renderers: ['netplan', 'eni', 'sysconfig', 'freebsd', 'netbsd', 'openbsd'] - - - Network Configuration Tools --- -2.31.1 - diff --git a/ci-Support-EC2-tags-in-instance-metadata-1309.patch b/ci-Support-EC2-tags-in-instance-metadata-1309.patch deleted file mode 100644 index 7e2c490..0000000 --- a/ci-Support-EC2-tags-in-instance-metadata-1309.patch +++ /dev/null @@ -1,165 +0,0 @@ -From f5e9ed6c698eddd30e8e97d6f71070e7b75b1381 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Mon, 30 May 2022 16:45:08 +0200 -Subject: [PATCH 1/2] Support EC2 tags in instance metadata (#1309) - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 27: Support EC2 tags in instance metadata (#1309) -RH-Commit: [1/1] f6a03e1619316959d3cd1806981b0bebf12bd3b0 (eesposit/cloud-init-centos-) -RH-Bugzilla: 2091640 -RH-Acked-by: Eduardo Otubo -RH-Acked-by: Vitaly Kuznetsov -RH-Acked-by: Mohamed Gamal Morsy - -commit 40c52ce1f4049449b04f93226721f63af874c5c7 -Author: Eduardo Dobay -Date: Wed Apr 6 01:28:01 2022 -0300 - - Support EC2 tags in instance metadata (#1309) - - Add support for newer EC2 metadata versions (up to 2021-03-23), so that - tags can be retrieved from the `ds.meta_data.tags` field, as well as - with any new fields that might have been added since the 2018-09-24 - version. - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/sources/DataSourceEc2.py | 5 +++-- - doc/rtd/topics/datasources/ec2.rst | 28 ++++++++++++++++++++++------ - tests/unittests/sources/test_ec2.py | 26 +++++++++++++++++++++++++- - tools/.github-cla-signers | 1 + - 4 files changed, 51 insertions(+), 9 deletions(-) - -diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py -index 03b3870c..a030b498 100644 ---- a/cloudinit/sources/DataSourceEc2.py -+++ b/cloudinit/sources/DataSourceEc2.py -@@ -61,8 +61,9 @@ class DataSourceEc2(sources.DataSource): - min_metadata_version = "2009-04-04" - - # Priority ordered list of additional metadata versions which will be tried -- # for extended metadata content. IPv6 support comes in 2016-09-02 -- extended_metadata_versions = ["2018-09-24", "2016-09-02"] -+ # for extended metadata content. IPv6 support comes in 2016-09-02. -+ # Tags support comes in 2021-03-23. -+ extended_metadata_versions = ["2021-03-23", "2018-09-24", "2016-09-02"] - - # Setup read_url parameters per get_url_params. - url_max_wait = 120 -diff --git a/doc/rtd/topics/datasources/ec2.rst b/doc/rtd/topics/datasources/ec2.rst -index 94e4158d..77232269 100644 ---- a/doc/rtd/topics/datasources/ec2.rst -+++ b/doc/rtd/topics/datasources/ec2.rst -@@ -38,11 +38,26 @@ Userdata is accessible via the following URL: - GET http://169.254.169.254/2009-04-04/user-data - 1234,fred,reboot,true | 4512,jimbo, | 173,,, - --Note that there are multiple versions of this data provided, cloud-init --by default uses **2009-04-04** but newer versions can be supported with --relative ease (newer versions have more data exposed, while maintaining --backward compatibility with the previous versions). --Version **2016-09-02** is required for secondary IP address support. -+Note that there are multiple EC2 Metadata versions of this data provided -+to instances. cloud-init will attempt to use the most recent API version it -+supports in order to get latest API features and instance-data. If a given -+API version is not exposed to the instance, those API features will be -+unavailable to the instance. -+ -+ -++----------------+----------------------------------------------------------+ -++ EC2 version | supported instance-data/feature | -++================+==========================================================+ -++ **2021-03-23** | Required for Instance tag support. This feature must be | -+| | enabled individually on each instance. See the | -+| | `EC2 tags user guide`_. | -++----------------+----------------------------------------------------------+ -+| **2016-09-02** | Required for secondary IP address support. | -++----------------+----------------------------------------------------------+ -+| **2009-04-04** | Minimum supports EC2 API version for meta-data and | -+| | user-data. | -++----------------+----------------------------------------------------------+ -+ - - To see which versions are supported from your cloud provider use the following - URL: -@@ -71,7 +86,7 @@ configuration (in `/etc/cloud/cloud.cfg` or `/etc/cloud/cloud.cfg.d/`). - - The settings that may be configured are: - -- * **metadata_urls**: This list of urls will be searched for an Ec2 -+ * **metadata_urls**: This list of urls will be searched for an EC2 - metadata service. The first entry that successfully returns a 200 response - for //meta-data/instance-id will be selected. - (default: ['http://169.254.169.254', 'http://instance-data:8773']). -@@ -121,4 +136,5 @@ Notes - For example: the primary NIC will have a DHCP route-metric of 100, - the next NIC will be 200. - -+.. _EC2 tags user guide: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html#work-with-tags-in-IMDS - .. vi: textwidth=79 -diff --git a/tests/unittests/sources/test_ec2.py b/tests/unittests/sources/test_ec2.py -index b376660d..7c8a5ea5 100644 ---- a/tests/unittests/sources/test_ec2.py -+++ b/tests/unittests/sources/test_ec2.py -@@ -210,6 +210,17 @@ SECONDARY_IP_METADATA_2018_09_24 = { - - M_PATH_NET = "cloudinit.sources.DataSourceEc2.net." - -+TAGS_METADATA_2021_03_23 = { -+ **DEFAULT_METADATA, -+ "tags": { -+ "instance": { -+ "Environment": "production", -+ "Application": "test", -+ "TagWithoutValue": "", -+ } -+ }, -+} -+ - - def _register_ssh_keys(rfunc, base_url, keys_data): - """handle ssh key inconsistencies. -@@ -670,7 +681,7 @@ class TestEc2(test_helpers.HttprettyTestCase): - logs_with_redacted = [log for log in all_logs if REDACT_TOK in log] - logs_with_token = [log for log in all_logs if "API-TOKEN" in log] - self.assertEqual(1, len(logs_with_redacted_ttl)) -- self.assertEqual(81, len(logs_with_redacted)) -+ self.assertEqual(83, len(logs_with_redacted)) - self.assertEqual(0, len(logs_with_token)) - - @mock.patch("cloudinit.net.dhcp.maybe_perform_dhcp_discovery") -@@ -811,6 +822,19 @@ class TestEc2(test_helpers.HttprettyTestCase): - ) - self.assertIn("Crawl of metadata service took", self.logs.getvalue()) - -+ def test_get_instance_tags(self): -+ ds = self._setup_ds( -+ platform_data=self.valid_platform_data, -+ sys_cfg={"datasource": {"Ec2": {"strict_id": False}}}, -+ md={"md": TAGS_METADATA_2021_03_23}, -+ ) -+ self.assertTrue(ds.get_data()) -+ self.assertIn("tags", ds.metadata) -+ self.assertIn("instance", ds.metadata["tags"]) -+ instance_tags = ds.metadata["tags"]["instance"] -+ self.assertEqual(instance_tags["Application"], "test") -+ self.assertEqual(instance_tags["Environment"], "production") -+ - - class TestGetSecondaryAddresses(test_helpers.CiTestCase): - -diff --git a/tools/.github-cla-signers b/tools/.github-cla-signers -index ac157a2f..9f71ea0c 100644 ---- a/tools/.github-cla-signers -+++ b/tools/.github-cla-signers -@@ -26,6 +26,7 @@ dermotbradley - dhensby - eandersson - eb3095 -+edudobay - emmanuelthome - eslerm - esposem --- -2.31.1 - diff --git a/ci-Use-Network-Manager-and-Netplan-as-default-renderers.patch b/ci-Use-Network-Manager-and-Netplan-as-default-renderers.patch deleted file mode 100644 index 553d8fc..0000000 --- a/ci-Use-Network-Manager-and-Netplan-as-default-renderers.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 840d6f7ca86fe9822c613f0f2c21f136271ce3b6 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Thu, 19 May 2022 15:44:03 +0200 -Subject: [PATCH 2/5] Use Network-Manager and Netplan as default renderers for - RHEL and Fedora (#1465) - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 24: Add native NetworkManager support (#1224) -RH-Commit: [2/3] e33081b15a8558967bb480ed659116e7e0872840 (eesposit/cloud-init-centos-) -RH-Bugzilla: 2056964 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Vitaly Kuznetsov - -commit 7703aa98b89c8daba207c28a0422268ead10019a -Author: Emanuele Giuseppe Esposito -Date: Thu May 19 15:05:01 2022 +0200 - - Use Network-Manager and Netplan as default renderers for RHEL and Fedora (#1465) - - This is adapted from Neal Gompa's PR: - https://github.com/canonical/cloud-init/pull/1435 - - The only difference is that we are not modifying renderers.py (thus - modifying the priority of all distros), but just tweaking cloud.cfg to - apply this change to Fedora and RHEL. Other distros can optionally - add themselves afterwards. - - net: Prefer Netplan and NetworkManager renderers by default - - NetworkManager is used by default on a variety of Linux distributions, - and exists as a cross-distribution network management service. - - Additionally, add information about the NetworkManager renderer to - the cloud-init documentation. - - Because Netplan can be explicitly used to manage NetworkManager, - it needs to be preferred before NetworkManager. - - This change is a follow-up to #1224, which added the native - NetworkManager renderer. - This patch has been deployed on Fedora's cloud-init package throughout - the development of Fedora Linux 36 to verify that it works. - - This should also make it tremendously easier for Linux distributions - to use cloud-init because now a standard configuration is supported - by default. - - Signed-off-by: Neal Gompa - - Signed-off-by: Emanuele Giuseppe Esposito - -Signed-off-by: Emanuele Giuseppe Esposito ---- - config/cloud.cfg.tmpl | 3 +++ - doc/rtd/topics/network-config.rst | 12 +++++++++++- - 2 files changed, 14 insertions(+), 1 deletion(-) - -diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl -index fb4b456c..86beee3c 100644 ---- a/config/cloud.cfg.tmpl -+++ b/config/cloud.cfg.tmpl -@@ -330,4 +330,7 @@ system_info: - {% elif variant in ["dragonfly"] %} - network: - renderers: ['freebsd'] -+{% elif variant in ["rhel", "fedora"] %} -+ network: -+ renderers: ['netplan', 'network-manager', 'networkd', 'sysconfig', 'eni'] - {% endif %} -diff --git a/doc/rtd/topics/network-config.rst b/doc/rtd/topics/network-config.rst -index c461a3fe..f503caab 100644 ---- a/doc/rtd/topics/network-config.rst -+++ b/doc/rtd/topics/network-config.rst -@@ -188,6 +188,15 @@ generated configuration into an internal network configuration state. From - 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 ``/etc/NetworkManager``. -+ -+It is the default for a number of Linux distributions, notably Fedora; -+CentOS/RHEL; and derivatives. -+ - - **ENI** - - /etc/network/interfaces or ``ENI`` is supported by the ``ifupdown`` package -@@ -215,6 +224,7 @@ is as follows: - - ENI - - Sysconfig - - Netplan -+- NetworkManager - - When applying the policy, `Cloud-init`_ checks if the current instance has the - correct binaries and paths to support the renderer. The first renderer that -@@ -223,7 +233,7 @@ supplying an updated configuration in cloud-config. :: - - system_info: - network: -- renderers: ['netplan', 'eni', 'sysconfig', 'freebsd', 'netbsd', 'openbsd'] -+ renderers: ['netplan', 'network-manager', 'eni', 'sysconfig', 'freebsd', 'netbsd', 'openbsd'] - - - Network Configuration Tools --- -2.31.1 - diff --git a/ci-cc_set_hostname-do-not-write-localhost-when-no-hostn.patch b/ci-cc_set_hostname-do-not-write-localhost-when-no-hostn.patch deleted file mode 100644 index a307e68..0000000 --- a/ci-cc_set_hostname-do-not-write-localhost-when-no-hostn.patch +++ /dev/null @@ -1,801 +0,0 @@ -From d1790e6462e509e3cd87fc449df84fbd02ca1d89 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Thu, 2 Jun 2022 16:03:43 +0200 -Subject: [PATCH 2/2] cc_set_hostname: do not write "localhost" when no - hostname is given (#1453) - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 28: cc_set_hostname: do not write "localhost" when no hostname is given (#1453) -RH-Commit: [1/1] 4370e9149371dc89be82cb05d30d33e4d2638cec (eesposit/cloud-init-centos-) -RH-Bugzilla: 1980403 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Mohamed Gamal Morsy - -commit 74e43496f353db52e15d96abeb54ad63baac5be9 -Author: Emanuele Giuseppe Esposito -Date: Tue May 31 16:03:44 2022 +0200 - - cc_set_hostname: do not write "localhost" when no hostname is given (#1453) - - Systemd used to sometimes ignore localhost in /etc/hostnames, and many programs - like cloud-init used this as a workaround to set a default hostname. - - From https://github.com/systemd/systemd/commit/d39079fcaa05e23540d2b1f0270fa31c22a7e9f1: - - We would sometimes ignore localhost-style names in /etc/hostname. That is - brittle. If the user configured some hostname, it's most likely because they - want to use that as the hostname. If they don't want to use such a hostname, - they should just not create the config. Everything becomes simples if we just - use the configured hostname as-is. - - This behaviour seems to have been a workaround for Anaconda installer and other - tools writing out /etc/hostname with the default of "localhost.localdomain". - Anaconda PR to stop doing that: rhinstaller/anaconda#3040. - That might have been useful as a work-around for other programs misbehaving if - /etc/hostname was not present, but nowadays it's not useful because systemd - mostly controls the hostname and it is perfectly happy without that file. - - Apart from making things simpler, this allows users to set a hostname like - "localhost" and have it honoured, if such a whim strikes them. - - As also suggested by the Anaconda PR, we need to stop writing default "localhost" - in /etc/hostnames, and let the right service (networking, user) do that if they - need to. Otherwise, "localhost" will permanently stay as hostname and will - prevent other tools like NetworkManager from setting the right one. - - Signed-off-by: Emanuele Giuseppe Esposito - - RHBZ: 1980403 - -Conflicts: - cloudinit/config/cc_update_etc_hosts.py - cloudinit/sources/DataSourceCloudSigma.py - cloudinit/util.py - tests/unittests/test_util.py - Additional imports and/or conditionals that are not present in this version - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/cmd/main.py | 2 +- - cloudinit/config/cc_apt_configure.py | 2 +- - cloudinit/config/cc_debug.py | 2 +- - cloudinit/config/cc_phone_home.py | 4 +- - cloudinit/config/cc_set_hostname.py | 6 ++- - cloudinit/config/cc_spacewalk.py | 2 +- - cloudinit/config/cc_update_etc_hosts.py | 4 +- - cloudinit/config/cc_update_hostname.py | 7 +++- - cloudinit/sources/DataSourceAliYun.py | 8 +++- - cloudinit/sources/DataSourceCloudSigma.py | 6 ++- - cloudinit/sources/DataSourceGCE.py | 5 ++- - cloudinit/sources/DataSourceScaleway.py | 3 +- - cloudinit/sources/__init__.py | 28 ++++++++++--- - cloudinit/util.py | 29 +++++++++++--- - .../unittests/config/test_cc_set_hostname.py | 40 ++++++++++++++++++- - tests/unittests/sources/test_aliyun.py | 2 +- - tests/unittests/sources/test_cloudsigma.py | 8 ++-- - tests/unittests/sources/test_digitalocean.py | 2 +- - tests/unittests/sources/test_gce.py | 4 +- - tests/unittests/sources/test_hetzner.py | 2 +- - tests/unittests/sources/test_init.py | 29 +++++++++----- - tests/unittests/sources/test_scaleway.py | 2 +- - tests/unittests/sources/test_vmware.py | 4 +- - tests/unittests/test_util.py | 17 ++++---- - tests/unittests/util.py | 3 +- - 25 files changed, 166 insertions(+), 55 deletions(-) - -diff --git a/cloudinit/cmd/main.py b/cloudinit/cmd/main.py -index c9be41b3..816d31aa 100644 ---- a/cloudinit/cmd/main.py -+++ b/cloudinit/cmd/main.py -@@ -813,7 +813,7 @@ def _maybe_set_hostname(init, stage, retry_stage): - @param retry_stage: String represented logs upon error setting hostname. - """ - cloud = init.cloudify() -- (hostname, _fqdn) = util.get_hostname_fqdn( -+ (hostname, _fqdn, _) = util.get_hostname_fqdn( - init.cfg, cloud, metadata_only=True - ) - if hostname: # meta-data or user-data hostname content -diff --git a/cloudinit/config/cc_apt_configure.py b/cloudinit/config/cc_apt_configure.py -index c558311a..0e6466ec 100644 ---- a/cloudinit/config/cc_apt_configure.py -+++ b/cloudinit/config/cc_apt_configure.py -@@ -753,7 +753,7 @@ def search_for_mirror_dns(configured, mirrortype, cfg, cloud): - raise ValueError("unknown mirror type") - - # if we have a fqdn, then search its domain portion first -- (_, fqdn) = util.get_hostname_fqdn(cfg, cloud) -+ fqdn = util.get_hostname_fqdn(cfg, cloud).fqdn - mydom = ".".join(fqdn.split(".")[1:]) - if mydom: - doms.append(".%s" % mydom) -diff --git a/cloudinit/config/cc_debug.py b/cloudinit/config/cc_debug.py -index c51818c3..a00f2823 100644 ---- a/cloudinit/config/cc_debug.py -+++ b/cloudinit/config/cc_debug.py -@@ -95,7 +95,7 @@ def handle(name, cfg, cloud, log, args): - "Datasource: %s\n" % (type_utils.obj_name(cloud.datasource)) - ) - to_print.write("Distro: %s\n" % (type_utils.obj_name(cloud.distro))) -- to_print.write("Hostname: %s\n" % (cloud.get_hostname(True))) -+ to_print.write("Hostname: %s\n" % (cloud.get_hostname(True).hostname)) - to_print.write("Instance ID: %s\n" % (cloud.get_instance_id())) - to_print.write("Locale: %s\n" % (cloud.get_locale())) - to_print.write("Launch IDX: %s\n" % (cloud.launch_index)) -diff --git a/cloudinit/config/cc_phone_home.py b/cloudinit/config/cc_phone_home.py -index a0e1da78..1cf270aa 100644 ---- a/cloudinit/config/cc_phone_home.py -+++ b/cloudinit/config/cc_phone_home.py -@@ -119,8 +119,8 @@ def handle(name, cfg, cloud, log, args): - - all_keys = {} - all_keys["instance_id"] = cloud.get_instance_id() -- all_keys["hostname"] = cloud.get_hostname() -- all_keys["fqdn"] = cloud.get_hostname(fqdn=True) -+ all_keys["hostname"] = cloud.get_hostname().hostname -+ all_keys["fqdn"] = cloud.get_hostname(fqdn=True).hostname - - pubkeys = { - "pub_key_dsa": "/etc/ssh/ssh_host_dsa_key.pub", -diff --git a/cloudinit/config/cc_set_hostname.py b/cloudinit/config/cc_set_hostname.py -index eb0ca328..2674fa20 100644 ---- a/cloudinit/config/cc_set_hostname.py -+++ b/cloudinit/config/cc_set_hostname.py -@@ -76,7 +76,7 @@ def handle(name, cfg, cloud, log, _args): - if hostname_fqdn is not None: - cloud.distro.set_option("prefer_fqdn_over_hostname", hostname_fqdn) - -- (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud) -+ (hostname, fqdn, is_default) = util.get_hostname_fqdn(cfg, cloud) - # Check for previous successful invocation of set-hostname - - # set-hostname artifact file accounts for both hostname and fqdn -@@ -94,6 +94,10 @@ def handle(name, cfg, cloud, log, _args): - if not hostname_changed: - log.debug("No hostname changes. Skipping set-hostname") - return -+ if is_default and hostname == "localhost": -+ # https://github.com/systemd/systemd/commit/d39079fcaa05e23540d2b1f0270fa31c22a7e9f1 -+ log.debug("Hostname is localhost. Let other services handle this.") -+ return - log.debug("Setting the hostname to %s (%s)", fqdn, hostname) - try: - cloud.distro.set_hostname(hostname, fqdn) -diff --git a/cloudinit/config/cc_spacewalk.py b/cloudinit/config/cc_spacewalk.py -index 3fa6c388..419c8b32 100644 ---- a/cloudinit/config/cc_spacewalk.py -+++ b/cloudinit/config/cc_spacewalk.py -@@ -89,7 +89,7 @@ def handle(name, cfg, cloud, log, _args): - if not is_registered(): - do_register( - spacewalk_server, -- cloud.datasource.get_hostname(fqdn=True), -+ cloud.datasource.get_hostname(fqdn=True).hostname, - proxy=cfg.get("proxy"), - log=log, - activation_key=cfg.get("activation_key"), -diff --git a/cloudinit/config/cc_update_etc_hosts.py b/cloudinit/config/cc_update_etc_hosts.py -index f0aa9b0f..d2ee6f45 100644 ---- a/cloudinit/config/cc_update_etc_hosts.py -+++ b/cloudinit/config/cc_update_etc_hosts.py -@@ -62,7 +62,7 @@ def handle(name, cfg, cloud, log, _args): - hosts_fn = cloud.distro.hosts_fn - - if util.translate_bool(manage_hosts, addons=["template"]): -- (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud) -+ (hostname, fqdn, _) = util.get_hostname_fqdn(cfg, cloud) - if not hostname: - log.warning( - "Option 'manage_etc_hosts' was set, but no hostname was found" -@@ -84,7 +84,7 @@ def handle(name, cfg, cloud, log, _args): - ) - - elif manage_hosts == "localhost": -- (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud) -+ (hostname, fqdn, _) = util.get_hostname_fqdn(cfg, cloud) - if not hostname: - log.warning( - "Option 'manage_etc_hosts' was set, but no hostname was found" -diff --git a/cloudinit/config/cc_update_hostname.py b/cloudinit/config/cc_update_hostname.py -index 09f6f6da..e2046020 100644 ---- a/cloudinit/config/cc_update_hostname.py -+++ b/cloudinit/config/cc_update_hostname.py -@@ -56,7 +56,12 @@ def handle(name, cfg, cloud, log, _args): - if hostname_fqdn is not None: - cloud.distro.set_option("prefer_fqdn_over_hostname", hostname_fqdn) - -- (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud) -+ (hostname, fqdn, is_default) = util.get_hostname_fqdn(cfg, cloud) -+ if is_default and hostname == "localhost": -+ # https://github.com/systemd/systemd/commit/d39079fcaa05e23540d2b1f0270fa31c22a7e9f1 -+ log.debug("Hostname is localhost. Let other services handle this.") -+ return -+ - try: - prev_fn = os.path.join(cloud.get_cpath("data"), "previous-hostname") - log.debug("Updating hostname to %s (%s)", fqdn, hostname) -diff --git a/cloudinit/sources/DataSourceAliYun.py b/cloudinit/sources/DataSourceAliYun.py -index 37f512e3..b9390aca 100644 ---- a/cloudinit/sources/DataSourceAliYun.py -+++ b/cloudinit/sources/DataSourceAliYun.py -@@ -2,6 +2,7 @@ - - from cloudinit import dmi, sources - from cloudinit.sources import DataSourceEc2 as EC2 -+from cloudinit.sources import DataSourceHostname - - ALIYUN_PRODUCT = "Alibaba Cloud ECS" - -@@ -16,7 +17,12 @@ class DataSourceAliYun(EC2.DataSourceEc2): - extended_metadata_versions = [] - - def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False): -- return self.metadata.get("hostname", "localhost.localdomain") -+ hostname = self.metadata.get("hostname") -+ is_default = False -+ if hostname is None: -+ hostname = "localhost.localdomain" -+ is_default = True -+ return DataSourceHostname(hostname, is_default) - - def get_public_ssh_keys(self): - return parse_public_keys(self.metadata.get("public-keys", {})) -diff --git a/cloudinit/sources/DataSourceCloudSigma.py b/cloudinit/sources/DataSourceCloudSigma.py -index de71c3e9..91ebb084 100644 ---- a/cloudinit/sources/DataSourceCloudSigma.py -+++ b/cloudinit/sources/DataSourceCloudSigma.py -@@ -11,6 +11,7 @@ from cloudinit import dmi - from cloudinit import log as logging - from cloudinit import sources - from cloudinit.cs_utils import SERIAL_PORT, Cepko -+from cloudinit.sources import DataSourceHostname - - LOG = logging.getLogger(__name__) - -@@ -90,9 +91,10 @@ class DataSourceCloudSigma(sources.DataSource): - the first part from uuid is being used. - """ - if re.match(r"^[A-Za-z0-9 -_\.]+$", self.metadata["name"]): -- return self.metadata["name"][:61] -+ ret = self.metadata["name"][:61] - else: -- return self.metadata["uuid"].split("-")[0] -+ ret = self.metadata["uuid"].split("-")[0] -+ return DataSourceHostname(ret, False) - - def get_public_ssh_keys(self): - return [self.ssh_public_key] -diff --git a/cloudinit/sources/DataSourceGCE.py b/cloudinit/sources/DataSourceGCE.py -index c470bea8..f7ec6b52 100644 ---- a/cloudinit/sources/DataSourceGCE.py -+++ b/cloudinit/sources/DataSourceGCE.py -@@ -12,6 +12,7 @@ from cloudinit import log as logging - from cloudinit import sources, url_helper, util - from cloudinit.distros import ug_util - from cloudinit.net.dhcp import EphemeralDHCPv4 -+from cloudinit.sources import DataSourceHostname - - LOG = logging.getLogger(__name__) - -@@ -122,7 +123,9 @@ class DataSourceGCE(sources.DataSource): - - def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False): - # GCE has long FDQN's and has asked for short hostnames. -- return self.metadata["local-hostname"].split(".")[0] -+ return DataSourceHostname( -+ self.metadata["local-hostname"].split(".")[0], False -+ ) - - @property - def availability_zone(self): -diff --git a/cloudinit/sources/DataSourceScaleway.py b/cloudinit/sources/DataSourceScaleway.py -index 8e5dd82c..8f08dc6d 100644 ---- a/cloudinit/sources/DataSourceScaleway.py -+++ b/cloudinit/sources/DataSourceScaleway.py -@@ -30,6 +30,7 @@ from cloudinit import log as logging - from cloudinit import net, sources, url_helper, util - from cloudinit.event import EventScope, EventType - from cloudinit.net.dhcp import EphemeralDHCPv4, NoDHCPLeaseError -+from cloudinit.sources import DataSourceHostname - - LOG = logging.getLogger(__name__) - -@@ -282,7 +283,7 @@ class DataSourceScaleway(sources.DataSource): - return ssh_keys - - def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False): -- return self.metadata["hostname"] -+ return DataSourceHostname(self.metadata["hostname"], False) - - @property - def availability_zone(self): -diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py -index 88028cfa..77b24fd7 100644 ---- a/cloudinit/sources/__init__.py -+++ b/cloudinit/sources/__init__.py -@@ -148,6 +148,11 @@ URLParams = namedtuple( - ], - ) - -+DataSourceHostname = namedtuple( -+ "DataSourceHostname", -+ ["hostname", "is_default"], -+) -+ - - class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta): - -@@ -291,7 +296,7 @@ class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta): - - def _get_standardized_metadata(self, instance_data): - """Return a dictionary of standardized metadata keys.""" -- local_hostname = self.get_hostname() -+ local_hostname = self.get_hostname().hostname - instance_id = self.get_instance_id() - availability_zone = self.availability_zone - # In the event of upgrade from existing cloudinit, pickled datasource -@@ -697,22 +702,33 @@ class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta): - @param metadata_only: Boolean, set True to avoid looking up hostname - if meta-data doesn't have local-hostname present. - -- @return: hostname or qualified hostname. Optionally return None when -+ @return: a DataSourceHostname namedtuple -+ , (str, bool). -+ is_default is a bool and -+ it's true only if hostname is localhost and was -+ returned by util.get_hostname() as a default. -+ This is used to differentiate with a user-defined -+ localhost hostname. -+ Optionally return (None, False) when - metadata_only is True and local-hostname data is not available. - """ - defdomain = "localdomain" - defhost = "localhost" - domain = defdomain -+ is_default = False - - if not self.metadata or not self.metadata.get("local-hostname"): - if metadata_only: -- return None -+ return DataSourceHostname(None, is_default) - # this is somewhat questionable really. - # the cloud datasource was asked for a hostname - # and didn't have one. raising error might be more appropriate - # but instead, basically look up the existing hostname - toks = [] - hostname = util.get_hostname() -+ if hostname == "localhost": -+ # default hostname provided by socket.gethostname() -+ is_default = True - hosts_fqdn = util.get_fqdn_from_hosts(hostname) - if hosts_fqdn and hosts_fqdn.find(".") > 0: - toks = str(hosts_fqdn).split(".") -@@ -745,9 +761,9 @@ class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta): - hostname = toks[0] - - if fqdn and domain != defdomain: -- return "%s.%s" % (hostname, domain) -- else: -- return hostname -+ hostname = "%s.%s" % (hostname, domain) -+ -+ return DataSourceHostname(hostname, is_default) - - def get_package_mirror_info(self): - return self.distro.get_package_mirror_info(data_source=self) -diff --git a/cloudinit/util.py b/cloudinit/util.py -index 569fc215..4cb21551 100644 ---- a/cloudinit/util.py -+++ b/cloudinit/util.py -@@ -32,7 +32,8 @@ import subprocess - import sys - import time - from base64 import b64decode, b64encode --from errno import ENOENT -+from collections import deque, namedtuple -+from errno import EACCES, ENOENT - from functools import lru_cache - from typing import List - from urllib import parse -@@ -1072,6 +1073,12 @@ def dos2unix(contents): - return contents.replace("\r\n", "\n") - - -+HostnameFqdnInfo = namedtuple( -+ "HostnameFqdnInfo", -+ ["hostname", "fqdn", "is_default"], -+) -+ -+ - def get_hostname_fqdn(cfg, cloud, metadata_only=False): - """Get hostname and fqdn from config if present and fallback to cloud. - -@@ -1079,9 +1086,17 @@ def get_hostname_fqdn(cfg, cloud, metadata_only=False): - @param cloud: Cloud instance from init.cloudify(). - @param metadata_only: Boolean, set True to only query cloud meta-data, - returning None if not present in meta-data. -- @return: a Tuple of strings , . Values can be none when -+ @return: a namedtuple of -+ , , (str, str, bool). -+ Values can be none when - metadata_only is True and no cfg or metadata provides hostname info. -+ is_default is a bool and -+ it's true only if hostname is localhost and was -+ returned by util.get_hostname() as a default. -+ This is used to differentiate with a user-defined -+ localhost hostname. - """ -+ is_default = False - if "fqdn" in cfg: - # user specified a fqdn. Default hostname then is based off that - fqdn = cfg["fqdn"] -@@ -1095,12 +1110,16 @@ def get_hostname_fqdn(cfg, cloud, metadata_only=False): - else: - # no fqdn set, get fqdn from cloud. - # get hostname from cfg if available otherwise cloud -- fqdn = cloud.get_hostname(fqdn=True, metadata_only=metadata_only) -+ fqdn = cloud.get_hostname( -+ fqdn=True, metadata_only=metadata_only -+ ).hostname - if "hostname" in cfg: - hostname = cfg["hostname"] - else: -- hostname = cloud.get_hostname(metadata_only=metadata_only) -- return (hostname, fqdn) -+ hostname, is_default = cloud.get_hostname( -+ metadata_only=metadata_only -+ ) -+ return HostnameFqdnInfo(hostname, fqdn, is_default) - - - def get_fqdn_from_hosts(hostname, filename="/etc/hosts"): -diff --git a/tests/unittests/config/test_cc_set_hostname.py b/tests/unittests/config/test_cc_set_hostname.py -index fd994c4e..3d1d86ee 100644 ---- a/tests/unittests/config/test_cc_set_hostname.py -+++ b/tests/unittests/config/test_cc_set_hostname.py -@@ -11,6 +11,7 @@ from configobj import ConfigObj - - from cloudinit import cloud, distros, helpers, util - from cloudinit.config import cc_set_hostname -+from cloudinit.sources import DataSourceNone - from tests.unittests import helpers as t_help - - LOG = logging.getLogger(__name__) -@@ -153,7 +154,8 @@ class TestHostname(t_help.FilesystemMockingTestCase): - ) - ] not in m_subp.call_args_list - -- def test_multiple_calls_skips_unchanged_hostname(self): -+ @mock.patch("cloudinit.util.get_hostname", return_value="localhost") -+ def test_multiple_calls_skips_unchanged_hostname(self, get_hostname): - """Only new hostname or fqdn values will generate a hostname call.""" - distro = self._fetch_distro("debian") - paths = helpers.Paths({"cloud_dir": self.tmp}) -@@ -182,6 +184,42 @@ class TestHostname(t_help.FilesystemMockingTestCase): - self.logs.getvalue(), - ) - -+ @mock.patch("cloudinit.util.get_hostname", return_value="localhost") -+ def test_localhost_default_hostname(self, get_hostname): -+ """ -+ No hostname set. Default value returned is localhost, -+ but we shouldn't write it in /etc/hostname -+ """ -+ distro = self._fetch_distro("debian") -+ paths = helpers.Paths({"cloud_dir": self.tmp}) -+ ds = DataSourceNone.DataSourceNone({}, None, paths) -+ cc = cloud.Cloud(ds, paths, {}, distro, None) -+ self.patchUtils(self.tmp) -+ -+ util.write_file("/etc/hostname", "") -+ cc_set_hostname.handle("cc_set_hostname", {}, cc, LOG, []) -+ contents = util.load_file("/etc/hostname") -+ self.assertEqual("", contents.strip()) -+ -+ @mock.patch("cloudinit.util.get_hostname", return_value="localhost") -+ def test_localhost_user_given_hostname(self, get_hostname): -+ """ -+ User set hostname is localhost. We should write it in /etc/hostname -+ """ -+ distro = self._fetch_distro("debian") -+ paths = helpers.Paths({"cloud_dir": self.tmp}) -+ ds = DataSourceNone.DataSourceNone({}, None, paths) -+ cc = cloud.Cloud(ds, paths, {}, distro, None) -+ self.patchUtils(self.tmp) -+ -+ # user-provided localhost should not be ignored -+ util.write_file("/etc/hostname", "") -+ cc_set_hostname.handle( -+ "cc_set_hostname", {"hostname": "localhost"}, cc, LOG, [] -+ ) -+ contents = util.load_file("/etc/hostname") -+ self.assertEqual("localhost", contents.strip()) -+ - def test_error_on_distro_set_hostname_errors(self): - """Raise SetHostnameError on exceptions from distro.set_hostname.""" - distro = self._fetch_distro("debian") -diff --git a/tests/unittests/sources/test_aliyun.py b/tests/unittests/sources/test_aliyun.py -index 8a61d5ee..e628dc02 100644 ---- a/tests/unittests/sources/test_aliyun.py -+++ b/tests/unittests/sources/test_aliyun.py -@@ -149,7 +149,7 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase): - - def _test_host_name(self): - self.assertEqual( -- self.default_metadata["hostname"], self.ds.get_hostname() -+ self.default_metadata["hostname"], self.ds.get_hostname().hostname - ) - - @mock.patch("cloudinit.sources.DataSourceAliYun._is_aliyun") -diff --git a/tests/unittests/sources/test_cloudsigma.py b/tests/unittests/sources/test_cloudsigma.py -index a2f26245..3dca7ea8 100644 ---- a/tests/unittests/sources/test_cloudsigma.py -+++ b/tests/unittests/sources/test_cloudsigma.py -@@ -58,12 +58,14 @@ class DataSourceCloudSigmaTest(test_helpers.CiTestCase): - - def test_get_hostname(self): - self.datasource.get_data() -- self.assertEqual("test_server", self.datasource.get_hostname()) -+ self.assertEqual( -+ "test_server", self.datasource.get_hostname().hostname -+ ) - self.datasource.metadata["name"] = "" -- self.assertEqual("65b2fb23", self.datasource.get_hostname()) -+ self.assertEqual("65b2fb23", self.datasource.get_hostname().hostname) - utf8_hostname = b"\xd1\x82\xd0\xb5\xd1\x81\xd1\x82".decode("utf-8") - self.datasource.metadata["name"] = utf8_hostname -- self.assertEqual("65b2fb23", self.datasource.get_hostname()) -+ self.assertEqual("65b2fb23", self.datasource.get_hostname().hostname) - - def test_get_public_ssh_keys(self): - self.datasource.get_data() -diff --git a/tests/unittests/sources/test_digitalocean.py b/tests/unittests/sources/test_digitalocean.py -index f3e6224e..47e46c66 100644 ---- a/tests/unittests/sources/test_digitalocean.py -+++ b/tests/unittests/sources/test_digitalocean.py -@@ -178,7 +178,7 @@ class TestDataSourceDigitalOcean(CiTestCase): - self.assertEqual(DO_META.get("vendor_data"), ds.get_vendordata_raw()) - self.assertEqual(DO_META.get("region"), ds.availability_zone) - self.assertEqual(DO_META.get("droplet_id"), ds.get_instance_id()) -- self.assertEqual(DO_META.get("hostname"), ds.get_hostname()) -+ self.assertEqual(DO_META.get("hostname"), ds.get_hostname().hostname) - - # Single key - self.assertEqual( -diff --git a/tests/unittests/sources/test_gce.py b/tests/unittests/sources/test_gce.py -index e030931b..1ce0c6ec 100644 ---- a/tests/unittests/sources/test_gce.py -+++ b/tests/unittests/sources/test_gce.py -@@ -126,7 +126,7 @@ class TestDataSourceGCE(test_helpers.HttprettyTestCase): - self.ds.get_data() - - shostname = GCE_META.get("instance/hostname").split(".")[0] -- self.assertEqual(shostname, self.ds.get_hostname()) -+ self.assertEqual(shostname, self.ds.get_hostname().hostname) - - self.assertEqual( - GCE_META.get("instance/id"), self.ds.get_instance_id() -@@ -147,7 +147,7 @@ class TestDataSourceGCE(test_helpers.HttprettyTestCase): - ) - - shostname = GCE_META_PARTIAL.get("instance/hostname").split(".")[0] -- self.assertEqual(shostname, self.ds.get_hostname()) -+ self.assertEqual(shostname, self.ds.get_hostname().hostname) - - def test_userdata_no_encoding(self): - """check that user-data is read.""" -diff --git a/tests/unittests/sources/test_hetzner.py b/tests/unittests/sources/test_hetzner.py -index f80ed45f..193b7e42 100644 ---- a/tests/unittests/sources/test_hetzner.py -+++ b/tests/unittests/sources/test_hetzner.py -@@ -116,7 +116,7 @@ class TestDataSourceHetzner(CiTestCase): - - self.assertTrue(m_readmd.called) - -- self.assertEqual(METADATA.get("hostname"), ds.get_hostname()) -+ self.assertEqual(METADATA.get("hostname"), ds.get_hostname().hostname) - - self.assertEqual(METADATA.get("public-keys"), ds.get_public_ssh_keys()) - -diff --git a/tests/unittests/sources/test_init.py b/tests/unittests/sources/test_init.py -index ce8fc970..79fc9c5b 100644 ---- a/tests/unittests/sources/test_init.py -+++ b/tests/unittests/sources/test_init.py -@@ -272,9 +272,11 @@ class TestDataSource(CiTestCase): - self.assertEqual( - "test-subclass-hostname", datasource.metadata["local-hostname"] - ) -- self.assertEqual("test-subclass-hostname", datasource.get_hostname()) -+ self.assertEqual( -+ "test-subclass-hostname", datasource.get_hostname().hostname -+ ) - datasource.metadata["local-hostname"] = "hostname.my.domain.com" -- self.assertEqual("hostname", datasource.get_hostname()) -+ self.assertEqual("hostname", datasource.get_hostname().hostname) - - def test_get_hostname_with_fqdn_returns_local_hostname_with_domain(self): - """Datasource.get_hostname with fqdn set gets qualified hostname.""" -@@ -285,7 +287,8 @@ class TestDataSource(CiTestCase): - self.assertTrue(datasource.get_data()) - datasource.metadata["local-hostname"] = "hostname.my.domain.com" - self.assertEqual( -- "hostname.my.domain.com", datasource.get_hostname(fqdn=True) -+ "hostname.my.domain.com", -+ datasource.get_hostname(fqdn=True).hostname, - ) - - def test_get_hostname_without_metadata_uses_system_hostname(self): -@@ -300,10 +303,12 @@ class TestDataSource(CiTestCase): - with mock.patch(mock_fqdn) as m_fqdn: - m_gethost.return_value = "systemhostname.domain.com" - m_fqdn.return_value = None # No maching fqdn in /etc/hosts -- self.assertEqual("systemhostname", datasource.get_hostname()) -+ self.assertEqual( -+ "systemhostname", datasource.get_hostname().hostname -+ ) - self.assertEqual( - "systemhostname.domain.com", -- datasource.get_hostname(fqdn=True), -+ datasource.get_hostname(fqdn=True).hostname, - ) - - def test_get_hostname_without_metadata_returns_none(self): -@@ -316,9 +321,13 @@ class TestDataSource(CiTestCase): - mock_fqdn = "cloudinit.sources.util.get_fqdn_from_hosts" - with mock.patch("cloudinit.sources.util.get_hostname") as m_gethost: - with mock.patch(mock_fqdn) as m_fqdn: -- self.assertIsNone(datasource.get_hostname(metadata_only=True)) - self.assertIsNone( -- datasource.get_hostname(fqdn=True, metadata_only=True) -+ datasource.get_hostname(metadata_only=True).hostname -+ ) -+ self.assertIsNone( -+ datasource.get_hostname( -+ fqdn=True, metadata_only=True -+ ).hostname - ) - self.assertEqual([], m_gethost.call_args_list) - self.assertEqual([], m_fqdn.call_args_list) -@@ -335,10 +344,12 @@ class TestDataSource(CiTestCase): - with mock.patch(mock_fqdn) as m_fqdn: - m_gethost.return_value = "systemhostname.domain.com" - m_fqdn.return_value = "fqdnhostname.domain.com" -- self.assertEqual("fqdnhostname", datasource.get_hostname()) -+ self.assertEqual( -+ "fqdnhostname", datasource.get_hostname().hostname -+ ) - self.assertEqual( - "fqdnhostname.domain.com", -- datasource.get_hostname(fqdn=True), -+ datasource.get_hostname(fqdn=True).hostname, - ) - - def test_get_data_does_not_write_instance_data_on_failure(self): -diff --git a/tests/unittests/sources/test_scaleway.py b/tests/unittests/sources/test_scaleway.py -index d7e8b969..56735dd0 100644 ---- a/tests/unittests/sources/test_scaleway.py -+++ b/tests/unittests/sources/test_scaleway.py -@@ -236,7 +236,7 @@ class TestDataSourceScaleway(HttprettyTestCase): - ].sort(), - ) - self.assertEqual( -- self.datasource.get_hostname(), -+ self.datasource.get_hostname().hostname, - MetadataResponses.FAKE_METADATA["hostname"], - ) - self.assertEqual( -diff --git a/tests/unittests/sources/test_vmware.py b/tests/unittests/sources/test_vmware.py -index dd331349..753bb774 100644 ---- a/tests/unittests/sources/test_vmware.py -+++ b/tests/unittests/sources/test_vmware.py -@@ -368,7 +368,9 @@ class TestDataSourceVMwareGuestInfo_InvalidPlatform(FilesystemMockingTestCase): - - def assert_metadata(test_obj, ds, metadata): - test_obj.assertEqual(metadata.get("instance-id"), ds.get_instance_id()) -- test_obj.assertEqual(metadata.get("local-hostname"), ds.get_hostname()) -+ test_obj.assertEqual( -+ metadata.get("local-hostname"), ds.get_hostname().hostname -+ ) - - expected_public_keys = metadata.get("public_keys") - if not isinstance(expected_public_keys, list): -diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py -index 3765511b..528b7f36 100644 ---- a/tests/unittests/test_util.py -+++ b/tests/unittests/test_util.py -@@ -19,6 +19,7 @@ import pytest - import yaml - - from cloudinit import importer, subp, util -+from cloudinit.sources import DataSourceHostname - from tests.unittests import helpers - from tests.unittests.helpers import CiTestCase - -@@ -331,8 +332,8 @@ class FakeCloud(object): - myargs["metadata_only"] = metadata_only - self.calls.append(myargs) - if fqdn: -- return self.fqdn -- return self.hostname -+ return DataSourceHostname(self.fqdn, False) -+ return DataSourceHostname(self.hostname, False) - - - class TestUtil(CiTestCase): -@@ -420,7 +421,7 @@ class TestShellify(CiTestCase): - class TestGetHostnameFqdn(CiTestCase): - def test_get_hostname_fqdn_from_only_cfg_fqdn(self): - """When cfg only has the fqdn key, derive hostname and fqdn from it.""" -- hostname, fqdn = util.get_hostname_fqdn( -+ hostname, fqdn, _ = util.get_hostname_fqdn( - cfg={"fqdn": "myhost.domain.com"}, cloud=None - ) - self.assertEqual("myhost", hostname) -@@ -428,7 +429,7 @@ class TestGetHostnameFqdn(CiTestCase): - - def test_get_hostname_fqdn_from_cfg_fqdn_and_hostname(self): - """When cfg has both fqdn and hostname keys, return them.""" -- hostname, fqdn = util.get_hostname_fqdn( -+ hostname, fqdn, _ = util.get_hostname_fqdn( - cfg={"fqdn": "myhost.domain.com", "hostname": "other"}, cloud=None - ) - self.assertEqual("other", hostname) -@@ -436,7 +437,7 @@ class TestGetHostnameFqdn(CiTestCase): - - def test_get_hostname_fqdn_from_cfg_hostname_with_domain(self): - """When cfg has only hostname key which represents a fqdn, use that.""" -- hostname, fqdn = util.get_hostname_fqdn( -+ hostname, fqdn, _ = util.get_hostname_fqdn( - cfg={"hostname": "myhost.domain.com"}, cloud=None - ) - self.assertEqual("myhost", hostname) -@@ -445,7 +446,7 @@ class TestGetHostnameFqdn(CiTestCase): - def test_get_hostname_fqdn_from_cfg_hostname_without_domain(self): - """When cfg has a hostname without a '.' query cloud.get_hostname.""" - mycloud = FakeCloud("cloudhost", "cloudhost.mycloud.com") -- hostname, fqdn = util.get_hostname_fqdn( -+ hostname, fqdn, _ = util.get_hostname_fqdn( - cfg={"hostname": "myhost"}, cloud=mycloud - ) - self.assertEqual("myhost", hostname) -@@ -457,7 +458,7 @@ class TestGetHostnameFqdn(CiTestCase): - def test_get_hostname_fqdn_from_without_fqdn_or_hostname(self): - """When cfg has neither hostname nor fqdn cloud.get_hostname.""" - mycloud = FakeCloud("cloudhost", "cloudhost.mycloud.com") -- hostname, fqdn = util.get_hostname_fqdn(cfg={}, cloud=mycloud) -+ hostname, fqdn, _ = util.get_hostname_fqdn(cfg={}, cloud=mycloud) - self.assertEqual("cloudhost", hostname) - self.assertEqual("cloudhost.mycloud.com", fqdn) - self.assertEqual( -@@ -468,7 +469,7 @@ class TestGetHostnameFqdn(CiTestCase): - def test_get_hostname_fqdn_from_passes_metadata_only_to_cloud(self): - """Calls to cloud.get_hostname pass the metadata_only parameter.""" - mycloud = FakeCloud("cloudhost", "cloudhost.mycloud.com") -- _hn, _fqdn = util.get_hostname_fqdn( -+ _hn, _fqdn, _def_hostname = util.get_hostname_fqdn( - cfg={}, cloud=mycloud, metadata_only=True - ) - self.assertEqual( -diff --git a/tests/unittests/util.py b/tests/unittests/util.py -index 79a6e1d0..6fb39506 100644 ---- a/tests/unittests/util.py -+++ b/tests/unittests/util.py -@@ -1,5 +1,6 @@ - # This file is part of cloud-init. See LICENSE file for license information. - from cloudinit import cloud, distros, helpers -+from cloudinit.sources import DataSourceHostname - from cloudinit.sources.DataSourceNone import DataSourceNone - - -@@ -37,7 +38,7 @@ def abstract_to_concrete(abclass): - - class DataSourceTesting(DataSourceNone): - def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False): -- return "hostname" -+ return DataSourceHostname("hostname", False) - - def persist_instance_data(self): - return True --- -2.31.1 - diff --git a/ci-cc_set_hostname-ignore-var-lib-cloud-data-set-hostna.patch b/ci-cc_set_hostname-ignore-var-lib-cloud-data-set-hostna.patch deleted file mode 100644 index c26c847..0000000 --- a/ci-cc_set_hostname-ignore-var-lib-cloud-data-set-hostna.patch +++ /dev/null @@ -1,77 +0,0 @@ -From d51546dee17c9abbb9d44fb33cf81be085a46dae Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Thu, 19 Jan 2023 09:40:10 +0100 -Subject: [PATCH 22/22] cc_set_hostname: ignore - /var/lib/cloud/data/set-hostname if it's empty (#1967) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2140893 - -commit 9c7502a801763520639c66125eb373123d1e4f44 -Author: Emanuele Giuseppe Esposito -Date: Wed Jan 18 17:55:16 2023 +0100 - - cc_set_hostname: ignore /var/lib/cloud/data/set-hostname if it's empty (#1967) - - If the file exists but is empty, do nothing. - Otherwise cloud-init will crash because it does not handle the empty file. - - RHBZ: 2140893 - - Signed-off-by: Emanuele Giuseppe Esposito - -Signed-off-by: Emanuele Giuseppe Esposito ---- - cloudinit/config/cc_set_hostname.py | 2 +- - tests/unittests/config/test_cc_set_hostname.py | 17 +++++++++++++++++ - 2 files changed, 18 insertions(+), 1 deletion(-) - -diff --git a/cloudinit/config/cc_set_hostname.py b/cloudinit/config/cc_set_hostname.py -index 2674fa20..7e3d5b74 100644 ---- a/cloudinit/config/cc_set_hostname.py -+++ b/cloudinit/config/cc_set_hostname.py -@@ -86,7 +86,7 @@ def handle(name, cfg, cloud, log, _args): - # distro._read_hostname implementation so we only validate one artifact. - prev_fn = os.path.join(cloud.get_cpath("data"), "set-hostname") - prev_hostname = {} -- if os.path.exists(prev_fn): -+ if os.path.exists(prev_fn) and os.stat(prev_fn).st_size > 0: - prev_hostname = util.load_json(util.load_file(prev_fn)) - hostname_changed = hostname != prev_hostname.get( - "hostname" -diff --git a/tests/unittests/config/test_cc_set_hostname.py b/tests/unittests/config/test_cc_set_hostname.py -index 3d1d86ee..2c92949f 100644 ---- a/tests/unittests/config/test_cc_set_hostname.py -+++ b/tests/unittests/config/test_cc_set_hostname.py -@@ -5,6 +5,7 @@ import os - import shutil - import tempfile - from io import BytesIO -+from pathlib import Path - from unittest import mock - - from configobj import ConfigObj -@@ -242,5 +243,21 @@ class TestHostname(t_help.FilesystemMockingTestCase): - str(ctx_mgr.exception), - ) - -+ def test_ignore_empty_previous_artifact_file(self): -+ cfg = { -+ "hostname": "blah", -+ "fqdn": "blah.blah.blah.yahoo.com", -+ } -+ distro = self._fetch_distro("debian") -+ paths = helpers.Paths({"cloud_dir": self.tmp}) -+ ds = None -+ cc = cloud.Cloud(ds, paths, {}, distro, None) -+ self.patchUtils(self.tmp) -+ prev_fn = Path(cc.get_cpath("data")) / "set-hostname" -+ prev_fn.touch() -+ cc_set_hostname.handle("cc_set_hostname", cfg, cc, LOG, []) -+ contents = util.load_file("/etc/hostname") -+ self.assertEqual("blah", contents.strip()) -+ - - # vi: ts=4 expandtab --- -2.39.1 - diff --git a/ci-cloud.cfg.tmpl-make-sure-centos-settings-are-identic.patch b/ci-cloud.cfg.tmpl-make-sure-centos-settings-are-identic.patch deleted file mode 100644 index df94668..0000000 --- a/ci-cloud.cfg.tmpl-make-sure-centos-settings-are-identic.patch +++ /dev/null @@ -1,139 +0,0 @@ -From dd5ae3081491a2a98bd74e1655b22c9354707630 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Thu, 8 Sep 2022 17:46:45 +0200 -Subject: [PATCH] cloud.cfg.tmpl: make sure "centos" settings are identical to - "rhel" (#1639) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2115576 - -commit 7593243a1abe2ccaf4698579720999380a4da73b -Author: Emanuele Giuseppe Esposito -Date: Wed Sep 7 14:53:26 2022 +0200 - - cloud.cfg.tmpl: make sure "centos" settings are identical to "rhel" (#1639) - - We have a couple of bugs where centos does not have the default user as rhel. - This PR makes sure the configuration is exactly the same. - - Signed-off-by: Emanuele Giuseppe Esposito - - RHBZ: 2115565 - RHBZ: 2115576 - Conflicts: - config/cloud.cfg.tmpl: "openmandriva" distro added in the options - -Signed-off-by: Emanuele Giuseppe Esposito ---- - config/cloud.cfg.tmpl | 27 +++++++++++++------------ - tests/unittests/test_render_cloudcfg.py | 1 + - 2 files changed, 15 insertions(+), 13 deletions(-) - -diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl -index 80ab4f96..08b6efbc 100644 ---- a/config/cloud.cfg.tmpl -+++ b/config/cloud.cfg.tmpl -@@ -2,6 +2,7 @@ - # The top level settings are used as module - # and system configuration. - {% set is_bsd = variant in ["dragonfly", "freebsd", "netbsd", "openbsd"] %} -+{% set is_rhel = variant in ["rhel", "centos"] %} - {% if is_bsd %} - syslog_fix_perms: root:wheel - {% elif variant in ["suse"] %} -@@ -32,9 +33,9 @@ disable_root: false - disable_root: true - {% endif %} - --{% if variant in ["almalinux", "alpine", "amazon", "centos", "cloudlinux", "eurolinux", -- "fedora", "miraclelinux", "openEuler", "rhel", "rocky", "virtuozzo"] %} --{% if variant == "rhel" %} -+{% if variant in ["almalinux", "alpine", "amazon", "cloudlinux", "eurolinux", -+ "fedora", "miraclelinux", "openEuler", "openmandriva", "rocky", "virtuozzo"] or is_rhel %} -+{% if is_rhel %} - mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service,_netdev', '0', '2'] - {% else %} - mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2'] -@@ -70,7 +71,7 @@ network: - config: disabled - {% endif %} - --{% if variant == "rhel" %} -+{% if is_rhel %} - # Default redhat settings: - ssh_deletekeys: true - ssh_genkeytypes: ['rsa', 'ecdsa', 'ed25519'] -@@ -119,16 +120,16 @@ cloud_config_modules: - {% endif %} - {% if variant not in ["photon"] %} - - ssh-import-id --{% if variant not in ["rhel"] %} -+{% if not is_rhel %} - - keyboard - {% endif %} - - locale - {% endif %} - - set-passwords --{% if variant in ["rhel"] %} -+{% if is_rhel %} - - rh_subscription - {% endif %} --{% if variant in ["rhel", "fedora", "photon"] %} -+{% if variant in ["fedora", "openmandriva", "photon"] or is_rhel %} - {% if variant not in ["photon"] %} - - spacewalk - {% endif %} -@@ -193,9 +194,9 @@ cloud_final_modules: - # (not accessible to handlers/transforms) - system_info: - # This will affect which distro class gets used --{% if variant in ["almalinux", "alpine", "amazon", "arch", "centos", "cloudlinux", "debian", -+{% if variant in ["almalinux", "alpine", "amazon", "arch", "cloudlinux", "debian", - "eurolinux", "fedora", "freebsd", "gentoo", "netbsd", "miraclelinux", "openbsd", "openEuler", -- "photon", "rhel", "rocky", "suse", "ubuntu", "virtuozzo"] %} -+ "openmandriva", "photon", "rocky", "suse", "ubuntu", "virtuozzo"] or is_rhel %} - distro: {{ variant }} - {% elif variant in ["dragonfly"] %} - distro: dragonflybsd -@@ -248,15 +249,15 @@ system_info: - primary: http://ports.ubuntu.com/ubuntu-ports - security: http://ports.ubuntu.com/ubuntu-ports - ssh_svcname: ssh --{% elif variant in ["almalinux", "alpine", "amazon", "arch", "centos", "cloudlinux", "eurolinux", -- "fedora", "gentoo", "miraclelinux", "openEuler", "rhel", "rocky", "suse", "virtuozzo"] %} -+{% elif variant in ["almalinux", "alpine", "amazon", "arch", "cloudlinux", "eurolinux", -+ "fedora", "gentoo", "miraclelinux", "openEuler", "openmandriva", "rocky", "suse", "virtuozzo"] or is_rhel %} - # Default user name + that default users groups (if added/used) - default_user: - {% if variant == "amazon" %} - name: ec2-user - lock_passwd: True - gecos: EC2 Default User --{% elif variant == "rhel" %} -+{% elif is_rhel %} - name: cloud-user - lock_passwd: true - gecos: Cloud User -@@ -275,7 +276,7 @@ system_info: - groups: [adm, sudo] - {% elif variant == "arch" %} - groups: [wheel, users] --{% elif variant == "rhel" %} -+{% elif is_rhel %} - groups: [adm, systemd-journal] - {% else %} - groups: [wheel, adm, systemd-journal] -diff --git a/tests/unittests/test_render_cloudcfg.py b/tests/unittests/test_render_cloudcfg.py -index 9f95d448..1a6e2715 100644 ---- a/tests/unittests/test_render_cloudcfg.py -+++ b/tests/unittests/test_render_cloudcfg.py -@@ -69,6 +69,7 @@ class TestRenderCloudCfg: - "amazon": "ec2-user", - "debian": "ubuntu", - "rhel": "cloud-user", -+ "centos": "cloud-user", - "unknown": "ubuntu", - } - default_user = system_cfg["system_info"]["default_user"]["name"] --- -2.37.3 - diff --git a/ci-setup.py-adjust-udev-rules-default-path-1513.patch b/ci-setup.py-adjust-udev-rules-default-path-1513.patch deleted file mode 100644 index c46af8d..0000000 --- a/ci-setup.py-adjust-udev-rules-default-path-1513.patch +++ /dev/null @@ -1,57 +0,0 @@ -From f771d841dbdef8fbb1c1a3d1b8d51ff101354502 Mon Sep 17 00:00:00 2001 -From: Emanuele Giuseppe Esposito -Date: Fri, 17 Jun 2022 09:41:23 +0200 -Subject: [PATCH 3/3] setup.py: adjust udev/rules default path (#1513) - -RH-Author: Emanuele Giuseppe Esposito -RH-MergeRequest: 30: setup.py: adjust udev/rules default path (#1513) -RH-Commit: [2/2] b71362acefa15587b2c72e8981708065d2fcfa07 (eesposit/cloud-init-centos-) -RH-Bugzilla: 2096270 -RH-Acked-by: Mohamed Gamal Morsy -RH-Acked-by: Vitaly Kuznetsov - -commit 70715125f3af118ae242770e61064c24f41e9a02 -Author: Emanuele Giuseppe Esposito -Date: Thu Jun 16 20:39:42 2022 +0200 - - setup.py: adjust udev/rules default path (#1513) - - RHEL must put cloudinit .rules files in /usr/lib/udev/rules.d - This place is a rhel standard and since it is used by all packages - cannot be modified. - - Signed-off-by: Emanuele Giuseppe Esposito - -Signed-off-by: Emanuele Giuseppe Esposito ---- - setup.py | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/setup.py b/setup.py -index a9132d2c..fdf27cd7 100755 ---- a/setup.py -+++ b/setup.py -@@ -302,6 +302,11 @@ data_files = [ - ), - ] - if not platform.system().endswith("BSD"): -+ -+ RULES_PATH = LIB -+ if os.path.isfile("/etc/redhat-release"): -+ RULES_PATH = "/usr/lib" -+ - data_files.extend( - [ - ( -@@ -309,7 +314,7 @@ if not platform.system().endswith("BSD"): - ["tools/hook-network-manager"], - ), - (ETC + "/dhcp/dhclient-exit-hooks.d/", ["tools/hook-dhclient"]), -- (LIB + "/udev/rules.d", [f for f in glob("udev/*.rules")]), -+ (RULES_PATH + "/udev/rules.d", [f for f in glob("udev/*.rules")]), - ( - ETC + "/systemd/system/sshd-keygen@.service.d/", - ["systemd/disable-sshd-keygen-if-cloud-init-active.conf"], --- -2.35.1 - diff --git a/cloud-init.spec b/cloud-init.spec index 3078090..99ae452 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -1,61 +1,19 @@ Name: cloud-init -Version: 22.1 -Release: 9%{?dist} +Version: 23.1.1 +Release: 1%{?dist} Summary: Cloud instance init scripts License: ASL 2.0 or GPLv3 URL: http://launchpad.net/cloud-init Source0: https://launchpad.net/cloud-init/trunk/%{version}/+download/%{name}-%{version}.tar.gz Source1: cloud-init-tmpfiles.conf -Patch0001: 0001-Add-initial-redhat-changes.patch -Patch0002: 0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch -Patch0003: 0003-Adding-_netdev-to-the-default-mount-configuration.patch -Patch0004: 0004-Setting-highest-autoconnect-priority-for-network-scr.patch -Patch0005: 0005-limit-permissions-on-def_log_file.patch -Patch0006: 0006-rhel-cloud.cfg-remove-ssh_genkeytypes-in-settings.py.patch -# For bz#2056964 - [RHEL-9]Rebase cloud-init from Fedora so it can configure networking using NM keyfiles -Patch7: ci-Add-native-NetworkManager-support-1224.patch -# For bz#2056964 - [RHEL-9]Rebase cloud-init from Fedora so it can configure networking using NM keyfiles -Patch8: ci-Use-Network-Manager-and-Netplan-as-default-renderers.patch -# For bz#2056964 - [RHEL-9]Rebase cloud-init from Fedora so it can configure networking using NM keyfiles -Patch9: ci-Revert-Setting-highest-autoconnect-priority-for-netw.patch -# For bz#2088448 - Align cloud.cfg file and systemd with cloud-init upstream .tmpl files -Patch10: ci-Align-rhel-custom-files-with-upstream-1431.patch -# For bz#2088448 - Align cloud.cfg file and systemd with cloud-init upstream .tmpl files -Patch11: ci-Remove-rhel-specific-files.patch -# For bz#2091640 - [cloud][init] Add support for reading tags from instance metadata -Patch12: ci-Support-EC2-tags-in-instance-metadata-1309.patch -# For bz#1980403 - [RHV] RHEL 9 VM with cloud-init without hostname set doesn't result in the FQDN as hostname -Patch13: ci-cc_set_hostname-do-not-write-localhost-when-no-hostn.patch -# For bz#2061604 - cloud-config will change /etc/locale.conf back to en_US.UTF-8 on rhel-guest-image-9.0 -Patch14: ci-Honor-system-locale-for-RHEL-1355.patch -# For bz#2096270 - Adjust udev/rules default path[rhel-9] -Patch15: ci-setup.py-adjust-udev-rules-default-path-1513.patch -# For bz#2107463 - [RHEL-9.1] Cannot run sysconfig when changing the priority of network renderers -# For bz#2104389 - [RHEL-9.1]Failed to config static IP and IPv6 according to VMware Customization Config File -# For bz#2117532 - [RHEL9.1] Revert patch of configuring networking by NM keyfiles -# For bz#2098501 - [RHEL-9.1] IPv6 not workable when cloud-init configure network using NM keyfiles -Patch16: ci-Revert-Add-native-NetworkManager-support-1224.patch -# For bz#2107463 - [RHEL-9.1] Cannot run sysconfig when changing the priority of network renderers -# For bz#2104389 - [RHEL-9.1]Failed to config static IP and IPv6 according to VMware Customization Config File -# For bz#2117532 - [RHEL9.1] Revert patch of configuring networking by NM keyfiles -# For bz#2098501 - [RHEL-9.1] IPv6 not workable when cloud-init configure network using NM keyfiles -Patch17: ci-Revert-Use-Network-Manager-and-Netplan-as-default-re.patch -# For bz#2107463 - [RHEL-9.1] Cannot run sysconfig when changing the priority of network renderers -# For bz#2104389 - [RHEL-9.1]Failed to config static IP and IPv6 according to VMware Customization Config File -# For bz#2117532 - [RHEL9.1] Revert patch of configuring networking by NM keyfiles -# For bz#2098501 - [RHEL-9.1] IPv6 not workable when cloud-init configure network using NM keyfiles -Patch18: ci-Revert-Revert-Setting-highest-autoconnect-priority-f.patch -# For bz#2115565 - cloud-init configures user "centos" or "rhel" instead of "cloud-user" with cloud-init-22.1 -Patch19: ci-cloud.cfg.tmpl-make-sure-centos-settings-are-identic.patch -# For bz#2152100 - [RHEL-9] Ensure network ready before cloud-init service runs on RHEL -Patch20: ci-Ensure-network-ready-before-cloud-init-service-runs-.patch -# For bz#2140893 - systemd[1]: Failed to start Initial cloud-init job after reboot system via sysrq 'b' -Patch21: ci-cc_set_hostname-ignore-var-lib-cloud-data-set-hostna.patch -# For bz#2166245 - Add support for resizing encrypted root volume -Patch22: ci-Allow-growpart-to-resize-encrypted-partitions-1316.patch - # 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 BuildArch: noarch @@ -214,6 +172,7 @@ 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 @@ -244,6 +203,10 @@ fi %config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf %changelog +* Thu Mar 30 2023 Camilla Conte - 23.1.1-1 +- Rebase to 23.1.1 [bz#2172811] +- Resolves: bz#2172811 + * Wed Feb 08 2023 Camilla Conte - 22.1-9 - ci-Allow-growpart-to-resize-encrypted-partitions-1316.patch [bz#2166245] - Resolves: bz#2166245 diff --git a/sources b/sources index e4f7158..d2fb51f 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (cloud-init-22.1.tar.gz) = 485e358777379a22dd2b0f6aa7afb1751eb44831c6e03ecbbd9c6823eaa20535e6e83fc245818ce1bb207425976839b356dadcfa3cfe62385b9d340b08ff21ab +SHA512 (cloud-init-23.1.1.tar.gz) = f84cf9085760e59111b52d3f8dc2f899b67fdf6b332a7a6ee1f04be97749be1acead820cd2b787a888839547fdd9c9e0ab04f10e7db25504811f48428bb8bbf6