config: Handle interface list in CloudRegion.get_all_version_data

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 "<frozen runpy>", line 198, in _run_module_as_main
    File "<frozen runpy>", line 88, in _run_code
    File "/dev/cfg-test/__main__.py", line 25, in <module>
      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 <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane
2025-06-05 17:25:21 +01:00
parent 36a7ccb6f5
commit 7c1e42b417
2 changed files with 22 additions and 8 deletions

View File

@@ -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,

View File

@@ -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