]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Decentralize the managemement of service providers
authorarmando-migliaccio <armamig@gmail.com>
Wed, 8 Jul 2015 20:48:11 +0000 (13:48 -0700)
committerArmando Migliaccio <armamig@gmail.com>
Tue, 1 Sep 2015 03:27:13 +0000 (03:27 +0000)
After the service split, some of the configuration, parsing and
validation was kept in the neutron core; ultimately this needs to
get closer to the services where it belongs.

This patch starts from ProviderConfiguration and ServiceTypeManager
classes, and aims at removing the hard-coded elements, like the list
of known advanced services, so that in the long run we can make
Neutron easier to plug with external services.

Partial-bug: #1473110

Depends-on: I44edcceba37ac58efcc0a53c9d1f835d9530344a
Depends-on: I8924234aadf786801ffc100d7daa27acc145a195
Change-Id: Ia4cad678e6c722ca05821dbdbf05d61523246a86

neutron/api/extensions.py
neutron/common/repos.py [deleted file]
neutron/db/servicetype_db.py
neutron/services/provider_configuration.py
neutron/tests/unit/api/test_extensions.py
neutron/tests/unit/extensions/test_servicetype.py
neutron/tests/unit/services/test_provider_configuration.py

index 1246087f90d820f014ddba1c0e8e375dcfc373a4..cc4074b705c0b6a72934fbfeb72efd3cd33c72c0 100644 (file)
@@ -27,10 +27,10 @@ import webob.dec
 import webob.exc
 
 from neutron.common import exceptions
-from neutron.common import repos
 import neutron.extensions
 from neutron.i18n import _LE, _LI, _LW
 from neutron import manager
+from neutron.services import provider_configuration
 from neutron import wsgi
 
 
@@ -579,8 +579,9 @@ class PluginAwareExtensionManager(ExtensionManager):
     @classmethod
     def get_instance(cls):
         if cls._instance is None:
-            cls._instance = cls(get_extensions_path(),
-                                manager.NeutronManager.get_service_plugins())
+            service_plugins = manager.NeutronManager.get_service_plugins()
+            cls._instance = cls(get_extensions_path(service_plugins),
+                                service_plugins)
         return cls._instance
 
     def get_supported_extension_aliases(self):
@@ -647,31 +648,30 @@ class ResourceExtension(object):
 
 # Returns the extension paths from a config entry and the __path__
 # of neutron.extensions
-def get_extensions_path():
-    paths = neutron.extensions.__path__
-
-    neutron_mods = repos.NeutronModules()
-    for x in neutron_mods.installed_list():
-        try:
-            paths += neutron_mods.module(x).extensions.__path__
-        except AttributeError:
-            # Occurs normally if module has no extensions sub-module
-            pass
+def get_extensions_path(service_plugins=None):
+    paths = collections.OrderedDict()
+
+    # Add Neutron core extensions
+    paths[neutron.extensions.__path__[0]] = 1
+    if service_plugins:
+        # Add Neutron *-aas extensions
+        for plugin in service_plugins.values():
+            neutron_mod = provider_configuration.NeutronModule(
+                plugin.__module__.split('.')[0])
+            try:
+                paths[neutron_mod.module().extensions.__path__[0]] = 1
+            except AttributeError:
+                # Occurs normally if module has no extensions sub-module
+                pass
 
+    # Add external/other plugins extensions
     if cfg.CONF.api_extensions_path:
-        paths.append(cfg.CONF.api_extensions_path)
-
-    # If the path has dups in it, from discovery + conf file, the duplicate
-    # import of the same module and super() do not play nicely, so weed
-    # out the duplicates, preserving search order.
-
-    z = collections.OrderedDict()
-    for x in paths:
-        z[x] = 1
-    paths = z.keys()
+        for path in cfg.CONF.api_extensions_path.split(":"):
+            paths[path] = 1
 
     LOG.debug("get_extension_paths = %s", paths)
 
+    # Re-build the extension string
     path = ':'.join(paths)
     return path
 
