import CS cloud-init-23.4-19.el9

This commit is contained in:
eabdullin 2024-09-30 15:13:55 +00:00
parent 942a7c2124
commit 85bcdbb092
24 changed files with 3716 additions and 3 deletions

View File

@ -0,0 +1,108 @@
From 808cd6f434a4ede1441cc1f5781abf59f53c4153 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Anders=20Bj=C3=B6rklund?= <anders.f.bjorklund@gmail.com>
Date: Mon, 22 Apr 2024 17:52:44 +0200
Subject: [PATCH 1/3] Deprecate the users ssh-authorized-keys property (#5162)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 95: Deprecate the users ssh-authorized-keys property (#5162)
RH-Jira: RHEL-45262
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/3] 27d6f99519a28ae91037fe47f9ef654b7fbd6236 (anisinha/cloud-init)
Deprecate the users ssh-authorized-keys property
Signed-off-by: Anders F Björklund <anders.f.bjorklund@gmail.com>
(cherry picked from commit 5205b4dd74eb2168ebbeba56579b6f116a272937)
---
.../schemas/schema-cloud-config-v1.json | 16 ++++++++++
.../unittests/config/test_cc_users_groups.py | 30 +++++++++++++++++++
tools/.github-cla-signers | 1 +
3 files changed, 47 insertions(+)
diff --git a/cloudinit/config/schemas/schema-cloud-config-v1.json b/cloudinit/config/schemas/schema-cloud-config-v1.json
index 8b10fe70..670ef4c2 100644
--- a/cloudinit/config/schemas/schema-cloud-config-v1.json
+++ b/cloudinit/config/schemas/schema-cloud-config-v1.json
@@ -272,6 +272,22 @@
},
"minItems": 1
},
+ "ssh-authorized-keys": {
+ "allOf": [
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1
+ },
+ {
+ "deprecated": true,
+ "deprecated_version": "18.3",
+ "deprecated_description": "Use ``ssh_authorized_keys`` instead."
+ }
+ ]
+ },
"ssh_import_id": {
"description": "List of SSH IDs to import for user. Can not be combined with ``ssh_redirect_user``.",
"type": "array",
diff --git a/tests/unittests/config/test_cc_users_groups.py b/tests/unittests/config/test_cc_users_groups.py
index 3300b77b..53e231e1 100644
--- a/tests/unittests/config/test_cc_users_groups.py
+++ b/tests/unittests/config/test_cc_users_groups.py
@@ -503,6 +503,36 @@ class TestUsersGroupsSchema:
),
True,
),
+ (
+ {
+ "users": [
+ {
+ "name": "lima",
+ "uid": "1000",
+ "homedir": "/home/lima.linux",
+ "shell": "/bin/bash",
+ "sudo": "ALL=(ALL) NOPASSWD:ALL",
+ "lock_passwd": True,
+ "ssh-authorized-keys": ["ssh-ed25519 ..."],
+ }
+ ]
+ },
+ pytest.raises(
+ SchemaValidationError,
+ match=(
+ "Cloud config schema deprecations: "
+ "users.0.ssh-authorized-keys: "
+ " Deprecated in version 18.3."
+ " Use ``ssh_authorized_keys`` instead."
+ ", "
+ "users.0.uid: "
+ " Changed in version 22.3."
+ " The use of ``string`` type is deprecated."
+ " Use an ``integer`` instead."
+ ),
+ ),
+ False,
+ ),
],
)
@skipUnlessJsonSchema()
diff --git a/tools/.github-cla-signers b/tools/.github-cla-signers
index f4da0989..8b119025 100644
--- a/tools/.github-cla-signers
+++ b/tools/.github-cla-signers
@@ -3,6 +3,7 @@ aciba90
acourdavAkamai
ader1990
adobley
+afbjorklund
ajmyyra
akutz
AlexBaranowski
--
2.39.3

View File

@ -0,0 +1,65 @@
From cc31dc321ae35995ceff93e67aaf0b0c660aa890 Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
Date: Tue, 12 Mar 2024 12:52:10 +0530
Subject: [PATCH] Retain exit code in cloud-init status for recoverable errors
RH-Author: Ani Sinha <None>
RH-MergeRequest: 71: Retain exit code in cloud-init status for recoverable errors
RH-Jira: RHEL-28549
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Cathy Avery <cavery@redhat.com>
RH-Commit: [1/1] 00934ade88c481c012bc1947fa44e5ed59f82858 (anisinha/cloud-init)
Version 23.4 of cloud-init changed the status code reported by cloud-init for
recoverable errors from 0 to 2. Please see the commit
70acb7f2a30d58 ("Add support for cloud-init "degraded" state (#4500)")
This change has the potential to break customers who are expecting a 0 status
and where warnings can be expected. Hence, revert the status code from 2 to 0
even in case of recoverable errors. This retains the old behavior and hence
avoids breaking scripts and software stack that expects 0 on the end user side.
Cannonical has made a similar change downstream for similar reasons. Please see
https://bugs.launchpad.net/ubuntu/+source/cloud-init/+bug/2048522
and the corresponding downstream patch:
https://github.com/canonical/cloud-init/pull/4747/commits/adce34bfd214e4eecdf87329486f30f0898dd303
This patch has limited risk as it narrowly only restores the old status
code for recoverable errors and does not modify anything else.
X-downstream-only: true
Signed-off-by: Ani Sinha <anisinha@redhat.com>
---
cloudinit/cmd/status.py | 2 +-
tests/unittests/cmd/test_status.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/cloudinit/cmd/status.py b/cloudinit/cmd/status.py
index f5ee9c11..849c80bc 100644
--- a/cloudinit/cmd/status.py
+++ b/cloudinit/cmd/status.py
@@ -225,7 +225,7 @@ def handle_status_args(name, args) -> int:
return 1
# Recoverable error
elif details.status in UXAppStatusDegradedMap.values():
- return 2
+ return 0
return 0
diff --git a/tests/unittests/cmd/test_status.py b/tests/unittests/cmd/test_status.py
index 6c85a59a..567b517a 100644
--- a/tests/unittests/cmd/test_status.py
+++ b/tests/unittests/cmd/test_status.py
@@ -636,7 +636,7 @@ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
},
None,
MyArgs(long=False, wait=False, format="json"),
- 2,
+ 0,
{
"boot_status_code": "enabled-by-kernel-cmdline",
"datasource": "nocloud",
--
2.39.3

View File

@ -0,0 +1,190 @@
From 87db4f8680222d2579d0ffb5fe507231f88d8aa5 Mon Sep 17 00:00:00 2001
From: PengpengSun <40026211+PengpengSun@users.noreply.github.com>
Date: Sat, 10 Aug 2024 03:32:40 +0800
Subject: [PATCH] Revert "fix(vmware): Set IPv6 to dhcp when there is no IPv6
addr (#5471)" (#5596)
RH-Author: xiachen <xiachen@redhat.com>
RH-MergeRequest: 108: Revert "fix(vmware): Set IPv6 to dhcp when there is no IPv6 addr (#5471)" (#5596)
RH-Jira: RHEL-54373
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] 96cccfca3d29c95d9c491d5995b7aa96adec4621 (xiachen/cloud-init-centos)
This reverts commit 2b6fe6403db769de14f7c7b7e4aa65f5bea8f3e0.
When there is no IPv6 set to dhcp explicitly, NetworkManager keyfile
defaults to method=auto, may-fail=true. When there is Ipv6 set to dhcp
explictily, NetworkManager keyfile will be set to
method=auto, may-fail=false. The default settings are what we want, so
revert the previous change to keep IPv6 not set explicitly.
(cherry picked from commit 65014b97420b41dcb6e7ea17c66bb2539f9b09fc)
Signed-off-by: Amy Chen <xiachen@redhat.com>
---
.../sources/helpers/vmware/imc/config_nic.py | 2 +-
.../sources/vmware/test_vmware_config_file.py | 68 +++++--------------
2 files changed, 18 insertions(+), 52 deletions(-)
diff --git a/cloudinit/sources/helpers/vmware/imc/config_nic.py b/cloudinit/sources/helpers/vmware/imc/config_nic.py
index 254518af..b07214a2 100644
--- a/cloudinit/sources/helpers/vmware/imc/config_nic.py
+++ b/cloudinit/sources/helpers/vmware/imc/config_nic.py
@@ -207,7 +207,7 @@ class NicConfigurator:
"""
if not nic.staticIpv6:
- return ([{"type": "dhcp6"}], [])
+ return ([], [])
subnet_list = []
# Static Ipv6
diff --git a/tests/unittests/sources/vmware/test_vmware_config_file.py b/tests/unittests/sources/vmware/test_vmware_config_file.py
index 25d3b093..b53ea96c 100644
--- a/tests/unittests/sources/vmware/test_vmware_config_file.py
+++ b/tests/unittests/sources/vmware/test_vmware_config_file.py
@@ -240,45 +240,27 @@ class TestVmwareConfigFile(CiTestCase):
elif cfg.get("name") == nic2.get("name"):
nic2.update(cfg)
- # Test NIC1
self.assertEqual("physical", nic1.get("type"), "type of NIC1")
self.assertEqual("NIC1", nic1.get("name"), "name of NIC1")
self.assertEqual(
"00:50:56:a6:8c:08", nic1.get("mac_address"), "mac address of NIC1"
)
subnets = nic1.get("subnets")
- self.assertEqual(2, len(subnets), "number of subnets for NIC1")
- subnet_ipv4 = subnets[0]
- self.assertEqual(
- "dhcp", subnet_ipv4.get("type"), "Ipv4 DHCP type for NIC1"
- )
- self.assertEqual(
- "auto", subnet_ipv4.get("control"), "NIC1 Control type"
- )
- subnet_ipv6 = subnets[1]
- self.assertEqual(
- "dhcp6", subnet_ipv6.get("type"), "Ipv6 DHCP type for NIC1"
- )
+ self.assertEqual(1, len(subnets), "number of subnets for NIC1")
+ subnet = subnets[0]
+ self.assertEqual("dhcp", subnet.get("type"), "DHCP type for NIC1")
+ self.assertEqual("auto", subnet.get("control"), "NIC1 Control type")
- # Test NIC2
self.assertEqual("physical", nic2.get("type"), "type of NIC2")
self.assertEqual("NIC2", nic2.get("name"), "name of NIC2")
self.assertEqual(
"00:50:56:a6:5a:de", nic2.get("mac_address"), "mac address of NIC2"
)
subnets = nic2.get("subnets")
- self.assertEqual(2, len(subnets), "number of subnets for NIC2")
- subnet_ipv4 = subnets[0]
- self.assertEqual(
- "dhcp", subnet_ipv4.get("type"), "Ipv4 DHCP type for NIC2"
- )
- self.assertEqual(
- "auto", subnet_ipv4.get("control"), "NIC2 Control type"
- )
- subnet_ipv6 = subnets[1]
- self.assertEqual(
- "dhcp6", subnet_ipv6.get("type"), "Ipv6 DHCP type for NIC2"
- )
+ self.assertEqual(1, len(subnets), "number of subnets for NIC2")
+ subnet = subnets[0]
+ self.assertEqual("dhcp", subnet.get("type"), "DHCP type for NIC2")
+ self.assertEqual("auto", subnet.get("control"), "NIC2 Control type")
def test_get_nics_list_static(self):
"""Tests if NicConfigurator properly calculates network subnets
@@ -303,7 +285,6 @@ class TestVmwareConfigFile(CiTestCase):
elif cfg.get("name") == nic2.get("name"):
nic2.update(cfg)
- # Test NIC1
self.assertEqual("physical", nic1.get("type"), "type of NIC1")
self.assertEqual("NIC1", nic1.get("name"), "name of NIC1")
self.assertEqual(
@@ -363,7 +344,6 @@ class TestVmwareConfigFile(CiTestCase):
else:
self.assertEqual(True, False, "invalid gateway %s" % (gateway))
- # Test NIC2
self.assertEqual("physical", nic2.get("type"), "type of NIC2")
self.assertEqual("NIC2", nic2.get("name"), "name of NIC2")
self.assertEqual(
@@ -371,18 +351,16 @@ class TestVmwareConfigFile(CiTestCase):
)
subnets = nic2.get("subnets")
- self.assertEqual(2, len(subnets), "Number of subnets for NIC2")
+ self.assertEqual(1, len(subnets), "Number of subnets for NIC2")
- subnet_ipv4 = subnets[0]
- self.assertEqual("static", subnet_ipv4.get("type"), "Subnet type")
+ subnet = subnets[0]
+ self.assertEqual("static", subnet.get("type"), "Subnet type")
self.assertEqual(
- "192.168.6.102", subnet_ipv4.get("address"), "Subnet address"
+ "192.168.6.102", subnet.get("address"), "Subnet address"
)
self.assertEqual(
- "255.255.0.0", subnet_ipv4.get("netmask"), "Subnet netmask"
+ "255.255.0.0", subnet.get("netmask"), "Subnet netmask"
)
- subnet_ipv6 = subnets[1]
- self.assertEqual("dhcp6", subnet_ipv6.get("type"), "Subnet type")
def test_custom_script(self):
cf = ConfigFile("tests/data/vmware/cust-dhcp-2nic.cfg")
@@ -469,10 +447,7 @@ class TestVmwareNetConfig(CiTestCase):
"type": "static",
"address": "10.20.87.154",
"netmask": "255.255.252.0",
- },
- {
- "type": "dhcp6",
- },
+ }
],
}
],
@@ -523,10 +498,7 @@ class TestVmwareNetConfig(CiTestCase):
"metric": 10000,
}
],
- },
- {
- "type": "dhcp6",
- },
+ }
],
}
],
@@ -586,10 +558,7 @@ class TestVmwareNetConfig(CiTestCase):
"metric": 10000,
}
],
- },
- {
- "type": "dhcp6",
- },
+ }
],
}
],
@@ -634,10 +603,7 @@ class TestVmwareNetConfig(CiTestCase):
"address": "10.20.87.154",
"netmask": "255.255.252.0",
"gateway": "10.20.87.253",
- },
- {
- "type": "dhcp6",
- },
+ }
],
}
],
--
2.39.3

View File

