Remove deprecated support for QoS notification_drivers

In Ocata, notification_drivers were deprecated in favor of
the new QoSDriver architecture.

This patch removes backwards compatible support for notification
drivers along with its testing.

Change-Id: I5f747635be3fd66b70326d9f94c85a6736286bd2
changes/77/441177/9
Miguel Angel Ajo 6 years ago committed by Ihar Hrachyshka
parent 79381c0bf0
commit 6037e53f07
  1. 1
      etc/oslo-config-generator/neutron.conf
  2. 26
      neutron/conf/services/qos_driver_manager.py
  3. 14
      neutron/objects/qos/rule_type.py
  4. 8
      neutron/opts.py
  5. 9
      neutron/services/qos/drivers/manager.py
  6. 0
      neutron/services/qos/notification_drivers/__init__.py
  7. 79
      neutron/services/qos/notification_drivers/manager.py
  8. 41
      neutron/services/qos/notification_drivers/message_queue.py
  9. 42
      neutron/services/qos/notification_drivers/qos_base.py
  10. 27
      neutron/services/qos/qos_plugin.py
  11. 18
      neutron/tests/unit/objects/qos/test_rule_type.py
  12. 4
      neutron/tests/unit/services/qos/drivers/test_manager.py
  13. 0
      neutron/tests/unit/services/qos/notification_drivers/__init__.py
  14. 30
      neutron/tests/unit/services/qos/notification_drivers/dummy.py
  15. 77
      neutron/tests/unit/services/qos/notification_drivers/test_manager.py
  16. 56
      neutron/tests/unit/services/qos/test_qos_plugin.py
  17. 3
      setup.cfg

@ -6,7 +6,6 @@ namespace = neutron
namespace = neutron.agent
namespace = neutron.db
namespace = neutron.extensions
namespace = neutron.qos
namespace = nova.auth
namespace = oslo.log
namespace = oslo.db

@ -1,26 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from neutron._i18n import _
QOS_PLUGIN_OPTS = [
cfg.ListOpt('notification_drivers',
default=['message_queue'],
help=_("Drivers list to use to send the update notification. "
"This option will be unused in Pike."),
deprecated_for_removal=True),
]
def register_qos_plugin_opts(cfg=cfg.CONF):
cfg.register_opts(QOS_PLUGIN_OPTS, "qos")

@ -16,7 +16,6 @@ from oslo_log import log as logging
from oslo_versionedobjects import base as obj_base
from oslo_versionedobjects import fields as obj_fields
from neutron._i18n import _LW
from neutron.objects import base
from neutron.services.qos import qos_consts
@ -48,21 +47,8 @@ class QosRuleType(base.NeutronObject):
if validate_filters:
cls.validate_filters(**kwargs)
#TODO(mangelajo): remove in backwards compatible available rule
# inspection in Pike
core_plugin_supported_rules = getattr(
directory.get_plugin(), 'supported_qos_rule_types', None)
rule_types = (
core_plugin_supported_rules or
directory.get_plugin(alias=constants.QOS).supported_rule_types)
if core_plugin_supported_rules:
LOG.warning(_LW(
"Your core plugin defines supported_qos_rule_types which is "
"deprecated and shall be implemented through a QoS driver."
))
# TODO(ihrachys): apply filters to returned result
return [cls(type=type_) for type_ in rule_types]