diff --git a/neutron/common/repos.py b/neutron/common/repos.py
deleted file mode 100644 (file)
index 2bd1573..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright (c) 2015, A10 Networks
-#
-# 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 importlib
-import os
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from six.moves import configparser as ConfigParser
-
-LOG = logging.getLogger(__name__)
-
-
-class NeutronModules(object):
-
-    MODULES = {
-        'neutron_fwaas': {
-            'alembic-name': 'fwaas',
-        },
-        'neutron_lbaas': {
-            'alembic-name': 'lbaas',
-        },
-        'neutron_vpnaas': {
-            'alembic-name': 'vpnaas',
-        },
-    }
-
-    def __init__(self):
-        self.repos = {}
-        for repo in self.MODULES:
-            self.repos[repo] = {}
-            self.repos[repo]['mod'] = self._import_or_none(repo)
-            self.repos[repo]['ini'] = None
-
-    def _import_or_none(self, module):
-            try:
-                return importlib.import_module(module)
-            except ImportError:
-                return None
-
-    def installed_list(self):
-        z = filter(lambda k: self.repos[k]['mod'] is not None, self.repos)
-        LOG.debug("NeutronModules related repos installed = %s", z)
-        return z
-
-    def module(self, module):
-        return self.repos[module]['mod']
-
-    def alembic_name(self, module):
-        return self.MODULES[module]['alembic-name']
-
-    # Return an INI parser for the child module. oslo.config is a bit too
-    # magical in its INI loading, and in one notable case, we need to merge
-    # together the [service_providers] section across at least four
-    # repositories.
-    def ini(self, module):
-        if self.repos[module]['ini'] is None:
-            neutron_dir = None
-            try:
-                neutron_dir = cfg.CONF.config_dir
-            except cfg.NoSuchOptError:
-                pass
-
-            if neutron_dir is None:
-                neutron_dir = '/etc/neutron'
-
-            ini = ConfigParser.SafeConfigParser()
-            ini_path = os.path.join(neutron_dir, '%s.conf' % module)
-            if os.path.exists(ini_path):
-                ini.read(ini_path)
-
-            self.repos[module]['ini'] = ini
-
-        return self.repos[module]['ini']
-
-    def service_providers(self, module):
-        ini = self.ini(module)
-
-        sp = []
-        try:
-            for name, value in ini.items('service_providers'):
-                if name == 'service_provider':
-                    sp.append(value)
-        except ConfigParser.NoSectionError:
-            pass
-
-        return sp
index 46a9a9448174e410c5b11df2b9846687af6ca704..0ef4f409a4aa929b6b9c4184b799556d7f56aecf 100644 (file)
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from itertools import chain
+
 from oslo_log import log as logging
 import sqlalchemy as sa
 
@@ -42,14 +44,36 @@ class ServiceTypeManager(object):
         return cls._instance
 
     def __init__(self):
-        self._load_conf()
-
-    def _load_conf(self):
-        self.conf = pconf.ProviderConfiguration(
-            pconf.parse_service_provider_opt())
+        self.config = {}
+        # TODO(armax): remove these as soon as *-aaS start using
+        # the newly introduced add_provider_configuration API
+        self.config['LOADBALANCER'] = (
+            pconf.ProviderConfiguration('neutron_lbaas'))
+        self.config['LOADBALANCERV2'] = (
+            pconf.ProviderConfiguration('neutron_lbaas'))
+        self.config['FIREWALL'] = (
+            pconf.ProviderConfiguration('neutron_fwaas'))
+        self.config['VPN'] = (
+            pconf.ProviderConfiguration('neutron_vpnaas'))
+
+    def add_provider_configuration(self, service_type, configuration):
+        """Add or update the provider configuration for the service type."""
+        LOG.debug('Adding provider configuration for service %s', service_type)
+        self.config.update({service_type: configuration})
 
     def get_service_providers(self, context, filters=None, fields=None):
-        return self.conf.get_service_providers(filters, fields)
+        if filters and 'service_type' in filters:
+            return list(
+                chain.from_iterable(self.config[svc_type].
+                                    get_service_providers(filters, fields)
+                    for svc_type in filters['service_type']
+                        if svc_type in self.config)
+            )
+        return list(
+            chain.from_iterable(
+                self.config[p].get_service_providers(filters, fields)
+                for p in self.config)
+        )
 
     def get_default_service_provider(self, context, service_type):
         """Return the default provider for a given service type."""
@@ -65,7 +89,7 @@ class ServiceTypeManager(object):
 
     def add_resource_association(self, context, service_type, provider_name,
                                  resource_id):
