diff --git a/SOURCES/ci-Fix-for-network-configuration-not-persisting-after-r.patch b/SOURCES/ci-Fix-for-network-configuration-not-persisting-after-r.patch new file mode 100644 index 0000000..41e27ff --- /dev/null +++ b/SOURCES/ci-Fix-for-network-configuration-not-persisting-after-r.patch @@ -0,0 +1,107 @@ +From 4ab5a61c0f8378889d2a6b78710f49b0fb71d3c9 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Fri, 22 Nov 2019 07:46:38 +0100 +Subject: [PATCH 1/2] Fix for network configuration not persisting after reboot + +RH-Author: Eduardo Otubo +Message-id: <20190906121211.23172-1-otubo@redhat.com> +Patchwork-id: 90300 +O-Subject: [RHEL-7.8/RHEL-8.1.0 cloud-init PATCH] Fix for network configuration not persisting after reboot +Bugzilla: 1706482 +RH-Acked-by: Mohammed Gamal +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Vitaly Kuznetsov + +The reasons the configuration does not persist after reboot includes +different aspects and they're all fixed on this patch: + + 1) The rpm package doesn't include the systemd-generator and +ds-identify. The systemd-generator is called early in the boot process +that calls ds-identify to check if there's any Data Source available in +the current boot. In the current use case, the Data Source is removed +from the VM on the second boot, this means cloud-init should disable +itself in order to keep the configuration it did in the first boot. + + 2) Even after adding those scripts, cloud-init was still being +executed and the configurations were being lost. The reason for this is +that the cloud-init systemd units had a wrong dependency + + WantedBy: multi-user.target + + Which would start them every time no matter the return of +ds-identify. The fix is to replace the dependency by the systemd unit to +cloud-init.target, which is the main cloud-init target enabled - or in +this case, disabled by ds-identify. The file cloud-init.target was also +missing on rpm package. + +After adding both scripts, the main cloud-init systemd target and +adjusting the systemd dependencies the configuration persists after +reboots and shutdowns. + +Signed-off-by: Eduardo Otubo +--- + redhat/cloud-init.spec.template | 15 +++++++++++++++ + rhel/systemd/cloud-config.service | 2 +- + rhel/systemd/cloud-final.service | 2 +- + rhel/systemd/cloud-init-local.service | 2 +- + rhel/systemd/cloud-init.service | 2 +- + rhel/systemd/cloud-init.target | 7 +++++++ + 6 files changed, 26 insertions(+), 4 deletions(-) + create mode 100644 rhel/systemd/cloud-init.target + +diff --git a/rhel/systemd/cloud-config.service b/rhel/systemd/cloud-config.service +index 12ca9df..f3dcd4b 100644 +--- a/rhel/systemd/cloud-config.service ++++ b/rhel/systemd/cloud-config.service +@@ -15,4 +15,4 @@ TimeoutSec=0 + StandardOutput=journal+console + + [Install] +-WantedBy=multi-user.target ++WantedBy=cloud-init.target +diff --git a/rhel/systemd/cloud-final.service b/rhel/systemd/cloud-final.service +index 32a83d8..739b7e3 100644 +--- a/rhel/systemd/cloud-final.service ++++ b/rhel/systemd/cloud-final.service +@@ -16,4 +16,4 @@ KillMode=process + StandardOutput=journal+console + + [Install] +-WantedBy=multi-user.target ++WantedBy=cloud-init.target +diff --git a/rhel/systemd/cloud-init-local.service b/rhel/systemd/cloud-init-local.service +index 656eddb..8f9f6c9 100644 +--- a/rhel/systemd/cloud-init-local.service ++++ b/rhel/systemd/cloud-init-local.service +@@ -28,4 +28,4 @@ TimeoutSec=0 + StandardOutput=journal+console + + [Install] +-WantedBy=multi-user.target ++WantedBy=cloud-init.target +diff --git a/rhel/systemd/cloud-init.service b/rhel/systemd/cloud-init.service +index 68fc5f1..d0023a0 100644 +--- a/rhel/systemd/cloud-init.service ++++ b/rhel/systemd/cloud-init.service +@@ -22,4 +22,4 @@ TimeoutSec=0 + StandardOutput=journal+console + + [Install] +-WantedBy=multi-user.target ++WantedBy=cloud-init.target +diff --git a/rhel/systemd/cloud-init.target b/rhel/systemd/cloud-init.target +new file mode 100644 +index 0000000..083c3b6 +--- /dev/null ++++ b/rhel/systemd/cloud-init.target +@@ -0,0 +1,7 @@ ++# cloud-init target is enabled by cloud-init-generator ++# To disable it you can either: ++# a.) boot with kernel cmdline of 'cloud-init=disabled' ++# b.) touch a file /etc/cloud/cloud-init.disabled ++[Unit] ++Description=Cloud-init target ++After=multi-user.target +-- +1.8.3.1 + diff --git a/SOURCES/ci-Remove-race-condition-between-cloud-init-and-Network.patch b/SOURCES/ci-Remove-race-condition-between-cloud-init-and-Network.patch new file mode 100644 index 0000000..a46559b --- /dev/null +++ b/SOURCES/ci-Remove-race-condition-between-cloud-init-and-Network.patch @@ -0,0 +1,56 @@ +From 312666820cb51a738d8112181c331eb2ce109732 Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Mon, 2 Mar 2020 10:46:35 +0100 +Subject: [PATCH] Remove race condition between cloud-init and NetworkManager + +Message-id: <20200302104635.11648-1-otubo@redhat.com> +Patchwork-id: 94098 +O-Subject: [RHEL-7.9/RHEL-8.2.0 cloud-init PATCH] Remove race condition between cloud-init and NetworkManager +Bugzilla: 1807797 +RH-Acked-by: Cathy Avery +RH-Acked-by: Mohammed Gamal + +BZ: 1748015 +BRANCH: rhel7/master-18.5 +BREW: 26924611 + +BZ: 1807797 +BRANCH: rhel820/master-18.5 +BREW: 26924957 + +cloud-init service is set to start before NetworkManager service starts, +but this does not avoid a race condition between them. NetworkManager +starts before cloud-init can write `dns=none' to the file: +/etc/NetworkManager/conf.d/99-cloud-init.conf. This way NetworkManager +doesn't read the configuration and erases all resolv.conf values upon +shutdown. On the next reboot neither cloud-init or NetworkManager will +write anything to resolv.conf, leaving it blank. + +This patch introduces a NM reload (try-restart) at the end of cloud-init +start up so it won't erase resolv.conf upon first shutdown. + +x-downstream-only: yes +resolves: rhbz#1748015, rhbz#1807797 and rhbz#1804780 + +Signed-off-by: Eduardo Otubo otubo@redhat.com +Signed-off-by: Miroslav Rezanina +--- + rhel/systemd/cloud-final.service | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/rhel/systemd/cloud-final.service b/rhel/systemd/cloud-final.service +index 739b7e3..f303483 100644 +--- a/rhel/systemd/cloud-final.service ++++ b/rhel/systemd/cloud-final.service +@@ -11,6 +11,8 @@ ExecStart=/usr/bin/cloud-init modules --mode=final + RemainAfterExit=yes + TimeoutSec=0 + KillMode=process ++ExecStartPost=/bin/echo "try restart NetworkManager.service" ++ExecStartPost=/usr/bin/systemctl try-restart NetworkManager.service + + # Output needs to appear in instance console output + StandardOutput=journal+console +-- +1.8.3.1 + diff --git a/SOURCES/ci-Removing-cloud-user-from-wheel.patch b/SOURCES/ci-Removing-cloud-user-from-wheel.patch new file mode 100644 index 0000000..b6a1b4d --- /dev/null +++ b/SOURCES/ci-Removing-cloud-user-from-wheel.patch @@ -0,0 +1,54 @@ +From 84cf125e1704034ccc6c379aced2924f9d0d30e6 Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Thu, 23 Jan 2020 11:13:17 +0100 +Subject: [PATCH] Removing cloud-user from wheel + +RH-Author: Eduardo Otubo +Message-id: <20200123111317.15542-1-otubo@redhat.com> +Patchwork-id: 93442 +O-Subject: [RHEL-7.9/RHEL-8 cloud-init PATCH] Removing cloud-user from wheel +Bugzilla: 1785648 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Vitaly Kuznetsov + +BZ: 1549638 +BRANCH: rhel7/master-18.5 +UPSTREAM: +BREW: 25963032 + +BZ: 1785648 +BRANCH: rhel8/master-18.5 +UPSTREAM: +BREW: 25962773 + +Including cloud-user to both sudoers and wheel group makes the command +`sudo -v' to ask for password. Besides the bogus behavior, it's +unecessary to have the user on both. Removing the user from `wheel' +group solves the issue + +X-downstream-only: yes +Resolves: rhbz#1549638 +Resolves: rhbz#1785648 + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + rhel/cloud.cfg | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg +index f0db3c1..82e8bf6 100644 +--- a/rhel/cloud.cfg ++++ b/rhel/cloud.cfg +@@ -57,7 +57,7 @@ system_info: + name: cloud-user + lock_passwd: true + gecos: Cloud User +- groups: [wheel, adm, systemd-journal] ++ groups: [adm, systemd-journal] + sudo: ["ALL=(ALL) NOPASSWD:ALL"] + shell: /bin/bash + distro: rhel +-- +1.8.3.1 + diff --git a/SOURCES/ci-azure-avoid-re-running-cloud-init-when-instance-id-i.patch b/SOURCES/ci-azure-avoid-re-running-cloud-init-when-instance-id-i.patch new file mode 100644 index 0000000..a902a13 --- /dev/null +++ b/SOURCES/ci-azure-avoid-re-running-cloud-init-when-instance-id-i.patch @@ -0,0 +1,225 @@ +From ff70ab92aa97b3d43dbde34ef9f70b9ee44e197e Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Wed, 19 Feb 2020 10:30:02 +0100 +Subject: [PATCH 1/3] azure: avoid re-running cloud-init when instance-id is + byte-swapped (#84) + +RH-Author: Eduardo Otubo +Message-id: <20200219103002.24735-1-otubo@redhat.com> +Patchwork-id: 93933 +O-Subject: [RHEL-8.2.0/RHEL-7.9 cloud-init PATCH] azure: avoid re-running cloud-init when instance-id is byte-swapped (#84) +Bugzilla: 1788684 +RH-Acked-by: Vitaly Kuznetsov +RH-Acked-by: Mohammed Gamal + +BZ: 1788684 +BRANCH: rhel820/master-18.5 +UPSTREAM: 129b1c4e +BREW: 26606326 + +BZ: 1788340 +BRANCH: rhel7/master-18.5 +UPSTREAM: 129b1c4e +BREW: 26606322 + +commit 129b1c4ea250619bd7caed7aaffacc796b0139f2 +Author: AOhassan <37305877+AOhassan@users.noreply.github.com> +Date: Thu Dec 12 13:51:42 2019 -0800 + + azure: avoid re-running cloud-init when instance-id is byte-swapped (#84) + + Azure stores the instance ID with an incorrect byte ordering for the + first three hyphen delimited parts. This results in invalid + is_new_instance checks forcing Azure datasource to recrawl the metadata + service. + + When persisting instance-id from the metadata service, swap the + instance-id string byte order such that it is consistent with + that returned by dmi information. Check whether the instance-id + string is a byte-swapped match when determining correctly whether + the Azure platform instance-id has actually changed. + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + cloudinit/sources/DataSourceAzure.py | 16 ++++++++++--- + cloudinit/sources/helpers/azure.py | 27 ++++++++++++++++++++++ + tests/unittests/test_datasource/test_azure.py | 24 ++++++++++++++++--- + .../unittests/test_datasource/test_azure_helper.py | 19 +++++++++++++++ + 4 files changed, 80 insertions(+), 6 deletions(-) + +diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py +index 5baf8da..66bbe5e 100755 +--- a/cloudinit/sources/DataSourceAzure.py ++++ b/cloudinit/sources/DataSourceAzure.py +@@ -28,7 +28,8 @@ from cloudinit.reporting import events + + from cloudinit.sources.helpers.azure import (azure_ds_reporter, + azure_ds_telemetry_reporter, +- get_metadata_from_fabric) ++ get_metadata_from_fabric, ++ is_byte_swapped) + + LOG = logging.getLogger(__name__) + +@@ -458,8 +459,7 @@ class DataSourceAzure(sources.DataSource): + seed = _get_random_seed() + if seed: + crawled_data['metadata']['random_seed'] = seed +- crawled_data['metadata']['instance-id'] = util.read_dmi_data( +- 'system-uuid') ++ crawled_data['metadata']['instance-id'] = self._iid() + + if perform_reprovision: + LOG.info("Reporting ready to Azure after getting ReprovisionData") +@@ -530,6 +530,16 @@ class DataSourceAzure(sources.DataSource): + # quickly (local check only) if self.instance_id is still valid + return sources.instance_id_matches_system_uuid(self.get_instance_id()) + ++ def _iid(self, previous=None): ++ prev_iid_path = os.path.join( ++ self.paths.get_cpath('data'), 'instance-id') ++ iid = util.read_dmi_data('system-uuid') ++ if os.path.exists(prev_iid_path): ++ previous = util.load_file(prev_iid_path).strip() ++ if is_byte_swapped(previous, iid): ++ return previous ++ return iid ++ + @azure_ds_telemetry_reporter + def setup(self, is_new_instance): + if self._negotiated is False: +diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py +index 82c4c8c..c2a57cc 100755 +--- a/cloudinit/sources/helpers/azure.py ++++ b/cloudinit/sources/helpers/azure.py +@@ -7,6 +7,7 @@ import re + import socket + import struct + import time ++import textwrap + + from cloudinit.net import dhcp + from cloudinit import stages +@@ -40,6 +41,32 @@ def azure_ds_telemetry_reporter(func): + return impl + + ++def is_byte_swapped(previous_id, current_id): ++ """ ++ Azure stores the instance ID with an incorrect byte ordering for the ++ first parts. This corrects the byte order such that it is consistent with ++ that returned by the metadata service. ++ """ ++ if previous_id == current_id: ++ return False ++ ++ def swap_bytestring(s, width=2): ++ dd = [byte for byte in textwrap.wrap(s, 2)] ++ dd.reverse() ++ return ''.join(dd) ++ ++ parts = current_id.split('-') ++ swapped_id = '-'.join([ ++ swap_bytestring(parts[0]), ++ swap_bytestring(parts[1]), ++ swap_bytestring(parts[2]), ++ parts[3], ++ parts[4] ++ ]) ++ ++ return previous_id == swapped_id ++ ++ + @contextmanager + def cd(newdir): + prevdir = os.getcwd() +diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py +index bc8b42c..1fb0565 100644 +--- a/tests/unittests/test_datasource/test_azure.py ++++ b/tests/unittests/test_datasource/test_azure.py +@@ -314,7 +314,7 @@ scbus-1 on xpt0 bus 0 + 'public-keys': [], + }) + +- self.instance_id = 'test-instance-id' ++ self.instance_id = 'D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8' + + def _dmi_mocks(key): + if key == 'system-uuid': +@@ -511,7 +511,7 @@ fdescfs /dev/fd fdescfs rw 0 0 + 'subnet': [{'address': '10.0.0.0', 'prefix': '24'}]}, + 'ipv6': {'ipAddress': []}, + 'macAddress': '000D3A047598'}]}}, +- 'instance-id': 'test-instance-id', ++ 'instance-id': 'D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8', + 'local-hostname': u'myhost', + 'random_seed': 'wild'} + +@@ -881,6 +881,24 @@ fdescfs /dev/fd fdescfs rw 0 0 + self.assertTrue(ret) + self.assertEqual('value', dsrc.metadata['test']) + ++ def test_instance_id_endianness(self): ++ """Return the previous iid when dmi uuid is the byteswapped iid.""" ++ ds = self._get_ds({'ovfcontent': construct_valid_ovf_env()}) ++ # byte-swapped previous ++ write_file( ++ os.path.join(self.paths.cloud_dir, 'data', 'instance-id'), ++ '544CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8') ++ ds.get_data() ++ self.assertEqual( ++ '544CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8', ds.metadata['instance-id']) ++ # not byte-swapped previous ++ write_file( ++ os.path.join(self.paths.cloud_dir, 'data', 'instance-id'), ++ '644CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8') ++ ds.get_data() ++ self.assertEqual( ++ 'D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8', ds.metadata['instance-id']) ++ + def test_instance_id_from_dmidecode_used(self): + ds = self._get_ds({'ovfcontent': construct_valid_ovf_env()}) + ds.get_data() +@@ -1080,7 +1098,7 @@ class TestAzureBounce(CiTestCase): + + def _dmi_mocks(key): + if key == 'system-uuid': +- return 'test-instance-id' ++ return 'D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8' + elif key == 'chassis-asset-tag': + return '7783-7084-3265-9085-8269-3286-77' + raise RuntimeError('should not get here') +diff --git a/tests/unittests/test_datasource/test_azure_helper.py b/tests/unittests/test_datasource/test_azure_helper.py +index bd006ab..7ad5cc1 100644 +--- a/tests/unittests/test_datasource/test_azure_helper.py ++++ b/tests/unittests/test_datasource/test_azure_helper.py +@@ -170,6 +170,25 @@ class TestGoalStateParsing(CiTestCase): + goal_state = self._get_goal_state(instance_id=instance_id) + self.assertEqual(instance_id, goal_state.instance_id) + ++ def test_instance_id_byte_swap(self): ++ """Return true when previous_iid is byteswapped current_iid""" ++ previous_iid = "D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" ++ current_iid = "544CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8" ++ self.assertTrue( ++ azure_helper.is_byte_swapped(previous_iid, current_iid)) ++ ++ def test_instance_id_no_byte_swap_same_instance_id(self): ++ previous_iid = "D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" ++ current_iid = "D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" ++ self.assertFalse( ++ azure_helper.is_byte_swapped(previous_iid, current_iid)) ++ ++ def test_instance_id_no_byte_swap_diff_instance_id(self): ++ previous_iid = "D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" ++ current_iid = "G0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" ++ self.assertFalse( ++ azure_helper.is_byte_swapped(previous_iid, current_iid)) ++ + def test_certificates_xml_parsed_and_fetched_correctly(self): + http_client = mock.MagicMock() + certificates_url = 'TestCertificatesUrl' +-- +1.8.3.1 + diff --git a/SOURCES/ci-azure-avoid.patch b/SOURCES/ci-azure-avoid.patch deleted file mode 100644 index 3507790..0000000 --- a/SOURCES/ci-azure-avoid.patch +++ /dev/null @@ -1,213 +0,0 @@ -From ba515fc24d309a40f5552b514b59381777d8ad0e Mon Sep 17 00:00:00 2001 -From: Eduardo Otubo -Date: Tue, 10 Mar 2020 16:04:18 +0100 -Subject: [PATCH] azure: avoid - -Message-id: <20200310160418.887-1-otubo@redhat.com> -Patchwork-id: 94221 -O-Subject: [RHEL-8.1.0/RHEL-7.8.z/RHEL-7.7.z cloud-init PATCH] azure: avoid re-running cloud-init when instance-id is byte-swapped (#84) -Bugzilla: 1810112 -RH-Acked-by: Vitaly Kuznetsov -RH-Acked-by: Mohammed Gamal - -commit 129b1c4ea250619bd7caed7aaffacc796b0139f2 -Author: AOhassan <37305877+AOhassan@users.noreply.github.com> -Date: Thu Dec 12 13:51:42 2019 -0800 - - azure: avoid re-running cloud-init when instance-id is byte-swapped (#84) - - Azure stores the instance ID with an incorrect byte ordering for the - first three hyphen delimited parts. This results in invalid - is_new_instance checks forcing Azure datasource to recrawl the metadata - service. - - When persisting instance-id from the metadata service, swap the - instance-id string byte order such that it is consistent with - that returned by dmi information. Check whether the instance-id - string is a byte-swapped match when determining correctly whether - the Azure platform instance-id has actually changed. - -Signed-off-by: Eduardo Otubo -Signed-off-by: Miroslav Rezanina ---- - cloudinit/sources/DataSourceAzure.py | 16 ++++++++++--- - cloudinit/sources/helpers/azure.py | 27 ++++++++++++++++++++++ - tests/unittests/test_datasource/test_azure.py | 24 ++++++++++++++++--- - .../unittests/test_datasource/test_azure_helper.py | 19 +++++++++++++++ - 4 files changed, 80 insertions(+), 6 deletions(-) - -diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py -index 5baf8da..66bbe5e 100755 ---- a/cloudinit/sources/DataSourceAzure.py -+++ b/cloudinit/sources/DataSourceAzure.py -@@ -28,7 +28,8 @@ from cloudinit.reporting import events - - from cloudinit.sources.helpers.azure import (azure_ds_reporter, - azure_ds_telemetry_reporter, -- get_metadata_from_fabric) -+ get_metadata_from_fabric, -+ is_byte_swapped) - - LOG = logging.getLogger(__name__) - -@@ -458,8 +459,7 @@ class DataSourceAzure(sources.DataSource): - seed = _get_random_seed() - if seed: - crawled_data['metadata']['random_seed'] = seed -- crawled_data['metadata']['instance-id'] = util.read_dmi_data( -- 'system-uuid') -+ crawled_data['metadata']['instance-id'] = self._iid() - - if perform_reprovision: - LOG.info("Reporting ready to Azure after getting ReprovisionData") -@@ -530,6 +530,16 @@ class DataSourceAzure(sources.DataSource): - # quickly (local check only) if self.instance_id is still valid - return sources.instance_id_matches_system_uuid(self.get_instance_id()) - -+ def _iid(self, previous=None): -+ prev_iid_path = os.path.join( -+ self.paths.get_cpath('data'), 'instance-id') -+ iid = util.read_dmi_data('system-uuid') -+ if os.path.exists(prev_iid_path): -+ previous = util.load_file(prev_iid_path).strip() -+ if is_byte_swapped(previous, iid): -+ return previous -+ return iid -+ - @azure_ds_telemetry_reporter - def setup(self, is_new_instance): - if self._negotiated is False: -diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py -index 82c4c8c..c2a57cc 100755 ---- a/cloudinit/sources/helpers/azure.py -+++ b/cloudinit/sources/helpers/azure.py -@@ -7,6 +7,7 @@ import re - import socket - import struct - import time -+import textwrap - - from cloudinit.net import dhcp - from cloudinit import stages -@@ -40,6 +41,32 @@ def azure_ds_telemetry_reporter(func): - return impl - - -+def is_byte_swapped(previous_id, current_id): -+ """ -+ Azure stores the instance ID with an incorrect byte ordering for the -+ first parts. This corrects the byte order such that it is consistent with -+ that returned by the metadata service. -+ """ -+ if previous_id == current_id: -+ return False -+ -+ def swap_bytestring(s, width=2): -+ dd = [byte for byte in textwrap.wrap(s, 2)] -+ dd.reverse() -+ return ''.join(dd) -+ -+ parts = current_id.split('-') -+ swapped_id = '-'.join([ -+ swap_bytestring(parts[0]), -+ swap_bytestring(parts[1]), -+ swap_bytestring(parts[2]), -+ parts[3], -+ parts[4] -+ ]) -+ -+ return previous_id == swapped_id -+ -+ - @contextmanager - def cd(newdir): - prevdir = os.getcwd() -diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py -index bc8b42c..1fb0565 100644 ---- a/tests/unittests/test_datasource/test_azure.py -+++ b/tests/unittests/test_datasource/test_azure.py -@@ -314,7 +314,7 @@ scbus-1 on xpt0 bus 0 - 'public-keys': [], - }) - -- self.instance_id = 'test-instance-id' -+ self.instance_id = 'D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8' - - def _dmi_mocks(key): - if key == 'system-uuid': -@@ -511,7 +511,7 @@ fdescfs /dev/fd fdescfs rw 0 0 - 'subnet': [{'address': '10.0.0.0', 'prefix': '24'}]}, - 'ipv6': {'ipAddress': []}, - 'macAddress': '000D3A047598'}]}}, -- 'instance-id': 'test-instance-id', -+ 'instance-id': 'D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8', - 'local-hostname': u'myhost', - 'random_seed': 'wild'} - -@@ -881,6 +881,24 @@ fdescfs /dev/fd fdescfs rw 0 0 - self.assertTrue(ret) - self.assertEqual('value', dsrc.metadata['test']) - -+ def test_instance_id_endianness(self): -+ """Return the previous iid when dmi uuid is the byteswapped iid.""" -+ ds = self._get_ds({'ovfcontent': construct_valid_ovf_env()}) -+ # byte-swapped previous -+ write_file( -+ os.path.join(self.paths.cloud_dir, 'data', 'instance-id'), -+ '544CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8') -+ ds.get_data() -+ self.assertEqual( -+ '544CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8', ds.metadata['instance-id']) -+ # not byte-swapped previous -+ write_file( -+ os.path.join(self.paths.cloud_dir, 'data', 'instance-id'), -+ '644CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8') -+ ds.get_data() -+ self.assertEqual( -+ 'D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8', ds.metadata['instance-id']) -+ - def test_instance_id_from_dmidecode_used(self): - ds = self._get_ds({'ovfcontent': construct_valid_ovf_env()}) - ds.get_data() -@@ -1080,7 +1098,7 @@ class TestAzureBounce(CiTestCase): - - def _dmi_mocks(key): - if key == 'system-uuid': -- return 'test-instance-id' -+ return 'D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8' - elif key == 'chassis-asset-tag': - return '7783-7084-3265-9085-8269-3286-77' - raise RuntimeError('should not get here') -diff --git a/tests/unittests/test_datasource/test_azure_helper.py b/tests/unittests/test_datasource/test_azure_helper.py -index bd006ab..7ad5cc1 100644 ---- a/tests/unittests/test_datasource/test_azure_helper.py -+++ b/tests/unittests/test_datasource/test_azure_helper.py -@@ -170,6 +170,25 @@ class TestGoalStateParsing(CiTestCase): - goal_state = self._get_goal_state(instance_id=instance_id) - self.assertEqual(instance_id, goal_state.instance_id) - -+ def test_instance_id_byte_swap(self): -+ """Return true when previous_iid is byteswapped current_iid""" -+ previous_iid = "D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" -+ current_iid = "544CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8" -+ self.assertTrue( -+ azure_helper.is_byte_swapped(previous_iid, current_iid)) -+ -+ def test_instance_id_no_byte_swap_same_instance_id(self): -+ previous_iid = "D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" -+ current_iid = "D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" -+ self.assertFalse( -+ azure_helper.is_byte_swapped(previous_iid, current_iid)) -+ -+ def test_instance_id_no_byte_swap_diff_instance_id(self): -+ previous_iid = "D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" -+ current_iid = "G0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8" -+ self.assertFalse( -+ azure_helper.is_byte_swapped(previous_iid, current_iid)) -+ - def test_certificates_xml_parsed_and_fetched_correctly(self): - http_client = mock.MagicMock() - certificates_url = 'TestCertificatesUrl' --- -1.8.3.1 - diff --git a/SOURCES/ci-cmd-main.py-Fix-missing-modules-init-key-in-modes-di.patch b/SOURCES/ci-cmd-main.py-Fix-missing-modules-init-key-in-modes-di.patch new file mode 100644 index 0000000..a8ed261 --- /dev/null +++ b/SOURCES/ci-cmd-main.py-Fix-missing-modules-init-key-in-modes-di.patch @@ -0,0 +1,67 @@ +From a3b9673481bbe2fa35986aa757fd5321c3a7a371 Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Wed, 12 Feb 2020 13:08:38 +0100 +Subject: [PATCH] cmd:main.py: Fix missing 'modules-init' key in modes dict + +RH-Author: Eduardo Otubo +Message-id: <20200212130838.24592-1-otubo@redhat.com> +Patchwork-id: 93781 +O-Subject: [RHEL-7.9/RHEL-8.2.0 cloud-init PATCH] cmd:main.py: Fix missing 'modules-init' key in modes dict +Bugzilla: 1802140 +RH-Acked-by: Cathy Avery +RH-Acked-by: Mohammed Gamal + +BZ: 1673170 +BRANCH: rhel7/master-18.5 +UPSTREAM: bdd9c0ac +BREW: 26372362 + +BZ: 1802140 +BRANCH: rhel820/master-18.5 +UPSTREAM: bdd9c0ac +BREW: 26372415 + +commit 96557ca26a73c490aee74a811c3a44ef1ac11d84 +Author: Antonio Romito +Date: Tue Apr 9 14:54:23 2019 +0000 + + cmd:main.py: Fix missing 'modules-init' key in modes dict + + Cloud-init's main.py will fail when presented with a new + stage name 'modules-init' if upgrading an older cloud-init. + Fix this by initializing unknown stage names before accessing. + + LP: #1815109 + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + cloudinit/cmd/main.py | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/cloudinit/cmd/main.py b/cloudinit/cmd/main.py +index 933c019..a5446da 100644 +--- a/cloudinit/cmd/main.py ++++ b/cloudinit/cmd/main.py +@@ -632,13 +632,14 @@ def status_wrapper(name, args, data_d=None, link_d=None): + 'start': None, + 'finished': None, + } ++ + if status is None: + status = {'v1': {}} +- for m in modes: +- status['v1'][m] = nullstatus.copy() + status['v1']['datasource'] = None +- elif mode not in status['v1']: +- status['v1'][mode] = nullstatus.copy() ++ ++ for m in modes: ++ if m not in status['v1']: ++ status['v1'][m] = nullstatus.copy() + + v1 = status['v1'] + v1['stage'] = mode +-- +1.8.3.1 + diff --git a/SOURCES/ci-net-add-is_master-check-for-filtering-device-list.patch b/SOURCES/ci-net-add-is_master-check-for-filtering-device-list.patch new file mode 100644 index 0000000..f71df31 --- /dev/null +++ b/SOURCES/ci-net-add-is_master-check-for-filtering-device-list.patch @@ -0,0 +1,101 @@ +From de86e93cc7993e068b7328bf69ec08b0aa02ca98 Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Wed, 19 Feb 2020 13:32:56 +0100 +Subject: [PATCH 3/3] net: add is_master check for filtering device list + +RH-Author: Eduardo Otubo +Message-id: <20200219133256.9544-3-otubo@redhat.com> +Patchwork-id: 93937 +O-Subject: [RHEL-7.9 cloud-init PATCHv2 2/2] net: add is_master check for filtering device list +Bugzilla: 1768770 +RH-Acked-by: Mohammed Gamal +RH-Acked-by: Vitaly Kuznetsov + +commit 059d049c57cac02cdeaca832233a19712e0b4ded +Author: Ryan Harper +Date: Tue Sep 17 10:11:00 2019 +0000 + + net: add is_master check for filtering device list + + Some network devices are transformed into a bond via kernel magic + and do not have the 'bonding' sysfs attribute, but like a bond they + have a duplicate MAC of other bond members. On Azure Advanced + Networking SRIOV devices are auto bonded and will have the same MAC + as the HyperV nic. We can detect this via the 'master' sysfs attribute + in the device sysfs path and this patch adds this to the list of devices + we ignore when enumerating device lists. + + LP: #1844191 + +Conflicts: Removing checks `has_master()' for net failover functions. Such +functions are not present because are not required so far. + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + cloudinit/net/__init__.py | 6 ++++++ + cloudinit/net/tests/test_init.py | 17 +++++++++++++++++ + 2 files changed, 23 insertions(+) + +diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py +index e758006..41659b1 100644 +--- a/cloudinit/net/__init__.py ++++ b/cloudinit/net/__init__.py +@@ -108,6 +108,10 @@ def is_bond(devname): + return os.path.exists(sys_dev_path(devname, "bonding")) + + ++def has_master(devname): ++ return os.path.exists(sys_dev_path(devname, path="master")) ++ ++ + def is_renamed(devname): + """ + /* interface name assignment types (sysfs name_assign_type attribute) */ +@@ -624,6 +628,8 @@ def get_interfaces(): + continue + if is_bond(name): + continue ++ if has_master(name): ++ continue + mac = get_interface_mac(name) + # some devices may not have a mac (tun0) + if not mac: +diff --git a/cloudinit/net/tests/test_init.py b/cloudinit/net/tests/test_init.py +index f55c31e..5519867 100644 +--- a/cloudinit/net/tests/test_init.py ++++ b/cloudinit/net/tests/test_init.py +@@ -157,6 +157,12 @@ class TestReadSysNet(CiTestCase): + ensure_file(os.path.join(self.sysdir, 'eth0', 'bonding')) + self.assertTrue(net.is_bond('eth0')) + ++ def test_has_master(self): ++ """has_master is True when /sys/net/devname/master exists.""" ++ self.assertFalse(net.has_master('enP1s1')) ++ ensure_file(os.path.join(self.sysdir, 'enP1s1', 'master')) ++ self.assertTrue(net.has_master('enP1s1')) ++ + def test_is_vlan(self): + """is_vlan is True when /sys/net/devname/uevent has DEVTYPE=vlan.""" + ensure_file(os.path.join(self.sysdir, 'eth0', 'uevent')) +@@ -364,6 +370,17 @@ class TestGetInterfaceMAC(CiTestCase): + expected = [('eth2', 'aa:bb:cc:aa:bb:cc', None, None)] + self.assertEqual(expected, net.get_interfaces()) + ++ def test_get_interfaces_by_mac_skips_master_devs(self): ++ """Ignore interfaces with a master device which would have dup mac.""" ++ mac1 = mac2 = 'aa:bb:cc:aa:bb:cc' ++ write_file(os.path.join(self.sysdir, 'eth1', 'addr_assign_type'), '0') ++ write_file(os.path.join(self.sysdir, 'eth1', 'address'), mac1) ++ write_file(os.path.join(self.sysdir, 'eth1', 'master'), "blah") ++ write_file(os.path.join(self.sysdir, 'eth2', 'addr_assign_type'), '0') ++ write_file(os.path.join(self.sysdir, 'eth2', 'address'), mac2) ++ expected = [('eth2', mac2, None, None)] ++ self.assertEqual(expected, net.get_interfaces()) ++ + + class TestInterfaceHasOwnMAC(CiTestCase): + +-- +1.8.3.1 + diff --git a/SOURCES/ci-net-skip-bond-interfaces-in-get_interfaces.patch b/SOURCES/ci-net-skip-bond-interfaces-in-get_interfaces.patch new file mode 100644 index 0000000..c193ee9 --- /dev/null +++ b/SOURCES/ci-net-skip-bond-interfaces-in-get_interfaces.patch @@ -0,0 +1,45 @@ +From bb7f0106264091ea4e0753f2a5c1276e9020045c Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Wed, 19 Feb 2020 13:32:55 +0100 +Subject: [PATCH 2/3] net: skip bond interfaces in get_interfaces + +RH-Author: Eduardo Otubo +Message-id: <20200219133256.9544-2-otubo@redhat.com> +Patchwork-id: 93936 +O-Subject: [RHEL-7.9 cloud-init PATCHv2 1/2] net: skip bond interfaces in get_interfaces +Bugzilla: 1768770 +RH-Acked-by: Mohammed Gamal +RH-Acked-by: Vitaly Kuznetsov + +commit e5f542132568a8da63823f478cea52bfb28ac655 +Author: Stanislav Makar +Date: Mon Jul 15 20:12:31 2019 +0000 + + net: skip bond interfaces in get_interfaces + + bonds may inherit mac address from a physical interface + + LP: #1812857 + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + cloudinit/net/__init__.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py +index 3642fb1..e758006 100644 +--- a/cloudinit/net/__init__.py ++++ b/cloudinit/net/__init__.py +@@ -622,6 +622,8 @@ def get_interfaces(): + continue + if is_vlan(name): + continue ++ if is_bond(name): ++ continue + mac = get_interface_mac(name) + # some devices may not have a mac (tun0) + if not mac: +-- +1.8.3.1 + diff --git a/SOURCES/ci-util-json.dumps-on-python-2.7-will-handle-UnicodeDec.patch b/SOURCES/ci-util-json.dumps-on-python-2.7-will-handle-UnicodeDec.patch new file mode 100644 index 0000000..d9cdbcc --- /dev/null +++ b/SOURCES/ci-util-json.dumps-on-python-2.7-will-handle-UnicodeDec.patch @@ -0,0 +1,144 @@ +From 4f1c3f5be0306da485135544ced4a676753a9373 Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Wed, 16 Oct 2019 12:10:24 +0200 +Subject: [PATCH 2/2] util: json.dumps on python 2.7 will handle + UnicodeDecodeError on binary + +RH-Author: Eduardo Otubo +Message-id: <20191016121024.23694-1-otubo@redhat.com> +Patchwork-id: 91812 +O-Subject: [RHEL-7.8/RHEL-8.1.0 cloud-init PATCH] util: json.dumps on python 2.7 will handle UnicodeDecodeError on binary +Bugzilla: 1744718 +RH-Acked-by: Vitaly Kuznetsov +RH-Acked-by: Mohammed Gamal + +commit 067516d7bc917e4921b9f1424b7a64e92cae0ad2 +Author: Chad Smith +Date: Fri Sep 27 20:46:00 2019 +0000 + + util: json.dumps on python 2.7 will handle UnicodeDecodeError on binary + + Since python 2.7 doesn't handle UnicodeDecodeErrors with the default + handler + + LP: #1801364 + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + cloudinit/sources/tests/test_init.py | 12 +++++------- + cloudinit/tests/test_util.py | 20 ++++++++++++++++++++ + cloudinit/util.py | 27 +++++++++++++++++++++++++-- + 3 files changed, 50 insertions(+), 9 deletions(-) + +diff --git a/cloudinit/sources/tests/test_init.py b/cloudinit/sources/tests/test_init.py +index 6378e98..9698261 100644 +--- a/cloudinit/sources/tests/test_init.py ++++ b/cloudinit/sources/tests/test_init.py +@@ -457,19 +457,17 @@ class TestDataSource(CiTestCase): + instance_json['ds']['meta_data']) + + @skipIf(not six.PY2, "Only python2 hits UnicodeDecodeErrors on non-utf8") +- def test_non_utf8_encoding_logs_warning(self): +- """When non-utf-8 values exist in py2 instance-data is not written.""" ++ def test_non_utf8_encoding_gets_b64encoded(self): ++ """When non-utf-8 values exist in py2 instance-data is b64encoded.""" + tmp = self.tmp_dir() + datasource = DataSourceTestSubclassNet( + self.sys_cfg, self.distro, Paths({'run_dir': tmp}), + custom_metadata={'key1': 'val1', 'key2': {'key2.1': b'ab\xaadef'}}) + self.assertTrue(datasource.get_data()) + json_file = self.tmp_path(INSTANCE_JSON_FILE, tmp) +- self.assertFalse(os.path.exists(json_file)) +- self.assertIn( +- "WARNING: Error persisting instance-data.json: 'utf8' codec can't" +- " decode byte 0xaa in position 2: invalid start byte", +- self.logs.getvalue()) ++ instance_json = util.load_json(util.load_file(json_file)) ++ key21_value = instance_json['ds']['meta_data']['key2']['key2.1'] ++ self.assertEqual('ci-b64:' + util.b64e(b'ab\xaadef'), key21_value) + + def test_get_hostname_subclass_support(self): + """Validate get_hostname signature on all subclasses of DataSource.""" +diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py +index e3d2dba..f4f95e9 100644 +--- a/cloudinit/tests/test_util.py ++++ b/cloudinit/tests/test_util.py +@@ -2,7 +2,9 @@ + + """Tests for cloudinit.util""" + ++import base64 + import logging ++import json + import platform + + import cloudinit.util as util +@@ -528,6 +530,24 @@ class TestGetLinuxDistro(CiTestCase): + self.assertEqual(('foo', '1.1', 'aarch64'), dist) + + ++class TestJsonDumps(CiTestCase): ++ def test_is_str(self): ++ """json_dumps should return a string.""" ++ self.assertTrue(isinstance(util.json_dumps({'abc': '123'}), str)) ++ ++ def test_utf8(self): ++ smiley = '\\ud83d\\ude03' ++ self.assertEqual( ++ {'smiley': smiley}, ++ json.loads(util.json_dumps({'smiley': smiley}))) ++ ++ def test_non_utf8(self): ++ blob = b'\xba\x03Qx-#y\xea' ++ self.assertEqual( ++ {'blob': 'ci-b64:' + base64.b64encode(blob).decode('utf-8')}, ++ json.loads(util.json_dumps({'blob': blob}))) ++ ++ + @mock.patch('os.path.exists') + class TestIsLXD(CiTestCase): + +diff --git a/cloudinit/util.py b/cloudinit/util.py +index a84112a..2c9ac66 100644 +--- a/cloudinit/util.py ++++ b/cloudinit/util.py +@@ -1590,10 +1590,33 @@ def json_serialize_default(_obj): + return 'Warning: redacted unserializable type {0}'.format(type(_obj)) + + ++def json_preserialize_binary(data): ++ """Preserialize any discovered binary values to avoid json.dumps issues. ++ ++ Used only on python 2.7 where default type handling is not honored for ++ failure to encode binary data. LP: #1801364. ++ TODO(Drop this function when py2.7 support is dropped from cloud-init) ++ """ ++ data = obj_copy.deepcopy(data) ++ for key, value in data.items(): ++ if isinstance(value, (dict)): ++ data[key] = json_preserialize_binary(value) ++ if isinstance(value, bytes): ++ data[key] = 'ci-b64:{0}'.format(b64e(value)) ++ return data ++ ++ + def json_dumps(data): + """Return data in nicely formatted json.""" +- return json.dumps(data, indent=1, sort_keys=True, +- separators=(',', ': '), default=json_serialize_default) ++ try: ++ return json.dumps( ++ data, indent=1, sort_keys=True, separators=(',', ': '), ++ default=json_serialize_default) ++ except UnicodeDecodeError: ++ if sys.version_info[:2] == (2, 7): ++ data = json_preserialize_binary(data) ++ return json.dumps(data) ++ raise + + + def yaml_dumps(obj, explicit_start=True, explicit_end=True): +-- +1.8.3.1 + diff --git a/SPECS/cloud-init.spec b/SPECS/cloud-init.spec index 79d6f6d..e452c36 100644 --- a/SPECS/cloud-init.spec +++ b/SPECS/cloud-init.spec @@ -6,7 +6,7 @@ Name: cloud-init Version: 18.5 -Release: 7%{?dist}.1 +Release: 12%{?dist} Summary: Cloud instance init scripts Group: System Environment/Base @@ -41,8 +41,22 @@ Patch17: ci-cc_mounts-check-if-mount-a-on-no-change-fstab-path.patch Patch18: ci-Revert-azure-ensure-that-networkmanager-hook-script-.patch # For bz#1691986 - [Azure] [RHEL 8.1] Cloud-init fixes to support fast provisioning for Azure Patch19: ci-Azure-Return-static-fallback-address-as-if-failed-to.patch -# For bz#1810112 - [RHEL-8] cloud-init Azure byte swap (hyperV Gen2 Only) [rhel-8.1.0.z] -Patch20: ci-azure-avoid.patch +# For bz#1706482 - [cloud-init][RHVM]cloud-init network configuration does not persist reboot [RHEL 8.2.0] +Patch20: ci-Fix-for-network-configuration-not-persisting-after-r.patch +# For bz#1744718 - [cloud-init][RHEL8][OpenStack] cloud-init can't persist instance-data.json +Patch21: ci-util-json.dumps-on-python-2.7-will-handle-UnicodeDec.patch +# For bz#1785648 - [RHEL8]cloud-user added to wheel group and sudoers.d causes 'sudo -v' prompts for passphrase +Patch22: ci-Removing-cloud-user-from-wheel.patch +# For bz#1802140 - [cloud-init][RHEL8.2]cloud-init cloud-final.service fail with KeyError: 'modules-init' after upgrade to version 18.2-1.el7_6.1 in RHV +Patch23: ci-cmd-main.py-Fix-missing-modules-init-key-in-modes-di.patch +# For bz#1788684 - [RHEL-8] cloud-init Azure byte swap (hyperV Gen2 Only) +Patch24: ci-azure-avoid-re-running-cloud-init-when-instance-id-i.patch +# For bz#1768770 - cloud-init complaining about enslaved mac +Patch25: ci-net-skip-bond-interfaces-in-get_interfaces.patch +# For bz#1768770 - cloud-init complaining about enslaved mac +Patch26: ci-net-add-is_master-check-for-filtering-device-list.patch +# For bz#1807797 - [cloud-init][RHEL-8.2.0] /etc/resolv.conf lose config after reboot (initial instance is ok) +Patch27: ci-Remove-race-condition-between-cloud-init-and-Network.patch BuildArch: noarch @@ -137,6 +151,12 @@ mv $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/hook-network-manager \ mkdir -p $RPM_BUILD_ROOT%{_unitdir} cp rhel/systemd/* $RPM_BUILD_ROOT%{_unitdir}/ +[ ! -d $RPM_BUILD_ROOT/usr/lib/systemd/system-generators ] && mkdir -p $RPM_BUILD_ROOT/usr/lib/systemd/system-generators +cp -p systemd/cloud-init-generator $RPM_BUILD_ROOT/usr/lib/systemd/system-generators + +[ ! -d $RPM_BUILD_ROOT/usr/lib/%{name} ] && mkdir -p $RPM_BUILD_ROOT/usr/lib/%{name} +cp -p tools/ds-identify $RPM_BUILD_ROOT/usr/lib/%{name}/ds-identify + %clean rm -rf $RPM_BUILD_ROOT @@ -150,6 +170,7 @@ if [ $1 -eq 1 ] ; then /bin/systemctl enable cloud-final.service >/dev/null 2>&1 || : /bin/systemctl enable cloud-init.service >/dev/null 2>&1 || : /bin/systemctl enable cloud-init-local.service >/dev/null 2>&1 || : + /bin/systemctl enable cloud-init.target >/dev/null 2>&1 || : elif [ $1 -eq 2 ]; then # Upgrade. If the upgrade is from a version older than 0.7.9-8, # there will be stale systemd config @@ -164,6 +185,9 @@ elif [ $1 -eq 2 ]; then /bin/systemctl is-enabled cloud-init-local.service >/dev/null 2>&1 && /bin/systemctl reenable cloud-init-local.service >/dev/null 2>&1 || : + + /bin/systemctl is-enabled cloud-init.target >/dev/null 2>&1 && + /bin/systemctl reenable cloud-init.target >/dev/null 2>&1 || : fi %preun @@ -173,6 +197,7 @@ if [ $1 -eq 0 ] ; then /bin/systemctl --no-reload disable cloud-final.service >/dev/null 2>&1 || : /bin/systemctl --no-reload disable cloud-init.service >/dev/null 2>&1 || : /bin/systemctl --no-reload disable cloud-init-local.service >/dev/null 2>&1 || : + /bin/systemctl --no-reload disable cloud-init.target >/dev/null 2>&1 || : # One-shot services -> no need to stop fi @@ -194,6 +219,7 @@ fi %{_unitdir}/cloud-final.service %{_unitdir}/cloud-init-local.service %{_unitdir}/cloud-init.service +%{_unitdir}/cloud-init.target %{_tmpfilesdir}/%{name}.conf %{python3_sitelib}/* %{_libexecdir}/%{name} @@ -205,15 +231,45 @@ fi %{_udevrulesdir}/66-azure-ephemeral.rules %{_sysconfdir}/bash_completion.d/cloud-init %{_bindir}/cloud-id +/usr/lib/%{name}/ds-identify +/usr/lib/systemd/system-generators/cloud-init-generator + %dir %{_sysconfdir}/rsyslog.d %config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf %changelog -* Mon Mar 16 2020 Miroslav Rezanina - 18.5-7.el8_1_0.1 -- ci-azure-avoid.patch [bz#1810112] -- Resolves: bz#1810112 - ([RHEL-8] cloud-init Azure byte swap (hyperV Gen2 Only) [rhel-8.1.0.z]) +* Tue Mar 10 2020 Miroslav Rezanina - 18.5-12.el8 +- ci-Remove-race-condition-between-cloud-init-and-Network.patch [bz#1807797] +- Resolves: bz#1807797 + ([cloud-init][RHEL-8.2.0] /etc/resolv.conf lose config after reboot (initial instance is ok)) + +* Thu Feb 20 2020 Miroslav Rezanina - 18.5-11.el8 +- ci-azure-avoid-re-running-cloud-init-when-instance-id-i.patch [bz#1788684] +- ci-net-skip-bond-interfaces-in-get_interfaces.patch [bz#1768770] +- ci-net-add-is_master-check-for-filtering-device-list.patch [bz#1768770] +- Resolves: bz#1768770 + (cloud-init complaining about enslaved mac) +- Resolves: bz#1788684 + ([RHEL-8] cloud-init Azure byte swap (hyperV Gen2 Only)) + +* Thu Feb 13 2020 Miroslav Rezanina - 18.5-10.el8 +- ci-cmd-main.py-Fix-missing-modules-init-key-in-modes-di.patch [bz#1802140] +- Resolves: bz#1802140 + ([cloud-init][RHEL8.2]cloud-init cloud-final.service fail with KeyError: 'modules-init' after upgrade to version 18.2-1.el7_6.1 in RHV) + +* Tue Jan 28 2020 Miroslav Rezanina - 18.5-9.el8 +- ci-Removing-cloud-user-from-wheel.patch [bz#1785648] +- Resolves: bz#1785648 + ([RHEL8]cloud-user added to wheel group and sudoers.d causes 'sudo -v' prompts for passphrase) + +* Fri Nov 22 2019 Miroslav Rezanina - 18.5-8.el8 +- ci-Fix-for-network-configuration-not-persisting-after-r.patch [bz#1706482] +- ci-util-json.dumps-on-python-2.7-will-handle-UnicodeDec.patch [bz#1744718] +- Resolves: bz#1706482 + ([cloud-init][RHVM]cloud-init network configuration does not persist reboot [RHEL 8.2.0]) +- Resolves: bz#1744718 + ([cloud-init][RHEL8][OpenStack] cloud-init can't persist instance-data.json) * Mon Jul 15 2019 Miroslav Rezanina - 18.5-7.el8 - Fixing TPS [bz#1729864]