Merge "Fix discover_version"
This commit is contained in:
commit
5badc3ef31
@ -19,7 +19,6 @@ import re
|
||||
|
||||
from oslo_utils import strutils
|
||||
|
||||
import cinderclient
|
||||
from cinderclient import exceptions
|
||||
from cinderclient import utils
|
||||
from cinderclient._i18n import _
|
||||
@ -29,7 +28,9 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
# key is a deprecated version and value is an alternative version.
|
||||
DEPRECATED_VERSIONS = {"1": "2"}
|
||||
DEPRECATED_VERSION = "2.0"
|
||||
MAX_VERSION = "3.27"
|
||||
MIN_VERSION = "3.0"
|
||||
|
||||
_SUBSTITUTIONS = {}
|
||||
|
||||
@ -234,12 +235,13 @@ def get_api_version(version_string):
|
||||
|
||||
|
||||
def _get_server_version_range(client):
|
||||
version = client.versions.get_current()
|
||||
versions = client.services.server_api_version()
|
||||
|
||||
if not hasattr(version, 'version') or not version.version:
|
||||
if not versions:
|
||||
return APIVersion(), APIVersion()
|
||||
|
||||
return APIVersion(version.min_version), APIVersion(version.version)
|
||||
for version in versions:
|
||||
if '3.' in version.version:
|
||||
return APIVersion(version.min_version), APIVersion(version.version)
|
||||
|
||||
|
||||
def discover_version(client, requested_version):
|
||||
@ -254,52 +256,87 @@ def discover_version(client, requested_version):
|
||||
server_start_version, server_end_version = _get_server_version_range(
|
||||
client)
|
||||
|
||||
both_versions_null = not (server_start_version or server_end_version)
|
||||
if (not requested_version.is_latest() and
|
||||
requested_version != APIVersion('2.0')):
|
||||
if both_versions_null:
|
||||
raise exceptions.UnsupportedVersion(
|
||||
_("Server doesn't support microversions"))
|
||||
if not requested_version.matches(server_start_version,
|
||||
server_end_version):
|
||||
valid_version = requested_version
|
||||
if not server_start_version and not server_end_version:
|
||||
msg = ("Server does not support microversions. Changing server "
|
||||
"version to %(min_version)s.")
|
||||
LOG.debug(msg, {"min_version": DEPRECATED_VERSION})
|
||||
valid_version = APIVersion(DEPRECATED_VERSION)
|
||||
else:
|
||||
valid_version = _validate_requested_version(
|
||||
requested_version,
|
||||
server_start_version,
|
||||
server_end_version)
|
||||
|
||||
_validate_server_version(server_start_version, server_end_version)
|
||||
return valid_version
|
||||
|
||||
|
||||
def _validate_requested_version(requested_version,
|
||||
server_start_version,
|
||||
server_end_version):
|
||||
"""Validates the requested version.
|
||||
|
||||
Checks 'requested_version' is within the min/max range supported by the
|
||||
server. If 'requested_version' is not within range then attempts to
|
||||
downgrade to 'server_end_version'. Otherwise an UnsupportedVersion
|
||||
exception is thrown.
|
||||
|
||||
:param requested_version: requestedversion represented by APIVersion obj
|
||||
:param server_start_version: APIVersion object representing server min
|
||||
:param server_end_version: APIVersion object representing server max
|
||||
"""
|
||||
valid_version = requested_version
|
||||
if not requested_version.matches(server_start_version, server_end_version):
|
||||
if server_end_version <= requested_version:
|
||||
if (APIVersion(MIN_VERSION) <= server_end_version and
|
||||
server_end_version <= APIVersion(MAX_VERSION)):
|
||||
msg = _("Requested version %(requested_version)s is "
|
||||
"not supported. Downgrading requested version "
|
||||
"to %(server_end_version)s.")
|
||||
LOG.debug(msg, {
|
||||
"requested_version": requested_version,
|
||||
"server_end_version": server_end_version})
|
||||
valid_version = server_end_version
|
||||
else:
|
||||
raise exceptions.UnsupportedVersion(
|
||||
_("The specified version isn't supported by server. The valid "
|
||||
"version range is '%(min)s' to '%(max)s'") % {
|
||||
"min": server_start_version.get_string(),
|
||||
"max": server_end_version.get_string()})
|
||||
return requested_version
|
||||
|
||||
if requested_version == APIVersion('2.0'):
|
||||
if server_start_version == APIVersion('2.1') or both_versions_null:
|
||||
return APIVersion('2.0')
|
||||
raise exceptions.UnsupportedVersion(
|
||||
_("The server isn't backward compatible with Cinder V2 REST "
|
||||
"API"))
|
||||
return valid_version
|
||||
|
||||
if both_versions_null:
|
||||
return APIVersion('2.0')
|
||||
if cinderclient.API_MIN_VERSION > server_end_version:
|
||||
|
||||
def _validate_server_version(server_start_version, server_end_version):
|
||||
"""Validates the server version.
|
||||
|
||||
Checks that the 'server_end_version' is greater than the minimum version
|
||||
supported by the client. Then checks that the 'server_start_version' is
|
||||
less than the maximum version supported by the client.
|
||||
|
||||
:param server_start_version:
|
||||
:param server_end_version:
|
||||
:return:
|
||||
"""
|
||||
if APIVersion(MIN_VERSION) > server_end_version:
|
||||
raise exceptions.UnsupportedVersion(
|
||||
_("Server version is too old. The client valid version range is "
|
||||
"'%(client_min)s' to '%(client_max)s'. The server valid version "
|
||||
"range is '%(server_min)s' to '%(server_max)s'.") % {
|
||||
'client_min': cinderclient.API_MIN_VERSION.get_string(),
|
||||
'client_max': cinderclient.API_MAX_VERSION.get_string(),
|
||||
_("Server's version is too old. The client's valid version range "
|
||||
"is '%(client_min)s' to '%(client_max)s'. The server valid "
|
||||
"version range is '%(server_min)s' to '%(server_max)s'.") % {
|
||||
'client_min': MIN_VERSION,
|
||||
'client_max': MAX_VERSION,
|
||||
'server_min': server_start_version.get_string(),
|
||||
'server_max': server_end_version.get_string()})
|
||||
elif cinderclient.API_MAX_VERSION < server_start_version:
|
||||
elif APIVersion(MAX_VERSION) < server_start_version:
|
||||
raise exceptions.UnsupportedVersion(
|
||||
_("Server version is too new. The client valid version range is "
|
||||
"'%(client_min)s' to '%(client_max)s'. The server valid version "
|
||||
"range is '%(server_min)s' to '%(server_max)s'.") % {
|
||||
'client_min': cinderclient.API_MIN_VERSION.get_string(),
|
||||
'client_max': cinderclient.API_MAX_VERSION.get_string(),
|
||||
_("Server's version is too new. The client's valid version range "
|
||||
"is '%(client_min)s' to '%(client_max)s'. The server valid "
|
||||
"version range is '%(server_min)s' to '%(server_max)s'.") % {
|
||||
'client_min': MIN_VERSION,
|
||||
'client_max': MAX_VERSION,
|
||||
'server_min': server_start_version.get_string(),
|
||||
'server_max': server_end_version.get_string()})
|
||||
elif cinderclient.API_MAX_VERSION <= server_end_version:
|
||||
return cinderclient.API_MAX_VERSION
|
||||
elif server_end_version < cinderclient.API_MAX_VERSION:
|
||||
return server_end_version
|
||||
|
||||
|
||||
def update_headers(headers, api_version):
|
||||
|
@ -104,6 +104,13 @@ def get_highest_client_server_version(url):
|
||||
return min(float(max_server_version), float(api_versions.MAX_VERSION))
|
||||
|
||||
|
||||
def get_highest_client_server_version(url):
|
||||
min_server, max_server = get_server_version(url)
|
||||
max_server_version = api_versions.APIVersion.get_string(max_server)
|
||||
|
||||
return min(float(max_server_version), float(api_versions.MAX_VERSION))
|
||||
|
||||
|
||||
def get_volume_api_from_url(url):
|
||||
scheme, netloc, path, query, frag = urlparse.urlsplit(url)
|
||||
components = path.split("/")
|
||||
@ -210,7 +217,7 @@ class SessionClient(adapter.LegacyJsonAdapter):
|
||||
'auth plugin.')
|
||||
|
||||
def _cs_request_base_url(self, url, method, **kwargs):
|
||||
base_url = self._get_base_url(**kwargs)
|
||||
base_url = self._get_base_url()
|
||||
return self._cs_request(
|
||||
base_url + url,
|
||||
method,
|
||||
|
@ -184,3 +184,72 @@ class GetAPIVersionTestCase(utils.TestCase):
|
||||
self.assertEqual(mock_apiversion.return_value,
|
||||
api_versions.get_api_version(version))
|
||||
mock_apiversion.assert_called_once_with(version)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class DiscoverVersionTestCase(utils.TestCase):
|
||||
def setUp(self):
|
||||
super(DiscoverVersionTestCase, self).setUp()
|
||||
self.orig_max = api_versions.MAX_VERSION
|
||||
self.orig_min = api_versions.MIN_VERSION or None
|
||||
self.addCleanup(self._clear_fake_version)
|
||||
self.fake_client = mock.MagicMock()
|
||||
|
||||
def _clear_fake_version(self):
|
||||
api_versions.MAX_VERSION = self.orig_max
|
||||
api_versions.MIN_VERSION = self.orig_min
|
||||
|
||||
def _mock_returned_server_version(self, server_version,
|
||||
server_min_version):
|
||||
version_mock = mock.MagicMock(version=server_version,
|
||||
min_version=server_min_version,
|
||||
status='CURRENT')
|
||||
val = [version_mock]
|
||||
if not server_version and not server_min_version:
|
||||
val = []
|
||||
self.fake_client.services.server_api_version.return_value = val
|
||||
|
||||
@ddt.data(
|
||||
("3.1", "3.3", "3.4", "3.7", "3.3", True), # Server too new
|
||||
("3.9", "3.10", "3.0", "3.3", "3.10", True), # Server too old
|
||||
("3.3", "3.9", "3.7", "3.17", "3.9", False), # Requested < server
|
||||
("3.5", "3.8", "3.0", "3.7", "3.8", False, "3.7"), # downgraded
|
||||
("3.5", "3.5", "3.0", "3.5", "3.5", False), # Server & client same
|
||||
("3.5", "3.5", "3.0", "3.5", "3.5", False, "2.0", []), # Pre-micro
|
||||
("3.1", "3.11", "3.4", "3.7", "3.7", False), # Requested in range
|
||||
("3.1", "3.11", None, None, "3.7", False), # Server w/o support
|
||||
("3.5", "3.5", "3.0", "3.5", "1.0", True) # Requested too old
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_microversion(self, client_min, client_max, server_min, server_max,
|
||||
requested_version, exp_range, end_version=None,
|
||||
ret_val=None):
|
||||
if ret_val is not None:
|
||||
self.fake_client.services.server_api_version.return_value = ret_val
|
||||
else:
|
||||
self._mock_returned_server_version(server_max, server_min)
|
||||
|
||||
api_versions.MAX_VERSION = client_max
|
||||
api_versions.MIN_VERSION = client_min
|
||||
|
||||
if exp_range:
|
||||
self.assertRaisesRegexp(exceptions.UnsupportedVersion,
|
||||
".*range is '%s' to '%s'.*" %
|
||||
(server_min, server_max),
|
||||
api_versions.discover_version,
|
||||
self.fake_client,
|
||||
api_versions.APIVersion(requested_version))
|
||||
else:
|
||||
discovered_version = api_versions.discover_version(
|
||||
self.fake_client,
|
||||
api_versions.APIVersion(requested_version))
|
||||
|
||||
version = requested_version
|
||||
if server_min is None and server_max is None:
|
||||
version = api_versions.DEPRECATED_VERSION
|
||||
elif end_version is not None:
|
||||
version = end_version
|
||||
self.assertEqual(version,
|
||||
discovered_version.get_string())
|
||||
self.assertTrue(
|
||||
self.fake_client.services.server_api_version.called)
|
||||
|
@ -36,3 +36,8 @@ class ServicesTest(utils.TestCase):
|
||||
# Make sure cluster fields from v3.7 is present and not None
|
||||
self.assertIsNotNone(getattr(service, 'cluster'))
|
||||
self._assert_request_id(services_list)
|
||||
|
||||
def test_api_version(self):
|
||||
client = fakes.FakeClient(version_header='3.0')
|
||||
svs = client.services.server_api_version()
|
||||
[self.assertIsInstance(s, services.Service) for s in svs]
|
||||
|
@ -25,14 +25,14 @@ Service = services.Service
|
||||
|
||||
class ServiceManager(services.ServiceManager):
|
||||
@api_versions.wraps("3.0")
|
||||
def server_api_version(self, url_append=""):
|
||||
def server_api_version(self):
|
||||
"""Returns the API Version supported by the server.
|
||||
|
||||
:param url_append: String to append to url to obtain specific version
|
||||
:return: Returns response obj for a server that supports microversions.
|
||||
Returns an empty list for Liberty and prior Cinder servers.
|
||||
"""
|
||||
|
||||
try:
|
||||
return self._get_with_base_url(url_append, response_key='versions')
|
||||
return self._get_with_base_url("", response_key='versions')
|
||||
except LookupError:
|
||||
return []
|
||||
|
Loading…
Reference in New Issue
Block a user