-        r = self.conf.get_service_providers(
+        r = self.get_service_providers(context,
             filters={'service_type': [service_type], 'name': [provider_name]})
         if not r:
             raise pconf.ServiceProviderNotFound(provider=provider_name,
index 938644f8c47d556653f155c800a19355eb6907f4..b4c03cbada645bc64bfc56d5f8936fdeb5a87428 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import importlib
+import os
+
 from oslo_config import cfg
 from oslo_log import log as logging
+from six.moves import configparser as ConfigParser
 import stevedore
 
 from neutron.common import exceptions as n_exc
-from neutron.common import repos
 from neutron.i18n import _LW
-from neutron.plugins.common import constants
 
 LOG = logging.getLogger(__name__)
 
@@ -36,6 +38,67 @@ serviceprovider_opts = [
 cfg.CONF.register_opts(serviceprovider_opts, 'service_providers')
 
 
+class NeutronModule(object):
+    """A Neutron extension module."""
+
+    def __init__(self, service_module):
+        self.module_name = service_module
+        self.repo = {
+            'mod': self._import_or_none(),
+            'ini': None
+        }
+
+    def _import_or_none(self):
+            try:
+                return importlib.import_module(self.module_name)
+            except ImportError:
+                return None
+
+    def installed(self):
+        LOG.debug("NeutronModule installed = %s", self.module_name)
+        return self.module_name
+
+    def module(self):
+        return self.repo['mod']
+
+    # Return an INI parser for the child module. oslo.config is a bit too
+    # magical in its INI loading, and in one notable case, we need to merge
+    # together the [service_providers] section across at least four
+    # repositories.
+    def ini(self):
+        if self.repo['ini'] is None:
+            neutron_dir = None
+            try:
+                neutron_dir = cfg.CONF.config_dir
+            except cfg.NoSuchOptError:
+                pass
+
+            if neutron_dir is None:
+                neutron_dir = '/etc/neutron'
+
+            ini = ConfigParser.SafeConfigParser()
+            ini_path = os.path.join(neutron_dir, '%s.conf' % self.module_name)
+            if os.path.exists(ini_path):
+                ini.read(ini_path)
+
+            self.repo['ini'] = ini
+
+        return self.repo['ini']
+
+    def service_providers(self):
+        ini = self.ini()
+
+        sp = []
+        try:
+            for name, value in ini.items('service_providers'):
+                if name == 'service_provider':
+                    sp.append(value)
+        except ConfigParser.NoSectionError:
+            pass
+
+        return sp
+
+
 #global scope function that should be used in service APIs
 def normalize_provider_name(name):
     return name.lower()
@@ -65,32 +128,16 @@ def get_provider_driver_class(driver, namespace=SERVICE_PROVIDERS):
     return new_driver
 
 
-def parse_service_provider_opt():
+def parse_service_provider_opt(service_module='neutron'):
+
     """Parse service definition opts and returns result."""
     def validate_name(name):
         if len(name) > 255:
             raise n_exc.Invalid(
                 _("Provider name is limited by 255 characters: %s") % name)
 
-    # TODO(dougwig) - phase out the neutron.conf location for service
-    # providers a cycle or two after Kilo.
-
-    # Look in neutron.conf for service providers first (legacy mode)
-    try:
-        svc_providers_opt = cfg.CONF.service_providers.service_provider
-    except cfg.NoSuchOptError:
-        svc_providers_opt = []
-
-    # Look in neutron-*aas.conf files for service provider configs
-    if svc_providers_opt:
-        LOG.warning(_LW("Reading service_providers from legacy location in "
-                        "neutron.conf, and ignoring values in "
-                        "neutron_*aas.conf files; this override will be "
-                        "going away soon."))
-    else:
-        neutron_mods = repos.NeutronModules()
-        for x in neutron_mods.installed_list():
-            svc_providers_opt += neutron_mods.service_providers(x)
+    neutron_mod = NeutronModule(service_module)
+    svc_providers_opt = neutron_mod.service_providers()
 
     LOG.debug("Service providers = %s", svc_providers_opt)
 
@@ -113,14 +160,7 @@ def parse_service_provider_opt():
                        prov_def)
                 LOG.error(msg)
                 raise n_exc.Invalid(msg)
-        ALLOWED_SERVICES = constants.EXT_TO_SERVICE_MAPPING.values()
-        if svc_type not in ALLOWED_SERVICES:
-            msg = (_("Service type '%(svc_type)s' is not allowed, "
-                     "allowed types: %(allowed)s") %
-                   {'svc_type': svc_type,
-                    'allowed': ALLOWED_SERVICES})
-            LOG.error(msg)
-            raise n_exc.Invalid(msg)
+
         driver = get_provider_driver_class(driver)
         res.append({'service_type': svc_type,
                     'name': name,
@@ -145,9 +185,10 @@ class ServiceProviderAlreadyAssociated(n_exc.Conflict):
 
 
 class ProviderConfiguration(object):
-    def __init__(self, prov_data):
+
+    def __init__(self, svc_module='neutron'):
         self.providers = {}
-        for prov in prov_data:
+        for prov in parse_service_provider_opt(svc_module):
             self.add_provider(prov)
 
     def _ensure_driver_unique(self, driver):
index 0aacc316ba8d827027474b740b06be17d64800db..69093f2bf8d98c7df822997927853e5486563f3a 100644 (file)
@@ -67,6 +67,40 @@ class FakePluginWithExtension(object):
         self._log("method_to_support_foxnsox_extension", context)
 
 
+class ExtensionPathTest(base.BaseTestCase):
+
+    def setUp(self):
+        self.base_path = extensions.get_extensions_path()
+        super(ExtensionPathTest, self).setUp()
+
+    def test_get_extensions_path_with_plugins(self):
+        path = extensions.get_extensions_path(
+            {constants.CORE: FakePluginWithExtension()})
+        self.assertEqual(path,
+                         '%s:neutron/tests/unit/extensions' % self.base_path)
+
+    def test_get_extensions_path_no_extensions(self):
+        # Reset to default value, as it's overriden by base class
+        cfg.CONF.set_override('api_extensions_path', '')
+        path = extensions.get_extensions_path()
+        self.assertEqual(path, self.base_path)
+
+    def test_get_extensions_path_single_extension(self):
+        cfg.CONF.set_override('api_extensions_path', 'path1')
+        path = extensions.get_extensions_path()
+        self.assertEqual(path, '%s:path1' % self.base_path)
+
+    def test_get_extensions_path_multiple_extensions(self):
+        cfg.CONF.set_override('api_extensions_path', 'path1:path2')
+        path = extensions.get_extensions_path()
+        self.assertEqual(path, '%s:path1:path2' % self.base_path)
+
+    def test_get_extensions_path_duplicate_extensions(self):
+        cfg.CONF.set_override('api_extensions_path', 'path1:path1')
+        path = extensions.get_extensions_path()
+        self.assertEqual(path, '%s:path1' % self.base_path)
+
+
 class PluginInterfaceTest(base.BaseTestCase):
     def test_issubclass_hook(self):
         class A(object):
index 13eab8fa2e612ed4fe8fa86ad9e42101f93079ca..53e23dfaec2c2559e44d0e7f764052e520cad78f 100644 (file)
@@ -38,65 +38,63 @@ _get_path = test_base._get_path
 
 class ServiceTypeManagerTestCase(testlib_api.SqlTestCase):
     def setUp(self):
+        self.service_providers = mock.patch.object(
+            provconf.NeutronModule, 'service_providers').start()
         super(ServiceTypeManagerTestCase, self).setUp()
+        self.ctx = context.get_admin_context()
+
+    def _set_override(self, service_providers):
+        self.service_providers.return_value = service_providers
         st_db.ServiceTypeManager._instance = None
         self.manager = st_db.ServiceTypeManager.get_instance()
-        self.ctx = context.get_admin_context()
+        for provider in service_providers:
+            self.manager.add_provider_configuration(
+                provider.split(':')[0], provconf.ProviderConfiguration())
 
     def test_service_provider_driver_not_unique(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas:driver'],
-                              'service_providers')
+        self._set_override([constants.LOADBALANCER + ':lbaas:driver'])
         prov = {'service_type': constants.LOADBALANCER,
                 'name': 'name2',
                 'driver': 'driver',
                 'default': False}
-        self.manager._load_conf()
         self.assertRaises(
-            n_exc.Invalid, self.manager.conf.add_provider, prov)
+            n_exc.Invalid,
+            self.manager.config['LOADBALANCER'].add_provider, prov)
 
     def test_get_service_providers(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas:driver_path',
-                               constants.DUMMY + ':dummy:dummy_dr'],
-                              'service_providers')
+        """Test that get_service_providers filters correctly."""
+        self._set_override(
+            [constants.LOADBALANCER +
+             ':lbaas:driver_path1',
+             constants.FIREWALL +
+             ':fwaas:driver_path2'])
         ctx = context.get_admin_context()
-        provconf.parse_service_provider_opt()
-        self.manager._load_conf()
-        res = self.manager.get_service_providers(ctx)
-        self.assertEqual(len(res), 2)
-
         res = self.manager.get_service_providers(
             ctx,
-            filters=dict(service_type=[constants.DUMMY])
+            filters=dict(service_type=[constants.LOADBALANCER])
         )
         self.assertEqual(len(res), 1)
 
         res = self.manager.get_service_providers(
             ctx,
-            filters=dict(service_type=[constants.LOADBALANCER])
+            filters=dict(service_type=[constants.FIREWALL])
         )
         self.assertEqual(len(res), 1)
 
     def test_multiple_default_providers_specified_for_service(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas1:driver_path:default',
-                               constants.LOADBALANCER +
-                               ':lbaas2:driver_path:default'],
-                              'service_providers')
-        self.assertRaises(n_exc.Invalid, self.manager._load_conf)
+        self.assertRaises(
+            n_exc.Invalid,
+            self._set_override,
+            [constants.LOADBALANCER +
+            ':lbaas1:driver_path:default',
+            constants.LOADBALANCER +
+            ':lbaas2:driver_path:default'])
 
     def test_get_default_provider(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas1:driver_path:default',
-                               constants.DUMMY +
-                               ':lbaas2:driver_path2'],
-                              'service_providers')
-        self.manager._load_conf()
+        self._set_override([constants.LOADBALANCER +
+                            ':lbaas1:driver_path:default',
+                            constants.DUMMY +
+                            ':lbaas2:driver_path2'])
         # can pass None as a context
         p = self.manager.get_default_service_provider(None,
                                                       constants.LOADBALANCER)