@ -44,7 +44,6 @@ import neutron.conf.plugins.ml2.drivers.ovs_conf
import neutron.conf.quota
import neutron.conf.service
import neutron.conf.services.metering_agent
import neutron.conf.services.qos_driver_manager
import neutron.conf.wsgi
import neutron.db.agents_db
import neutron.db.agentschedulers_db
@ -143,13 +142,6 @@ def list_opts():
]
def list_qos_opts():
return [
('qos',
neutron.conf.services.qos_driver_manager.QOS_PLUGIN_OPTS)
]
def list_base_agent_opts():
return [
('DEFAULT',

@ -21,11 +21,9 @@ from neutron.api.rpc.callbacks import resources
from neutron.api.rpc.handlers import resources_rpc
from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.conf.services import qos_driver_manager as qos_mgr
from neutron.objects.qos import policy as policy_object
from neutron.services.qos import qos_consts
qos_mgr.register_qos_plugin_opts()
LOG = logging.getLogger(__name__)
@ -38,13 +36,10 @@ SKIPPED_VIF_TYPES = [
class QosServiceDriverManager(object):
def __init__(self, enable_rpc=False):
def __init__(self):
self._drivers = []
self.notification_api = resources_rpc.ResourcesPushRpcApi()
#TODO(mangelajo): remove the enable_rpc parameter in Pike since
# we only use it when a message_queue derived driver
# is found in the notification_drivers
self.rpc_notifications_required = enable_rpc
self.rpc_notifications_required = False
rpc_registry.provide(self._get_qos_policy_cb, resources.QOS_POLICY)
# notify any registered QoS driver that we're ready, those will
# call the driver manager back with register_driver if they

@ -1,79 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from oslo_log import log as logging
from neutron._i18n import _LI
from neutron.conf.services import qos_driver_manager as qos_mgr
from neutron import manager
from neutron.services.qos.notification_drivers import message_queue
QOS_DRIVER_NAMESPACE = 'neutron.qos.notification_drivers'
qos_mgr.register_qos_plugin_opts()
LOG = logging.getLogger(__name__)
class QosServiceNotificationDriverManager(object):
def __init__(self):
self.notification_drivers = []
self._load_drivers(cfg.CONF.qos.notification_drivers)
def update_policy(self, context, qos_policy):
for driver in self.notification_drivers:
driver.update_policy(context, qos_policy)
def delete_policy(self, context, qos_policy):
for driver in self.notification_drivers:
driver.delete_policy(context, qos_policy)
def create_policy(self, context, qos_policy):
for driver in self.notification_drivers:
driver.create_policy(context, qos_policy)
@property
def has_message_queue_driver(self):
"""Determine if we have any message_queue derived driver in the
notifications drivers, so the QoS plugin will forcefully enable
the rpc notifications for Pike, since our message_queue driver
is a dummy which doesn't send any messages.
"""
#TODO(mangelajo): remove this in Pike
return any(
isinstance(driver, message_queue.RpcQosServiceNotificationDriver)
for driver in self.notification_drivers)
def _load_drivers(self, notification_drivers):
"""Load all the instances of the configured QoS notification drivers
:param notification_drivers: comma separated string
"""
for notification_driver in notification_drivers:
driver_ins = self._load_driver_instance(notification_driver)
self.notification_drivers.append(driver_ins)
def _load_driver_instance(self, notification_driver):
"""Returns an instance of the configured QoS notification driver
:returns: An instance of Driver for the QoS notification
"""
mgr = manager.NeutronManager
driver = mgr.load_class_for_provider(QOS_DRIVER_NAMESPACE,
notification_driver)
driver_instance = driver()
LOG.info(
_LI("Loading %(name)s (%(description)s) notification driver "
"for QoS plugin"),
{"name": notification_driver,
"description": driver_instance.get_description()})
return driver_instance

@ -1,41 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log as logging
from neutron._i18n import _LW
from neutron.services.qos.notification_drivers import qos_base
LOG = logging.getLogger(__name__)
class RpcQosServiceNotificationDriver(
qos_base.QosServiceNotificationDriverBase):
"""RPC message queue service notification driver for QoS."""
def __init__(self):
LOG.warning(_LW("The QoS message_queue notification driver "
"has been ignored, since rpc push is implemented "
"for any QoS driver that requests it."))
def get_description(self):
return "Message queue updates"
def create_policy(self, context, policy):
pass
def update_policy(self, context, policy):
pass
def delete_policy(self, context, policy):
pass

@ -1,42 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class QosServiceNotificationDriverBase(object):
"""QoS service notification driver base class."""
@abc.abstractmethod
def get_description(self):
"""Get the notification driver description.
"""
@abc.abstractmethod
def create_policy(self, context, policy):
"""Create the QoS policy."""
@abc.abstractmethod
def update_policy(self, context, policy):
"""Update the QoS policy.
Apply changes to the QoS policy.
"""
@abc.abstractmethod
def delete_policy(self, context, policy):
"""Delete the QoS policy.
Remove all rules for this policy and free up all the resources.
"""

@ -26,7 +26,6 @@ from neutron.objects import ports as ports_object
from neutron.objects.qos import policy as policy_object
from neutron.objects.qos import rule_type as rule_type_object
from neutron.services.qos.drivers import manager
from neutron.services.qos.notification_drivers import manager as driver_mgr
from neutron.services.qos import qos_consts
@ -44,13 +43,7 @@ class QoSPlugin(qos.QoSPluginBase):
def __init__(self):
super(QoSPlugin, self).__init__()
# TODO(mangelajo): remove notification_driver_manager in Pike
self.notification_driver_manager = (
driver_mgr.QosServiceNotificationDriverManager())
self.driver_manager = manager.QosServiceDriverManager(enable_rpc=(
self.notification_driver_manager.has_message_queue_driver))
self.driver_manager = manager.QosServiceDriverManager()
callbacks_registry.subscribe(
self._validate_create_port_callback,
@ -170,9 +163,6 @@ class QoSPlugin(qos.QoSPluginBase):
self.driver_manager.call('create_policy', context, policy_obj)
#TODO(majopela): remove notification_driver_manager call in Pike
self.notification_driver_manager.create_policy(context, policy_obj)
return policy_obj
@db_base_plugin_common.convert_result_to_dict
@ -195,9 +185,6 @@ class QoSPlugin(qos.QoSPluginBase):
self.driver_manager.call('update_policy', context, policy_obj)
#TODO(majopela): remove notification_driver_manager call in Pike
self.notification_driver_manager.update_policy(context, policy_obj)
return policy_obj
def delete_policy(self, context, policy_id):
@ -216,9 +203,6 @@ class QoSPlugin(qos.QoSPluginBase):
self.driver_manager.call('delete_policy', context, policy)
#TODO(majopela): remove notification_driver_manager call in Pike
self.notification_driver_manager.delete_policy(context, policy)
def _get_policy_obj(self, context, policy_id):
"""Fetch a QoS policy.
@ -307,9 +291,6 @@ class QoSPlugin(qos.QoSPluginBase):
self.driver_manager.call('update_policy', context, policy)
#TODO(majopela): remove notification_driver_manager call in Pike
self.notification_driver_manager.update_policy(context, policy)
return rule
@db_base_plugin_common.convert_result_to_dict
@ -346,9 +327,6 @@ class QoSPlugin(qos.QoSPluginBase):
self.driver_manager.call('update_policy', context, policy)
#TODO(majopela): remove notification_driver_manager call in Pike
self.notification_driver_manager.update_policy(context, policy)
return rule
def delete_policy_rule(self, context, rule_cls, rule_id, policy_id):
@ -374,9 +352,6 @@ class QoSPlugin(qos.QoSPluginBase):
self.driver_manager.call('update_policy', context, policy)
#TODO(majopela): remove notification_driver_manager call in Pike
self.notification_driver_manager.update_policy(context, policy)
@db_base_plugin_common.filter_fields
@db_base_plugin_common.convert_result_to_dict
def get_policy_rule(self, context, rule_cls, rule_id, policy_id,

@ -14,10 +14,12 @@
# class on the common base class for all objects
import mock
from neutron_lib.plugins import directory
from oslo_config import cfg
from neutron import manager
from neutron.objects.qos import rule_type
from neutron.services.qos import qos_consts
from neutron.services.qos import qos_plugin
from neutron.tests import base as test_base
@ -29,15 +31,17 @@ class QosRuleTypeObjectTestCase(test_base.BaseTestCase):
def setUp(self):
super(QosRuleTypeObjectTestCase, self).setUp()
self.config_parse()
self.setup_coreplugin(DB_PLUGIN_KLASS)
self.setup_coreplugin(load_plugins=False)
cfg.CONF.set_override("core_plugin", DB_PLUGIN_KLASS)
cfg.CONF.set_override("service_plugins", ["qos"])
manager.init()
def test_get_objects(self):
core_plugin = directory.get_plugin()
rule_types_mock = mock.PropertyMock(
return_value=qos_consts.VALID_RULE_TYPES)
with mock.patch.object(core_plugin, 'supported_qos_rule_types',
new_callable=rule_types_mock,
create=True):
return_value=set(qos_consts.VALID_RULE_TYPES))
with mock.patch.object(qos_plugin.QoSPlugin, 'supported_rule_types',
new_callable=rule_types_mock):
types = rule_type.QosRuleType.get_objects()
self.assertEqual(sorted(qos_consts.VALID_RULE_TYPES),
sorted(type_['type'] for type_ in types))

@ -13,11 +13,9 @@
import mock
from neutron_lib.api.definitions import portbindings
from neutron_lib import context
from oslo_config import cfg
from oslo_utils import uuidutils
from neutron.common import constants
from neutron.conf.services import qos_driver_manager as notif_driver_mgr_config
from neutron.objects import ports as ports_object
from neutron.objects.qos import rule as rule_object
from neutron.services.qos.drivers import base as qos_driver_base
@ -32,8 +30,6 @@ class TestQosDriversManagerBase(base.BaseQosTestCase):
super(TestQosDriversManagerBase, self).setUp()
self.config_parse()
self.setup_coreplugin(load_plugins=False)
config = cfg.ConfigOpts()
notif_driver_mgr_config.register_qos_plugin_opts(config)
@staticmethod
def _create_manager_with_drivers(drivers_details):

@ -1,30 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.services.qos.notification_drivers import qos_base
class DummyQosServiceNotificationDriver(
qos_base.QosServiceNotificationDriverBase):
"""Dummy service notification driver for QoS."""
def get_description(self):
return "Dummy"
def create_policy(self, policy):
pass
def update_policy(self, policy):
pass
def delete_policy(self, policy):
pass

@ -1,77 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from neutron_lib import context
from oslo_config import cfg
from oslo_utils import uuidutils
from neutron.conf.services import qos_driver_manager as driver_mgr_config
from neutron.objects.qos import policy as policy_object
from neutron.services.qos.notification_drivers import manager as driver_mgr
from neutron.services.qos.notification_drivers import message_queue
from neutron.tests.unit.services.qos import base
DUMMY_DRIVER = ("neutron.tests.unit.services.qos.notification_drivers."
"dummy.DummyQosServiceNotificationDriver")
def _load_multiple_drivers():
cfg.CONF.set_override(
"notification_drivers",
["message_queue", DUMMY_DRIVER],
"qos")
class TestQosDriversManagerBase(base.BaseQosTestCase):
def setUp(self):
super(TestQosDriversManagerBase, self).setUp()
self.config_parse()
self.setup_coreplugin(load_plugins=False)
config = cfg.ConfigOpts()
driver_mgr_config.register_qos_plugin_opts(config)
self.policy_data = {'policy': {
'id': uuidutils.generate_uuid(),
'project_id': uuidutils.generate_uuid(),
'name': 'test-policy',
'description': 'test policy description',
'shared': True}}
self.context = context.get_admin_context()
self.policy = policy_object.QosPolicy(self.context,
**self.policy_data['policy'])
ctxt = None
self.kwargs = {'context': ctxt}
class TestQosDriversManagerMulti(TestQosDriversManagerBase):
def _test_multi_drivers_configuration_op(self, op):
_load_multiple_drivers()
driver_manager = driver_mgr.QosServiceNotificationDriverManager()
handler = '%s_policy' % op
with mock.patch('.'.join([DUMMY_DRIVER, handler])) as dummy_mock:
rpc_driver = message_queue.RpcQosServiceNotificationDriver
with mock.patch.object(rpc_driver, handler) as rpc_mock:
getattr(driver_manager, handler)(self.context, self.policy)
for mock_ in (dummy_mock, rpc_mock):
mock_.assert_called_with(self.context, self.policy)
def test_multi_drivers_configuration_create(self):
self._test_multi_drivers_configuration_op('create')
def test_multi_drivers_configuration_update(self):
self._test_multi_drivers_configuration_op('update')
def test_multi_drivers_configuration_delete(self):
self._test_multi_drivers_configuration_op('delete')

@ -22,6 +22,7 @@ from neutron.objects.qos import policy as policy_object
from neutron.objects.qos import rule as rule_object
from neutron.plugins.common import constants
from neutron.services.qos import qos_consts
from neutron.services.qos import qos_plugin
from neutron.tests.unit.services.qos import base
@ -52,8 +53,6 @@ class TestQosPlugin(base.BaseQosTestCase):
manager.init()
self.qos_plugin = directory.get_plugin(constants.QOS)
#TODO(mangelajo): Remove notification_driver_manager mock in Pike
self.qos_plugin.notification_driver_manager = mock.Mock()
self.qos_plugin.driver_manager = mock.Mock()
self.rpc_push = mock.patch('neutron.api.rpc.handlers.resources_rpc'
@ -87,12 +86,6 @@ class TestQosPlugin(base.BaseQosTestCase):
self.ctxt, **self.rule_data['dscp_marking_rule'])
def _validate_driver_params(self, method_name):
method = getattr(self.qos_plugin.notification_driver_manager,
method_name)
self.assertTrue(method.called)
self.assertIsInstance(
method.call_args[0][1], policy_object.QosPolicy)
self.assertTrue(self.qos_plugin.driver_manager.call.called)
self.assertEqual(self.qos_plugin.driver_manager.call.call_args[0][0],
method_name)
@ -617,46 +610,15 @@ class TestQosPlugin(base.BaseQosTestCase):
'create_policy_bandwidth_limit_rules')
def test_get_rule_types(self):
core_plugin = directory.get_plugin()
rule_types_mock = mock.PropertyMock(
return_value=qos_consts.VALID_RULE_TYPES)
filters = {'type': 'type_id'}
with mock.patch.object(core_plugin, 'supported_qos_rule_types',
new_callable=rule_types_mock,
create=True):
with mock.patch.object(qos_plugin.QoSPlugin, 'supported_rule_types',
new_callable=rule_types_mock):
types = self.qos_plugin.get_rule_types(self.ctxt, filters=filters)
self.assertEqual(sorted(qos_consts.VALID_RULE_TYPES),
sorted(type_['type'] for type_ in types))
@mock.patch('neutron.objects.qos.policy.QosPolicy')
def test_policy_notification_ordering(self, qos_policy_mock):
policy_actions = {'create': [self.ctxt, {'policy': {}}],
'update': [self.ctxt, self.policy.id,
{'policy': {}}],
'delete': [self.ctxt, self.policy.id]}
self.qos_plugin.notification_driver_manager = mock.Mock()
mock_manager = mock.Mock()
mock_manager.attach_mock(qos_policy_mock, 'QosPolicy')
mock_manager.attach_mock(self.qos_plugin.notification_driver_manager,
'notification_driver')
for action, arguments in policy_actions.items():
mock_manager.reset_mock()
method = getattr(self.qos_plugin, "%s_policy" % action)
method(*arguments)
policy_mock_call = getattr(mock.call.QosPolicy(), action)()
notify_mock_call = getattr(mock.call.notification_driver,
'%s_policy' % action)(self.ctxt,
mock.ANY)
self.assertTrue(mock_manager.mock_calls.index(policy_mock_call) <
mock_manager.mock_calls.index(notify_mock_call))
@mock.patch('neutron.objects.ports.Port')
@mock.patch('neutron.objects.qos.policy.QosPolicy')
def test_rule_notification_and_driver_ordering(self, qos_policy_mock,
@ -672,16 +634,10 @@ class TestQosPlugin(base.BaseQosTestCase):
'delete': [self.ctxt, rule_cls_mock,
self.rule.id, self.policy.id]}
# TODO(mangelajo): Remove notification_driver_manager checks in Pike
# and rename this test
self.qos_plugin.notification_driver_manager = mock.Mock()
mock_manager = mock.Mock()
mock_manager.attach_mock(qos_policy_mock, 'QosPolicy')
mock_manager.attach_mock(port_mock, 'Port')
mock_manager.attach_mock(rule_cls_mock, 'RuleCls')
mock_manager.attach_mock(self.qos_plugin.notification_driver_manager,
'notification_driver')
mock_manager.attach_mock(self.qos_plugin.driver_manager, 'driver')
for action, arguments in rule_actions.items():
@ -695,9 +651,6 @@ class TestQosPlugin(base.BaseQosTestCase):
# some actions construct rule from class reference
rule_mock_call = getattr(mock.call.RuleCls(), action)()
notify_mock_call = mock.call.notification_driver.update_policy(
self.ctxt, mock.ANY)
driver_mock_call = mock.call.driver.call('update_policy',
self.ctxt, mock.ANY)
@ -707,8 +660,5 @@ class TestQosPlugin(base.BaseQosTestCase):
action_index = mock_manager.mock_calls.index(
get_rule_mock_call)
self.assertTrue(
action_index < mock_manager.mock_calls.index(notify_mock_call))
self.assertTrue(
action_index < mock_manager.mock_calls.index(driver_mock_call))

@ -80,8 +80,6 @@ neutron.service_plugins =
timestamp = neutron.services.timestamp.timestamp_plugin:TimeStampPlugin
trunk = neutron.services.trunk.plugin:TrunkPlugin
loki = neutron.services.loki.loki_plugin:LokiPlugin
neutron.qos.notification_drivers =
message_queue = neutron.services.qos.notification_drivers.message_queue:RpcQosServiceNotificationDriver
neutron.ml2.type_drivers =
flat = neutron.plugins.ml2.drivers.type_flat:FlatTypeDriver
local = neutron.plugins.ml2.drivers.type_local:LocalTypeDriver
@ -137,7 +135,6 @@ oslo.config.opts =
neutron.ml2.ovs.agent = neutron.opts:list_ovs_opts
neutron.ml2.sriov.agent = neutron.opts:list_sriov_agent_opts
neutron.ml2.xenapi = neutron.opts:list_xenapi_opts
neutron.qos = neutron.opts:list_qos_opts
nova.auth = neutron.opts:list_auth_opts
oslo.config.opts.defaults =
neutron = neutron.common.config:set_cors_middleware_defaults

Loading…
Cancel
Save