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
This commit is contained in:
parent
a9d9d34778
commit
d1b044b82a
@ -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):
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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')
|
||||
|
@ -40,6 +40,14 @@ For example, in Bash you'd use::
|
||||
export OS_AUTH_URL=http://auth.example.com:5000/v3
|
||||
export OS_VOLUME_API_VERSION=3
|
||||
|
||||
If OS_VOLUME_API_VERSION is not set, the highest version
|
||||
supported by the server will be used.
|
||||
|
||||
If OS_VOLUME_API_VERSION exceeds the highest version
|
||||
supported by the server, the highest version supported by
|
||||
both the client and server will be used. A warning
|
||||
message is printed when this occurs.
|
||||
|
||||
From there, all shell commands take the form::
|
||||
|
||||
cinder <command> [arguments...]
|
||||
|
@ -0,0 +1,12 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Automatic version negotiation for the cinderclient CLI.
|
||||
If an API version is not specified, the CLI will use the newest
|
||||
supported by the client and the server.
|
||||
If an API version newer than the server supports is requested,
|
||||
the CLI will fall back to the newest version supported by the server
|
||||
and issue a warning message.
|
||||
This does not affect cinderclient library usage.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user