@@ -112,13 +110,10 @@ class ServiceTypeManagerTestCase(testlib_api.SqlTestCase):
         )
 
     def test_add_resource_association(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas1:driver_path:default',
-                               constants.DUMMY +
-                               ':lbaas2:driver_path2'],
-                              'service_providers')
-        self.manager._load_conf()
+        self._set_override([constants.LOADBALANCER +
+                            ':lbaas1:driver_path:default',
+                            constants.DUMMY +
+                            ':lbaas2:driver_path2'])
         ctx = context.get_admin_context()
         self.manager.add_resource_association(ctx,
                                               constants.LOADBALANCER,
@@ -130,13 +125,10 @@ class ServiceTypeManagerTestCase(testlib_api.SqlTestCase):
         ctx.session.delete(assoc)
 
     def test_invalid_resource_association(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas1:driver_path:default',
-                               constants.DUMMY +
-                               ':lbaas2:driver_path2'],
-                              'service_providers')
-        self.manager._load_conf()
+        self._set_override([constants.LOADBALANCER +
+                            ':lbaas1:driver_path:default',
+                            constants.DUMMY +
+                            ':lbaas2:driver_path2'])
         ctx = context.get_admin_context()
         self.assertRaises(provconf.ServiceProviderNotFound,
                           self.manager.add_resource_association,
@@ -200,13 +192,19 @@ class ServiceTypeExtensionTestCase(ServiceTypeExtensionTestCaseBase):
 class ServiceTypeManagerExtTestCase(ServiceTypeExtensionTestCaseBase):
     """Tests ServiceTypemanager as a public API."""
     def setUp(self):
+        self.service_providers = mock.patch.object(
+            provconf.NeutronModule, 'service_providers').start()
+        service_providers = [
+            constants.LOADBALANCER + ':lbaas:driver_path',
+            constants.DUMMY + ':dummy:dummy_dr'
+        ]
+        self.service_providers.return_value = service_providers
         # Blank out service type manager instance
         st_db.ServiceTypeManager._instance = None
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas:driver_path',
-                               constants.DUMMY + ':dummy:dummy_dr'],
-                              'service_providers')
+        self.manager = st_db.ServiceTypeManager.get_instance()
+        for provider in service_providers:
+            self.manager.add_provider_configuration(
+                provider.split(':')[0], provconf.ProviderConfiguration())
         super(ServiceTypeManagerExtTestCase, self).setUp()
 
     def _list_service_providers(self):