@ -0,0 +1,140 @@
From 96b10adc942f5117e35584d28ba88071849e8e29 Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
Date: Thu, 27 Jun 2024 18:38:22 +0530
Subject: [PATCH 1/2] Support metalink in yum repository config (#5444)
RH-Author: xiachen <xiachen@redhat.com>
RH-MergeRequest: 97: Support metalink in yum repository config (#5444)
RH-Jira: RHEL-44916
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Commit: [1/1] 4671fd3a3f6842f1f590d5a89a429facd0d8bb4d (xiachen/cloud-init-centos)
'metalink' config can be specified instead or along with 'baseurl' in the yum
repository config. Add support for specifying metalink instead of 'baseurl'.
Fixes GH-5359
Signed-off-by: Ani Sinha <anisinha@redhat.com>
Co-authored-by: Ben Gray <ben.gray@clearcapital.com>
(cherry picked from commit 525026061404ef09baebb85631d9af3b0a4d8930)
---
cloudinit/config/cc_yum_add_repo.py | 24 ++++++------
doc/examples/cloud-config-yum-repo.txt | 3 +-
.../unittests/config/test_cc_yum_add_repo.py | 38 +++++++++++++++++++
3 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/cloudinit/config/cc_yum_add_repo.py b/cloudinit/config/cc_yum_add_repo.py
index 1ab5008f..4fd66250 100644
--- a/cloudinit/config/cc_yum_add_repo.py
+++ b/cloudinit/config/cc_yum_add_repo.py
@@ -210,24 +210,22 @@ def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None:
n_repo_config[k] = v
repo_config = n_repo_config
missing_required = 0
- for req_field in ["baseurl"]:
+ req_fields = ["baseurl", "metalink"]
+ for req_field in req_fields:
if req_field not in repo_config:
- LOG.warning(
- "Repository %s does not contain a %s"
- " configuration 'required' entry",
- repo_id,
- req_field,
- )
missing_required += 1
- if not missing_required:
- repo_configs[canon_repo_id] = repo_config
- repo_locations[canon_repo_id] = repo_fn_pth
- else:
+
+ if missing_required == len(req_fields):
LOG.warning(
- "Repository %s is missing %s required fields, skipping!",
+ "Repository %s should contain atleast one of the"
+ " following configuration entries: %s, skipping!",
repo_id,
- missing_required,
+ ", ".join(req_fields),
)
+ else:
+ repo_configs[canon_repo_id] = repo_config
+ repo_locations[canon_repo_id] = repo_fn_pth
+
for (c_repo_id, path) in repo_locations.items():
repo_blob = _format_repository_config(
c_repo_id, repo_configs.get(c_repo_id)
diff --git a/doc/examples/cloud-config-yum-repo.txt b/doc/examples/cloud-config-yum-repo.txt
index e8f2bbb4..6a4037e2 100644
--- a/doc/examples/cloud-config-yum-repo.txt
+++ b/doc/examples/cloud-config-yum-repo.txt
@@ -11,8 +11,9 @@ yum_repos:
# Any repository configuration options
# See: man yum.conf
#
- # This one is required!
+ # At least one of 'baseurl' or 'metalink' is required!
baseurl: http://download.fedoraproject.org/pub/epel/testing/5/$basearch
+ metalink: https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch&infra=$infra&content=$contentdir
enabled: false
failovermethod: priority
gpgcheck: true
diff --git a/tests/unittests/config/test_cc_yum_add_repo.py b/tests/unittests/config/test_cc_yum_add_repo.py
index d2c2912f..1f27d1fb 100644
--- a/tests/unittests/config/test_cc_yum_add_repo.py
+++ b/tests/unittests/config/test_cc_yum_add_repo.py
@@ -31,6 +31,7 @@ class TestConfig(helpers.FilesystemMockingTestCase):
"yum_repos": {
"epel-testing": {
"name": "Extra Packages for Enterprise Linux 5 - Testing",
+ # At least one of baseurl or metalink must be present.
# Missing this should cause the repo not to be written
# 'baseurl': 'http://blah.org/pub/epel/testing/5/$barch',
"enabled": False,
@@ -46,6 +47,43 @@ class TestConfig(helpers.FilesystemMockingTestCase):
IOError, util.load_file, "/etc/yum.repos.d/epel_testing.repo"
)
+ def test_metalink_config(self):
+ cfg = {
+ "yum_repos": {
+ "epel-testing": {
+ "name": "Extra Packages for Enterprise Linux 5 - Testing",
+ "metalink": "http://blah.org/pub/epel/testing/5/$basearch",
+ "enabled": False,
+ "gpgcheck": True,
+ "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL",
+ "failovermethod": "priority",
+ },
+ },
+ }
+ self.patchUtils(self.tmp)
+ self.patchOS(self.tmp)
+ cc_yum_add_repo.handle("yum_add_repo", cfg, None, [])
+ contents = util.load_file("/etc/yum.repos.d/epel-testing.repo")
+ parser = configparser.ConfigParser()
+ parser.read_string(contents)
+ expected = {
+ "epel-testing": {
+ "name": "Extra Packages for Enterprise Linux 5 - Testing",
+ "failovermethod": "priority",
+ "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL",
+ "enabled": "0",
+ "metalink": "http://blah.org/pub/epel/testing/5/$basearch",
+ "gpgcheck": "1",
+ }
+ }
+ for section in expected:
+ self.assertTrue(
+ parser.has_section(section),
+ "Contains section {0}".format(section),
+ )
+ for k, v in expected[section].items():
+ self.assertEqual(parser.get(section, k), v)
+
def test_write_config(self):
cfg = {
"yum_repos": {
--
2.39.3

View File

@ -0,0 +1,145 @@
From d27ac077dac3474fea3c7bb1a19afe50ecbcc64d Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
Date: Thu, 18 Jul 2024 13:36:39 +0530
Subject: [PATCH 2/2] Support setting mirrorlist in yum repository config
(#5522)
RH-Author: xiachen <xiachen@redhat.com>
RH-MergeRequest: 104: Support setting mirrorlist in yum repository config (#5522)
RH-Jira: RHEL-49674
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Commit: [1/1] 4605a0304c6bed6614990b7194465230afa79778 (xiachen/cloud-init-centos)
'mirrorlist' config can be specified instead or along with 'baseurl' in the yum
repository config. Add support for specifying mirrorlist instead of 'baseurl'.
Fixes GH-5520
Signed-off-by: Ani Sinha <anisinha@redhat.com>
(cherry picked from commit 0b4084374440d2a5a9968129e0460a1a009d9830)
Signed-off-by: Amy Chen <xiachen@redhat.com>
---
cloudinit/config/cc_yum_add_repo.py | 2 +-
.../schemas/schema-cloud-config-v1.json | 10 +++++
doc/examples/cloud-config-yum-repo.txt | 3 +-
.../unittests/config/test_cc_yum_add_repo.py | 40 ++++++++++++++++++-
4 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/cloudinit/config/cc_yum_add_repo.py b/cloudinit/config/cc_yum_add_repo.py
index 4fd66250..3870d24e 100644
--- a/cloudinit/config/cc_yum_add_repo.py
+++ b/cloudinit/config/cc_yum_add_repo.py
@@ -210,7 +210,7 @@ def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None:
n_repo_config[k] = v
repo_config = n_repo_config
missing_required = 0
- req_fields = ["baseurl", "metalink"]
+ req_fields = ["baseurl", "metalink", "mirrorlist"]
for req_field in req_fields:
if req_field not in repo_config:
missing_required += 1
diff --git a/cloudinit/config/schemas/schema-cloud-config-v1.json b/cloudinit/config/schemas/schema-cloud-config-v1.json
index 4fb7fd93..c5f46f37 100644
--- a/cloudinit/config/schemas/schema-cloud-config-v1.json
+++ b/cloudinit/config/schemas/schema-cloud-config-v1.json
@@ -3447,6 +3447,11 @@
"format": "uri",
"description": "Specifies a URL to a metalink file for the repomd.xml"
},
+ "mirrorlist": {
+ "type": "string",
+ "format": "uri",
+ "description": "Specifies a URL to a file containing a baseurls list"
+ },
"name": {
"type": "string",
"description": "Optional human-readable name of the yum repo."
@@ -3484,6 +3489,11 @@
"required": [
"metalink"
]
+ },
+ {
+ "required": [
+ "mirrorlist"
+ ]
}
]
}
diff --git a/doc/examples/cloud-config-yum-repo.txt b/doc/examples/cloud-config-yum-repo.txt
index 6a4037e2..cee26677 100644
--- a/doc/examples/cloud-config-yum-repo.txt
+++ b/doc/examples/cloud-config-yum-repo.txt
@@ -11,9 +11,10 @@ yum_repos:
# Any repository configuration options
# See: man yum.conf
#
- # At least one of 'baseurl' or 'metalink' is required!
+ # At least one of 'baseurl' or 'metalink' or 'mirrorlist' is required!
baseurl: http://download.fedoraproject.org/pub/epel/testing/5/$basearch
metalink: https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch&infra=$infra&content=$contentdir
+ mirrorlist: https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&
enabled: false
failovermethod: priority
gpgcheck: true
diff --git a/tests/unittests/config/test_cc_yum_add_repo.py b/tests/unittests/config/test_cc_yum_add_repo.py
index 1f27d1fb..000792b4 100644
--- a/tests/unittests/config/test_cc_yum_add_repo.py
+++ b/tests/unittests/config/test_cc_yum_add_repo.py
@@ -31,7 +31,8 @@ class TestConfig(helpers.FilesystemMockingTestCase):
"yum_repos": {
"epel-testing": {
"name": "Extra Packages for Enterprise Linux 5 - Testing",
- # At least one of baseurl or metalink must be present.
+ # At least one of baseurl or metalink or mirrorlist
+ # must be present.
# Missing this should cause the repo not to be written
# 'baseurl': 'http://blah.org/pub/epel/testing/5/$barch',
"enabled": False,
@@ -84,6 +85,43 @@ class TestConfig(helpers.FilesystemMockingTestCase):
for k, v in expected[section].items():
self.assertEqual(parser.get(section, k), v)
+ def test_mirrorlist_config(self):
+ cfg = {
+ "yum_repos": {
+ "epel-testing": {
+ "name": "Extra Packages for Enterprise Linux 5 - Testing",
+ "mirrorlist": "http://mirrors.blah.org/metalink?repo=rhel-$releasever",
+ "enabled": False,
+ "gpgcheck": True,
+ "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL",
+ "failovermethod": "priority",
+ },
+ },
+ }
+ self.patchUtils(self.tmp)
+ self.patchOS(self.tmp)
+ cc_yum_add_repo.handle("yum_add_repo", cfg, None, [])
+ contents = util.load_file("/etc/yum.repos.d/epel-testing.repo")
+ parser = configparser.ConfigParser()
+ parser.read_string(contents)
+ expected = {
+ "epel-testing": {
+ "name": "Extra Packages for Enterprise Linux 5 - Testing",
+ "failovermethod": "priority",
+ "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL",
+ "enabled": "0",
+ "mirrorlist": "http://mirrors.blah.org/metalink?repo=rhel-$releasever",
+ "gpgcheck": "1",
+ }
+ }
+ for section in expected:
+ self.assertTrue(
+ parser.has_section(section),
+ "Contains section {0}".format(section),
+ )
+ for k, v in expected[section].items():
+ self.assertEqual(parser.get(section, k), v)
+
def test_write_config(self):
cfg = {
"yum_repos": {
--
2.39.3

View File

@ -0,0 +1,235 @@
From c34f5c4275c3ef7bee9a99e87bf6e37c5886b160 Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
Date: Wed, 29 May 2024 03:34:38 +0530
Subject: [PATCH 6/6] Update pylint version to support python 3.12 (#5338)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 92: Update pylint version to support python 3.12
RH-Jira: RHEL-44598
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [3/3] d6185e0a126e1589260ee59709fe933b5a780b78 (anisinha/cloud-init)
Fedora 39 and above comes with python version 3.12. When running `tox -e pylint`
on cloud-init, we may experience issue such as the one reported here:
https://github.com/pylint-dev/pylint/issues/8782
Minimum version of pylint required in order to support python 3.12 is 3.0.2.
Please see https://github.com/pylint-dev/astroid/issues/2201 . Upon further
experimentation, it is seen that we need minimum pylint version 3.2.0 for
cloud-init. Update tox.ini in order to use this pylint version.
Signed-off-by: Ani Sinha <anisinha@redhat.com>
(cherry picked from commit 5ad609ffdf4bb76c5665e12e34e1867b72bd4435)
Conflicts:
cloudinit/sources/DataSourceWSL.py (does not exist)
cloudinit/util.py (doc added upstream)
---
cloudinit/config/cc_mounts.py | 4 ++++
cloudinit/distros/bsd.py | 2 ++
cloudinit/distros/netbsd.py | 2 +-
cloudinit/sources/DataSourceAzure.py | 2 +-
cloudinit/sources/DataSourceEc2.py | 3 ++-
cloudinit/sources/DataSourceLXD.py | 2 +-
tests/integration_tests/conftest.py | 6 +++---
tests/integration_tests/util.py | 2 +-
tests/unittests/config/test_cc_ntp.py | 2 ++
tests/unittests/sources/test_gce.py | 1 +
tests/unittests/test_util.py | 2 ++
tox.ini | 2 +-
12 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/cloudinit/config/cc_mounts.py b/cloudinit/config/cc_mounts.py
index 4efa2a29..d445b440 100644
--- a/cloudinit/config/cc_mounts.py
+++ b/cloudinit/config/cc_mounts.py
@@ -304,6 +304,10 @@ def create_swapfile(fname: str, size: str) -> None:
"bs=1M",
"count=%s" % size,
]
+ else:
+ raise subp.ProcessExecutionError(
+ "Missing dependency: 'dd' and 'fallocate' are not available"
+ )
try:
subp.subp(cmd, capture=True)
diff --git a/cloudinit/distros/bsd.py b/cloudinit/distros/bsd.py
index 761cf5c4..77e0385f 100644
--- a/cloudinit/distros/bsd.py
+++ b/cloudinit/distros/bsd.py
@@ -120,6 +120,8 @@ class BSD(distros.Distro):
if not self.pkg_cmd_upgrade_prefix:
return
cmd = self.pkg_cmd_upgrade_prefix
+ else:
+ cmd = []
if args and isinstance(args, str):
cmd.append(args)
diff --git a/cloudinit/distros/netbsd.py b/cloudinit/distros/netbsd.py
index a5678907..b7f3f3d8 100644
--- a/cloudinit/distros/netbsd.py
+++ b/cloudinit/distros/netbsd.py
@@ -12,7 +12,7 @@ import cloudinit.distros.bsd
from cloudinit import subp, util
try:
- import crypt
+ import crypt # pylint: disable=W4901
salt = crypt.METHOD_BLOWFISH # pylint: disable=E1101
blowfish_hash: Any = functools.partial(
diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
index 11c14e20..eb0304c3 100644
--- a/cloudinit/sources/DataSourceAzure.py
+++ b/cloudinit/sources/DataSourceAzure.py
@@ -51,7 +51,7 @@ from cloudinit.sources.helpers.azure import (
from cloudinit.url_helper import UrlError
try:
- import crypt
+ import crypt # pylint: disable=W4901
blowfish_hash: Any = functools.partial(
crypt.crypt, salt=f"$6${util.rand_str(strlen=16)}"
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
index 9e6bfbd1..384e4074 100644
--- a/cloudinit/sources/DataSourceEc2.py
+++ b/cloudinit/sources/DataSourceEc2.py
@@ -312,6 +312,8 @@ class DataSourceEc2(sources.DataSource):
return None
def wait_for_metadata_service(self):
+ urls = []
+ start_time = 0
mcfg = self.ds_cfg
url_params = self.get_url_params()
@@ -345,7 +347,6 @@ class DataSourceEc2(sources.DataSource):
and self.cloud_name not in IDMSV2_SUPPORTED_CLOUD_PLATFORMS
):
# if we can't get a token, use instance-id path
- urls = []
url2base = {}
url_path = "{ver}/meta-data/instance-id".format(
ver=self.min_metadata_version
diff --git a/cloudinit/sources/DataSourceLXD.py b/cloudinit/sources/DataSourceLXD.py
index cd316101..4c95b907 100644
--- a/cloudinit/sources/DataSourceLXD.py
+++ b/cloudinit/sources/DataSourceLXD.py
@@ -331,7 +331,7 @@ class MetaDataKeys(Flag):
CONFIG = auto()
DEVICES = auto()
META_DATA = auto()
- ALL = CONFIG | DEVICES | META_DATA
+ ALL = CONFIG | DEVICES | META_DATA # pylint: disable=E1131
class _MetaDataReader:
diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py
index fa729b7d..ec211a00 100644
--- a/tests/integration_tests/conftest.py
+++ b/tests/integration_tests/conftest.py
@@ -241,7 +241,7 @@ def _client(
@pytest.fixture
-def client(
+def client( # pylint: disable=W0135
request, fixture_utils, session_cloud, setup_image
) -> Iterator[IntegrationInstance]:
"""Provide a client that runs for every test."""
@@ -250,7 +250,7 @@ def client(
@pytest.fixture(scope="module")
-def module_client(
+def module_client( # pylint: disable=W0135
request, fixture_utils, session_cloud, setup_image
) -> Iterator[IntegrationInstance]:
"""Provide a client that runs once per module."""
@@ -259,7 +259,7 @@ def module_client(
@pytest.fixture(scope="class")
-def class_client(
+def class_client( # pylint: disable=W0135
request, fixture_utils, session_cloud, setup_image
) -> Iterator[IntegrationInstance]:
"""Provide a client that runs once per class."""
diff --git a/tests/integration_tests/util.py b/tests/integration_tests/util.py
index 0a15203c..e26e466c 100644
--- a/tests/integration_tests/util.py
+++ b/tests/integration_tests/util.py
@@ -182,7 +182,7 @@ def wait_for_cloud_init(client: IntegrationInstance, num_retries: int = 30):
except Exception as e:
last_exception = e
time.sleep(1)
- raise Exception(
+ raise Exception( # pylint: disable=W0719
"cloud-init status did not return successfully."
) from last_exception
diff --git a/tests/unittests/config/test_cc_ntp.py b/tests/unittests/config/test_cc_ntp.py
index a9444ec5..c9ce5daa 100644
--- a/tests/unittests/config/test_cc_ntp.py
+++ b/tests/unittests/config/test_cc_ntp.py
@@ -248,6 +248,7 @@ class TestNtp(FilesystemMockingTestCase):
)
def _get_expected_pools(self, pools, distro, client):
+ expected_pools = None
if client in ["ntp", "chrony"]:
if client == "ntp" and distro == "alpine":
# NTP for Alpine Linux is Busybox's ntp which does not
@@ -263,6 +264,7 @@ class TestNtp(FilesystemMockingTestCase):
return expected_pools
def _get_expected_servers(self, servers, distro, client):
+ expected_servers = None
if client in ["ntp", "chrony"]:
if client == "ntp" and distro == "alpine":
# NTP for Alpine Linux is Busybox's ntp which only supports
diff --git a/tests/unittests/sources/test_gce.py b/tests/unittests/sources/test_gce.py
index c0b19d3c..30a50236 100644
--- a/tests/unittests/sources/test_gce.py
+++ b/tests/unittests/sources/test_gce.py
@@ -101,6 +101,7 @@ class TestDataSourceGCE(test_helpers.ResponsesTestCase):
gce_meta = GCE_META
def _request_callback(request):
+ recursive = False
url_path = urlparse(request.url).path
if url_path.startswith("/computeMetadata/v1/"):
path = url_path.split("/computeMetadata/v1/")[1:][0]
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 519ef63c..de1326d4 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -1677,6 +1677,8 @@ class TestRedirectOutputPreexecFn:
args = (test_string, None)
elif request.param == "errfmt":
args = (None, test_string)
+ else:
+ args = (None, None)
with mock.patch(M_PATH + "subprocess.Popen") as m_popen:
util.redirect_output(*args)
diff --git a/tox.ini b/tox.ini
index 5f01a9a8..5199ca13 100644
--- a/tox.ini
+++ b/tox.ini
@@ -25,7 +25,7 @@ hypothesis==6.31.6
hypothesis_jsonschema==0.20.1
isort==5.10.1
mypy==0.950
-pylint==2.13.9
+pylint==3.2.0
pytest==7.0.1
ruff==0.0.285
types-jsonschema==4.4.2
--
2.39.3

View File

@ -0,0 +1,51 @@
From 52c04e1a523a450dfce70bc441963eb6a026eb59 Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
Date: Thu, 20 Jun 2024 11:18:40 +0530
Subject: [PATCH 3/6] doc: update examples to reflect alternative ways to
provide `sudo` option (#5418)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 90: fix(jsonschema): Add missing sudo definition (#5418)
RH-Jira: RHEL-44337
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/2] 62eac6d731cb725c32cd0beac0219ecc2b407198 (anisinha/cloud-init)
For creating users and groups, it is possible to pass a `sudo` option to the
config file that accepts a sudo rule. The option can be a sudo rule string,
a list of sudo rule strings or `False` to explicitly deny sudo usage. Update
examples to show how a list of strings can be used with `sudo` option.
Signed-off-by: Ani Sinha <anisinha@redhat.com>
(cherry picked from commit cbcb05349e35023ee6e81ccaf13e79adb8f65f63)
---
doc/examples/cloud-config-user-groups.txt | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/doc/examples/cloud-config-user-groups.txt b/doc/examples/cloud-config-user-groups.txt
index 87fc52e8..56eb674f 100644
--- a/doc/examples/cloud-config-user-groups.txt
+++ b/doc/examples/cloud-config-user-groups.txt
@@ -35,6 +35,10 @@ users:
lock_passwd: true
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDSL7uWGj8cgWyIOaspgKdVy0cKJ+UTjfv7jBOjG2H/GN8bJVXy72XAvnhM0dUM+CCs8FOf0YlPX+Frvz2hKInrmRhZVwRSL129PasD12MlI3l44u6IwS1o/W86Q+tkQYEljtqDOo0a+cOsaZkvUNzUyEXUwz/lmYa6G4hMKZH4NBj7nbAAF96wsMCoyNwbWryBnDYUr6wMbjRR1J9Pw7Xh7WRC73wy4Va2YuOgbD3V/5ZrFPLbWZW/7TFXVrql04QVbyei4aiFR5n//GvoqwQDNe58LmbzX/xvxyKJYdny2zXmdAhMxbrpFQsfpkJ9E/H5w0yOdSvnWbUoG5xNGoOB csmith@fringe
+ - name: testuser
+ gecos: Mr. Test
+ homedir: /local/testdir
+ sudo: ["ALL=(ALL) NOPASSWD:ALL"]
- name: cloudy
gecos: Magic Cloud App Daemon User
inactive: '5'
@@ -100,6 +104,8 @@ users:
#
# Allow a user unrestricted sudo access.
# sudo: ALL=(ALL) NOPASSWD:ALL
+# or
+# sudo: ["ALL=(ALL) NOPASSWD:ALL"]
#
# Adding multiple sudo rule strings.
# sudo:
--
2.39.3

View File

@ -0,0 +1,166 @@
From c933187af44a5de1d6eafde5dcd48e8ac369cf34 Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Thu, 18 Apr 2024 20:21:14 -0500
Subject: [PATCH 2/3] docs: Add deprecated system_info to schema (#5168)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 95: Deprecate the users ssh-authorized-keys property (#5162)
RH-Jira: RHEL-45262
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/3] c4ea6f45ee0997e2f749c290fb8f2ceb8c05c691 (anisinha/cloud-init)
In some cases, `system_info` can be passed via user data or vendor data
to override the system_info in /etc/cloud/cloud.cfg . While this
technically can work, this is a use case we no longer support and should
indicate that it is deprecated.
Also remove/update examples.
(cherry picked from commit 7c67f7732f04b41600934818f7d5bcb4d085ed7c)
Conflicts:
cloudinit/config/schemas/schema-cloud-config-v1.json
- due to change fdefe08ad19cea5eb ("fix: Fix typos (#4850)") not
present in downstream.
doc/examples/cloud-config-user-groups.txt
- due to change 0aa17cd10bdd6 ("docs: set the home directory using homedir, not home (#5101)")
not present downstream.
tests/unittests/sources/test_vultr.py
- due to change 144782a838 ("test: Remove side effects from tests (#5074)") not present
downstream.
---
.../schemas/schema-cloud-config-v1.json | 7 ++++++
doc/examples/cloud-config-apt.txt | 23 -------------------
doc/examples/cloud-config-user-groups.txt | 12 ++--------
tests/data/user_data.1.txt | 10 --------
tests/unittests/runs/test_merge_run.py | 16 ++++++++++++-
5 files changed, 24 insertions(+), 44 deletions(-)
diff --git a/cloudinit/config/schemas/schema-cloud-config-v1.json b/cloudinit/config/schemas/schema-cloud-config-v1.json
index 670ef4c2..97cf2b74 100644
--- a/cloudinit/config/schemas/schema-cloud-config-v1.json
+++ b/cloudinit/config/schemas/schema-cloud-config-v1.json
@@ -513,6 +513,12 @@
},
"merge_type": {
"$ref": "#/$defs/merge_defintion"
+ },
+ "system_info": {
+ "type": "object",
+ "description": "System and/or distro specific settings. This is not intended to be overridden by user data or vendor data.",
+ "deprecated": true,
+ "deprecated_version": "24.2"
}
}
},
@@ -3905,6 +3911,7 @@
"ssh_pwauth": {},
"ssh_quiet_keygen": {},
"swap": {},
+ "system_info": {},
"timezone": {},
"ubuntu_advantage": {},
"updates": {},
diff --git a/doc/examples/cloud-config-apt.txt b/doc/examples/cloud-config-apt.txt
index dd6a0f6a..04968035 100644
--- a/doc/examples/cloud-config-apt.txt
+++ b/doc/examples/cloud-config-apt.txt
@@ -8,29 +8,6 @@
# Number: Set pipelining to some number (not recommended)
apt_pipelining: False
-## apt config via system_info:
-# under the 'system_info', you can customize cloud-init's interaction
-# with apt.
-# system_info:
-# apt_get_command: [command, argument, argument]
-# apt_get_upgrade_subcommand: dist-upgrade
-#
-# apt_get_command:
-# To specify a different 'apt-get' command, set 'apt_get_command'.
-# This must be a list, and the subcommand (update, upgrade) is appended to it.
-# default is:
-# ['apt-get', '--option=Dpkg::Options::=--force-confold',
-# '--option=Dpkg::options::=--force-unsafe-io', '--assume-yes', '--quiet']
-#
-# apt_get_upgrade_subcommand: "dist-upgrade"
-# Specify a different subcommand for 'upgrade. The default is 'dist-upgrade'.
-# This is the subcommand that is invoked for package_upgrade.
-#
-# apt_get_wrapper:
-# command: eatmydata
-# enabled: [True, False, "auto"]
-#
-
# Install additional packages on first boot
#
# Default: none
diff --git a/doc/examples/cloud-config-user-groups.txt b/doc/examples/cloud-config-user-groups.txt
index 56eb674f..2cafef88 100644
--- a/doc/examples/cloud-config-user-groups.txt
+++ b/doc/examples/cloud-config-user-groups.txt
@@ -143,13 +143,5 @@ users:
#
# users[0] (the first user in users) overrides the user directive.
#
-# The 'default' user above references the distro's config:
-# system_info:
-# default_user:
-# name: Ubuntu
-# plain_text_passwd: 'ubuntu'
-# home: /home/ubuntu
-# shell: /bin/bash
-# lock_passwd: True
-# gecos: Ubuntu
-# groups: [adm, cdrom, dip, lxd, sudo]
+# The 'default' user above references the distro's config set in
+# /etc/cloud/cloud.cfg.
diff --git a/tests/data/user_data.1.txt b/tests/data/user_data.1.txt
index 4c4543de..a1b5aa60 100644
--- a/tests/data/user_data.1.txt
+++ b/tests/data/user_data.1.txt
@@ -3,13 +3,3 @@ write_files:
- content: blah
path: /etc/blah.ini
permissions: 493
-
-system_info:
- package_mirrors:
- - arches: [i386, amd64, blah]
- failsafe:
- primary: http://my.archive.mydomain.com/ubuntu
- security: http://my.security.mydomain.com/ubuntu
- search:
- primary: []
- security: []
diff --git a/tests/unittests/runs/test_merge_run.py b/tests/unittests/runs/test_merge_run.py
index afc256ec..251c5ae5 100644
--- a/tests/unittests/runs/test_merge_run.py
+++ b/tests/unittests/runs/test_merge_run.py
@@ -22,7 +22,21 @@ class TestMergeRun(helpers.FilesystemMockingTestCase):
cfg = {
"datasource_list": ["None"],
"cloud_init_modules": ["write_files"],
- "system_info": {"paths": {"run_dir": new_root}},
+ "system_info": {
+ "paths": {"run_dir": new_root},
+ "package_mirrors": [
+ {
+ "arches": ["i386", "amd64", "blah"],
+ "failsafe": {
+ "primary": "http://my.archive.mydomain.com/ubuntu",
+ "security": (
+ "http://my.security.mydomain.com/ubuntu"
+ ),
+ },
+ "search": {"primary": [], "security": []},
+ },
+ ],
+ },
}
ud = helpers.readResource("user_data.1.txt")
cloud_cfg = safeyaml.dumps(cfg)
--
2.39.3

View File

@ -0,0 +1,207 @@
From c21351ad9da5aebcb252aa36cbfa92ac16fa9746 Mon Sep 17 00:00:00 2001
From: Florian Apolloner <florian@apolloner.eu>
Date: Fri, 5 Jan 2024 19:07:12 +0100
Subject: [PATCH 2/3] feat: apply global DNS to interfaces in network-manager
(#4723)
RH-Author: Cathy Avery <cavery@redhat.com>
RH-MergeRequest: 72: Fixes for cloud-init fails to configure DNS/search domains for network-config v1
RH-Jira: RHEL-20964
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Commit: [2/2] 1d2b10133ec2558e9665f21f53e4b1a898e283a8 (cavery/cloud-init-c-9-s)
Sometimes DNS settings in cloud configs are specified globally and
not per interface / subnet. This results in a configuration without
proper nameservers. This was fixed for netplan in d29eeccd and is
now also applied to the network-manager renderer.
Co-authored-by: James Falcon <james.falcon@canonical.com>
(cherry picked from commit 0d787d0a262f70ff848b315633742aa8fc45a1de)
Signed-off-by: Cathy Avery <cavery@redhat.com>
---
cloudinit/net/network_manager.py | 52 ++++++++++++++---------
tests/unittests/net/test_net_rendering.py | 3 ++
tests/unittests/test_net.py | 11 +++++
tools/.github-cla-signers | 1 +
4 files changed, 47 insertions(+), 20 deletions(-)
diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py
index bd6e6d75..0ba210b7 100644
--- a/cloudinit/net/network_manager.py
+++ b/cloudinit/net/network_manager.py
@@ -246,7 +246,7 @@ class NMConnection:
"""
return addr.replace("-", ":").upper()
- def render_interface(self, iface, renderer):
+ def render_interface(self, iface, network_state, renderer):
"""
Integrate information from network state interface information
into the connection. Most of the work is done here.
@@ -311,7 +311,6 @@ class NMConnection:
found_dns_search = []
# Deal with Layer 3 configuration
- use_top_level_dns = "dns" in iface
for subnet in iface["subnets"]:
family = "ipv6" if subnet_is_ipv6(subnet) else "ipv4"
@@ -322,26 +321,39 @@ class NMConnection:
self.config[family]["gateway"] = subnet["gateway"]
for route in subnet["routes"]:
self._add_route(route)
- if not use_top_level_dns and "dns_nameservers" in subnet:
- for nameserver in subnet["dns_nameservers"]:
- found_nameservers.append(nameserver)
- if not use_top_level_dns and "dns_search" in subnet:
- found_dns_search.append(subnet["dns_search"])
+ # Add subnet-level DNS
+ if "dns_nameservers" in subnet:
+ found_nameservers.extend(subnet["dns_nameservers"])
+ if "dns_search" in subnet:
+ found_dns_search.extend(subnet["dns_search"])
if family == "ipv4" and "mtu" in subnet:
ipv4_mtu = subnet["mtu"]
- # Now add our DNS search domains. We add them later because we
- # only want them if an IP family has already been defined
- if use_top_level_dns:
- for nameserver in iface["dns"]["nameservers"]:
- self._add_nameserver(nameserver)
- if iface["dns"]["search"]:
- self._add_dns_search(iface["dns"]["search"])
- else:
- for nameserver in found_nameservers:
- self._add_nameserver(nameserver)
- for dns_search in found_dns_search:
- self._add_dns_search(dns_search)
+ # Add interface-level DNS
+ if "dns" in iface:
+ found_nameservers += [
+ dns
+ for dns in iface["dns"]["nameservers"]
+ if dns not in found_nameservers
+ ]
+ found_dns_search += [
+ search
+ for search in iface["dns"]["search"]
+ if search not in found_dns_search
+ ]
+
+ # We prefer any interface-specific DNS entries, but if we do not
+ # have any, add the global DNS to the connection
+ if not found_nameservers and network_state.dns_nameservers:
+ found_nameservers = network_state.dns_nameservers
+ if not found_dns_search and network_state.dns_searchdomains:
+ found_dns_search = network_state.dns_searchdomains
+
+ # Write out all DNS entries to the connection
+ for nameserver in found_nameservers:
+ self._add_nameserver(nameserver)
+ if found_dns_search:
+ self._add_dns_search(found_dns_search)
# we do not want to set may-fail to false for both ipv4 and ipv6 dhcp
# at the at the same time. This will make the network configuration
@@ -457,7 +469,7 @@ class Renderer(renderer.Renderer):
# Now render the actual interface configuration
for iface in network_state.iter_interfaces():
conn = self.connections[iface["name"]]
- conn.render_interface(iface, self)
+ conn.render_interface(iface, network_state, self)
# And finally write the files
for con_id, conn in self.connections.items():
diff --git a/tests/unittests/net/test_net_rendering.py b/tests/unittests/net/test_net_rendering.py
index 06feab89..f340ffc1 100644
--- a/tests/unittests/net/test_net_rendering.py
+++ b/tests/unittests/net/test_net_rendering.py
@@ -88,6 +88,9 @@ def _check_network_manager(network_state: NetworkState, tmp_path: Path):
"test_name, renderers",
[("no_matching_mac_v2", Renderer.Netplan | Renderer.NetworkManager)],
)
+@pytest.mark.xfail(
+ reason="v2 interface-specific DNS errantly gets applied globally"
+)
def test_convert(test_name, renderers, tmp_path):
network_config = safeyaml.load(
Path(ARTIFACT_DIR, f"{test_name}.yaml").read_text()
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 2a99f150..d7c9a414 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -646,6 +646,7 @@ method=manual
may-fail=false
address1=172.19.1.34/22
route1=0.0.0.0/0,172.19.3.254
+dns=172.19.0.12;
""".lstrip(),
),
@@ -2797,6 +2798,8 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
[ipv4]
method=auto
may-fail=false
+ dns=8.8.8.8;4.4.4.4;8.8.4.4;
+ dns-search=barley.maas;wark.maas;foobar.maas;
"""
),
@@ -2822,6 +2825,8 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
method=manual
may-fail=false
address1=192.168.200.7/24
+ dns=8.8.8.8;4.4.4.4;8.8.4.4;
+ dns-search=barley.maas;wark.maas;foobar.maas;
"""
),
@@ -2846,6 +2851,8 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
[ipv4]
method=auto
may-fail=false
+ dns=8.8.8.8;4.4.4.4;8.8.4.4;
+ dns-search=barley.maas;wark.maas;foobar.maas;
"""
),
@@ -2930,12 +2937,15 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
method=manual
may-fail=false
address1=192.168.14.2/24
+ dns=8.8.8.8;4.4.4.4;8.8.4.4;
+ dns-search=barley.maas;wark.maas;foobar.maas;
[ipv6]
method=manual
may-fail=false
address1=2001:1::1/64
route1=::/0,2001:4800:78ff:1b::1
+ dns-search=barley.maas;wark.maas;foobar.maas;
"""
),
@@ -2990,6 +3000,7 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
[ipv6]
method=auto
may-fail=false
+ dns-search=barley.maas;wark.maas;foobar.maas;
"""
),
diff --git a/tools/.github-cla-signers b/tools/.github-cla-signers
index dbdb9cfa..f4da0989 100644
--- a/tools/.github-cla-signers
+++ b/tools/.github-cla-signers
@@ -13,6 +13,7 @@ andrewbogott
andrewlukoshko
ani-sinha
antonyc
+apollo13
aswinrajamannar
bdrung
beantaxi
--
2.39.3

View File

@ -0,0 +1,351 @@
From 6b32b371bfd37759ddce3d7f29d15546500698e6 Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
Date: Thu, 20 Jun 2024 22:27:03 +0530
Subject: [PATCH 1/6] feat(sysconfig): Add DNS from interface config to
resolv.conf (#5401)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 88: feat(sysconfig): Add DNS from interface config to resolv.conf (#5401)
RH-Jira: RHEL-17961
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] f353b73cc0f4bb9e1aee037708a1d3cb23b83cc3 (anisinha/cloud-init)
sysconfig renderer currently only uses global dns and search domain
configuration in order to populate /etc/resolv.conf. This means it ignores
interface specific dns configuration completely. This means, when global dns
information is absent and only interface specific dns configuration is present,
/etc/resolv.conf will not have complete dns information. Fix this so that
per interface dns information is also taken into account along with global dns
configuration in order to populate /etc/resolv.conf.
Fixes: GH-5400
Signed-off-by: Ani Sinha <anisinha@redhat.com>
(cherry picked from commit 1b8030e0c7fd6fbff7e38ad1e3e6266ae50c83a5)
---
cloudinit/net/sysconfig.py | 52 +++++++++-
tests/unittests/test_net.py | 184 +++++++++++++++++++++++++++++++++++-
2 files changed, 230 insertions(+), 6 deletions(-)
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
index d39f4fe3..7eb430ed 100644
--- a/cloudinit/net/sysconfig.py
+++ b/cloudinit/net/sysconfig.py
@@ -825,20 +825,62 @@ class Renderer(renderer.Renderer):
@staticmethod
def _render_dns(network_state, existing_dns_path=None):
- # skip writing resolv.conf if network_state doesn't include any input.
+
+ found_nameservers = []
+ found_dns_search = []
+
+ for iface in network_state.iter_interfaces():
+ for subnet in iface["subnets"]:
+ # Add subnet-level DNS
+ if "dns_nameservers" in subnet:
+ found_nameservers.extend(subnet["dns_nameservers"])
+ if "dns_search" in subnet:
+ found_dns_search.extend(subnet["dns_search"])
+
+ # Add interface-level DNS
+ if "dns" in iface:
+ found_nameservers += [
+ dns
+ for dns in iface["dns"]["nameservers"]
+ if dns not in found_nameservers
+ ]
+ found_dns_search += [
+ search
+ for search in iface["dns"]["search"]
+ if search not in found_dns_search
+ ]
+
+ # When both global and interface specific entries are present,
+ # use them both to generate /etc/resolv.conf eliminating duplicate
+ # entries. Otherwise use global or interface specific entries whichever
+ # is provided.
+ if network_state.dns_nameservers:
+ found_nameservers += [
+ nameserver
+ for nameserver in network_state.dns_nameservers
+ if nameserver not in found_nameservers
+ ]
+ if network_state.dns_searchdomains:
+ found_dns_search += [
+ search
+ for search in network_state.dns_searchdomains
+ if search not in found_dns_search
+ ]
+
+ # skip writing resolv.conf if no dns information is provided in conf.
if not any(
[
- len(network_state.dns_nameservers),
- len(network_state.dns_searchdomains),
+ len(found_nameservers),
+ len(found_dns_search),
]
):
return None
content = resolv_conf.ResolvConf("")
if existing_dns_path and os.path.isfile(existing_dns_path):
content = resolv_conf.ResolvConf(util.load_file(existing_dns_path))
- for nameserver in network_state.dns_nameservers:
+ for nameserver in found_nameservers:
content.add_nameserver(nameserver)
- for searchdomain in network_state.dns_searchdomains:
+ for searchdomain in found_dns_search:
content.add_search_domain(searchdomain)
header = _make_header(";")
content_str = str(content)
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index d7c9a414..2d716f4b 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -516,6 +516,8 @@ OS_SAMPLES = [
}
],
"ip_address": "172.19.1.34",
+ "dns_search": ["testweb.com"],
+ "dns_nameservers": ["172.19.0.13"],
"id": "network0",
}
],
@@ -550,7 +552,9 @@ STARTMODE=auto
"""
; Created by cloud-init automatically, do not edit.
;
+nameserver 172.19.0.13
nameserver 172.19.0.12
+search testweb.com
""".lstrip(),
),
(
@@ -582,6 +586,8 @@ AUTOCONNECT_PRIORITY=120
BOOTPROTO=none
DEFROUTE=yes
DEVICE=eth0
+DNS1=172.19.0.13
+DOMAIN=testweb.com
GATEWAY=172.19.3.254
HWADDR=fa:16:3e:ed:9a:59
IPADDR=172.19.1.34
@@ -596,7 +602,174 @@ USERCTL=no
"""
; Created by cloud-init automatically, do not edit.
;
+nameserver 172.19.0.13
nameserver 172.19.0.12
+search testweb.com
+""".lstrip(),
+ ),
+ (
+ "etc/NetworkManager/conf.d/99-cloud-init.conf",
+ """
+# Created by cloud-init automatically, do not edit.
+#
+[main]
+dns = none
+""".lstrip(),
+ ),
+ (
+ "etc/udev/rules.d/70-persistent-net.rules",
+ "".join(
+ [
+ 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
+ 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n',
+ ]
+ ),
+ ),
+ ],
+ "expected_network_manager": [
+ (
+ "".join(
+ [
+ "etc/NetworkManager/system-connections",
+ "/cloud-init-eth0.nmconnection",
+ ]
+ ),
+ """
+# Generated by cloud-init. Changes will be lost.
+
+[connection]
+id=cloud-init eth0
+uuid=1dd9a779-d327-56e1-8454-c65e2556c12c
+autoconnect-priority=120
+type=ethernet
+
+[user]
+org.freedesktop.NetworkManager.origin=cloud-init
+
+[ethernet]
+mac-address=FA:16:3E:ED:9A:59
+
+[ipv4]
+method=manual
+may-fail=false
+address1=172.19.1.34/22
+route1=0.0.0.0/0,172.19.3.254
+dns=172.19.0.13;
+dns-search=testweb.com;
+
+""".lstrip(),
+ ),
+ ],
+ },
+ {
+ "in_data": {
+ "services": [
+ {
+ "type": "dns",
+ "address": "172.19.0.12",
+ "search": ["example1.com", "example2.com"],
+ }
+ ],
+ "networks": [
+ {
+ "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4",
+ "type": "ipv4",
+ "netmask": "255.255.252.0",
+ "link": "eth0",
+ "routes": [
+ {
+ "netmask": "0.0.0.0",
+ "network": "0.0.0.0",
+ "gateway": "172.19.3.254",
+ }
+ ],
+ "ip_address": "172.19.1.34",
+ "dns_search": ["example3.com"],
+ "dns_nameservers": ["172.19.0.12"],
+ "id": "network0",
+ }
+ ],
+ "links": [
+ {
+ "ethernet_mac_address": "fa:16:3e:ed:9a:59",
+ "mtu": None,
+ "type": "physical",
+ "id": "eth0",
+ },
+ ],
+ },
+ "in_macs": {
+ "fa:16:3e:ed:9a:59": "eth0",
+ },
+ "out_sysconfig_opensuse": [
+ (
+ "etc/sysconfig/network/ifcfg-eth0",
+ """
+# Created by cloud-init automatically, do not edit.
+#
+BOOTPROTO=static
+IPADDR=172.19.1.34
+LLADDR=fa:16:3e:ed:9a:59
+NETMASK=255.255.252.0
+STARTMODE=auto
+""".lstrip(),
+ ),
+ (
+ "etc/resolv.conf",
+ """
+; Created by cloud-init automatically, do not edit.
+;
+nameserver 172.19.0.12
+search example3.com example1.com example2.com
+""".lstrip(),
+ ),
+ (
+ "etc/NetworkManager/conf.d/99-cloud-init.conf",
+ """
+# Created by cloud-init automatically, do not edit.
+#
+[main]
+dns = none
+""".lstrip(),
+ ),
+ (
+ "etc/udev/rules.d/85-persistent-net-cloud-init.rules",
+ "".join(
+ [
+ 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
+ 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n',
+ ]
+ ),
+ ),
+ ],
+ "out_sysconfig_rhel": [
+ (
+ "etc/sysconfig/network-scripts/ifcfg-eth0",
+ """
+# Created by cloud-init automatically, do not edit.
+#
+AUTOCONNECT_PRIORITY=120
+BOOTPROTO=none
+DEFROUTE=yes
+DEVICE=eth0
+DNS1=172.19.0.12
+DOMAIN=example3.com
+GATEWAY=172.19.3.254
+HWADDR=fa:16:3e:ed:9a:59
+IPADDR=172.19.1.34
+NETMASK=255.255.252.0
+ONBOOT=yes
+TYPE=Ethernet
+USERCTL=no
+""".lstrip(),
+ ),
+ (
+ "etc/resolv.conf",
+ """
+; Created by cloud-init automatically, do not edit.
+;
+nameserver 172.19.0.12
+search example3.com example1.com example2.com
""".lstrip(),
),
(
@@ -647,6 +820,7 @@ may-fail=false
address1=172.19.1.34/22
route1=0.0.0.0/0,172.19.3.254
dns=172.19.0.12;
+dns-search=example3.com;
""".lstrip(),
),
@@ -654,7 +828,13 @@ dns=172.19.0.12;
},
{
"in_data": {
- "services": [{"type": "dns", "address": "172.19.0.12"}],
+ "services": [
+ {
+ "type": "dns",
+ "address": "172.19.0.12",
+ "search": "example.com",
+ }
+ ],
"networks": [
{
"network_id": "public-ipv4",
@@ -715,6 +895,7 @@ STARTMODE=auto
; Created by cloud-init automatically, do not edit.
;
nameserver 172.19.0.12
+search example.com
""".lstrip(),
),
(
@@ -763,6 +944,7 @@ USERCTL=no
; Created by cloud-init automatically, do not edit.
;
nameserver 172.19.0.12
+search example.com
""".lstrip(),
),
(
--
2.39.3

View File

@ -0,0 +1,45 @@
From 6a61ce0f0cde11551bfe92835d0b33c7b1022b68 Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Thu, 18 Apr 2024 20:27:27 -0500
Subject: [PATCH] fix: Add subnet ipv4/ipv6 to network schema (#5191)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 109: fix: Add subnet ipv4/ipv6 to network schema (#5191)
RH-Jira: RHEL-54686
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Cathy Avery <cavery@redhat.com>
RH-Commit: [1/1] 83692fac8f9af1831970091bdf7c43d0e59f314c (anisinha/cloud-init)
These are used by our openstack network_data.json parsing code and
get used by the sysconfig renderer.
Fixes GH-4911
(cherry picked from commit 0b1ca174095e3ad685e6d6649bb08aafb19a95b9)
Signed-off-by: Ani Sinha <anisinha@redhat.com>
---
cloudinit/config/schemas/schema-network-config-v1.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/cloudinit/config/schemas/schema-network-config-v1.json b/cloudinit/config/schemas/schema-network-config-v1.json
index 64c492a4..f485c784 100644
--- a/cloudinit/config/schemas/schema-network-config-v1.json
+++ b/cloudinit/config/schemas/schema-network-config-v1.json
@@ -523,6 +523,14 @@
"items": {
"$ref": "#/$defs/anyOf_type_route"
}
+ },
+ "ipv4": {
+ "type": "boolean",
+ "description": "Indicate if the subnet is IPv4. If not specified, it will be inferred from the subnet type or address. This exists for compatibility with OpenStack's ``network_data.json`` when rendered through sysconfig."
+ },
+ "ipv6": {
+ "type": "boolean",
+ "description": "Indicate if the subnet is IPv6. If not specified, it will be inferred from the subnet type or address. This is exists for compatibility with OpenStack's ``network_data.json`` when rendered through sysconfig."
}
}
},
--
2.39.3

View File

@ -0,0 +1,73 @@
From 8ead44cb39f7726a695aa21a34820f6d40270829 Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Mon, 12 Feb 2024 14:48:01 -0600
Subject: [PATCH 5/6] fix: Address TIOBE abstract interpretation issues (#4866)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 92: Update pylint version to support python 3.12
RH-Jira: RHEL-44598
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/3] 3ca11206fa159ab45b2db21e78c4cfaf358b1e01 (anisinha/cloud-init)
These involve operations on possibly null variables or impossible logic.
(cherry picked from commit 5e7ef1032a12267a9a518358fbf89da0a88ddb99)
---
cloudinit/config/cc_lxd.py | 2 +-
cloudinit/distros/parsers/ifconfig.py | 6 ++++++
cloudinit/util.py | 1 +
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/cloudinit/config/cc_lxd.py b/cloudinit/config/cc_lxd.py
index cb9fc4f3..9f267b4c 100644
--- a/cloudinit/config/cc_lxd.py
+++ b/cloudinit/config/cc_lxd.py
@@ -432,7 +432,7 @@ def bridge_to_cmd(bridge_cfg):
% (bridge_cfg.get("ipv6_address"), bridge_cfg.get("ipv6_netmask"))
)
- if bridge_cfg.get("ipv6_nat", "false") == "true":
+ if bridge_cfg.get("ipv6_nat") == "true":
cmd_create.append("ipv6.nat=true")
else:
diff --git a/cloudinit/distros/parsers/ifconfig.py b/cloudinit/distros/parsers/ifconfig.py
index 516b5eb5..d671df1f 100644
--- a/cloudinit/distros/parsers/ifconfig.py
+++ b/cloudinit/distros/parsers/ifconfig.py
@@ -102,6 +102,7 @@ class Ifconfig:
"""
ifindex = 0
ifs_by_mac = defaultdict(list)
+ dev = None
for line in text.splitlines():
if len(line) == 0:
continue
@@ -119,6 +120,11 @@ class Ifconfig:
dev.index = ifindex
self._ifs_by_name[curif] = dev
+ if not dev:
+ # This shouldn't happen with normal ifconfig output, but
+ # if it does, ensure we don't Traceback
+ continue
+
toks = line.lower().strip().split()
if len(toks) > 1 and toks[1].startswith("flags="):
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 3295735c..5f787c5c 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -1417,6 +1417,7 @@ def find_devs_with_netbsd(
devlist = []
label = None
_type = None
+ mscdlabel_out = ""
if criteria:
if criteria.startswith("LABEL="):
label = criteria.lstrip("LABEL=")
--
2.39.3

View File

@ -0,0 +1,66 @@
From 62cec1e38e117fe6b24888862576ac57be14bbda Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Tue, 26 Mar 2024 15:55:50 -0500
Subject: [PATCH] fix: Always use single datasource if specified (#5098)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 82: fix: Always use single datasource if specified (#5098)
RH-Jira: RHEL-36255
RH-Acked-by: Cathy Avery <cavery@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] 068e97fcc18dd99f1112a9109acdb30fe2880f6e (anisinha/cloud-init)
This change may require a user to add `None` to the `datasource_list`
defined in `/etc/cloud/cloud.cfg[.d]` if they have a customized
datasource_list and want the DataSourceNone fallback behavior.
ds-identify would automatically append "None" to the datasource_list
if a single entry was provided in /etc/cloud/cloud.cfg[.d].
This wasn't a problem in the past as the python code would detect
a single datasource along with None as an indication to automatically
use that datasource. Since the python code no longer does that,
we should ensure that one specified datasource results in one specified
datasource after ds-identify has run.
Fixes GH-5091
(cherry picked from commit cdbbd17ae400e432d13f674c18a6f5c873fa328b)
Signed-off-by: Ani Sinha <anisinha@redhat.com>
---
tests/unittests/test_ds_identify.py | 2 +-
tools/ds-identify | 6 +++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
index ba0bf779..acbf3f03 100644
--- a/tests/unittests/test_ds_identify.py
+++ b/tests/unittests/test_ds_identify.py
@@ -522,7 +522,7 @@ class TestDsIdentify(DsIdentifyBase):
mydata = copy.deepcopy(VALID_CFG["Ec2-hvm"])
cfgpath = "etc/cloud/cloud.cfg.d/myds.cfg"
mydata["files"][cfgpath] = 'datasource_list: ["NoCloud"]\n'
- self._check_via_dict(mydata, rc=RC_FOUND, dslist=["NoCloud", DS_NONE])
+ self._check_via_dict(mydata, rc=RC_FOUND, dslist=["NoCloud"])
def test_configured_list_with_none(self):
"""When datasource_list already contains None, None is not added.
diff --git a/tools/ds-identify b/tools/ds-identify
index ec2cc18a..6e49ded3 100755
--- a/tools/ds-identify
+++ b/tools/ds-identify
@@ -1865,7 +1865,11 @@ _main() {
# if there is only a single entry in $DI_DSLIST
if [ $# -eq 1 ] || [ $# -eq 2 -a "$2" = "None" ] ; then
debug 1 "single entry in datasource_list ($DI_DSLIST) use that."
- found "$@"
+ if [ $# -eq 1 ]; then
+ write_result "datasource_list: [ $1 ]"
+ else
+ found "$@"
+ fi
return
fi
--
2.39.3

View File

@ -0,0 +1,246 @@
From 914ac26ebd889b1f5cbb13d55fc011e92fc213c6 Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Thu, 18 Jul 2024 09:04:54 -0400
Subject: [PATCH 1/2] fix: Clean cache if no datasource fallback (#5499)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 103: fix: Clean cache if no datasource fallback (#5499)
RH-Jira: RHEL-49736
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Commit: [1/1] 37eacd97f5e60fae2f71d401c528d508d3db517e (anisinha/cloud-init)
9929a00 added the ability to used a cached datasource when none is
found. This was supposed to be per-datasource, but the lack of cache
cleaning got applied universally. This commit makes it so cache will be
cleaned as it was before if fallback isn't implemented in datasource.
Fixes GH-5486
(cherry picked from commit 550c685c98551f65c30832b186fe091721b48477)
Signed-off-by: Ani Sinha <anisinha@redhat.com>
---
cloudinit/stages.py | 1 +
.../assets/DataSourceNoCacheNetworkOnly.py | 23 ++++
.../assets/DataSourceNoCacheWithFallback.py | 29 +++++
.../datasources/test_caching.py | 115 ++++++++++++++++++
tests/integration_tests/instances.py | 4 +-
5 files changed, 171 insertions(+), 1 deletion(-)
create mode 100644 tests/integration_tests/assets/DataSourceNoCacheNetworkOnly.py
create mode 100644 tests/integration_tests/assets/DataSourceNoCacheWithFallback.py
create mode 100644 tests/integration_tests/datasources/test_caching.py
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index 0b795624..ace94c9a 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -378,6 +378,7 @@ class Init:
ds,
)
else:
+ util.del_file(self.paths.instance_link)
raise e
self.datasource = ds
# Ensure we adjust our path members datasource
diff --git a/tests/integration_tests/assets/DataSourceNoCacheNetworkOnly.py b/tests/integration_tests/assets/DataSourceNoCacheNetworkOnly.py
new file mode 100644
index 00000000..54a7bab3
--- /dev/null
+++ b/tests/integration_tests/assets/DataSourceNoCacheNetworkOnly.py
@@ -0,0 +1,23 @@
+import logging
+
+from cloudinit import sources
+
+LOG = logging.getLogger(__name__)
+
+
+class DataSourceNoCacheNetworkOnly(sources.DataSource):
+ def _get_data(self):
+ LOG.debug("TEST _get_data called")
+ return True
+
+
+datasources = [
+ (
+ DataSourceNoCacheNetworkOnly,
+ (sources.DEP_FILESYSTEM, sources.DEP_NETWORK),
+ ),
+]
+
+
+def get_datasource_list(depends):
+ return sources.list_from_depends(depends, datasources)
diff --git a/tests/integration_tests/assets/DataSourceNoCacheWithFallback.py b/tests/integration_tests/assets/DataSourceNoCacheWithFallback.py
new file mode 100644
index 00000000..fdfc473f
--- /dev/null
+++ b/tests/integration_tests/assets/DataSourceNoCacheWithFallback.py
@@ -0,0 +1,29 @@
+import logging
+import os
+
+from cloudinit import sources
+
+LOG = logging.getLogger(__name__)
+
+
+class DataSourceNoCacheWithFallback(sources.DataSource):
+ def _get_data(self):
+ if os.path.exists("/ci-test-firstboot"):
+ LOG.debug("TEST _get_data called")
+ return True
+ return False
+
+ def check_if_fallback_is_allowed(self):
+ return True
+
+
+datasources = [
+ (
+ DataSourceNoCacheWithFallback,
+ (sources.DEP_FILESYSTEM,),
+ ),
+]
+
+
+def get_datasource_list(depends):
+ return sources.list_from_depends(depends, datasources)
diff --git a/tests/integration_tests/datasources/test_caching.py b/tests/integration_tests/datasources/test_caching.py
new file mode 100644
index 00000000..33e4b671
--- /dev/null
+++ b/tests/integration_tests/datasources/test_caching.py
@@ -0,0 +1,115 @@
+import pytest
+
+from tests.integration_tests import releases, util
+from tests.integration_tests.instances import IntegrationInstance
+
+
+def setup_custom_datasource(client: IntegrationInstance, datasource_name: str):
+ client.write_to_file(
+ "/etc/cloud/cloud.cfg.d/99-imds.cfg",
+ f"datasource_list: [ {datasource_name}, None ]\n"
+ "datasource_pkg_list: [ cisources ]",
+ )
+ assert client.execute(
+ "mkdir -p /usr/lib/python3/dist-packages/cisources"
+ )
+ client.push_file(
+ util.ASSETS_DIR / f"DataSource{datasource_name}.py",
+ "/usr/lib/python3/dist-packages/cisources/"
+ f"DataSource{datasource_name}.py",
+ )
+
+
+def verify_no_cache_boot(client: IntegrationInstance):
+ log = client.read_from_file("/var/log/cloud-init.log")
+ util.verify_ordered_items_in_text(
+ [
+ "No local datasource found",
+ "running 'init'",
+ "no cache found",
+ "Detected platform",
+ "TEST _get_data called",
+ ],
+ text=log,
+ )
+ util.verify_clean_boot(client)
+
+
+@pytest.mark.skipif(
+ not releases.IS_UBUNTU,
+ reason="hardcoded dist-packages directory",
+)
+def test_no_cache_network_only(client: IntegrationInstance):
+ """Test cache removal per boot. GH-5486
+
+ This tests the CloudStack password reset use case. The expectation is:
+ - Metadata is fetched in network timeframe only
+ - Because `check_instance_id` is not defined, no cached datasource
+ is found in the init-local phase, but the cache is used in the
+ remaining phases due to existance of /run/cloud-init/.instance-id
+ - Because `check_if_fallback_is_allowed` is not defined, cloud-init
+ does NOT fall back to the pickled datasource, and will
+ instead delete the cache during the init-local phase
+ - Metadata is therefore fetched every boot in the network phase
+ """
+ setup_custom_datasource(client, "NoCacheNetworkOnly")
+
+ # Run cloud-init as if first boot
+ assert client.execute("cloud-init clean --logs")
+ client.restart()
+
+ verify_no_cache_boot(client)
+
+ # Clear the log without clean and run cloud-init for subsequent boot
+ assert client.execute("echo '' > /var/log/cloud-init.log")
+ client.restart()
+
+ verify_no_cache_boot(client)
+
+
+@pytest.mark.skipif(
+ not releases.IS_UBUNTU,
+ reason="hardcoded dist-packages directory",
+)
+def test_no_cache_with_fallback(client: IntegrationInstance):
+ """Test we use fallback when defined and no cache available."""
+ setup_custom_datasource(client, "NoCacheWithFallback")
+
+ # Run cloud-init as if first boot
+ assert client.execute("cloud-init clean --logs")
+ # Used by custom datasource
+ client.execute("touch /ci-test-firstboot")
+ client.restart()
+
+ log = client.read_from_file("/var/log/cloud-init.log")
+ util.verify_ordered_items_in_text(
+ [
+ "no cache found",
+ "Detected platform",
+ "TEST _get_data called",
+ "running 'init'",
+ "restored from cache with run check",
+ "running 'modules:config'",
+ ],
+ text=log,
+ )
+ util.verify_clean_boot(client)
+
+ # Clear the log without clean and run cloud-init for subsequent boot
+ assert client.execute("echo '' > /var/log/cloud-init.log")
+ client.execute("rm /ci-test-firstboot")
+ client.restart()
+
+ log = client.read_from_file("/var/log/cloud-init.log")
+ util.verify_ordered_items_in_text(
+ [
+ "cache invalid in datasource",
+ "Detected platform",
+ "Restored fallback datasource from checked cache",
+ "running 'init'",
+ "restored from cache with run check",
+ "running 'modules:config'",
+ ],
+ text=log,
+ )
+ util.verify_clean_boot(client)
diff --git a/tests/integration_tests/instances.py b/tests/integration_tests/instances.py
index 3fc6558a..23c0dc98 100644
--- a/tests/integration_tests/instances.py
+++ b/tests/integration_tests/instances.py
@@ -88,7 +88,9 @@ class IntegrationInstance:
# First push to a temporary directory because of permissions issues
tmp_path = _get_tmp_path()
self.instance.push_file(str(local_path), tmp_path)
- assert self.execute("mv {} {}".format(tmp_path, str(remote_path))).ok
+ assert self.execute(
+ "mv {} {}".format(tmp_path, str(remote_path))
+ ), f"Failed to push {tmp_path} to {remote_path}"
def read_from_file(self, remote_path) -> str:
result = self.execute("cat {}".format(remote_path))
--
2.39.3

View File

@ -0,0 +1,391 @@
From aaf1d063f198ce09f0d539a85e1a1a2bb834520b Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Tue, 2 Jan 2024 11:29:17 -0600
Subject: [PATCH 1/3] fix: Correct v2 NetworkManager route rendering (#4637)
RH-Author: Cathy Avery <cavery@redhat.com>
RH-MergeRequest: 72: Fixes for cloud-init fails to configure DNS/search domains for network-config v1
RH-Jira: RHEL-20964
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Commit: [1/2] fb865987dbcf506a674eb9798f9c06859539a696 (cavery/cloud-init-c-9-s)
fix: Correct v2 NetworkManager route rendering
Because network v2 route defintions can have mixed v4 and v6 routes, we
need to determine the IP family per route rather than per subnet.
Similar, ensure dns-search is rendered correctly.
Fixes GH-4518
(cherry picked from commit c2c100e8c9fd8709539b3ab2b0ee34c66ba3f2f7)
Signed-off-by: Cathy Avery <cavery@redhat.com>
---
cloudinit/net/__init__.py | 2 +
cloudinit/net/network_manager.py | 87 +++++++++-------
tests/unittests/test_net.py | 165 ++++++++++++++++++++++++++++++-
3 files changed, 219 insertions(+), 35 deletions(-)
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
index c0888f52..65e7ff33 100644
--- a/cloudinit/net/__init__.py
+++ b/cloudinit/net/__init__.py
@@ -1287,6 +1287,8 @@ def subnet_is_ipv6(subnet) -> bool:
"""Common helper for checking network_state subnets for ipv6."""
# 'static6', 'dhcp6', 'ipv6_dhcpv6-stateful', 'ipv6_dhcpv6-stateless' or
# 'ipv6_slaac'
+ # This function is inappropriate for v2-based routes as routes defined
+ # under v2 subnets can contain ipv4 and ipv6 simultaneously
if subnet["type"].endswith("6") or subnet["type"] in IPV6_DYNAMIC_TYPES:
# This is a request either static6 type or DHCPv6.
return True
diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py
index 76a0ac15..bd6e6d75 100644
--- a/cloudinit/net/network_manager.py
+++ b/cloudinit/net/network_manager.py
@@ -12,10 +12,15 @@ import itertools
import logging
import os
import uuid
-from typing import Optional
+from typing import List, Optional
from cloudinit import subp, util
-from cloudinit.net import is_ipv6_address, renderer, subnet_is_ipv6
+from cloudinit.net import (
+ is_ipv6_address,
+ is_ipv6_network,
+ renderer,
+ subnet_is_ipv6,
+)
from cloudinit.net.network_state import NetworkState
from cloudinit.net.sysconfig import available_nm_ifcfg_rh
@@ -158,11 +163,11 @@ class NMConnection:
if self.config[family]["method"] == "auto" and method == "manual":
return
- if (
- subnet_type == "ipv6_dhcpv6-stateful"
- or subnet_type == "ipv6_dhcpv6-stateless"
- or subnet_type == "ipv6_slaac"
- ):
+ if subnet_type in [
+ "ipv6_dhcpv6-stateful",
+ "ipv6_dhcpv6-stateless",
+ "ipv6_slaac",
+ ]:
# set ipv4 method to 'disabled' to align with sysconfig renderer.
self._set_default("ipv4", "method", "disabled")
@@ -174,7 +179,8 @@ class NMConnection:
Adds a numbered property, such as address<n> or route<n>, ensuring
the appropriate value gets used for <n>.
"""
-
+ if not self.config.has_section(section):
+ self.config[section] = {}
for index in itertools.count(1):
key = f"{key_prefix}{index}"
if not self.config.has_option(section, key):
@@ -189,40 +195,37 @@ class NMConnection:
value = subnet["address"] + "/" + str(subnet["prefix"])
self._add_numbered(family, "address", value)
- def _add_route(self, family, route):
- """
- Adds a ipv[46].route<n> property.
- """
-
+ def _add_route(self, route):
+ """Adds a ipv[46].route<n> property."""
+ # Because network v2 route definitions can have mixed v4 and v6
+ # routes, determine the family per route based on the gateway
+ family = "ipv6" if is_ipv6_network(route["gateway"]) else "ipv4"
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):
+ def _add_nameserver(self, dns: str) -> None:
"""
Extends the ipv[46].dns property with a name server.
"""
-
- # FIXME: the subnet contains IPv4 and IPv6 name server mixed
- # together. We might be getting an IPv6 name server while
- # we're dealing with an IPv4 subnet. Sort this out by figuring
- # out the correct family and making sure a valid section exist.
family = "ipv6" if is_ipv6_address(dns) else "ipv4"
- self._set_default(family, "method", "disabled")
-
- self._set_default(family, "dns", "")
- self.config[family]["dns"] = self.config[family]["dns"] + dns + ";"
+ if self.config.has_section(family):
+ self._set_default(family, "dns", "")
+ self.config[family]["dns"] = self.config[family]["dns"] + dns + ";"
- def _add_dns_search(self, family, dns_search):
+ def _add_dns_search(self, dns_search: List[str]) -> None:
"""
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) + ";"
- )
+ for family in ["ipv4", "ipv6"]:
+ if self.config.has_section(family):
+ self._set_default(family, "dns-search", "")
+ self.config[family]["dns-search"] = (
+ self.config[family]["dns-search"]
+ + ";".join(dns_search)
+ + ";"
+ )
def con_uuid(self):
"""
@@ -304,8 +307,11 @@ class NMConnection:
device_mtu = iface["mtu"]
ipv4_mtu = None
+ found_nameservers = []
+ found_dns_search = []
# Deal with Layer 3 configuration
+ use_top_level_dns = "dns" in iface
for subnet in iface["subnets"]:
family = "ipv6" if subnet_is_ipv6(subnet) else "ipv4"
@@ -315,15 +321,28 @@ class NMConnection:
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:
+ self._add_route(route)
+ if not use_top_level_dns and "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"])
+ found_nameservers.append(nameserver)
+ if not use_top_level_dns and "dns_search" in subnet:
+ found_dns_search.append(subnet["dns_search"])
if family == "ipv4" and "mtu" in subnet:
ipv4_mtu = subnet["mtu"]
+ # Now add our DNS search domains. We add them later because we
+ # only want them if an IP family has already been defined
+ if use_top_level_dns:
+ for nameserver in iface["dns"]["nameservers"]:
+ self._add_nameserver(nameserver)
+ if iface["dns"]["search"]:
+ self._add_dns_search(iface["dns"]["search"])
+ else:
+ for nameserver in found_nameservers:
+ self._add_nameserver(nameserver)
+ for dns_search in found_dns_search:
+ self._add_dns_search(dns_search)
+
# we do not want to set may-fail to false for both ipv4 and ipv6 dhcp
# at the at the same time. This will make the network configuration
# work only when both ipv4 and ipv6 dhcp succeeds. This may not be
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index d9ef493b..2a99f150 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -2962,9 +2962,9 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
may-fail=false
address1=192.168.0.2/24
gateway=192.168.0.1
+ address2=192.168.2.10/24
dns=192.168.0.10;10.23.23.134;
dns-search=barley.maas;sacchromyces.maas;brettanomyces.maas;
- address2=192.168.2.10/24
"""
),
@@ -4154,6 +4154,148 @@ iface bond0 inet6 static
"""
),
},
+ "v2-mixed-routes": {
+ "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
+ autoconnect-priority=120
+ type=ethernet
+ interface-name=eth0
+
+ [user]
+ org.freedesktop.NetworkManager.origin=cloud-init
+
+ [ethernet]
+
+ [ipv4]
+ method=auto
+ may-fail=true
+ route1=169.254.42.42/32,62.210.0.1
+ route2=169.254.42.43/32,62.210.0.2
+ address1=192.168.1.20/16
+ dns=8.8.8.8;
+ dns-search=lab;home;
+
+ [ipv6]
+ route1=::/0,fe80::dc00:ff:fe20:186
+ route2=fe80::dc00:ff:fe20:188/64,fe80::dc00:ff:fe20:187
+ method=auto
+ may-fail=true
+ address1=2001:bc8:1210:232:dc00:ff:fe20:185/64
+ dns=FEDC::1;
+ dns-search=lab;home;
+
+ """
+ )
+ },
+ "yaml": textwrap.dedent(
+ """\
+ version: 2
+ ethernets:
+ eth0:
+ dhcp4: true
+ dhcp6: true
+ nameservers:
+ search: [lab, home]
+ addresses: [8.8.8.8, "FEDC::1"]
+ routes:
+ - to: 169.254.42.42/32
+ via: 62.210.0.1
+ - via: fe80::dc00:ff:fe20:186
+ to: ::/0
+ - to: 169.254.42.43/32
+ via: 62.210.0.2
+ - via: fe80::dc00:ff:fe20:187
+ to: fe80::dc00:ff:fe20:188
+ addresses:
+ - 192.168.1.20/16
+ - 2001:bc8:1210:232:dc00:ff:fe20:185/64
+ """
+ ),
+ },
+ "v2-dns-no-if-ips": {
+ "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
+ autoconnect-priority=120
+ type=ethernet
+ interface-name=eth0
+
+ [user]
+ org.freedesktop.NetworkManager.origin=cloud-init
+
+ [ethernet]
+
+ [ipv4]
+ method=auto
+ may-fail=true
+ dns=8.8.8.8;
+ dns-search=lab;home;
+
+ [ipv6]
+ method=auto
+ may-fail=true
+ dns=FEDC::1;
+ dns-search=lab;home;
+
+ """
+ )
+ },
+ "yaml": textwrap.dedent(
+ """\
+ version: 2
+ ethernets:
+ eth0:
+ dhcp4: true
+ dhcp6: true
+ nameservers:
+ search: [lab, home]
+ addresses: [8.8.8.8, "FEDC::1"]
+ """
+ ),
+ },
+ "v2-dns-no-dhcp": {
+ "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
+ autoconnect-priority=120
+ type=ethernet
+ interface-name=eth0
+
+ [user]
+ org.freedesktop.NetworkManager.origin=cloud-init
+
+ [ethernet]
+
+ """
+ )
+ },
+ "yaml": textwrap.dedent(
+ """\
+ version: 2
+ ethernets:
+ eth0:
+ nameservers:
+ search: [lab, home]
+ addresses: [8.8.8.8, "FEDC::1"]
+ """
+ ),
+ },
}
@@ -6267,6 +6409,27 @@ class TestNetworkManagerRendering(CiTestCase):
entry[self.expected_name], self.expected_conf_d, found
)
+ def test_v2_mixed_routes(self):
+ entry = NETWORK_CONFIGS["v2-mixed-routes"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+ self._compare_files_to_expected(
+ entry[self.expected_name], self.expected_conf_d, found
+ )
+
+ def test_v2_dns_no_ips(self):
+ entry = NETWORK_CONFIGS["v2-dns-no-if-ips"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+ self._compare_files_to_expected(
+ entry[self.expected_name], self.expected_conf_d, found
+ )
+
+ def test_v2_dns_no_dhcp(self):
+ entry = NETWORK_CONFIGS["v2-dns-no-dhcp"]
+ found = self._render_and_read(network_config=yaml.load(entry["yaml"]))
+ self._compare_files_to_expected(
+ entry[self.expected_name], self.expected_conf_d, found
+ )
+
@mock.patch(
"cloudinit.net.is_openvswitch_internal_interface",
--
2.39.3

View File

@ -0,0 +1,156 @@
From cf35040b46abb66c7239d156bd92c7267d7c40f7 Mon Sep 17 00:00:00 2001
From: PengpengSun <40026211+PengpengSun@users.noreply.github.com>
Date: Fri, 29 Mar 2024 22:39:13 +0800
Subject: [PATCH] fix: Fall back to cached local ds if no valid ds found
(#4997)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 75: fix: Fall back to cached local ds if no valid ds found (#4997)
RH-Jira: RHEL-32846
RH-Acked-by: Cathy Avery <cavery@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] 408c41fd8009255d98c31210ef936f2e68dfde75 (anisinha/cloud-init)
Rebooting an instance which has finished VMware guest
customization with DataSourceVMware will load
DataSourceNone due to metadata is NOT available.
This is mostly a re-post of PR#229, few differences are:
1. Let ds decide if fallback is allowed, not always fall back
to previous cached LOCAL ds.
2. No comparing instance-id of cached ds with previous instance-id
due to I think they are always identical.
Fixes GH-3402
(cherry picked from commit 9929a00580d50afc60bf4e0fb9f2f39d4f797b4b)
Signed-off-by: Ani Sinha <anisinha@redhat.com>
Conflicts:
cloudinit/sources/__init__.py
Conflicts because of changes in upstream source coming from
30d5e9a3358f4cbaced ("refactor: Use _unpickle rather than hasattr() in sources")
---
cloudinit/sources/DataSourceVMware.py | 14 +++++++++-
cloudinit/sources/__init__.py | 14 ++++++++++
cloudinit/stages.py | 40 +++++++++++++++++----------
3 files changed, 53 insertions(+), 15 deletions(-)
diff --git a/cloudinit/sources/DataSourceVMware.py b/cloudinit/sources/DataSourceVMware.py
index 1591121d..2d5d42eb 100644
--- a/cloudinit/sources/DataSourceVMware.py
+++ b/cloudinit/sources/DataSourceVMware.py
@@ -197,7 +197,7 @@ class DataSourceVMware(sources.DataSource):
break
if not self.data_access_method:
- LOG.error("failed to find a valid data access method")
+ LOG.debug("failed to find a valid data access method")
return False
LOG.info("using data access method %s", self._get_subplatform())
@@ -291,6 +291,18 @@ class DataSourceVMware(sources.DataSource):
self.metadata["instance-id"] = str(id_file.read()).rstrip().lower()
return self.metadata["instance-id"]
+ def check_if_fallback_is_allowed(self):
+ if (
+ self.data_access_method
+ and self.data_access_method == DATA_ACCESS_METHOD_IMC
+ and is_vmware_platform()
+ ):
+ LOG.debug(
+ "Cache fallback is allowed for : %s", self._get_subplatform()
+ )
+ return True
+ return False
+
def get_public_ssh_keys(self):
for key_name in (
"public-keys-data",
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py
index c207b5ed..453801be 100644
--- a/cloudinit/sources/__init__.py
+++ b/cloudinit/sources/__init__.py
@@ -312,6 +312,10 @@ class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta):
self.vendordata2_raw = None
if not hasattr(self, "skip_hotplug_detect"):
self.skip_hotplug_detect = False
+
+ if not hasattr(self, "check_if_fallback_is_allowed"):
+ setattr(self, "check_if_fallback_is_allowed", lambda: False)
+
if hasattr(self, "userdata") and self.userdata is not None:
# If userdata stores MIME data, on < python3.6 it will be
# missing the 'policy' attribute that exists on >=python3.6.
@@ -914,6 +918,16 @@ class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta):
# quickly (local check only) if self.instance_id is still
return False
+ def check_if_fallback_is_allowed(self):
+ """check_if_fallback_is_allowed()
+ Checks if a cached ds is allowed to be restored when no valid ds is
+ found in local mode by checking instance-id and searching valid data
+ through ds list.
+
+ @return True if a ds allows fallback, False otherwise.
+ """
+ return False
+
@staticmethod
def _determine_dsmode(candidates, default=None, valid=None):
# return the first candidate that is non None, warn if not valid
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index 3b6405f5..0b795624 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -353,20 +353,32 @@ class Init:
LOG.debug(myrep.description)
if not ds:
- util.del_file(self.paths.instance_link)
- (cfg_list, pkg_list) = self._get_datasources()
- # Deep copy so that user-data handlers can not modify
- # (which will affect user-data handlers down the line...)
- (ds, dsname) = sources.find_source(
- self.cfg,
- self.distro,
- self.paths,
- copy.deepcopy(self.ds_deps),
- cfg_list,
- pkg_list,
- self.reporter,
- )
- LOG.info("Loaded datasource %s - %s", dsname, ds)
+ try:
+ cfg_list, pkg_list = self._get_datasources()
+ # Deep copy so that user-data handlers can not modify
+ # (which will affect user-data handlers down the line...)
+ ds, dsname = sources.find_source(
+ self.cfg,
+ self.distro,
+ self.paths,
+ copy.deepcopy(self.ds_deps),
+ cfg_list,
+ pkg_list,
+ self.reporter,
+ )
+ util.del_file(self.paths.instance_link)
+ LOG.info("Loaded datasource %s - %s", dsname, ds)
+ except sources.DataSourceNotFoundException as e:
+ if existing != "check":
+ raise e
+ ds = self._restore_from_cache()
+ if ds and ds.check_if_fallback_is_allowed():
+ LOG.info(
+ "Restored fallback datasource from checked cache: %s",
+ ds,
+ )
+ else:
+ raise e
self.datasource = ds
# Ensure we adjust our path members datasource
# now that we have one (thus allowing ipath to be used)
--
2.39.3

View File

@ -0,0 +1,42 @@
From 332bb23bcfde801edf792e6c629ec350be07b952 Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Tue, 19 Mar 2024 14:24:11 -0500
Subject: [PATCH 3/3] fix: Undeprecate 'network' in schema route definition
(#5072)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 73: fix: Undeprecate 'network' in schema route definition (#5072)
RH-Jira: RHEL-29709
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Cathy Avery <cavery@redhat.com>
RH-Commit: [1/1] 61c660be43fd25999bca0cfd66d7b2150fee5a14 (anisinha/cloud-init)
It is passed through to our v1 schema from OpenStack network_data.json
Fixes GH-5051
(cherry picked from commit ff40d1af8a6de3ee27937382ec4ceea931d80a88)
Signed-off-by: Ani Sinha <anisinha@redhat.com>
---
cloudinit/config/schemas/schema-network-config-v1.json | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/cloudinit/config/schemas/schema-network-config-v1.json b/cloudinit/config/schemas/schema-network-config-v1.json
index 56dc27c9..64c492a4 100644
--- a/cloudinit/config/schemas/schema-network-config-v1.json
+++ b/cloudinit/config/schemas/schema-network-config-v1.json
@@ -445,10 +445,7 @@
},
"network": {
"type": "string",
- "description": "IPv4 network address with CIDR netmask notation or IPv6 with prefix length. Alias for ``destination`` and only read when ``destination`` key is absent.",
- "deprecated": true,
- "deprecated_version": "23.3",
- "deprecated_description": "Use ``destination`` instead."
+ "description": "IPv4 network address with CIDR netmask notation or IPv6 with prefix length. Alias for ``destination`` and only read when ``destination`` key is absent. This exists for OpenStack support. OpenStack route definitions are passed through to v1 config and OpenStack's ``network_data.json`` uses ``network`` instead of ``destination``."
},
"destination": {
"type": "string",
--
2.39.3

View File

@ -0,0 +1,66 @@
From ed3c05af60c0d50a4576a63c8638e148e58ebf06 Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
Date: Thu, 11 Jul 2024 00:49:58 +0530
Subject: [PATCH] fix: add schema rules for 'baseurl' and 'metalink' in yum
repo config (#5501)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 101: fix: add schema rules for 'baseurl' and 'metalink' in yum repo config (#5501)
RH-Jira: RHEL-46873
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: xiachen <xiachen@redhat.com>
RH-Commit: [1/1] df01c93fde517e66ce71a66f80ee54d3ed504906 (anisinha/cloud-init)
At least one of (or both) 'baseurl' or 'metalink' should be provided for yum
repository specification. Add schema changes to enforce it. Without this,
with just 'metalink' property set, one would get the schema validator error
\---
Error: Cloud config schema errors: yum_repos.epel-release: 'baseurl' is a required property
\---
Signed-off-by: Ani Sinha <anisinha@redhat.com>
(cherry picked from commit 7d35664ef8b85840f92f18cc48187f7284d227bc)
---
.../config/schemas/schema-cloud-config-v1.json | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/cloudinit/config/schemas/schema-cloud-config-v1.json b/cloudinit/config/schemas/schema-cloud-config-v1.json
index 03e723e2..4fb7fd93 100644
--- a/cloudinit/config/schemas/schema-cloud-config-v1.json
+++ b/cloudinit/config/schemas/schema-cloud-config-v1.json
@@ -3442,6 +3442,11 @@
"format": "uri",
"description": "URL to the directory where the yum repository's 'repodata' directory lives"
},
+ "metalink": {
+ "type": "string",
+ "format": "uri",
+ "description": "Specifies a URL to a metalink file for the repomd.xml"
+ },
"name": {
"type": "string",
"description": "Optional human-readable name of the yum repo."
@@ -3469,8 +3474,17 @@
"description": "Any supported yum repository configuration options will be written to the yum repo config file. See: man yum.conf"
}
},
- "required": [
- "baseurl"
+ "anyOf": [
+ {
+ "required": [
+ "baseurl"
+ ]
+ },
+ {
+ "required": [
+ "metalink"
+ ]
+ }
]
}
}
--
2.39.3

View File

@ -0,0 +1,58 @@
From fcaff2e02a07af587d8366f61df1685435e32288 Mon Sep 17 00:00:00 2001
From: Brett Holman <brett.holman@canonical.com>
Date: Wed, 3 Jan 2024 09:11:40 -0700
Subject: [PATCH] fix(cloudstack): Use parsed lease file for virtual router in
cloudstack
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 85: fix(cloudstack): Use parsed lease file for virtual router in cloudstack
RH-Jira: RHEL-40217
RH-Acked-by: Cathy Avery <cavery@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] 9d1353620ee2c773170e424479bb2664116554f4 (anisinha/cloud-init)
Fixes 5942f4023e2581a
(cherry picked from commit cb36bf38b823f811a3e938ccffc03d7d13190095)
Signed-off-by: Ani Sinha <anisinha@redhat.com>
---
cloudinit/sources/DataSourceCloudStack.py | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/cloudinit/sources/DataSourceCloudStack.py b/cloudinit/sources/DataSourceCloudStack.py
index fd2482a3..f752765d 100644
--- a/cloudinit/sources/DataSourceCloudStack.py
+++ b/cloudinit/sources/DataSourceCloudStack.py
@@ -229,18 +229,18 @@ def get_vr_address():
)
return latest_address
- # Try dhcp lease files next...
+ # Try dhcp lease files next
lease_file = dhcp.IscDhclient.get_latest_lease()
- if not lease_file:
- LOG.debug("No lease file found, using default gateway")
- return get_default_gateway()
-
- lease_file = dhcp.IscDhclient.parse_dhcp_server_from_lease_file(lease_file)
- if not latest_address:
- # No virtual router found, fallback on default gateway
- LOG.debug("No DHCP found, using default gateway")
- return get_default_gateway()
- return latest_address
+ if lease_file:
+ latest_address = dhcp.IscDhclient.parse_dhcp_server_from_lease_file(
+ lease_file
+ )
+ if latest_address:
+ return latest_address
+
+ # No virtual router found, fallback to default gateway
+ LOG.debug("No DHCP found, using default gateway")
+ return get_default_gateway()
# Used to match classes to dependencies
--
2.39.3

View File

@ -0,0 +1,132 @@
From 2b74b0eb94edfd7caa42bc0d8affc37311ba041b Mon Sep 17 00:00:00 2001
From: Brett Holman <brett.holman@canonical.com>
Date: Wed, 3 Jan 2024 09:11:21 -0700
Subject: [PATCH 4/6] fix(dhcp): Guard against FileNotFoundError and NameError
exceptions
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 92: Update pylint version to support python 3.12
RH-Jira: RHEL-44598
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/3] 730b8de9ceb2c380d3b15573d83691ab95a1487e (anisinha/cloud-init)
(cherry picked from commit 53eb8555e091474803b724700815adc09aa84f05)
---
cloudinit/net/dhcp.py | 20 ++++++++++------
tests/unittests/net/test_dhcp.py | 40 ++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+), 7 deletions(-)
diff --git a/cloudinit/net/dhcp.py b/cloudinit/net/dhcp.py
index 07c13390..a0aee98c 100644
--- a/cloudinit/net/dhcp.py
+++ b/cloudinit/net/dhcp.py
@@ -5,15 +5,15 @@
# This file is part of cloud-init. See LICENSE file for license information.
import abc
-import contextlib
import glob
import logging
import os
import re
import signal
import time
+from contextlib import suppress
from io import StringIO
-from typing import Any, Dict, List
+from typing import Any, Dict, List, Optional
import configobj
@@ -268,7 +268,7 @@ class IscDhclient(DhcpClient):
# this function waits for these files to exist, clean previous runs
# to avoid false positive in wait_for_files
- with contextlib.suppress(FileNotFoundError):
+ with suppress(FileNotFoundError):
os.remove(pid_file)
os.remove(lease_file)
@@ -514,9 +514,15 @@ class IscDhclient(DhcpClient):
return latest_file
@staticmethod
- def parse_dhcp_server_from_lease_file(lease_file):
- with open(lease_file, "r") as fd:
- for line in fd:
+ def parse_dhcp_server_from_lease_file(lease_file) -> Optional[str]:
+ """Parse a lease file for the dhcp server address
+
+ @param lease_file: Name of a file to be parsed
+ @return: An address if found, or None
+ """
+ latest_address = None
+ with suppress(FileNotFoundError), open(lease_file, "r") as file:
+ for line in file:
if "dhcp-server-identifier" in line:
words = line.strip(" ;\r\n").split(" ")
if len(words) > 2:
@@ -561,7 +567,7 @@ class Udhcpc(DhcpClient):
tmp_dir = temp_utils.get_tmp_ancestor(needs_exe=True)
lease_file = os.path.join(tmp_dir, interface + ".lease.json")
- with contextlib.suppress(FileNotFoundError):
+ with suppress(FileNotFoundError):
os.remove(lease_file)
# udhcpc needs the interface up to send initial discovery packets
diff --git a/tests/unittests/net/test_dhcp.py b/tests/unittests/net/test_dhcp.py
index a7b62312..8ec96eef 100644
--- a/tests/unittests/net/test_dhcp.py
+++ b/tests/unittests/net/test_dhcp.py
@@ -32,6 +32,46 @@ LEASE_F = "/run/dhclient.lease"
DHCLIENT = "/sbin/dhclient"
+@pytest.mark.parametrize(
+ "server_address,lease_file_content",
+ (
+ pytest.param(None, None, id="no_server_addr_on_absent_lease_file"),
+ pytest.param(None, "", id="no_server_addr_on_empty_lease_file"),
+ pytest.param(
+ None,
+ "lease {\n fixed-address: 10.1.2.3;\n}\n",
+ id="no_server_addr_when_no_server_ident",
+ ),
+ pytest.param(
+ "10.4.5.6",
+ "lease {\n fixed-address: 10.1.2.3;\n"
+ " option dhcp-server-identifier 10.4.5.6;\n"
+ " option dhcp-renewal-time 1800;\n}\n",
+ id="server_addr_found_when_server_ident_present",
+ ),
+ ),
+)
+class TestParseDHCPServerFromLeaseFile:
+ def test_find_server_address_when_present(
+ self, server_address, lease_file_content, tmp_path
+ ):
+ """Test that we return None in the case of no file or file contains no
+ server address, otherwise return the address.
+ """
+ lease_file = tmp_path / "dhcp.leases"
+ if server_address:
+ if lease_file_content:
+ lease_file.write_text(lease_file_content)
+ assert (
+ server_address
+ == IscDhclient.parse_dhcp_server_from_lease_file(lease_file)
+ )
+ else:
+ assert not IscDhclient.parse_dhcp_server_from_lease_file(
+ lease_file
+ )
+
+
class TestParseDHCPLeasesFile(CiTestCase):
def test_parse_empty_lease_file_errors(self):
"""parse_dhcp_lease_file errors when file content is empty."""
--
2.39.3

View File

@ -0,0 +1,53 @@
From b7fddab36d805099639358736dab474d2924906b Mon Sep 17 00:00:00 2001
From: Brett Holman <brett.holman@canonical.com>
Date: Wed, 19 Jun 2024 17:07:56 -0600
Subject: [PATCH 2/6] fix(jsonschema): Add missing sudo definition (#5418)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 90: fix(jsonschema): Add missing sudo definition (#5418)
RH-Jira: RHEL-44337
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/2] 9e56c7ab35744c6530c8cef2f122ffdcc0480d29 (anisinha/cloud-init)
This configuration:
```
users:
- name: osadmin
lock_passwd: false
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
```
Is valid syntax but is missing from the jsonschema definition.
Fixes GH-5399
(cherry picked from commit b533fa51acb850ed754e2b1925e276ff8e5f3507)
---
cloudinit/config/schemas/schema-cloud-config-v1.json | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/cloudinit/config/schemas/schema-cloud-config-v1.json b/cloudinit/config/schemas/schema-cloud-config-v1.json
index a553c52c..8b10fe70 100644
--- a/cloudinit/config/schemas/schema-cloud-config-v1.json
+++ b/cloudinit/config/schemas/schema-cloud-config-v1.json
@@ -299,6 +299,15 @@
],
"description": "Sudo rule to use or false. Absence of a sudo value or ``null`` will result in no sudo rules added for this user."
},
+ {
+ "type": "array",
+ "items": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
{
"type": "boolean",
"changed": true,
--
2.39.3

View File

@ -0,0 +1,412 @@
From ce69cd178d9c05827db1ca1654de82dc3f9f521e Mon Sep 17 00:00:00 2001
From: Chad Smith <chad.smith@canonical.com>
Date: Thu, 27 Jun 2024 18:12:31 -0600
Subject: [PATCH 3/3] fix(schema): permit deprecated hyphenated keys under
users key (#5456)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 95: Deprecate the users ssh-authorized-keys property (#5162)
RH-Jira: RHEL-45262
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [3/3] 76804599a9166796dc52bab2031a706993ad2e3c (anisinha/cloud-init)
Both hyphenated and underscore delimited key names are permitted
by cloudinit/distros/ug_util.py#L114 due to magic replacement
of key names.
Since this is still valid json schema, add the necessary hyphenated
aliases for all users/groups keys. Because the goal in the future is
to only support one config key for a given configuraion option, add
deprecated keys to those schema definitions.
Also drop the description key from the deprecates lock-passwd schema
key.
Any deprecated schema key which provides a suggested replacement should
not provide duplicated key descriptions as the preferred replacement
will provided the necessary context.
Fixes GH-5454
(cherry picked from commit b3618d44a37ae6345f0c3d935b77ae0ae9dd1c92)
---
.../schemas/schema-cloud-config-v1.json | 103 +++++++++++++-----
tests/unittests/config/test_cc_grub_dpkg.py | 4 +-
.../test_cc_package_update_upgrade_install.py | 11 +-
.../unittests/config/test_cc_users_groups.py | 33 +++---
tests/unittests/config/test_schema.py | 15 ++-
5 files changed, 108 insertions(+), 58 deletions(-)
diff --git a/cloudinit/config/schemas/schema-cloud-config-v1.json b/cloudinit/config/schemas/schema-cloud-config-v1.json
index 97cf2b74..03e723e2 100644
--- a/cloudinit/config/schemas/schema-cloud-config-v1.json
+++ b/cloudinit/config/schemas/schema-cloud-config-v1.json
@@ -178,9 +178,9 @@
"patternProperties": {
"^.+$": {
"label": "<group_name>",
- "description": "When providing an object for users.groups the ``<group_name>`` keys are the groups to add this user to",
"deprecated": true,
"deprecated_version": "23.1",
+ "deprecated_description": "The use of ``object`` type is deprecated. Use ``string`` or ``array`` of ``string`` instead.",
"type": [
"null"
],
@@ -203,9 +203,7 @@
"type": "string"
},
"lock-passwd": {
- "default": true,
"type": "boolean",
- "description": "Default: ``true``",
"deprecated": true,
"deprecated_version": "22.3",
"deprecated_description": "Use ``lock_passwd`` instead."
@@ -215,16 +213,34 @@
"description": "Disable password login. Default: ``true``",
"type": "boolean"
},
+ "no-create-home": {
+ "type": "boolean",
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``no_create_home`` instead."
+ },
"no_create_home": {
"default": false,
"description": "Do not create home directory. Default: ``false``",
"type": "boolean"
},
+ "no-log-init": {
+ "type": "boolean",
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``no_log_init`` instead."
+ },
"no_log_init": {
"default": false,
"description": "Do not initialize lastlog and faillog for user. Default: ``false``",
"type": "boolean"
},
+ "no-user-group": {
+ "type": "boolean",
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``no_user_group`` instead."
+ },
"no_user_group": {
"default": false,
"description": "Do not create group named after user. Default: ``false``",
@@ -234,24 +250,54 @@
"description": "Hash of user password applied when user does not exist. This will NOT be applied if the user already exists. To generate this hash, run: mkpasswd --method=SHA-512 --rounds=4096. **Note:** While hashed password is better than plain text, using ``passwd`` in user-data represents a security risk as user-data could be accessible by third-parties depending on your cloud platform.",
"type": "string"
},
+ "hashed-passwd": {
+ "type": "string",
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``hashed_passwd`` instead."
+ },
"hashed_passwd": {
"description": "Hash of user password to be applied. This will be applied even if the user is pre-existing. To generate this hash, run: mkpasswd --method=SHA-512 --rounds=4096. **Note:** While ``hashed_password`` is better than ``plain_text_passwd``, using ``passwd`` in user-data represents a security risk as user-data could be accessible by third-parties depending on your cloud platform.",
"type": "string"
},
+ "plain-text-passwd": {
+ "type": "string",
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``plain_text_passwd`` instead."
+ },
"plain_text_passwd": {
"description": "Clear text of user password to be applied. This will be applied even if the user is pre-existing. There are many more secure options than using plain text passwords, such as ``ssh_import_id`` or ``hashed_passwd``. Do not use this in production as user-data and your password can be exposed.",
"type": "string"
},
+ "create-groups": {
+ "type": "boolean",
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``create_groups`` instead."
+ },
"create_groups": {
"default": true,
"description": "Boolean set ``false`` to disable creation of specified user ``groups``. Default: ``true``.",
"type": "boolean"
},
+ "primary-group": {
+ "type": "string",
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``primary_group`` instead."
+ },
"primary_group": {
"default": "``<username>``",
"description": "Primary group for user. Default: ``<username>``",
"type": "string"
},
+ "selinux-user": {
+ "type": "string",
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``selinux_user`` instead."
+ },
"selinux_user": {
"description": "SELinux user for user's login. Default to default SELinux user.",
"type": "string"
@@ -273,20 +319,24 @@
"minItems": 1
},
"ssh-authorized-keys": {
- "allOf": [
- {
- "type": "array",
- "items": {
- "type": "string"
- },
- "minItems": 1
- },
- {
- "deprecated": true,
- "deprecated_version": "18.3",
- "deprecated_description": "Use ``ssh_authorized_keys`` instead."
- }
- ]
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "deprecated": true,
+ "deprecated_version": "18.3",
+ "deprecated_description": "Use ``ssh_authorized_keys`` instead."
+ },
+ "ssh-import-id": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``ssh_import_id`` instead."
},
"ssh_import_id": {
"description": "List of SSH IDs to import for user. Can not be combined with ``ssh_redirect_user``.",
@@ -296,6 +346,12 @@
},
"minItems": 1
},
+ "ssh-redirect-user": {
+ "type": "boolean",
+ "deprecated": true,
+ "deprecated_version": "24.2",
+ "deprecated_description": "Use ``ssh_redirect_user`` instead."
+ },
"ssh_redirect_user": {
"type": "boolean",
"default": false,
@@ -398,7 +454,6 @@
"properties": {
"remove-defaults": {
"type": "boolean",
- "default": false,
"deprecated": true,
"deprecated_version": "22.3",
"deprecated_description": "Use ``remove_defaults`` instead."
@@ -516,9 +571,9 @@
},
"system_info": {
"type": "object",
- "description": "System and/or distro specific settings. This is not intended to be overridden by user data or vendor data.",
"deprecated": true,
- "deprecated_version": "24.2"
+ "deprecated_version": "24.2",
+ "deprecated_description": "System and/or distro specific settings. This is not intended to be overridden by user data or vendor data."
}
}
},
@@ -1483,7 +1538,6 @@
},
"grub-dpkg": {
"type": "object",
- "description": "An alias for ``grub_dpkg``",
"deprecated": true,
"deprecated_version": "22.2",
"deprecated_description": "Use ``grub_dpkg`` instead."
@@ -2082,24 +2136,18 @@
},
"apt_update": {
"type": "boolean",
- "default": false,
- "description": "Default: ``false``.",
"deprecated": true,
"deprecated_version": "22.2",
"deprecated_description": "Use ``package_update`` instead."
},
"apt_upgrade": {
"type": "boolean",
- "default": false,
- "description": "Default: ``false``.",
"deprecated": true,
"deprecated_version": "22.2",
"deprecated_description": "Use ``package_upgrade`` instead."
},
"apt_reboot_if_required": {
"type": "boolean",
- "default": false,
- "description": "Default: ``false``.",
"deprecated": true,
"deprecated_version": "22.2",
"deprecated_description": "Use ``package_reboot_if_required`` instead."
@@ -2798,7 +2846,6 @@
}
],
"minItems": 1,
- "description": "List of ``username:password`` pairs. Each user will have the corresponding password set. A password can be randomly generated by specifying ``RANDOM`` or ``R`` as a user's password. A hashed password, created by a tool like ``mkpasswd``, can be specified. A regex (``r'\\$(1|2a|2y|5|6)(\\$.+){2}'``) is used to determine if a password value should be treated as a hash.",
"deprecated": true,
"deprecated_version": "22.2",
"deprecated_description": "Use ``users`` instead."
diff --git a/tests/unittests/config/test_cc_grub_dpkg.py b/tests/unittests/config/test_cc_grub_dpkg.py
index b4bd48df..36ef7fd9 100644
--- a/tests/unittests/config/test_cc_grub_dpkg.py
+++ b/tests/unittests/config/test_cc_grub_dpkg.py
@@ -300,8 +300,8 @@ class TestGrubDpkgSchema:
pytest.raises(
SchemaValidationError,
match=(
- "Cloud config schema deprecations: grub-dpkg: An alias"
- " for ``grub_dpkg`` Deprecated in version 22.2. Use "
+ "Cloud config schema deprecations: grub-dpkg:"
+ " Deprecated in version 22.2. Use "
"``grub_dpkg`` instead."
),
),
diff --git a/tests/unittests/config/test_cc_package_update_upgrade_install.py b/tests/unittests/config/test_cc_package_update_upgrade_install.py
index 9ba7f178..734dbc53 100644
--- a/tests/unittests/config/test_cc_package_update_upgrade_install.py
+++ b/tests/unittests/config/test_cc_package_update_upgrade_install.py
@@ -192,16 +192,16 @@ class TestPackageUpdateUpgradeSchema:
(
{"apt_update": False},
(
- "Cloud config schema deprecations: apt_update: "
- "Default: ``false``. Deprecated in version 22.2. "
+ "Cloud config schema deprecations: apt_update: "
+ "Deprecated in version 22.2. "
"Use ``package_update`` instead."
),
),
(
{"apt_upgrade": False},
(
- "Cloud config schema deprecations: apt_upgrade: "
- "Default: ``false``. Deprecated in version 22.2. "
+ "Cloud config schema deprecations: apt_upgrade: "
+ "Deprecated in version 22.2. "
"Use ``package_upgrade`` instead."
),
),
@@ -209,8 +209,7 @@ class TestPackageUpdateUpgradeSchema:
{"apt_reboot_if_required": False},
(
"Cloud config schema deprecations: "
- "apt_reboot_if_required: Default: ``false``. "
- "Deprecated in version 22.2. Use "
+ "apt_reboot_if_required: Deprecated in version 22.2. Use "
"``package_reboot_if_required`` instead."
),
),
diff --git a/tests/unittests/config/test_cc_users_groups.py b/tests/unittests/config/test_cc_users_groups.py
index 53e231e1..4ca67f77 100644
--- a/tests/unittests/config/test_cc_users_groups.py
+++ b/tests/unittests/config/test_cc_users_groups.py
@@ -371,9 +371,20 @@ class TestUsersGroupsSchema:
SchemaValidationError,
match=(
"Cloud config schema deprecations: "
- "users.0.lock-passwd: Default: ``true`` "
- "Deprecated in version 22.3. Use "
- "``lock_passwd`` instead."
+ "users.0.lock-passwd: Deprecated in version 22.3."
+ " Use ``lock_passwd`` instead."
+ ),
+ ),
+ False,
+ ),
+ (
+ {"users": [{"name": "bbsw", "no-create-home": True}]},
+ pytest.raises(
+ SchemaValidationError,
+ match=(
+ "Cloud config schema deprecations: "
+ "users.0.no-create-home: Deprecated in version 24.2."
+ " Use ``no_create_home`` instead."
),
),
False,
@@ -394,13 +405,10 @@ class TestUsersGroupsSchema:
SchemaValidationError,
match=(
"Cloud config schema deprecations: "
- "users.0.groups.adm: When providing an object "
- "for users.groups the ``<group_name>`` keys "
- "are the groups to add this user to Deprecated"
- " in version 23.1., users.0.groups.sudo: When "
- "providing an object for users.groups the "
- "``<group_name>`` keys are the groups to add "
- "this user to Deprecated in version 23.1."
+ "users.0.groups.adm: Deprecated in version 23.1. "
+ "The use of ``object`` type is deprecated. Use "
+ "``string`` or ``array`` of ``string`` instead., "
+ "users.0.groups.sudo: Deprecated in version 23.1."
),
),
False,
@@ -456,10 +464,7 @@ class TestUsersGroupsSchema:
SchemaValidationError,
match=(
"Cloud config schema deprecations: "
- "user.groups.sbuild: When providing an object "
- "for users.groups the ``<group_name>`` keys "
- "are the groups to add this user to Deprecated"
- " in version 23.1."
+ "user.groups.sbuild: Deprecated in version 23.1."
),
),
False,
diff --git a/tests/unittests/config/test_schema.py b/tests/unittests/config/test_schema.py
index 52667332..8208affc 100644
--- a/tests/unittests/config/test_schema.py
+++ b/tests/unittests/config/test_schema.py
@@ -2251,9 +2251,9 @@ class TestHandleSchemaArgs:
apt_reboot_if_required: true # D3
# Deprecations: -------------
- # D1: Default: ``false``. Deprecated in version 22.2. Use ``package_update`` instead.
- # D2: Default: ``false``. Deprecated in version 22.2. Use ``package_upgrade`` instead.
- # D3: Default: ``false``. Deprecated in version 22.2. Use ``package_reboot_if_required`` instead.
+ # D1: Deprecated in version 22.2. Use ``package_update`` instead.
+ # D2: Deprecated in version 22.2. Use ``package_upgrade`` instead.
+ # D3: Deprecated in version 22.2. Use ``package_reboot_if_required`` instead.
Valid schema {cfg_file}
""" # noqa: E501
@@ -2264,11 +2264,10 @@ class TestHandleSchemaArgs:
dedent(
"""\
Cloud config schema deprecations: \
-apt_reboot_if_required: Default: ``false``. Deprecated in version 22.2.\
- Use ``package_reboot_if_required`` instead., apt_update: Default: \
-``false``. Deprecated in version 22.2. Use ``package_update`` instead.,\
- apt_upgrade: Default: ``false``. Deprecated in version 22.2. Use \
-``package_upgrade`` instead.\
+apt_reboot_if_required: Deprecated in version 22.2. Use\
+ ``package_reboot_if_required`` instead., apt_update: Deprecated in version\
+ 22.2. Use ``package_update`` instead., apt_upgrade: Deprecated in version\
+ 22.2. Use ``package_upgrade`` instead.\
Valid schema {cfg_file}
""" # noqa: E501
),
--
2.39.3

View File

@ -0,0 +1,185 @@
From 9ee9fe608b906fe4e523cbf7fbe4539f0322ba2f Mon Sep 17 00:00:00 2001
From: PengpengSun <40026211+PengpengSun@users.noreply.github.com>
Date: Thu, 4 Jul 2024 04:06:39 +0800
Subject: [PATCH 2/2] fix(vmware): Set IPv6 to dhcp when there is no IPv6 addr
(#5471)
RH-Author: xiachen <xiachen@redhat.com>
RH-MergeRequest: 99: fix(vmware): Set IPv6 to dhcp when there is no IPv6 addr (#5471)
RH-Jira: RHEL-46194
RH-Acked-by: Ani Sinha <anisinha@redhat.com>
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Commit: [1/1] fbae24c7e7f48239200eaf457d260203fb550845 (xiachen/cloud-init-centos)
When there is no IPv6 addr given in the customization configuration,
we shall set IPv6 type to dhcp6, then customized Linux network will be
set to dhcp IPv6 explicitly.
(cherry picked from commit 2b6fe6403db769de14f7c7b7e4aa65f5bea8f3e0)
---
.../sources/helpers/vmware/imc/config_nic.py | 2 +-
.../sources/vmware/test_vmware_config_file.py | 68 ++++++++++++++-----
2 files changed, 52 insertions(+), 18 deletions(-)
diff --git a/cloudinit/sources/helpers/vmware/imc/config_nic.py b/cloudinit/sources/helpers/vmware/imc/config_nic.py
index b07214a2..254518af 100644
--- a/cloudinit/sources/helpers/vmware/imc/config_nic.py
+++ b/cloudinit/sources/helpers/vmware/imc/config_nic.py
@@ -207,7 +207,7 @@ class NicConfigurator:
"""
if not nic.staticIpv6:
- return ([], [])
+ return ([{"type": "dhcp6"}], [])
subnet_list = []
# Static Ipv6
diff --git a/tests/unittests/sources/vmware/test_vmware_config_file.py b/tests/unittests/sources/vmware/test_vmware_config_file.py
index b53ea96c..25d3b093 100644
--- a/tests/unittests/sources/vmware/test_vmware_config_file.py
+++ b/tests/unittests/sources/vmware/test_vmware_config_file.py
@@ -240,27 +240,45 @@ class TestVmwareConfigFile(CiTestCase):
elif cfg.get("name") == nic2.get("name"):
nic2.update(cfg)
+ # Test NIC1
self.assertEqual("physical", nic1.get("type"), "type of NIC1")
self.assertEqual("NIC1", nic1.get("name"), "name of NIC1")
self.assertEqual(
"00:50:56:a6:8c:08", nic1.get("mac_address"), "mac address of NIC1"
)
subnets = nic1.get("subnets")
- self.assertEqual(1, len(subnets), "number of subnets for NIC1")
- subnet = subnets[0]
- self.assertEqual("dhcp", subnet.get("type"), "DHCP type for NIC1")
- self.assertEqual("auto", subnet.get("control"), "NIC1 Control type")
+ self.assertEqual(2, len(subnets), "number of subnets for NIC1")
+ subnet_ipv4 = subnets[0]
+ self.assertEqual(
+ "dhcp", subnet_ipv4.get("type"), "Ipv4 DHCP type for NIC1"
+ )
+ self.assertEqual(
+ "auto", subnet_ipv4.get("control"), "NIC1 Control type"
+ )
+ subnet_ipv6 = subnets[1]
+ self.assertEqual(
+ "dhcp6", subnet_ipv6.get("type"), "Ipv6 DHCP type for NIC1"
+ )
+ # Test NIC2
self.assertEqual("physical", nic2.get("type"), "type of NIC2")
self.assertEqual("NIC2", nic2.get("name"), "name of NIC2")
self.assertEqual(
"00:50:56:a6:5a:de", nic2.get("mac_address"), "mac address of NIC2"
)
subnets = nic2.get("subnets")
- self.assertEqual(1, len(subnets), "number of subnets for NIC2")
- subnet = subnets[0]
- self.assertEqual("dhcp", subnet.get("type"), "DHCP type for NIC2")
- self.assertEqual("auto", subnet.get("control"), "NIC2 Control type")
+ self.assertEqual(2, len(subnets), "number of subnets for NIC2")
+ subnet_ipv4 = subnets[0]
+ self.assertEqual(
+ "dhcp", subnet_ipv4.get("type"), "Ipv4 DHCP type for NIC2"
+ )
+ self.assertEqual(
+ "auto", subnet_ipv4.get("control"), "NIC2 Control type"
+ )
+ subnet_ipv6 = subnets[1]
+ self.assertEqual(
+ "dhcp6", subnet_ipv6.get("type"), "Ipv6 DHCP type for NIC2"
+ )
def test_get_nics_list_static(self):
"""Tests if NicConfigurator properly calculates network subnets
@@ -285,6 +303,7 @@ class TestVmwareConfigFile(CiTestCase):
elif cfg.get("name") == nic2.get("name"):
nic2.update(cfg)
+ # Test NIC1
self.assertEqual("physical", nic1.get("type"), "type of NIC1")
self.assertEqual("NIC1", nic1.get("name"), "name of NIC1")
self.assertEqual(
@@ -344,6 +363,7 @@ class TestVmwareConfigFile(CiTestCase):
else:
self.assertEqual(True, False, "invalid gateway %s" % (gateway))
+ # Test NIC2
self.assertEqual("physical", nic2.get("type"), "type of NIC2")
self.assertEqual("NIC2", nic2.get("name"), "name of NIC2")
self.assertEqual(
@@ -351,16 +371,18 @@ class TestVmwareConfigFile(CiTestCase):
)
subnets = nic2.get("subnets")
- self.assertEqual(1, len(subnets), "Number of subnets for NIC2")
+ self.assertEqual(2, len(subnets), "Number of subnets for NIC2")
- subnet = subnets[0]
- self.assertEqual("static", subnet.get("type"), "Subnet type")
+ subnet_ipv4 = subnets[0]
+ self.assertEqual("static", subnet_ipv4.get("type"), "Subnet type")
self.assertEqual(
- "192.168.6.102", subnet.get("address"), "Subnet address"
+ "192.168.6.102", subnet_ipv4.get("address"), "Subnet address"
)
self.assertEqual(
- "255.255.0.0", subnet.get("netmask"), "Subnet netmask"
+ "255.255.0.0", subnet_ipv4.get("netmask"), "Subnet netmask"
)
+ subnet_ipv6 = subnets[1]
+ self.assertEqual("dhcp6", subnet_ipv6.get("type"), "Subnet type")
def test_custom_script(self):
cf = ConfigFile("tests/data/vmware/cust-dhcp-2nic.cfg")
@@ -447,7 +469,10 @@ class TestVmwareNetConfig(CiTestCase):
"type": "static",
"address": "10.20.87.154",
"netmask": "255.255.252.0",
- }
+ },
+ {
+ "type": "dhcp6",
+ },
],
}
],
@@ -498,7 +523,10 @@ class TestVmwareNetConfig(CiTestCase):
"metric": 10000,
}
],
- }
+ },
+ {
+ "type": "dhcp6",
+ },
],
}
],
@@ -558,7 +586,10 @@ class TestVmwareNetConfig(CiTestCase):
"metric": 10000,
}
],
- }
+ },
+ {
+ "type": "dhcp6",
+ },
],
}
],
@@ -603,7 +634,10 @@ class TestVmwareNetConfig(CiTestCase):
"address": "10.20.87.154",
"netmask": "255.255.252.0",
"gateway": "10.20.87.253",
- }
+ },
+ {
+ "type": "dhcp6",
+ },
],
}
],
--
2.39.3

