From 7c1e42b4175cd34a2eefb86996221fa55ab895d2 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 5 Jun 2025 17:25:21 +0100 Subject: [PATCH] config: Handle interface list in CloudRegion.get_all_version_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a connection is created via an oslo.config cfg.ConfigOpts object, then it's possible for interface to be a list of interfaces (due to valid_interfaces). We were not previously handling this, resulting in the following error: ❯ python -m cfg_test --config-file sample.conf Traceback (most recent call last): File "", line 198, in _run_module_as_main File "", line 88, in _run_code File "/dev/cfg-test/__main__.py", line 25, in print(conn.config.get_all_version_data('placement')) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ File "/dev/openstacksdk/openstack/config/cloud_region.py", line 926, in get_all_version_data interface_versions = region_versions.get(interface, {}) TypeError: unhashable type: 'list' Correct this by iterating through all interfaces until we find a non-null version information. Change-Id: I6e5e1b0f5357afa0462703eb18b9f2da340e90a4 Signed-off-by: Stephen Finucane --- openstack/config/cloud_region.py | 28 +++++++++++++++++++++------- openstack/connection.py | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/openstack/config/cloud_region.py b/openstack/config/cloud_region.py index 75cba2c27..b7899358b 100644 --- a/openstack/config/cloud_region.py +++ b/openstack/config/cloud_region.py @@ -909,22 +909,36 @@ class CloudRegion: def get_all_version_data( self, service_type: str ) -> list[discover.VersionData]: + """Retrieve version data for the given service. + + :param service_type: The service to fetch version data for. + :returns: A `~keystoneauth1.discover.VersionData` object containing the + version data for the requested service. + """ # Seriously. Don't think about the existential crisis # that is the next line. You'll wind up in cthulhu's lair. service_type = self.get_service_type(service_type) region_name = self.get_region_name(service_type) + assert region_name is not None # narrow type + interface = self.get_interface(service_type) + assert interface is not None # narrow type + + interfaces = interface if isinstance(interface, list) else [interface] + versions = self.get_session().get_all_version_data( service_type=service_type, - interface=self.get_interface(service_type), + interface=interface, region_name=region_name, ) - region_versions = versions.get(region_name, {}) # type: ignore - interface_versions = region_versions.get( - self.get_interface(service_type), # type: ignore - {}, - ) - return interface_versions.get(service_type, []) + region_versions = versions.get(region_name, {}) + for interface in interfaces: + interface_versions = region_versions.get(interface, {}) + service_version_data = interface_versions.get(service_type) + if service_version_data is not None: + return service_version_data + + return [] def _get_endpoint_from_catalog( self, diff --git a/openstack/connection.py b/openstack/connection.py index 74bcdf777..b5b75c833 100644 --- a/openstack/connection.py +++ b/openstack/connection.py @@ -134,8 +134,8 @@ construct a Connection with the ``CONF`` object and an authenticated Session. .. code-block:: python from keystoneauth1 import loading as ks_loading - from oslo_config import cfg from openstack import connection + from oslo_config import cfg CONF = cfg.CONF