From 0e31866d6024618d9f638aa8c4eb3bc35ee136f8 Mon Sep 17 00:00:00 2001 From: Adrian Vladu Date: Fri, 5 Jun 2026 16:37:52 +0300 Subject: [PATCH] config_drive: ensure the search locations are ordered alphabetically The internal Python implementation for the configured config drive search locations is not deterministic. Make it deterministic by using alphabetically sorted order. In this case, the search order becomes: - type: iso, vfat - location: cdrom, hdd, partition Change-Id: I622700c9408d3acee6d44eabfd73c662df7e7cfd Signed-off-by: Adrian Vladu --- cloudbaseinit/constant.py | 11 ++++--- .../metadata/services/baseconfigdrive.py | 33 +++++++++++-------- .../metadata/services/test_baseconfigdrive.py | 6 ++-- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/cloudbaseinit/constant.py b/cloudbaseinit/constant.py index 3a7b772aa..3313d211c 100644 --- a/cloudbaseinit/constant.py +++ b/cloudbaseinit/constant.py @@ -13,11 +13,12 @@ # under the License. # Config Drive types and possible locations. -CD_TYPES = { - "vfat", # Visible device (with partition table). +# This order is respected. +CD_TYPES = [ "iso", # "Raw" format containing ISO bytes. -} -CD_LOCATIONS = { + "vfat", # Visible device (with partition table). +] +CD_LOCATIONS = [ # Look into optical devices. Only an ISO format could be # used here (vfat ignored). "cdrom", @@ -27,7 +28,7 @@ # Search through partitions for raw ISO content or through volumes # containing configuration drive's content. "partition", -} +] POLICY_IGNORE_ALL_FAILURES = "ignoreallfailures" diff --git a/cloudbaseinit/metadata/services/baseconfigdrive.py b/cloudbaseinit/metadata/services/baseconfigdrive.py index 0f8a6eb4c..641726ad9 100644 --- a/cloudbaseinit/metadata/services/baseconfigdrive.py +++ b/cloudbaseinit/metadata/services/baseconfigdrive.py @@ -39,31 +39,38 @@ def __init__(self, drive_label, metadata_file, self._metadata_file = metadata_file self._userdata_file = userdata_file self._metadata_path = None - self._searched_types = set() - self._searched_locations = set() + self._searched_types = list() + self._searched_locations = list() def _preprocess_options(self): - self._searched_types = set(CONF.config_drive.types) - self._searched_locations = set(CONF.config_drive.locations) + self._searched_types = sorted(set(CONF.config_drive.types)) + self._searched_locations = sorted(set(CONF.config_drive.locations)) # Deprecation backward compatibility. - if CONF.config_drive.raw_hdd: - self._searched_types.add("iso") - self._searched_locations.add("hdd") if CONF.config_drive.cdrom: - self._searched_types.add("iso") - self._searched_locations.add("cdrom") + self._searched_types.append("iso") + self._searched_locations.append("cdrom") + if CONF.config_drive.raw_hdd: + self._searched_types.append("iso") + self._searched_locations.append("hdd") if CONF.config_drive.vfat: - self._searched_types.add("vfat") - self._searched_locations.add("hdd") + self._searched_types.append("vfat") + self._searched_locations.append("hdd") # Check for invalid option values. - if self._searched_types | CD_TYPES != CD_TYPES: + SCD_TYPES = set(CD_TYPES) + if set(self._searched_types) | SCD_TYPES != SCD_TYPES: raise exception.CloudbaseInitException( "Invalid Config Drive types %s", self._searched_types) - if self._searched_locations | CD_LOCATIONS != CD_LOCATIONS: + SCD_LOCATIONS = set(CD_LOCATIONS) + if set(self._searched_locations) | SCD_LOCATIONS != SCD_LOCATIONS: raise exception.CloudbaseInitException( "Invalid Config Drive locations %s", self._searched_locations) + # Note(avladu): sort the order of the searched locations + # This is needed to be sure that the order is respected + # See: https://github.com/cloudbase/cloudbase-init/issues/200 + self._searched_types = sorted(set(self._searched_types)) + self._searched_locations = sorted(set(self._searched_locations)) def load(self): super(BaseConfigDriveService, self).load() diff --git a/cloudbaseinit/tests/metadata/services/test_baseconfigdrive.py b/cloudbaseinit/tests/metadata/services/test_baseconfigdrive.py index eae2bf710..a89451f4b 100644 --- a/cloudbaseinit/tests/metadata/services/test_baseconfigdrive.py +++ b/cloudbaseinit/tests/metadata/services/test_baseconfigdrive.py @@ -70,7 +70,7 @@ def _test_preprocess_options(self, fail=False): "cdrom": False, "vfat": True, # Deprecated options above. - "types": ["vfat", "iso"], + "types": ["iso", "vfat"], "locations": ["partition"] } contexts = [testutils.ConfPatcher(key, value, group="config_drive") @@ -78,9 +78,9 @@ def _test_preprocess_options(self, fail=False): with contexts[0], contexts[1], contexts[2], \ contexts[3], contexts[4]: self._config_drive._preprocess_options() - self.assertEqual({"vfat", "iso"}, + self.assertEqual(["iso", "vfat"], self._config_drive._searched_types) - self.assertEqual({"hdd", "partition"}, + self.assertEqual(["hdd", "partition"], self._config_drive._searched_locations) def test_preprocess_options_fail(self):