@@ -217,4 +215,4 @@ class ServiceTypeManagerExtTestCase(ServiceTypeExtensionTestCaseBase):
         self.assertEqual(res.status_int, webexc.HTTPOk.code)
         data = self.deserialize(res)
         self.assertIn('service_providers', data)
-        self.assertEqual(len(data['service_providers']), 2)
+        self.assertGreaterEqual(len(data['service_providers']), 2)
index a10b6f783a9c190e82c2b34ed78e06bc2db38a13..1930c278beffd8c2a7bc29c3d85fe04824630f95 100644 (file)
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import mock
+
 from oslo_config import cfg
 
 from neutron.common import exceptions as n_exc
@@ -22,15 +24,22 @@ from neutron.tests import base
 
 
 class ParseServiceProviderConfigurationTestCase(base.BaseTestCase):
+
+    def setUp(self):
+        super(ParseServiceProviderConfigurationTestCase, self).setUp()
+        self.service_providers = mock.patch.object(
+            provconf.NeutronModule, 'service_providers').start()
+
+    def _set_override(self, service_providers):
+        self.service_providers.return_value = service_providers
+
     def test_default_service_provider_configuration(self):
         providers = cfg.CONF.service_providers.service_provider
         self.assertEqual(providers, [])
 
     def test_parse_single_service_provider_opt(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas:driver_path'],
-                              'service_providers')
+        self._set_override([constants.LOADBALANCER +
+                           ':lbaas:driver_path'])
         expected = {'service_type': constants.LOADBALANCER,
                     'name': 'lbaas',
                     'driver': 'driver_path',
@@ -40,10 +49,8 @@ class ParseServiceProviderConfigurationTestCase(base.BaseTestCase):
         self.assertEqual(res, [expected])
 
     def test_parse_single_default_service_provider_opt(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas:driver_path:default'],
-                              'service_providers')
+        self._set_override([constants.LOADBALANCER +
+                           ':lbaas:driver_path:default'])
         expected = {'service_type': constants.LOADBALANCER,
                     'name': 'lbaas',
                     'driver': 'driver_path',
@@ -53,56 +60,46 @@ class ParseServiceProviderConfigurationTestCase(base.BaseTestCase):
         self.assertEqual(res, [expected])
 
     def test_parse_multi_service_provider_opt(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas:driver_path',
-                               constants.LOADBALANCER + ':name1:path1',
-                               constants.LOADBALANCER +
-                               ':name2:path2:default'],
-                              'service_providers')
+        self._set_override([constants.LOADBALANCER +
+                            ':lbaas:driver_path',
+                            constants.LOADBALANCER + ':name1:path1',
+                            constants.LOADBALANCER +
+                            ':name2:path2:default'])
         res = provconf.parse_service_provider_opt()
         # This parsing crosses repos if additional projects are installed,
         # so check that at least what we expect is there; there may be more.
         self.assertTrue(len(res) >= 3)
 
-    def test_parse_service_provider_opt_not_allowed_raises(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas:driver_path',
-                               'svc_type:name1:path1'],
-                              'service_providers')
-        self.assertRaises(n_exc.Invalid, provconf.parse_service_provider_opt)
-
     def test_parse_service_provider_invalid_format(self):
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':lbaas:driver_path',
-                               'svc_type:name1:path1:def'],
-                              'service_providers')
+        self._set_override([constants.LOADBALANCER +
+                           ':lbaas:driver_path',
+                           'svc_type:name1:path1:def'])
         self.assertRaises(n_exc.Invalid, provconf.parse_service_provider_opt)
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':',
-                               'svc_type:name1:path1:def'],
-                              'service_providers')
+        self._set_override([constants.LOADBALANCER +
+                           ':',
+                           'svc_type:name1:path1:def'])
         self.assertRaises(n_exc.Invalid, provconf.parse_service_provider_opt)
 
     def test_parse_service_provider_name_too_long(self):
         name = 'a' * 256
