From 918775cb0109209561fd62f1b52a3d9f7cc226c6 Mon Sep 17 00:00:00 2001 From: Pavlo Shchelokovskyy Date: Wed, 27 Dec 2017 15:53:49 +0200 Subject: [PATCH] Add keystoneauth adapters Inspector sets API urls for ironic and swift from the config. The better way would be to discovery them from the keystone catalog. Supporting this requires to register keystoneauth adapter options to all config sections for service clients auth. swiftclient still does not support adapter session client, so pass all options from adapter explicitly. New options were added 'service_type`, `service_name`, `region_name` `endpoint_override`, `interfaces`. Related-Bug: #1699547 Change-Id: I2e7ec02fdeeea21ef43136ddeabc98d499a8ba7f Co-Authored-By: Anton Arefiev --- devstack/plugin.sh | 2 +- example.conf | 161 ++++++++++++++++-- ironic_inspector/common/ironic.py | 49 ++++-- ironic_inspector/common/keystone.py | 20 ++- ironic_inspector/common/swift.py | 16 +- ironic_inspector/conf/ironic.py | 34 +++- ironic_inspector/conf/swift.py | 20 ++- ironic_inspector/test/functional.py | 8 +- .../test/unit/test_common_ironic.py | 22 +-- ironic_inspector/test/unit/test_keystone.py | 8 +- .../test/unit/test_plugins_rules.py | 2 + .../test/unit/test_plugins_standard.py | 1 + ironic_inspector/test/unit/test_swift.py | 30 +++- .../notes/ksadapters-abc9edc63cafa405.yaml | 24 +++ 14 files changed, 318 insertions(+), 79 deletions(-) create mode 100644 releasenotes/notes/ksadapters-abc9edc63cafa405.yaml diff --git a/devstack/plugin.sh b/devstack/plugin.sh index 246bf2e6a..9e1dd0d11 100644 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -195,7 +195,7 @@ function inspector_configure_auth_for { inspector_iniset $1 user_domain_id default inspector_iniset $1 project_domain_id default inspector_iniset $1 cafile $SSL_BUNDLE_FILE - inspector_iniset $1 os_region $REGION_NAME + inspector_iniset $1 region_name $REGION_NAME } function is_dnsmasq_filter_required { diff --git a/example.conf b/example.conf index 0b341f22f..60dd06b4e 100644 --- a/example.conf +++ b/example.conf @@ -15,7 +15,9 @@ # Authentication method used on the ironic-inspector API. Either # "noauth" or "keystone" are currently valid options. "noauth" will # disable all authentication. (string value) -# Allowed values: keystone, noauth +# Possible values: +# keystone - +# noauth - #auth_strategy = keystone # Timeout after which introspection is considered failed, set to 0 to @@ -414,8 +416,16 @@ # Authentication URL (string value) #auth_url = -# Method to use for authentication: noauth or keystone. (string value) -# Allowed values: keystone, noauth +# DEPRECATED: Method to use for authentication: noauth or keystone. +# (string value) +# Possible values: +# keystone - +# noauth - +# This option is deprecated for removal. +# Its value may be silently ignored in the future. +# Reason: Use [ironic]/auth_type, for noauth case set +# [ironic]/auth_type to `none` and specify ironic API URL via +# [ironic]/endpoint_override option. #auth_strategy = keystone # Authentication type to load (string value) @@ -445,28 +455,60 @@ # Domain name to scope to (string value) #domain_name = +# Always use this endpoint URL for requests for this client. NOTE: The +# unversioned endpoint should be specified here; to request a +# particular API version, use the `version`, `min-version`, and/or +# `max-version` options. (string value) +#endpoint_override = + # Verify HTTPS connections. (boolean value) #insecure = false -# Ironic API URL, used to set Ironic API URL when auth_strategy option -# is noauth to work with standalone Ironic without keystone. (string -# value) +# DEPRECATED: Ironic API URL, used to set Ironic API URL when +# auth_strategy option is noauth or auth_type is "none" to work with +# standalone Ironic without keystone. (string value) +# This option is deprecated for removal. +# Its value may be silently ignored in the future. +# Reason: Use [ironic]/endpoint_override option to set a specific +# ironic API url. #ironic_url = http://localhost:6385/ # PEM encoded client certificate key file (string value) #keyfile = +# The maximum major version of a given API, intended to be used as the +# upper bound of a range with min_version. Mutually exclusive with +# version. (string value) +#max_version = + # Maximum number of retries in case of conflict error (HTTP 409). # (integer value) #max_retries = 30 -# Ironic endpoint type. (string value) +# The minimum major version of a given API, intended to be used as the +# lower bound of a range with max_version. Mutually exclusive with +# version. If min_version is given with no max_version it is as if max +# version is "latest". (string value) +#min_version = + +# DEPRECATED: Ironic endpoint type. (string value) +# This option is deprecated for removal. +# Its value may be silently ignored in the future. +# Reason: Use [ironic]/valid_interfaces option to specify endpoint +# interfaces. #os_endpoint_type = internalURL -# Keystone region used to get Ironic endpoints. (string value) +# DEPRECATED: Keystone region used to get Ironic endpoints. (string +# value) +# This option is deprecated for removal. +# Its value may be silently ignored in the future. +# Reason: Use [ironic]/region_name option instead to configure region. #os_region = -# Ironic service type. (string value) +# DEPRECATED: Ironic service type. (string value) +# This option is deprecated for removal. +# Its value may be silently ignored in the future. +# Reason: Use [ironic]/service_type option to set a specific type. #os_service_type = baremetal # User's password (string value) @@ -486,10 +528,19 @@ # Deprecated group/name - [ironic]/tenant_name #project_name = +# The default region_name for endpoint URL discovery. (string value) +#region_name = + # Interval between retries in case of conflict error (HTTP 409). # (integer value) #retry_interval = 2 +# The default service_name for endpoint URL discovery. (string value) +#service_name = + +# The default service_type for endpoint URL discovery. (string value) +#service_type = baremetal + # Tenant ID (string value) #tenant_id = @@ -515,6 +566,15 @@ # Deprecated group/name - [ironic]/user_name #username = +# List of interfaces, in order of preference, for endpoint URL. (list +# value) +#valid_interfaces = internal,public + +# Minimum Major API version within a given Major API version for +# endpoint URL discovery. Mutually exclusive with min_version and +# max_version (string value) +#version = + [keystone_authtoken] @@ -627,7 +687,10 @@ # encrypted and authenticated in the cache. If the value is not one of # these options or empty, auth_token will raise an exception on # initialization. (string value) -# Allowed values: None, MAC, ENCRYPT +# Possible values: +# None - +# MAC - +# ENCRYPT - #memcache_security_strategy = None # (Optional, mandatory if memcache_security_strategy is defined) This @@ -725,6 +788,14 @@ # From oslo.policy # +# This option controls whether or not to enforce scope when evaluating +# policies. If ``True``, the scope of the token used in the request is +# compared to the ``scope_types`` of the policy being enforced. If the +# scopes do not match, an ``InvalidScope`` exception will be raised. +# If ``False``, a message will be logged informing operators that +# policies are being invoked with mismatching scope. (boolean value) +#enforce_scope = false + # The file that defines policies. (string value) #policy_file = policy.json @@ -741,7 +812,9 @@ # Content Type to send and receive data for REST based policy check # (string value) -# Allowed values: application/x-www-form-urlencoded, application/json +# Possible values: +# application/x-www-form-urlencoded - +# application/json - #remote_content_type = application/x-www-form-urlencoded # server identity verification for REST based policy check (boolean @@ -783,14 +856,21 @@ # IP addresses), pxe (only MAC address of NIC node PXE booted from, # falls back to "active" if PXE MAC is not supplied by the ramdisk). # (string value) -# Allowed values: all, active, pxe, disabled +# Possible values: +# all - +# active - +# pxe - +# disabled - #add_ports = pxe # Which ports (already present on a node) to keep after introspection. # Possible values: all (do not delete anything), present (keep ports # which MACs were present in introspection data), added (keep only # MACs that we added during introspection). (string value) -# Allowed values: all, present, added +# Possible values: +# all - +# present - +# added - #keep_ports = all # Whether to overwrite existing values in node database. Disable this @@ -827,7 +907,9 @@ # Method for storing introspection data. If set to 'none', # introspection data will not be stored. (string value) -# Allowed values: none, swift +# Possible values: +# none - +# swift - #store_data = none # Name of the key to store the location of stored data in the extra @@ -908,23 +990,50 @@ # Domain name to scope to (string value) #domain_name = +# Always use this endpoint URL for requests for this client. NOTE: The +# unversioned endpoint should be specified here; to request a +# particular API version, use the `version`, `min-version`, and/or +# `max-version` options. (string value) +#endpoint_override = + # Verify HTTPS connections. (boolean value) #insecure = false # PEM encoded client certificate key file (string value) #keyfile = +# The maximum major version of a given API, intended to be used as the +# upper bound of a range with min_version. Mutually exclusive with +# version. (string value) +#max_version = + # Maximum number of times to retry a Swift request, before failing. # (integer value) #max_retries = 2 -# Swift endpoint type. (string value) +# The minimum major version of a given API, intended to be used as the +# lower bound of a range with max_version. Mutually exclusive with +# version. If min_version is given with no max_version it is as if max +# version is "latest". (string value) +#min_version = + +# DEPRECATED: Swift endpoint type. (string value) +# This option is deprecated for removal. +# Its value may be silently ignored in the future. +# Reason: Use [swift]/valid_interfaces option to specify endpoint +# interfaces. #os_endpoint_type = internalURL -# Keystone region to get endpoint for. (string value) +# DEPRECATED: Keystone region to get endpoint for. (string value) +# This option is deprecated for removal. +# Its value may be silently ignored in the future. +# Reason: Use [swift]/region_name option to configure region. #os_region = -# Swift service type. (string value) +# DEPRECATED: Swift service type. (string value) +# This option is deprecated for removal. +# Its value may be silently ignored in the future. +# Reason: Use [swift]/service_type option to set specific service type #os_service_type = object-store # User's password (string value) @@ -944,6 +1053,15 @@ # Deprecated group/name - [swift]/tenant_name #project_name = +# The default region_name for endpoint URL discovery. (string value) +#region_name = + +# The default service_name for endpoint URL discovery. (string value) +#service_name = + +# The default service_type for endpoint URL discovery. (string value) +#service_type = object-store + # Tenant ID (string value) #tenant_id = @@ -968,3 +1086,12 @@ # Username (string value) # Deprecated group/name - [swift]/user_name #username = + +# List of interfaces, in order of preference, for endpoint URL. (list +# value) +#valid_interfaces = internal,public + +# Minimum Major API version within a given Major API version for +# endpoint URL discovery. Mutually exclusive with min_version and +# max_version (string value) +#version = diff --git a/ironic_inspector/common/ironic.py b/ironic_inspector/common/ironic.py index 7541453fe..e9374ad2b 100644 --- a/ironic_inspector/common/ironic.py +++ b/ironic_inspector/common/ironic.py @@ -82,29 +82,42 @@ def get_ipmi_address(node): def get_client(token=None, api_version=DEFAULT_IRONIC_API_VERSION): # pragma: no cover """Get Ironic client instance.""" + global IRONIC_SESSION + if not IRONIC_SESSION: + IRONIC_SESSION = keystone.get_session('ironic') + + args = { + 'os_ironic_api_version': api_version, + 'max_retries': CONF.ironic.max_retries, + 'retry_interval': CONF.ironic.retry_interval} + + adapter_opts = dict() + # NOTE: To support standalone ironic without keystone + # TODO(pas-ha) remove handling of deprecated opts in Rocky + # TODO(pas-ha) rewrite when ironicclient natively supports 'none' auth + # via sessions https://review.openstack.org/#/c/359061/ if CONF.ironic.auth_strategy == 'noauth': - args = {'token': 'noauth', - 'endpoint': CONF.ironic.ironic_url} + CONF.set_override('auth_type', 'none', group='ironic') else: - global IRONIC_SESSION - if not IRONIC_SESSION: - IRONIC_SESSION = keystone.get_session('ironic') + # TODO(pas-ha) use service auth with incoming token if token is None: - args = {'session': IRONIC_SESSION, - 'region_name': CONF.ironic.os_region} + args['session'] = IRONIC_SESSION else: - ironic_url = IRONIC_SESSION.get_endpoint( - service_type=CONF.ironic.os_service_type, - endpoint_type=CONF.ironic.os_endpoint_type, - region_name=CONF.ironic.os_region - ) - args = {'token': token, - 'endpoint': ironic_url} - args['os_ironic_api_version'] = api_version - args['max_retries'] = CONF.ironic.max_retries - args['retry_interval'] = CONF.ironic.retry_interval - return client.Client(1, **args) + args['token'] = token + + # TODO(pas-ha): remove handling of deprecated options in Rocky + if CONF.ironic.os_region and not CONF.ironic.region_name: + adapter_opts['region_name'] = CONF.ironic.os_region + if (CONF.ironic.auth_type == 'none' and + not CONF.ironic.endpoint_override and + CONF.ironic.ironic_url): + adapter_opts['endpoint_override'] = CONF.ironic.ironic_url + + adapter = keystone.get_adapter('ironic', session=IRONIC_SESSION, + **adapter_opts) + endpoint = adapter.get_endpoint() + return client.Client(1, endpoint, **args) def check_provision_state(node): diff --git a/ironic_inspector/common/keystone.py b/ironic_inspector/common/keystone.py index 52dc6afc9..4dae71dfa 100644 --- a/ironic_inspector/common/keystone.py +++ b/ironic_inspector/common/keystone.py @@ -18,12 +18,18 @@ from oslo_config import cfg CONF = cfg.CONF +DEFAULT_VALID_INTERFACES = ['internal', 'public'] -def register_auth_opts(group): +# TODO(pas-ha) set default values in conf.opts.set_defaults() +def register_auth_opts(group, service_type): loading.register_session_conf_options(CONF, group) loading.register_auth_conf_options(CONF, group) CONF.set_default('auth_type', default='password', group=group) + loading.register_adapter_conf_options(CONF, group) + CONF.set_default('valid_interfaces', DEFAULT_VALID_INTERFACES, + group=group) + CONF.set_default('service_type', service_type, group=group) def get_session(group): @@ -33,8 +39,13 @@ def get_session(group): return session -def add_auth_options(options): +def get_adapter(group, **adapter_kwargs): + return loading.load_adapter_from_conf_options(CONF, group, + **adapter_kwargs) + +# TODO(pas-ha) set default values in conf.opts.set_defaults() +def add_auth_options(options, service_type): def add_options(opts, opts_to_add): for new_opt in opts_to_add: for opt in opts: @@ -52,5 +63,10 @@ def add_auth_options(options): plugin = loading.get_plugin_loader(name) add_options(opts, loading.get_auth_plugin_conf_options(plugin)) add_options(opts, loading.get_session_conf_options()) + adapter_opts = loading.get_adapter_conf_options( + include_deprecated=False) + cfg.set_defaults(adapter_opts, service_type=service_type, + valid_interfaces=DEFAULT_VALID_INTERFACES) + add_options(opts, adapter_opts) opts.sort(key=lambda x: x.name) return opts diff --git a/ironic_inspector/common/swift.py b/ironic_inspector/common/swift.py index 5bf2c8d1b..a06e49dce 100644 --- a/ironic_inspector/common/swift.py +++ b/ironic_inspector/common/swift.py @@ -51,7 +51,21 @@ class SwiftAPI(object): if not SWIFT_SESSION: SWIFT_SESSION = keystone.get_session('swift') - self.connection = swift_client.Connection(session=SWIFT_SESSION) + adapter_opts = dict() + # TODO(pas-ha): remove handling deprecated options in Rocky + if CONF.swift.os_region and not CONF.swift.region_name: + adapter_opts['region_name'] = CONF.swift.os_region + + adapter = keystone.get_adapter('swift', session=SWIFT_SESSION, + **adapter_opts) + + # TODO(pas-ha) reverse-construct SSL-related session options here + params = { + 'os_options': { + 'object_storage_url': adapter.get_endpoint()}} + + self.connection = swift_client.Connection(session=SWIFT_SESSION, + **params) def create_object(self, object, data, container=CONF.swift.container, headers=None): diff --git a/ironic_inspector/conf/ironic.py b/ironic_inspector/conf/ironic.py index ea26371cc..257174571 100644 --- a/ironic_inspector/conf/ironic.py +++ b/ironic_inspector/conf/ironic.py @@ -18,27 +18,45 @@ from ironic_inspector.common import keystone IRONIC_GROUP = 'ironic' +SERVICE_TYPE = 'baremetal' _OPTS = [ cfg.StrOpt('os_region', - help=_('Keystone region used to get Ironic endpoints.')), + help=_('Keystone region used to get Ironic endpoints.'), + deprecated_for_removal=True, + deprecated_reason=_("Use [ironic]/region_name option instead " + "to configure region.")), cfg.StrOpt('auth_strategy', default='keystone', choices=('keystone', 'noauth'), help=_('Method to use for authentication: noauth or ' - 'keystone.')), + 'keystone.'), + deprecated_for_removal=True, + deprecated_reason=_("Use [ironic]/auth_type, for noauth case " + "set [ironic]/auth_type to `none` and " + "specify ironic API URL via " + "[ironic]/endpoint_override option.")), cfg.StrOpt('ironic_url', default='http://localhost:6385/', help=_('Ironic API URL, used to set Ironic API URL when ' - 'auth_strategy option is noauth to work with standalone ' - 'Ironic without keystone.')), + 'auth_strategy option is noauth or auth_type is "none" ' + 'to work with standalone Ironic without keystone.'), + deprecated_for_removal=True, + deprecated_reason=_('Use [ironic]/endpoint_override option ' + 'to set a specific ironic API url.')), cfg.StrOpt('os_service_type', default='baremetal', - help=_('Ironic service type.')), + help=_('Ironic service type.'), + deprecated_for_removal=True, + deprecated_reason=_('Use [ironic]/service_type option ' + 'to set a specific type.')), cfg.StrOpt('os_endpoint_type', default='internalURL', - help=_('Ironic endpoint type.')), + help=_('Ironic endpoint type.'), + deprecated_for_removal=True, + deprecated_reason=_('Use [ironic]/valid_interfaces option ' + 'to specify endpoint interfaces.')), cfg.IntOpt('retry_interval', default=2, help=_('Interval between retries in case of conflict error ' @@ -52,8 +70,8 @@ _OPTS = [ def register_opts(conf): conf.register_opts(_OPTS, IRONIC_GROUP) - keystone.register_auth_opts(IRONIC_GROUP) + keystone.register_auth_opts(IRONIC_GROUP, SERVICE_TYPE) def list_opts(): - return keystone.add_auth_options(_OPTS) + return keystone.add_auth_options(_OPTS, SERVICE_TYPE) diff --git a/ironic_inspector/conf/swift.py b/ironic_inspector/conf/swift.py index d6c5f66c9..b0429d257 100644 --- a/ironic_inspector/conf/swift.py +++ b/ironic_inspector/conf/swift.py @@ -18,6 +18,7 @@ from ironic_inspector.common import keystone SWIFT_GROUP = 'swift' +SERVICE_TYPE = 'object-store' _OPTS = [ @@ -36,19 +37,28 @@ _OPTS = [ 'objects.')), cfg.StrOpt('os_service_type', default='object-store', - help=_('Swift service type.')), + help=_('Swift service type.'), + deprecated_for_removal=True, + deprecated_reason=_('Use [swift]/service_type option ' + 'to set specific service type')), cfg.StrOpt('os_endpoint_type', default='internalURL', - help=_('Swift endpoint type.')), + help=_('Swift endpoint type.'), + deprecated_for_removal=True, + deprecated_reason=_('Use [swift]/valid_interfaces option ' + 'to specify endpoint interfaces.')), cfg.StrOpt('os_region', - help=_('Keystone region to get endpoint for.')), + help=_('Keystone region to get endpoint for.'), + deprecated_for_removal=True, + deprecated_reason=_("Use [swift]/region_name option to " + "configure region.")) ] def register_opts(conf): conf.register_opts(_OPTS, SWIFT_GROUP) - keystone.register_auth_opts(SWIFT_GROUP) + keystone.register_auth_opts(SWIFT_GROUP, SERVICE_TYPE) def list_opts(): - return keystone.add_auth_options(_OPTS) + return keystone.add_auth_options(_OPTS, SERVICE_TYPE) diff --git a/ironic_inspector/test/functional.py b/ironic_inspector/test/functional.py index 092cb6c08..f30b33cd7 100644 --- a/ironic_inspector/test/functional.py +++ b/ironic_inspector/test/functional.py @@ -49,16 +49,14 @@ from ironic_inspector.test.unit import test_rules CONF = """ [ironic] -os_auth_url = http://url -os_username = user -os_password = password -os_tenant_name = tenant +auth_type=none +endpoint_override=http://url [pxe_filter] driver = noop [DEFAULT] debug = True -auth_strategy = noauth introspection_delay = 0 +auth_strategy=noauth [database] connection = sqlite:///%(db_file)s [processing] diff --git a/ironic_inspector/test/unit/test_common_ironic.py b/ironic_inspector/test/unit/test_common_ironic.py index c9b7ba2ae..8b69a68fd 100644 --- a/ironic_inspector/test/unit/test_common_ironic.py +++ b/ironic_inspector/test/unit/test_common_ironic.py @@ -27,6 +27,7 @@ from ironic_inspector import utils CONF = cfg.CONF +@mock.patch.object(keystone, 'get_adapter') @mock.patch.object(keystone, 'register_auth_opts') @mock.patch.object(keystone, 'get_session') @mock.patch.object(client, 'Client') @@ -39,35 +40,34 @@ class TestGetClient(base.BaseTest): self.addCleanup(ir_utils.reset_ironic_session) def test_get_client_with_auth_token(self, mock_client, mock_load, - mock_opts): + mock_opts, mock_adapter): fake_token = 'token' fake_ironic_url = 'http://127.0.0.1:6385' mock_sess = mock.Mock() - mock_sess.get_endpoint.return_value = fake_ironic_url + mock_adapter.return_value.get_endpoint.return_value = fake_ironic_url mock_load.return_value = mock_sess ir_utils.get_client(fake_token) - mock_sess.get_endpoint.assert_called_once_with( - endpoint_type=CONF.ironic.os_endpoint_type, - service_type=CONF.ironic.os_service_type, - region_name=CONF.ironic.os_region) + mock_adapter.assert_called_once_with( + 'ironic', region_name='somewhere', session=mock_sess) + mock_adapter.return_value.get_endpoint.assert_called_once_with() args = {'token': fake_token, - 'endpoint': fake_ironic_url, 'os_ironic_api_version': ir_utils.DEFAULT_IRONIC_API_VERSION, 'max_retries': CONF.ironic.max_retries, 'retry_interval': CONF.ironic.retry_interval} - mock_client.assert_called_once_with(1, **args) + mock_client.assert_called_once_with(1, fake_ironic_url, **args) def test_get_client_without_auth_token(self, mock_client, mock_load, - mock_opts): + mock_opts, mock_adapter): + fake_ironic_url = 'http://127.0.0.1:6385' + mock_adapter.return_value.get_endpoint.return_value = fake_ironic_url mock_sess = mock.Mock() mock_load.return_value = mock_sess ir_utils.get_client(None) args = {'session': mock_sess, - 'region_name': 'somewhere', 'os_ironic_api_version': ir_utils.DEFAULT_IRONIC_API_VERSION, 'max_retries': CONF.ironic.max_retries, 'retry_interval': CONF.ironic.retry_interval} - mock_client.assert_called_once_with(1, **args) + mock_client.assert_called_once_with(1, fake_ironic_url, **args) class TestGetIpmiAddress(base.BaseTest): diff --git a/ironic_inspector/test/unit/test_keystone.py b/ironic_inspector/test/unit/test_keystone.py index 54f4ba0ca..b1191dadf 100644 --- a/ironic_inspector/test/unit/test_keystone.py +++ b/ironic_inspector/test/unit/test_keystone.py @@ -29,16 +29,18 @@ class KeystoneTest(base.BaseTest): self.cfg.conf.register_group(cfg.OptGroup(TESTGROUP)) def test_register_auth_opts(self): - keystone.register_auth_opts(TESTGROUP) + keystone.register_auth_opts(TESTGROUP, 'fake-service') auth_opts = ['auth_type', 'auth_section'] sess_opts = ['certfile', 'keyfile', 'insecure', 'timeout', 'cafile'] for o in auth_opts + sess_opts: self.assertIn(o, self.cfg.conf[TESTGROUP]) self.assertEqual('password', self.cfg.conf[TESTGROUP]['auth_type']) + self.assertEqual('fake-service', + self.cfg.conf[TESTGROUP]['service_type']) @mock.patch.object(kaloading, 'load_auth_from_conf_options', autospec=True) def test_get_session(self, auth_mock): - keystone.register_auth_opts(TESTGROUP) + keystone.register_auth_opts(TESTGROUP, 'fake-service') self.cfg.config(group=TESTGROUP, cafile='/path/to/ca/file') auth1 = mock.Mock() @@ -48,7 +50,7 @@ class KeystoneTest(base.BaseTest): self.assertEqual(auth1, sess.auth) def test_add_auth_options(self): - opts = keystone.add_auth_options([]) + opts = keystone.add_auth_options([], 'fake-service') # check that there is no duplicates names = {o.dest for o in opts} self.assertEqual(len(names), len(opts)) diff --git a/ironic_inspector/test/unit/test_plugins_rules.py b/ironic_inspector/test/unit/test_plugins_rules.py index d5017e9fd..cfdbbb540 100644 --- a/ironic_inspector/test/unit/test_plugins_rules.py +++ b/ironic_inspector/test/unit/test_plugins_rules.py @@ -166,6 +166,7 @@ class TestSetAttributeAction(test_base.NodeTest): 'value': 42}]) +@mock.patch('ironic_inspector.common.ironic.get_client', new=mock.Mock()) class TestSetCapabilityAction(test_base.NodeTest): act = rules_plugins.SetCapabilityAction() params = {'name': 'cap1', 'value': 'val'} @@ -191,6 +192,7 @@ class TestSetCapabilityAction(test_base.NodeTest): self.assertEqual({'cap1': 'val', 'x': 'y', 'answer': '42'}, new_caps) +@mock.patch('ironic_inspector.common.ironic.get_client', new=mock.Mock()) class TestExtendAttributeAction(test_base.NodeTest): act = rules_plugins.ExtendAttributeAction() params = {'path': '/extra/value', 'value': 42} diff --git a/ironic_inspector/test/unit/test_plugins_standard.py b/ironic_inspector/test/unit/test_plugins_standard.py index d76a84ae7..b1d4a7836 100644 --- a/ironic_inspector/test/unit/test_plugins_standard.py +++ b/ironic_inspector/test/unit/test_plugins_standard.py @@ -26,6 +26,7 @@ from ironic_inspector import utils CONF = cfg.CONF +@mock.patch('ironic_inspector.common.ironic.get_client', new=mock.Mock()) class TestSchedulerHook(test_base.NodeTest): def setUp(self): super(TestSchedulerHook, self).setUp() diff --git a/ironic_inspector/test/unit/test_swift.py b/ironic_inspector/test/unit/test_swift.py index 0491968ea..c32071c76 100644 --- a/ironic_inspector/test/unit/test_swift.py +++ b/ironic_inspector/test/unit/test_swift.py @@ -14,6 +14,8 @@ # Mostly copied from ironic/tests/test_swift.py + +from keystoneauth1 import loading as kloading import mock from swiftclient import client as swift_client from swiftclient import exceptions as swift_exception @@ -44,6 +46,7 @@ class BaseTest(test_base.NodeTest): } +@mock.patch.object(keystone, 'get_adapter', autospec=True) @mock.patch.object(keystone, 'register_auth_opts') @mock.patch.object(keystone, 'get_session') @mock.patch.object(swift_client, 'Connection', autospec=True) @@ -58,14 +61,23 @@ class SwiftTestCase(BaseTest): os_endpoint_type='internalURL', os_region='somewhere', max_retries=2) + # NOTE(aarefiev) register keystoneauth dynamic options + adapter_opts = kloading.get_adapter_conf_options( + include_deprecated=False) + self.cfg.register_opts(adapter_opts, 'swift') self.addCleanup(swift.reset_swift_session) - def test___init__(self, connection_mock, load_mock, opts_mock): + def test___init__(self, connection_mock, load_mock, + opts_mock, adapter_mock): + fake_endpoint = "http://localhost:6000" + adapter_mock.return_value.get_endpoint.return_value = fake_endpoint swift.SwiftAPI() connection_mock.assert_called_once_with( - session=load_mock.return_value) + session=load_mock.return_value, + os_options={'object_storage_url': fake_endpoint}) - def test_create_object(self, connection_mock, load_mock, opts_mock): + def test_create_object(self, connection_mock, load_mock, + opts_mock, adapter_mock): swiftapi = swift.SwiftAPI() connection_obj_mock = connection_mock.return_value @@ -79,8 +91,8 @@ class SwiftTestCase(BaseTest): 'ironic-inspector', 'object', 'some-string-data', headers=None) self.assertEqual('object-uuid', object_uuid) - def test_create_object_create_container_fails(self, connection_mock, - load_mock, opts_mock): + def test_create_object_create_container_fails( + self, connection_mock, load_mock, opts_mock, adapter_mock): swiftapi = swift.SwiftAPI() connection_obj_mock = connection_mock.return_value connection_obj_mock.put_container.side_effect = self.swift_exception @@ -91,7 +103,7 @@ class SwiftTestCase(BaseTest): self.assertFalse(connection_obj_mock.put_object.called) def test_create_object_put_object_fails(self, connection_mock, load_mock, - opts_mock): + opts_mock, adapter_mock): swiftapi = swift.SwiftAPI() connection_obj_mock = connection_mock.return_value connection_obj_mock.put_object.side_effect = self.swift_exception @@ -102,7 +114,8 @@ class SwiftTestCase(BaseTest): connection_obj_mock.put_object.assert_called_once_with( 'ironic-inspector', 'object', 'some-string-data', headers=None) - def test_get_object(self, connection_mock, load_mock, opts_mock): + def test_get_object(self, connection_mock, load_mock, + opts_mock, adapter_mock): swiftapi = swift.SwiftAPI() connection_obj_mock = connection_mock.return_value @@ -115,7 +128,8 @@ class SwiftTestCase(BaseTest): 'ironic-inspector', 'object') self.assertEqual(expected_obj, swift_obj) - def test_get_object_fails(self, connection_mock, load_mock, opts_mock): + def test_get_object_fails(self, connection_mock, load_mock, + opts_mock, adapter_mock): swiftapi = swift.SwiftAPI() connection_obj_mock = connection_mock.return_value connection_obj_mock.get_object.side_effect = self.swift_exception diff --git a/releasenotes/notes/ksadapters-abc9edc63cafa405.yaml b/releasenotes/notes/ksadapters-abc9edc63cafa405.yaml new file mode 100644 index 000000000..8d0cd5461 --- /dev/null +++ b/releasenotes/notes/ksadapters-abc9edc63cafa405.yaml @@ -0,0 +1,24 @@ +--- +deprecations: + - | + Several configuration options related to ironic API access + are deprecated and will be removed in the Rocky release. + These include: + + - ``[ironic]/os_region`` - use ``[ironic]/region_name`` option instead + - ``[ironic]/auth_strategy`` - set ``[ironic]/auth_type`` option to + ``none`` to access ironic API in noauth mode + - ``[ironic]/ironic_url`` - use ``[ironic]/endpoint_override`` option + to set specific ironic API endpoint address if discovery of ironic API + endpoint is not desired or impossible (for example in standalone mode) + - ``[ironic]/os_service_type`` - use ``[ironic]/service_type`` option + - ``[ironic]/os_endpoint_type`` - use ``[ironic]/valid_interfaces`` + option to set ironic endpoint types that will be attempted to be used + - | + Several configuration options related to swift API access are deprecated + and will be removed in Rocky release. + These include: + + - ``[swift]/os_service_type`` - use ``[swift]/service_type`` option + - ``[swift]/os_endpoint_type`` - use ``[swift]/valid_interfaces`` option + - ``[swift]/os_region`` - use ``[swift]region_name`` option