summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/api/openstack/__init__.py20
-rw-r--r--nova/exception.py4
-rw-r--r--nova/tests/api/openstack/compute/test_v3_extensions.py69
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)