Merge "Autonegotiate API version for shell"
This commit is contained in:
commit
4bd9000edd
cinderclient
doc/source/user
releasenotes/notes
@ -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
|
||||
@ -92,7 +93,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):
|
||||
@ -295,6 +301,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…
x
Reference in New Issue
Block a user