summaryrefslogtreecommitdiff
path: root/cinderclient
diff options
context:
space:
mode:
authorEric Harney <eharney@redhat.com>2019-06-10 13:07:37 -0400
committerEric Harney <eharney@redhat.com>2019-08-28 11:57:02 -0400
commitd1b044b82a9d632e5769b377abe4f7f653cb94d4 (patch)
tree7437a4bd9586a04f91bf3ba174b0358d573c7b62 /cinderclient
parenta9d9d347788f6a604d3dc7bbd43393efb73d8553 (diff)
downloadpython-cinderclient-d1b044b82a9d632e5769b377abe4f7f653cb94d4.tar.gz
Autonegotiate API version for shell
If OS_VOLUME_API_VERSION is not set, use the highest supported by both the client and the server. If OS_VOLUME_API_VERSION exceeds that supported by the server, use the highest supported by both the client and the server. A warning message is printed for the user indicating that this happened. (This is similar to the behavior of the manila CLI, and is mostly code from manilaclient tweaked to work in cinderclient.) Change-Id: Ie1403eca2a191f62169e60c0cde1622575327387
Diffstat (limited to 'cinderclient')
-rw-r--r--cinderclient/api_versions.py3
-rw-r--r--cinderclient/shell.py105
-rw-r--r--cinderclient/tests/unit/v3/test_shell.py16
3 files changed, 112 insertions, 12 deletions
diff --git a/cinderclient/api_versions.py b/cinderclient/api_versions.py
index 5fa6340..ab8b20e 100644
--- a/cinderclient/api_versions.py
+++ b/cinderclient/api_versions.py
@@ -160,6 +160,9 @@ class APIVersion(object):
return "%s.%s" % (self.ver_major, "latest")
return "%s.%s" % (self.ver_major, self.ver_minor)
+ def get_major_version(self):
+ return "%s" % self.ver_major
+
class VersionedMethod(object):
diff --git a/cinderclient/shell.py b/cinderclient/shell.py
index ecc5862..75e42e9 100644
--- a/cinderclient/shell.py
+++ b/cinderclient/shell.py
@@ -516,6 +516,21 @@ class OpenStackCinderShell(object):
else:
return argv
+ @staticmethod
+ def _validate_input_api_version(options):
+ if not options.os_volume_api_version:
+ api_version = api_versions.APIVersion(api_versions.MAX_VERSION)
+ else:
+ api_version = api_versions.get_api_version(
+ options.os_volume_api_version)
+ return api_version
+
+ @staticmethod
+ def downgrade_warning(requested, discovered):
+ logger.warning("API version %s requested, " % requested.get_string())
+ logger.warning("downgrading to %s based on server support." %
+ discovered.get_string())
+
def main(self, argv):
# Parse args once to find version and debug settings
parser = self.get_base_parser()
@@ -527,14 +542,7 @@ class OpenStackCinderShell(object):
do_help = ('help' in argv) or (
'--help' in argv) or ('-h' in argv) or not argv
- if not options.os_volume_api_version:
- use_version = DEFAULT_MAJOR_OS_VOLUME_API_VERSION
- if do_help:
- use_version = api_versions.MAX_VERSION
- api_version = api_versions.get_api_version(use_version)
- else:
- api_version = api_versions.get_api_version(
- options.os_volume_api_version)
+ api_version = self._validate_input_api_version(options)
# build available subcommands based on version
major_version_string = "%s" % api_version.ver_major
@@ -670,9 +678,7 @@ class OpenStackCinderShell(object):
insecure = self.options.insecure
- self.cs = client.Client(
- api_version, os_username,
- os_password, os_project_name, os_auth_url,
+ client_args = dict(
region_name=os_region_name,
tenant_id=os_project_id,
endpoint_type=endpoint_type,
@@ -689,6 +695,11 @@ class OpenStackCinderShell(object):
session=auth_session,
logger=self.ks_logger if auth_session else self.client_logger)
+ self.cs = client.Client(
+ api_version, os_username,
+ os_password, os_project_name, os_auth_url,
+ **client_args)
+
try:
if not utils.isunauthenticated(args.func):
self.cs.authenticate()
@@ -718,6 +729,28 @@ class OpenStackCinderShell(object):
"to the default API version: %s",
endpoint_api_version)
+ API_MAX_VERSION = api_versions.APIVersion(api_versions.MAX_VERSION)
+ if endpoint_api_version[0] == '3':
+ disc_client = client.Client(API_MAX_VERSION,
+ os_username,
+ os_password,
+ os_project_name,
+ os_auth_url,
+ **client_args)
+ self.cs, discovered_version = self._discover_client(
+ disc_client,
+ api_version,
+ args.os_endpoint_type,
+ args.service_type,
+ os_username,
+ os_password,
+ os_project_name,
+ os_auth_url,
+ client_args)
+
+ if discovered_version < api_version:
+ self.downgrade_warning(api_version, discovered_version)
+
profile = osprofiler_profiler and options.profile
if profile:
osprofiler_profiler.init(options.profile)
@@ -731,6 +764,56 @@ class OpenStackCinderShell(object):
print("To display trace use next command:\n"
"osprofiler trace show --html %s " % trace_id)
+ def _discover_client(self,
+ current_client,
+ os_api_version,
+ os_endpoint_type,
+ os_service_type,
+ os_username,
+ os_password,
+ os_project_name,
+ os_auth_url,
+ client_args):
+
+ if (os_api_version.get_major_version() in
+ api_versions.DEPRECATED_VERSIONS):
+ discovered_version = api_versions.DEPRECATED_VERSION
+ os_service_type = 'volume'
+ else:
+ discovered_version = api_versions.discover_version(
+ current_client,
+ os_api_version)
+
+ if not os_endpoint_type:
+ os_endpoint_type = DEFAULT_CINDER_ENDPOINT_TYPE
+
+ if not os_service_type:
+ os_service_type = self._discover_service_type(discovered_version)
+
+ API_MAX_VERSION = api_versions.APIVersion(api_versions.MAX_VERSION)
+
+ if (discovered_version != API_MAX_VERSION or
+ os_service_type != 'volume' or
+ os_endpoint_type != DEFAULT_CINDER_ENDPOINT_TYPE):
+ client_args['service_type'] = os_service_type
+ client_args['endpoint_type'] = os_endpoint_type
+
+ return (client.Client(discovered_version,
+ os_username,
+ os_password,
+ os_project_name,
+ os_auth_url,
+ **client_args),
+ discovered_version)
+ else:
+ return current_client, discovered_version
+
+ def _discover_service_type(self, discovered_version):
+ SERVICE_TYPES = {'1': 'volume', '2': 'volumev2', '3': 'volumev3'}
+ major_version = discovered_version.get_major_version()
+ service_type = SERVICE_TYPES[major_version]
+ return service_type
+
def _run_extension_hooks(self, hook_type, *args, **kwargs):
"""Runs hooks for all registered extensions."""
for extension in self.extensions:
diff --git a/cinderclient/tests/unit/v3/test_shell.py b/cinderclient/tests/unit/v3/test_shell.py
index b145d8e..6e7a33d 100644
--- a/cinderclient/tests/unit/v3/test_shell.py
+++ b/cinderclient/tests/unit/v3/test_shell.py
@@ -46,6 +46,7 @@ import six
from six.moves.urllib import parse
import cinderclient
+from cinderclient import api_versions
from cinderclient import base
from cinderclient import client
from cinderclient import exceptions
@@ -91,7 +92,12 @@ class ShellTest(utils.TestCase):
self.cs = mock.Mock()
def run_command(self, cmd):
- self.shell.main(cmd.split())
+ # Ensure the version negotiation indicates that
+ # all versions are supported
+ with mock.patch('cinderclient.api_versions._get_server_version_range',
+ return_value=(api_versions.APIVersion('3.0'),
+ api_versions.APIVersion('3.99'))):
+ self.shell.main(cmd.split())
def assert_called(self, method, url, body=None,
partial_body=None, **kwargs):
@@ -284,6 +290,14 @@ class ShellTest(utils.TestCase):
mock_print.assert_called_once_with(mock.ANY, key_list,
exclude_unavailable=True, sortby_index=0)
+ @mock.patch("cinderclient.shell.OpenStackCinderShell.downgrade_warning")
+ def test_list_version_downgrade(self, mock_warning):
+ self.run_command('--os-volume-api-version 3.998 list')
+ mock_warning.assert_called_once_with(
+ api_versions.APIVersion('3.998'),
+ api_versions.APIVersion(api_versions.MAX_VERSION)
+ )
+
def test_list_availability_zone(self):
self.run_command('availability-zone-list')
self.assert_called('GET', '/os-availability-zone')