-        cfg.CONF.set_override('service_provider',
-                              [constants.LOADBALANCER +
-                               ':' + name + ':driver_path',
-                               'svc_type:name1:path1:def'],
-                              'service_providers')
+        self._set_override([constants.LOADBALANCER +
+                           ':' + name + ':driver_path',
+                           'svc_type:name1:path1:def'])
         self.assertRaises(n_exc.Invalid, provconf.parse_service_provider_opt)
 
 
 class ProviderConfigurationTestCase(base.BaseTestCase):
+
     def setUp(self):
         super(ProviderConfigurationTestCase, self).setUp()
+        self.service_providers = mock.patch.object(
+            provconf.NeutronModule, 'service_providers').start()
+
+    def _set_override(self, service_providers):
+        self.service_providers.return_value = service_providers
 
     def test_ensure_driver_unique(self):
-        pconf = provconf.ProviderConfiguration([])
+        pconf = provconf.ProviderConfiguration()
         pconf.providers[('svctype', 'name')] = {'driver': 'driver',
                                                 'default': True}
         self.assertRaises(n_exc.Invalid,
@@ -110,7 +107,7 @@ class ProviderConfigurationTestCase(base.BaseTestCase):
         self.assertIsNone(pconf._ensure_driver_unique('another_driver1'))
 
     def test_ensure_default_unique(self):
-        pconf = provconf.ProviderConfiguration([])
+        pconf = provconf.ProviderConfiguration()
         pconf.providers[('svctype', 'name')] = {'driver': 'driver',
                                                 'default': True}
         self.assertRaises(n_exc.Invalid,
@@ -121,7 +118,7 @@ class ProviderConfigurationTestCase(base.BaseTestCase):
         self.assertIsNone(pconf._ensure_default_unique('svctype1', False))
 
     def test_add_provider(self):
-        pconf = provconf.ProviderConfiguration([])
+        pconf = provconf.ProviderConfiguration()
         prov = {'service_type': constants.LOADBALANCER,
                 'name': 'name',
                 'driver': 'path',
@@ -134,7 +131,7 @@ class ProviderConfigurationTestCase(base.BaseTestCase):
                          [{'driver': 'path', 'default': False}])
 
     def test_add_duplicate_provider(self):
-        pconf = provconf.ProviderConfiguration([])
+        pconf = provconf.ProviderConfiguration()
         prov = {'service_type': constants.LOADBALANCER,
                 'name': 'name',
                 'driver': 'path',
@@ -144,6 +141,10 @@ class ProviderConfigurationTestCase(base.BaseTestCase):
         self.assertEqual(len(pconf.providers), 1)
 
     def test_get_service_providers(self):
+        self._set_override([constants.LOADBALANCER + ':name:path',
+                            constants.LOADBALANCER + ':name2:path2',
+                            'st2:name:driver:default',
+                            'st3:name2:driver2:default'])
         provs = [{'service_type': constants.LOADBALANCER,
                   'name': 'name',
                   'driver': 'path',
@@ -161,7 +162,7 @@ class ProviderConfigurationTestCase(base.BaseTestCase):
                   'name': 'name2',
                   'driver': 'driver2',
                   'default': True}]
-        pconf = provconf.ProviderConfiguration(provs)
+        pconf = provconf.ProviderConfiguration()
         for prov in provs:
             p = pconf.get_service_providers(
                 filters={'name': [prov['name']],
@@ -170,6 +171,8 @@ class ProviderConfigurationTestCase(base.BaseTestCase):
             self.assertEqual(p, [prov])
 
     def test_get_service_providers_with_fields(self):
+        self._set_override([constants.LOADBALANCER + ":name:path",
+                            constants.LOADBALANCER + ":name2:path2"])
         provs = [{'service_type': constants.LOADBALANCER,
                   'name': 'name',
                   'driver': 'path',
@@ -178,7 +181,7 @@ class ProviderConfigurationTestCase(base.BaseTestCase):
                   'name': 'name2',
                   'driver': 'path2',
                   'default': False}]
-        pconf = provconf.ProviderConfiguration(provs)
+        pconf = provconf.ProviderConfiguration()
         for prov in provs:
             p = pconf.get_service_providers(
                 filters={'name': [prov['name']],