diff options
-rw-r--r-- | nova/api/openstack/__init__.py | 20 | ||||
-rw-r--r-- | nova/exception.py | 4 | ||||
-rw-r--r-- | nova/tests/api/openstack/compute/test_v3_extensions.py | 69 |
3 files changed, 93 insertions, 0 deletions
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 3687ce111..3455b812d 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -28,6 +28,7 @@ import webob.exc from nova.api.openstack import extensions from nova.api.openstack import wsgi +from nova import exception from nova import notifications from nova.openstack.common import log as logging from nova import utils @@ -55,6 +56,11 @@ CONF = cfg.CONF CONF.register_group(api_opts_group) CONF.register_opts(api_opts, api_opts_group) +# List of v3 API extensions which are considered to form +# the core API and so must be present +# TODO(cyeoh): Expand this list as the core APIs are ported to V3 +API_V3_CORE_EXTENSIONS = set(['servers']) + class FaultWrapper(base_wsgi.Middleware): """Calls down the middleware stack, making exceptions into faults.""" @@ -306,8 +312,22 @@ class APIRouterV3(base_wsgi.Router): mapper=mapper) self.api_extension_manager.map(self._register_controllers) + missing_core_extensions = self.get_missing_core_extensions( + self.loaded_extension_info.get_extensions().keys()) + if missing_core_extensions: + LOG.critical(_("Missing core API extensions: %s"), + missing_core_extensions) + raise exception.CoreAPIMissing( + missing_apis=missing_core_extensions) + super(APIRouterV3, self).__init__(mapper) + @staticmethod + def get_missing_core_extensions(extensions_loaded): + extensions_loaded = set(extensions_loaded) + missing_extensions = API_V3_CORE_EXTENSIONS - extensions_loaded + return missing_extensions + @property def loaded_extension_info(self): raise NotImplementedError() diff --git a/nova/exception.py b/nova/exception.py index 487eaae8e..88c038201 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -1220,3 +1220,7 @@ class OrphanedObjectError(NovaException): class IncompatibleObjectVersion(NovaException): message = _('Version %(objver)s of %(objname)s is not supported') + + +class CoreAPIMissing(NovaException): + message = _("Core API extensions are missing: %(missing_apis)s") diff --git a/nova/tests/api/openstack/compute/test_v3_extensions.py b/nova/tests/api/openstack/compute/test_v3_extensions.py index f7c1bf39c..97429ca45 100644 --- a/nova/tests/api/openstack/compute/test_v3_extensions.py +++ b/nova/tests/api/openstack/compute/test_v3_extensions.py @@ -15,9 +15,12 @@ # under the License. from oslo.config import cfg +import stevedore +from nova.api import openstack from nova.api.openstack import compute from nova.api.openstack.compute import plugins +from nova import exception from nova import test CONF = cfg.CONF @@ -28,8 +31,35 @@ class fake_bad_extension(object): alias = "fake-bad" +class fake_stevedore_enabled_extensions(object): + def __init__(self, namespace, check_func, invoke_on_load=False, + invoke_args=(), invoke_kwds={}): + self.extensions = [] + + def map(self, func, *args, **kwds): + pass + + def __iter__(self): + return iter(self.extensions) + + +class fake_loaded_extension_info(object): + def __init__(self): + self.extensions = {} + + def register_extension(self, ext): + self.extensions[ext] = ext + return True + + def get_extensions(self): + return {'core1': None, 'core2': None, 'noncore1': None} + + class ExtensionLoadingTestCase(test.TestCase): + def _set_v3_core(self, core_extensions): + openstack.API_V3_CORE_EXTENSIONS = core_extensions + def test_extensions_loaded(self): app = compute.APIRouterV3() self.assertIn('servers', app._loaded_extension_info.extensions) @@ -70,3 +100,42 @@ class ExtensionLoadingTestCase(test.TestCase): self.assertNotIn('os-fixed-ips', app._loaded_extension_info.extensions) self.assertIn('servers', app._loaded_extension_info.extensions) self.assertEqual(len(app._loaded_extension_info.extensions), 1) + + def test_get_missing_core_extensions(self): + v3_core = openstack.API_V3_CORE_EXTENSIONS + openstack.API_V3_CORE_EXTENSIONS = set(['core1', 'core2']) + self.addCleanup(self._set_v3_core, v3_core) + self.assertEqual(len(compute.APIRouterV3.get_missing_core_extensions( + ['core1', 'core2', 'noncore1'])), 0) + missing_core = compute.APIRouterV3.get_missing_core_extensions( + ['core1']) + self.assertEqual(len(missing_core), 1) + self.assertIn('core2', missing_core) + missing_core = compute.APIRouterV3.get_missing_core_extensions([]) + self.assertEqual(len(missing_core), 2) + self.assertIn('core1', missing_core) + self.assertIn('core2', missing_core) + missing_core = compute.APIRouterV3.get_missing_core_extensions( + ['noncore1']) + self.assertEqual(len(missing_core), 2) + self.assertIn('core1', missing_core) + self.assertIn('core2', missing_core) + + def test_core_extensions_present(self): + self.stubs.Set(stevedore.enabled, 'EnabledExtensionManager', + fake_stevedore_enabled_extensions) + self.stubs.Set(plugins, 'LoadedExtensionInfo', + fake_loaded_extension_info) + v3_core = openstack.API_V3_CORE_EXTENSIONS + openstack.API_V3_CORE_EXTENSIONS = set(['core1', 'core2']) + self.addCleanup(self._set_v3_core, v3_core) + # if no core API extensions are missing then an exception will + # not be raised when creating an instance of compute.APIRouterV3 + _ = compute.APIRouterV3() + + def test_core_extensions_missing(self): + self.stubs.Set(stevedore.enabled, 'EnabledExtensionManager', + fake_stevedore_enabled_extensions) + self.stubs.Set(plugins, 'LoadedExtensionInfo', + fake_loaded_extension_info) + self.assertRaises(exception.CoreAPIMissing, compute.APIRouterV3) |