Get rid of the oslo.config requirement

It is only used to populate the list of supported Session options.
Use openstacksdk to create a session with all arguments instead.
Since it's already a dependency of osc-lib, this changes adds no
new dependencies, while substantially simplifying the code.

Change-Id: I6100f94c18cbf3e90d4a6d3ec2a3fc74ebea53a5
This commit is contained in:
Dmitry Tantsur 2020-04-06 13:49:27 +02:00
parent 565a256f4e
commit b21dc1dddd
4 changed files with 45 additions and 51 deletions

View File

@ -12,7 +12,7 @@
import logging import logging
from keystoneauth1 import loading as kaloading from openstack import config
from oslo_utils import importutils from oslo_utils import importutils
from ironicclient.common.i18n import _ from ironicclient.common.i18n import _
@ -22,7 +22,9 @@ LOG = logging.getLogger(__name__)
def get_client(api_version, auth_type=None, os_ironic_api_version=None, def get_client(api_version, auth_type=None, os_ironic_api_version=None,
max_retries=None, retry_interval=None, session=None, **kwargs): max_retries=None, retry_interval=None, session=None,
valid_interfaces=None, interface=None, service_type=None,
region_name=None, **kwargs):
"""Get an authenticated client, based on the credentials. """Get an authenticated client, based on the credentials.
:param api_version: the API version to use. Valid value: '1'. :param api_version: the API version to use. Valid value: '1'.
@ -33,6 +35,12 @@ def get_client(api_version, auth_type=None, os_ironic_api_version=None,
of conflict error. of conflict error.
:param session: An existing keystoneauth session. Will be created from :param session: An existing keystoneauth session. Will be created from
kwargs if not provided. kwargs if not provided.
:param valid_interfaces: List of valid endpoint interfaces to use if
the bare metal endpoint is not provided.
:param interface: An alias for valid_interfaces.
:param service_type: Bare metal endpoint service type.
:param region_name: Name of the region to use when searching the bare metal
endpoint.
:param kwargs: all the other params that are passed to keystoneauth. :param kwargs: all the other params that are passed to keystoneauth.
""" """
# TODO(TheJulia): At some point, we should consider possibly noting # TODO(TheJulia): At some point, we should consider possibly noting
@ -50,30 +58,22 @@ def get_client(api_version, auth_type=None, os_ironic_api_version=None,
auth_type = 'token' auth_type = 'token'
else: else:
auth_type = 'password' auth_type = 'password'
if not session: if not session:
loader = kaloading.get_plugin_loader(auth_type) # TODO(dtantsur): consider flipping load_yaml_config to True to support
loader_options = loader.get_options() # the clouds.yaml format.
# option.name looks like 'project-name', while dest will be the actual region = config.get_cloud_region(load_yaml_config=False,
# argument name to which the value will be passed to (project_name) load_envvars=False,
auth_options = [o.dest for o in loader_options] auth_type=auth_type,
# Include deprecated names as well **kwargs)
auth_options.extend([d.dest for o in loader_options session = region.get_session()
for d in o.deprecated])
auth_kwargs = {k: v for (k, v) in kwargs.items() if k in auth_options}
auth_plugin = loader.load_from_options(**auth_kwargs)
# Let keystoneauth do the necessary parameter conversions
session_loader = kaloading.session.Session()
session_opts = {k: v for (k, v) in kwargs.items() if k in
[o.dest for o in session_loader.get_conf_options()]}
session = session_loader.load_from_options(auth=auth_plugin,
**session_opts)
# Make sure we also pass the endpoint interface to the HTTP client. # Make sure we also pass the endpoint interface to the HTTP client.
# NOTE(gyee/efried): 'interface' in ksa config is deprecated in favor of # NOTE(gyee/efried): 'interface' in ksa config is deprecated in favor of
# 'valid_interfaces'. So, since the caller may be deriving kwargs from # 'valid_interfaces'. So, since the caller may be deriving kwargs from
# conf, accept 'valid_interfaces' first. But keep support for 'interface', # conf, accept 'valid_interfaces' first. But keep support for 'interface',
# in case the caller is deriving kwargs from, say, an existing Adapter. # in case the caller is deriving kwargs from, say, an existing Adapter.
interface = kwargs.get('valid_interfaces', kwargs.get('interface')) interface = valid_interfaces or interface
endpoint = kwargs.get('endpoint') endpoint = kwargs.get('endpoint')
if not endpoint: if not endpoint:
@ -84,9 +84,9 @@ def get_client(api_version, auth_type=None, os_ironic_api_version=None,
# empty or None so there's no need to set it to publicURL # empty or None so there's no need to set it to publicURL
# explicitly. # explicitly.
endpoint = session.get_endpoint( endpoint = session.get_endpoint(
service_type=kwargs.get('service_type') or 'baremetal', service_type=service_type or 'baremetal',
interface=interface, interface=interface,
region_name=kwargs.get('region_name') region_name=region_name,
) )
except Exception as e: except Exception as e:
raise exc.AmbiguousAuthSystem( raise exc.AmbiguousAuthSystem(

View File

@ -12,7 +12,7 @@
import mock import mock
from keystoneauth1 import loading as kaloading from openstack import config
from ironicclient import client as iroclient from ironicclient import client as iroclient
from ironicclient.common import filecache from ironicclient.common import filecache
@ -25,50 +25,39 @@ from ironicclient.v1 import client as v1
class ClientTest(utils.BaseTestCase): class ClientTest(utils.BaseTestCase):
@mock.patch.object(filecache, 'retrieve_data', autospec=True) @mock.patch.object(filecache, 'retrieve_data', autospec=True)
@mock.patch.object(kaloading.session, 'Session', autospec=True) @mock.patch.object(config, 'get_cloud_region', autospec=True)
@mock.patch.object(kaloading, 'get_plugin_loader', autospec=True) def _test_get_client(self, mock_cloud_region, mock_retrieve_data,
def _test_get_client(self, mock_ks_loader, mock_ks_session, version=None, auth='password',
mock_retrieve_data, version=None, expected_interface=None, **kwargs):
auth='password', expected_interface=None, **kwargs): session = mock_cloud_region.return_value.get_session.return_value
session = mock_ks_session.return_value.load_from_options.return_value
session.get_endpoint.return_value = 'http://localhost:6385/v1/f14b4123' session.get_endpoint.return_value = 'http://localhost:6385/v1/f14b4123'
class Opt(object):
def __init__(self, name):
self.dest = name
session_loader_options = [
Opt('insecure'), Opt('cafile'), Opt('certfile'), Opt('keyfile'),
Opt('timeout')]
mock_ks_session.return_value.get_conf_options.return_value = (
session_loader_options)
mock_ks_loader.return_value.load_from_options.return_value = 'auth'
mock_retrieve_data.return_value = version mock_retrieve_data.return_value = version
client = iroclient.get_client('1', **kwargs) client = iroclient.get_client('1', **kwargs)
mock_ks_loader.assert_called_once_with(auth) expected_version = kwargs.pop('os_ironic_api_version', None)
session_opts = {k: v for (k, v) in kwargs.items() if k in kwargs.pop('interface', None)
[o.dest for o in session_loader_options]} kwargs.pop('valid_interfaces', None)
mock_ks_session.return_value.load_from_options.assert_called_once_with(
auth='auth', **session_opts)
get_endpoint_call = mock.call( get_endpoint_call = mock.call(
service_type=kwargs.get('service_type') or 'baremetal', service_type=kwargs.pop('service_type', None) or 'baremetal',
interface=expected_interface, interface=expected_interface,
region_name=kwargs.get('region_name')) region_name=kwargs.pop('region_name', None))
if not {'endpoint'}.intersection(kwargs): mock_cloud_region.assert_called_once_with(load_yaml_config=False,
load_envvars=False,
auth_type=auth, **kwargs)
if 'endpoint' not in kwargs:
self.assertEqual([get_endpoint_call], self.assertEqual([get_endpoint_call],
session.get_endpoint.call_args_list) session.get_endpoint.call_args_list)
else: else:
# we use adaper.get_endpoint instead of session.get_endpoint # we use adaper.get_endpoint instead of session.get_endpoint
self.assertFalse(session.get_endpoint.called) self.assertFalse(session.get_endpoint.called)
if 'os_ironic_api_version' in kwargs: if expected_version is not None:
# NOTE(TheJulia): This does not test the negotiation logic # NOTE(TheJulia): This does not test the negotiation logic
# as a request must be triggered in order for any version # as a request must be triggered in order for any version
# negotiation actions to occur. # negotiation actions to occur.
self.assertEqual(0, mock_retrieve_data.call_count) self.assertEqual(0, mock_retrieve_data.call_count)
self.assertEqual(kwargs['os_ironic_api_version'], self.assertEqual(expected_version, client.current_api_version)
client.current_api_version)
self.assertFalse(client.is_api_version_negotiated) self.assertFalse(client.is_api_version_negotiated)
else: else:
mock_retrieve_data.assert_called_once_with( mock_retrieve_data.assert_called_once_with(

View File

@ -0,0 +1,6 @@
---
upgrade:
- |
When no session is provided in the ``get_client`` call, a session is now
created using OpenStackSDK. Only arguments that are supported by it are
supported now.

View File

@ -9,7 +9,6 @@ jsonschema>=2.6.0 # MIT
keystoneauth1>=3.4.0 # Apache-2.0 keystoneauth1>=3.4.0 # Apache-2.0
openstacksdk>=0.18.0 # Apache-2.0 openstacksdk>=0.18.0 # Apache-2.0
osc-lib>=1.10.0 # Apache-2.0 osc-lib>=1.10.0 # Apache-2.0
oslo.config>=5.2.0 # Apache-2.0
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0 oslo.utils>=3.33.0 # Apache-2.0
PyYAML>=3.12 # MIT PyYAML>=3.12 # MIT