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, "latest")
|
||||||
return "%s.%s" % (self.ver_major, self.ver_minor)
|
return "%s.%s" % (self.ver_major, self.ver_minor)
|
||||||
|
|
||||||
|
def get_major_version(self):
|
||||||
|
return "%s" % self.ver_major
|
||||||
|
|
||||||
|
|
||||||
class VersionedMethod(object):
|
class VersionedMethod(object):
|
||||||
|
|
||||||
|
@ -516,6 +516,21 @@ class OpenStackCinderShell(object):
|
|||||||
else:
|
else:
|
||||||
return argv
|
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):
|
def main(self, argv):
|
||||||
# Parse args once to find version and debug settings
|
# Parse args once to find version and debug settings
|
||||||
parser = self.get_base_parser()
|
parser = self.get_base_parser()
|
||||||
@ -527,14 +542,7 @@ class OpenStackCinderShell(object):
|
|||||||
do_help = ('help' in argv) or (
|
do_help = ('help' in argv) or (
|
||||||
'--help' in argv) or ('-h' in argv) or not argv
|
'--help' in argv) or ('-h' in argv) or not argv
|
||||||
|
|
||||||
if not options.os_volume_api_version:
|
api_version = self._validate_input_api_version(options)
|
||||||
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)
|
|
||||||
|
|
||||||
# build available subcommands based on version
|
# build available subcommands based on version
|
||||||
major_version_string = "%s" % api_version.ver_major
|
major_version_string = "%s" % api_version.ver_major
|
||||||
@ -670,9 +678,7 @@ class OpenStackCinderShell(object):
|
|||||||
|
|
||||||
insecure = self.options.insecure
|
insecure = self.options.insecure
|
||||||
|
|
||||||
self.cs = client.Client(
|
client_args = dict(
|
||||||
api_version, os_username,
|
|
||||||
os_password, os_project_name, os_auth_url,
|
|
||||||
region_name=os_region_name,
|
region_name=os_region_name,
|
||||||
tenant_id=os_project_id,
|
tenant_id=os_project_id,
|
||||||
endpoint_type=endpoint_type,
|
endpoint_type=endpoint_type,
|
||||||
@ -689,6 +695,11 @@ class OpenStackCinderShell(object):
|
|||||||
session=auth_session,
|
session=auth_session,
|
||||||
logger=self.ks_logger if auth_session else self.client_logger)
|
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:
|
try:
|
||||||
if not utils.isunauthenticated(args.func):
|
if not utils.isunauthenticated(args.func):
|
||||||
self.cs.authenticate()
|
self.cs.authenticate()
|
||||||
@ -718,6 +729,28 @@ class OpenStackCinderShell(object):
|
|||||||
"to the default API version: %s",
|
"to the default API version: %s",
|
||||||
endpoint_api_version)
|
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
|
profile = osprofiler_profiler and options.profile
|
||||||
if profile:
|
if profile:
|
||||||
osprofiler_profiler.init(options.profile)
|
osprofiler_profiler.init(options.profile)
|
||||||
@ -731,6 +764,56 @@ class OpenStackCinderShell(object):
|
|||||||
print("To display trace use next command:\n"
|
print("To display trace use next command:\n"
|
||||||
"osprofiler trace show --html %s " % trace_id)
|
"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):
|
def _run_extension_hooks(self, hook_type, *args, **kwargs):
|
||||||
"""Runs hooks for all registered extensions."""
|
"""Runs hooks for all registered extensions."""
|
||||||
for extension in self.extensions:
|
for extension in self.extensions:
|
||||||
|
@ -46,6 +46,7 @@ import six
|
|||||||
from six.moves.urllib import parse
|
from six.moves.urllib import parse
|
||||||
|
|
||||||
import cinderclient
|
import cinderclient
|
||||||
|
from cinderclient import api_versions
|
||||||
from cinderclient import base
|
from cinderclient import base
|
||||||
from cinderclient import client
|
from cinderclient import client
|
||||||
from cinderclient import exceptions
|
from cinderclient import exceptions
|
||||||
@ -92,7 +93,12 @@ class ShellTest(utils.TestCase):
|
|||||||
self.cs = mock.Mock()
|
self.cs = mock.Mock()
|
||||||
|
|
||||||
def run_command(self, cmd):
|
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,
|
def assert_called(self, method, url, body=None,
|
||||||
partial_body=None, **kwargs):
|
partial_body=None, **kwargs):
|
||||||
@ -295,6 +301,14 @@ class ShellTest(utils.TestCase):
|
|||||||
mock_print.assert_called_once_with(mock.ANY, key_list,
|
mock_print.assert_called_once_with(mock.ANY, key_list,
|
||||||
exclude_unavailable=True, sortby_index=0)
|
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):
|
def test_list_availability_zone(self):
|
||||||
self.run_command('availability-zone-list')
|
self.run_command('availability-zone-list')
|
||||||
self.assert_called('GET', '/os-availability-zone')
|
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_AUTH_URL=http://auth.example.com:5000/v3
|
||||||
export OS_VOLUME_API_VERSION=3
|
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::
|
From there, all shell commands take the form::
|
||||||
|
|
||||||
cinder <command> [arguments...]
|
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