Quality of life improvements to APIVersionManager
* Verifies that the API version values provided are of the right type (currently all version keys are ints or floats, not strings). * Provides a list of the version keys which would be acceptable if an invalid version is provided. * Raises a useful and explanatory exception if these values are incorrect. * Adds the "preferred" API version to the "supported" versions as a convenience during init. Change-Id: I0bc75b145bba757ff6cd405e1a654aeef296f2df Closes-Bug: 1411427
This commit is contained in:
parent
359f92fa34
commit
59ad632a68
@ -172,6 +172,11 @@ class AlreadyExists(HorizonException):
|
||||
return self.msg % self.attrs
|
||||
|
||||
|
||||
class ConfigurationError(HorizonException):
|
||||
"""Exception to be raised when invalid settings have been provided."""
|
||||
pass
|
||||
|
||||
|
||||
class NotAvailable(HorizonException):
|
||||
"""Exception to be raised when something is not available."""
|
||||
pass
|
||||
|
@ -23,6 +23,8 @@ from django.conf import settings
|
||||
|
||||
from horizon import exceptions
|
||||
|
||||
import six
|
||||
|
||||
|
||||
__all__ = ('APIResourceWrapper', 'APIDictWrapper',
|
||||
'get_service_from_catalog', 'url_for',)
|
||||
@ -41,6 +43,13 @@ class APIVersionManager(object):
|
||||
self.preferred = preferred_version
|
||||
self._active = None
|
||||
self.supported = {}
|
||||
# As a convenience, we can drop in a placeholder for APIs that we
|
||||
# have not yet needed to version. This is useful, for example, when
|
||||
# panels such as the admin metadata_defs wants to check the active
|
||||
# version even though it's not explicitly defined. Previously
|
||||
# this caused a KeyError.
|
||||
if self.preferred:
|
||||
self.supported[self.preferred] = {"version": self.preferred}
|
||||
|
||||
@property
|
||||
def active(self):
|
||||
@ -60,9 +69,26 @@ class APIVersionManager(object):
|
||||
# the setting in as a way of overriding the latest available
|
||||
# version.
|
||||
key = self.preferred
|
||||
# Since we do a key lookup in the supported dict the type matters,
|
||||
# let's ensure people know if they use a string when the key isn't.
|
||||
if isinstance(key, six.string_types):
|
||||
msg = ('The version "%s" specified for the %s service should be '
|
||||
'either an integer or a float, not a string.' %
|
||||
(key, self.service_type))
|
||||
raise exceptions.ConfigurationError(msg)
|
||||
# Provide a helpful error message if the specified version isn't in the
|
||||
# supported list.
|
||||
if key not in self.supported:
|
||||
choices = ", ".join(str(k) for k in six.iterkeys(self.supported))
|
||||
msg = ('%s is not a supported API version for the %s service, '
|
||||
' choices are: %s' % (key, self.service_type, choices))
|
||||
raise exceptions.ConfigurationError(msg)
|
||||
self._active = key
|
||||
return self.supported[self._active]
|
||||
|
||||
def clear_active_cache(self):
|
||||
self._active = None
|
||||
|
||||
|
||||
class APIResourceWrapper(object):
|
||||
"""Simple wrapper for api objects.
|
||||
|
@ -28,9 +28,10 @@ TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
# Overrides for OpenStack API versions. Use this setting to force the
|
||||
# OpenStack dashboard to use a specific API version for a given service API.
|
||||
# Versions specified here should be integers or floats, not strings.
|
||||
# NOTE: The version should be formatted as it appears in the URL for the
|
||||
# service API. For example, The identity service APIs have inconsistent
|
||||
# use of the decimal point, so valid options would be "2.0" or "3".
|
||||
# use of the decimal point, so valid options would be 2.0 or 3.
|
||||
# OPENSTACK_API_VERSIONS = {
|
||||
# "data_processing": 1.1,
|
||||
# "identity": 3,
|
||||
|
@ -18,9 +18,14 @@
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from horizon import exceptions
|
||||
|
||||
from openstack_dashboard.api import base as api_base
|
||||
from openstack_dashboard.api import cinder
|
||||
from openstack_dashboard.api import glance
|
||||
from openstack_dashboard.api import keystone
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
|
||||
@ -147,6 +152,39 @@ class APIDictWrapperTests(test.TestCase):
|
||||
self.assertFalse(0 in resource)
|
||||
|
||||
|
||||
class ApiVersionTests(test.TestCase):
|
||||
def setUp(self):
|
||||
super(ApiVersionTests, self).setUp()
|
||||
self.previous_settings = settings.OPENSTACK_API_VERSIONS
|
||||
settings.OPENSTACK_API_VERSIONS = {
|
||||
"data_processing": 1.1,
|
||||
"identity": "2.0",
|
||||
"volume": 1
|
||||
}
|
||||
# Make sure cached data from other tests doesn't interfere
|
||||
cinder.VERSIONS.clear_active_cache()
|
||||
keystone.VERSIONS.clear_active_cache()
|
||||
glance.VERSIONS.clear_active_cache()
|
||||
|
||||
def tearDown(self):
|
||||
super(ApiVersionTests, self).tearDown()
|
||||
settings.OPENSTACK_API_VERSIONS = self.previous_settings
|
||||
# Clear out our bogus data so it doesn't interfere
|
||||
cinder.VERSIONS.clear_active_cache()
|
||||
keystone.VERSIONS.clear_active_cache()
|
||||
glance.VERSIONS.clear_active_cache()
|
||||
|
||||
def test_invalid_versions(self):
|
||||
with self.assertRaises(exceptions.ConfigurationError):
|
||||
getattr(keystone.VERSIONS, 'active')
|
||||
with self.assertRaises(exceptions.ConfigurationError):
|
||||
getattr(cinder.VERSIONS, 'active')
|
||||
try:
|
||||
getattr(glance.VERSIONS, 'active')
|
||||
except exceptions.ConfigurationError:
|
||||
self.fail("ConfigurationError raised inappropriately.")
|
||||
|
||||
|
||||
class ApiHelperTests(test.TestCase):
|
||||
"""Tests for functions that don't use one of the api objects."""
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user