View File

@ -1,6 +1,6 @@
Name: cloud-init
Version: 23.4
Release: 6%{?dist}
Release: 19%{?dist}
Summary: Cloud instance init scripts
License: ASL 2.0 or GPLv3
URL: http://launchpad.net/cloud-init
@ -21,6 +21,52 @@ Patch9: ci-Revert-Use-grep-for-faster-parsing-of-cloud-config-i.patch
Patch10: ci-Pin-pythes-8.0.0.patch
# For RHEL-21324 - [rhel-9] The schema WARNING info for network-config.json is not suitable in cloud-init-23.4
Patch11: ci-fix-Add-types-to-network-v1-schema-4841.patch
# For RHEL-28549 - [RHEL 9.4] cloud-init 23.4 returns 2 on recoverable errors instead of 0
Patch12: ci-Retain-exit-code-in-cloud-init-status-for-recoverabl.patch
# For RHEL-20964 - [rhel-9]cloud-init fails to configure DNS/search domains for network-config v1
Patch13: ci-fix-Correct-v2-NetworkManager-route-rendering-4637.patch
# For RHEL-20964 - [rhel-9]cloud-init fails to configure DNS/search domains for network-config v1
Patch14: ci-feat-apply-global-DNS-to-interfaces-in-network-manag.patch
# For RHEL-29709 - Suggest to backport patch ff40d1a to undeprecate 'network' in schema route definition
Patch15: ci-fix-Undeprecate-network-in-schema-route-definition-5.patch
# For RHEL-32846 - [cloud-init][ESXi]VMware datasource resets on every boot causing it to lose network configuration [rhel-9]
Patch16: ci-fix-Fall-back-to-cached-local-ds-if-no-valid-ds-foun.patch
# For RHEL-36255 - [rhel-9.5] DataSourceNoCloudNet not configurable via config files
Patch17: ci-fix-Always-use-single-datasource-if-specified-5098.patch
# For RHEL-40217 - [Cloud-init] CloudstackDataSource cannot work with NetworkManager
Patch18: ci-fix-cloudstack-Use-parsed-lease-file-for-virtual-rou.patch
# For RHEL-17961 - [RHEL-9] cloud-init fails to configure DNS search domains
Patch19: ci-feat-sysconfig-Add-DNS-from-interface-config-to-reso.patch
# For RHEL-44337 - [rhel-9] fix `SUDO` configuration schema for users and groups
Patch20: ci-fix-jsonschema-Add-missing-sudo-definition-5418.patch
# For RHEL-44337 - [rhel-9] fix `SUDO` configuration schema for users and groups
Patch21: ci-doc-update-examples-to-reflect-alternative-ways-to-p.patch
# For RHEL-44598 - fix pylint error and support python 3.12
Patch22: ci-fix-dhcp-Guard-against-FileNotFoundError-and-NameErr.patch
# For RHEL-44598 - fix pylint error and support python 3.12
Patch23: ci-fix-Address-TIOBE-abstract-interpretation-issues-486.patch
# For RHEL-44598 - fix pylint error and support python 3.12
Patch24: ci-Update-pylint-version-to-support-python-3.12-5338.patch
# For RHEL-45262 - Deprecate the users ssh-authorized-keys property and permit deprecated hyphenated keys under users key
Patch25: ci-Deprecate-the-users-ssh-authorized-keys-property-516.patch
# For RHEL-45262 - Deprecate the users ssh-authorized-keys property and permit deprecated hyphenated keys under users key
Patch26: ci-docs-Add-deprecated-system_info-to-schema-5168.patch
# For RHEL-45262 - Deprecate the users ssh-authorized-keys property and permit deprecated hyphenated keys under users key
Patch27: ci-fix-schema-permit-deprecated-hyphenated-keys-under-u.patch
# For RHEL-44916 - [RFE] Support metalink in yum repository config
Patch28: ci-Support-metalink-in-yum-repository-config-5444.patch
# For RHEL-46194 - [RHEL-9] It leaves the ipv6 networking config as blank in NM keyfile when config dhcp ipv6 with customization spec
Patch29: ci-fix-vmware-Set-IPv6-to-dhcp-when-there-is-no-IPv6-ad.patch
# For RHEL-46873 - Suggest to update schema to support metalink
Patch30: ci-fix-add-schema-rules-for-baseurl-and-metalink-in-yum.patch
# For RHEL-49736 - [Cloud-init] [RHEL-9] Password reset feature broken with CloudstackDataSource
Patch31: ci-fix-Clean-cache-if-no-datasource-fallback-5499.patch
# For RHEL-49674 - Support setting mirrorlist in yum repository config
Patch32: ci-Support-setting-mirrorlist-in-yum-repository-config-.patch
# For RHEL-54373 - [RHEL9]Revert "fix(vmware): Set IPv6 to dhcp when there is no IPv6 addr (#5471)"
Patch33: ci-Revert-fix-vmware-Set-IPv6-to-dhcp-when-there-is-no-.patch
# For RHEL-54686 - [RHEL-9.5] cloud-init schema validation fails.
Patch34: ci-fix-Add-subnet-ipv4-ipv6-to-network-schema-5191.patch
BuildArch: noarch
@ -34,8 +80,6 @@ BuildRequires: iproute
BuildRequires: python3-configobj
# https://bugzilla.redhat.com/show_bug.cgi?id=1695953
BuildRequires: python3-distro
# https://bugzilla.redhat.com/show_bug.cgi?id=1417029
BuildRequires: python3-httpretty >= 0.8.14-2
BuildRequires: python3-jinja2
BuildRequires: python3-jsonpatch
BuildRequires: python3-oauthlib
@ -237,6 +281,92 @@ fi
%config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf
%changelog
* Mon Aug 26 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-19
- ci-fix-Add-subnet-ipv4-ipv6-to-network-schema-5191.patch [RHEL-54686]
- Resolves: RHEL-54686
([RHEL-9.5] cloud-init schema validation fails.)
* Mon Aug 19 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-18
- ci-Revert-fix-vmware-Set-IPv6-to-dhcp-when-there-is-no-.patch [RHEL-54373]
- Resolves: RHEL-54373
([RHEL9]Revert "fix(vmware): Set IPv6 to dhcp when there is no IPv6 addr (#5471)")
* Thu Jul 25 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-17
- ci-fix-Clean-cache-if-no-datasource-fallback-5499.patch [RHEL-49736]
- ci-Support-setting-mirrorlist-in-yum-repository-config-.patch [RHEL-49674]
- Resolves: RHEL-49736
([Cloud-init] [RHEL-9] Password reset feature broken with CloudstackDataSource)
- Resolves: RHEL-49674
(Support setting mirrorlist in yum repository config)
* Fri Jul 12 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-16
- ci-fix-add-schema-rules-for-baseurl-and-metalink-in-yum.patch [RHEL-46873]
- Resolves: RHEL-46873
(Suggest to update schema to support metalink)
* Mon Jul 08 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-15
- ci-Support-metalink-in-yum-repository-config-5444.patch [RHEL-44916]
- ci-fix-vmware-Set-IPv6-to-dhcp-when-there-is-no-IPv6-ad.patch [RHEL-46194]
- Resolves: RHEL-44916
([RFE] Support metalink in yum repository config)
- Resolves: RHEL-46194
([RHEL-9] It leaves the ipv6 networking config as blank in NM keyfile when config dhcp ipv6 with customization spec)
* Mon Jul 01 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-14
- ci-Deprecate-the-users-ssh-authorized-keys-property-516.patch [RHEL-45262]
- ci-docs-Add-deprecated-system_info-to-schema-5168.patch [RHEL-45262]
- ci-fix-schema-permit-deprecated-hyphenated-keys-under-u.patch [RHEL-45262]
- Resolves: RHEL-45262
(Deprecate the users ssh-authorized-keys property and permit deprecated hyphenated keys under users key)
* Tue Jun 25 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-13
- ci-feat-sysconfig-Add-DNS-from-interface-config-to-reso.patch [RHEL-17961]
- ci-fix-jsonschema-Add-missing-sudo-definition-5418.patch [RHEL-44337]
- ci-doc-update-examples-to-reflect-alternative-ways-to-p.patch [RHEL-44337]
- ci-fix-dhcp-Guard-against-FileNotFoundError-and-NameErr.patch [RHEL-44598]
- ci-fix-Address-TIOBE-abstract-interpretation-issues-486.patch [RHEL-44598]
- ci-Update-pylint-version-to-support-python-3.12-5338.patch [RHEL-44598]
- Resolves: RHEL-17961
([RHEL-9] cloud-init fails to configure DNS search domains)
- Resolves: RHEL-44337
([rhel-9] fix `SUDO` configuration schema for users and groups)
- Resolves: RHEL-44598
(fix pylint error and support python 3.12)
* Mon Jun 17 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-12
- ci-fix-cloudstack-Use-parsed-lease-file-for-virtual-rou.patch [RHEL-40217]
- Resolves: RHEL-40217
([Cloud-init] CloudstackDataSource cannot work with NetworkManager)
* Thu May 16 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-11
- ci-fix-Always-use-single-datasource-if-specified-5098.patch [RHEL-36255]
- Resolves: RHEL-36255
([rhel-9.5] DataSourceNoCloudNet not configurable via config files)
* Mon Apr 29 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-10
- ci-Remove-dependency-on-python3-httpretty.patch [RHEL-33973]
- Resolves: RHEL-33973
([RFE] Remove dependency on python3-httpretty)
* Mon Apr 22 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-9
- ci-fix-Fall-back-to-cached-local-ds-if-no-valid-ds-foun.patch [RHEL-32846]
- Resolves: RHEL-32846
([cloud-init][ESXi]VMware datasource resets on every boot causing it to lose network configuration [rhel-9])
* Mon Apr 08 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-8
- ci-fix-Correct-v2-NetworkManager-route-rendering-4637.patch [RHEL-20964]
- ci-feat-apply-global-DNS-to-interfaces-in-network-manag.patch [RHEL-20964]
- ci-fix-Undeprecate-network-in-schema-route-definition-5.patch [RHEL-29709]
- Resolves: RHEL-20964
([rhel-9]cloud-init fails to configure DNS/search domains for network-config v1)
- Resolves: RHEL-29709
(Suggest to backport patch ff40d1a to undeprecate 'network' in schema route definition)
* Thu Mar 14 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-7
- ci-Retain-exit-code-in-cloud-init-status-for-recoverabl.patch [RHEL-28549]
- Resolves: RHEL-28549
([RHEL 9.4] cloud-init 23.4 returns 2 on recoverable errors instead of 0)
* Mon Feb 26 2024 Miroslav Rezanina <mrezanin@redhat.com> - 23.4-6
- ci-fix-Add-types-to-network-v1-schema-4841.patch [RHEL-21324]
- Resolves: RHEL-21324