Merge "Remove v2 support from the shell"

This commit is contained in:
Zuul 2021-07-20 12:17:11 +00:00 committed by Gerrit Code Review
commit 593d3f6bd4
13 changed files with 188 additions and 1454 deletions

View File

@ -13,8 +13,6 @@
import functools import functools
import logging import logging
import os
import pkgutil
import re import re
from oslo_utils import strutils from oslo_utils import strutils
@ -26,9 +24,8 @@ from cinderclient import utils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
# key is a deprecated version and value is an alternative version. # key is unsupported version, value is appropriate supported alternative
DEPRECATED_VERSIONS = {"2": "3"} REPLACEMENT_VERSIONS = {"1": "3", "2": "3"}
DEPRECATED_VERSION = "2.0"
MAX_VERSION = "3.64" MAX_VERSION = "3.64"
MIN_VERSION = "3.0" MIN_VERSION = "3.0"
@ -190,14 +187,12 @@ class VersionedMethod(object):
def get_available_major_versions(): def get_available_major_versions():
# NOTE(andreykurilin): available clients version should not be # NOTE: the discovery code previously here assumed that if a v2
# hardcoded, so let's discover them. # module exists, it must contain a client. This will be False
matcher = re.compile(r"v[0-9]*$") # during the transition period when the v2 client is removed but
submodules = pkgutil.iter_modules([os.path.dirname(__file__)]) # we are still using other classes in that module. Right now there's
available_versions = [name[1:] for loader, name, ispkg in submodules # only one client version available, so we simply hard-code it.
if matcher.search(name)] return ['3']
return available_versions
def check_major_version(api_version): def check_major_version(api_version):
@ -224,11 +219,11 @@ def check_major_version(api_version):
def get_api_version(version_string): def get_api_version(version_string):
"""Returns checked APIVersion object""" """Returns checked APIVersion object"""
version_string = str(version_string) version_string = str(version_string)
if version_string in DEPRECATED_VERSIONS: if version_string in REPLACEMENT_VERSIONS:
LOG.warning("Version %(deprecated_version)s is deprecated, use " LOG.warning("Version %(old)s is not supported, use "
"alternative version %(alternative)s instead.", "supported version %(now)s instead.",
{"deprecated_version": version_string, {"old": version_string,
"alternative": DEPRECATED_VERSIONS[version_string]}) "now": REPLACEMENT_VERSIONS[version_string]})
if strutils.is_int_like(version_string): if strutils.is_int_like(version_string):
version_string = "%s.0" % version_string version_string = "%s.0" % version_string
@ -248,11 +243,20 @@ def _get_server_version_range(client):
client.version) client.version)
if not versions: if not versions:
return APIVersion(), APIVersion() msg = _("Server does not support microversions. You cannot use this "
"version of the cinderclient with the requested server. "
"Try using a cinderclient version less than 8.0.0.")
raise exceptions.UnsupportedVersion(msg)
for version in versions: for version in versions:
if '3.' in version.version: if '3.' in version.version:
return APIVersion(version.min_version), APIVersion(version.version) return APIVersion(version.min_version), APIVersion(version.version)
# if we're still here, there's nothing we understand in the versions
msg = _("You cannot use this version of the cinderclient with the "
"requested server.")
raise exceptions.UnsupportedVersion(msg)
def get_highest_version(client): def get_highest_version(client):
"""Queries the server version info and returns highest supported """Queries the server version info and returns highest supported
@ -278,12 +282,6 @@ def discover_version(client, requested_version):
server_start_version, server_end_version = _get_server_version_range( server_start_version, server_end_version = _get_server_version_range(
client) client)
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})
return APIVersion(DEPRECATED_VERSION)
_validate_server_version(server_start_version, server_end_version) _validate_server_version(server_start_version, server_end_version)
# get the highest version the server can handle relative to the # get the highest version the server can handle relative to the

View File

@ -57,16 +57,14 @@ except Exception:
pass pass
_VALID_VERSIONS = ['v2', 'v3'] _VALID_VERSIONS = ['v3']
V3_SERVICE_TYPE = 'volumev3' V3_SERVICE_TYPE = 'volumev3'
V2_SERVICE_TYPE = 'volumev2' SERVICE_TYPES = {'3': V3_SERVICE_TYPE}
SERVICE_TYPES = {'2': V2_SERVICE_TYPE,
'3': V3_SERVICE_TYPE}
REQ_ID_HEADER = 'X-OpenStack-Request-ID' REQ_ID_HEADER = 'X-OpenStack-Request-ID'
# tell keystoneclient that we can ignore the /v1|v2/{project_id} component of # tell keystoneclient that we can ignore the /v1|v2/{project_id} component of
# the service catalog when doing discovery lookups # the service catalog when doing discovery lookups
for svc in ('volume', 'volumev2', 'volumev3'): for svc in ('volume', 'volumev3'):
discover.add_catalog_discover_hack(svc, re.compile(r'/v[12]/\w+/?$'), '/') discover.add_catalog_discover_hack(svc, re.compile(r'/v[12]/\w+/?$'), '/')
@ -85,6 +83,8 @@ def get_server_version(url, insecure=False, cacert=None, cert=None):
:returns: APIVersion object for min and max version supported by :returns: APIVersion object for min and max version supported by
the server the server
""" """
# NOTE: we (the client) don't support v2 anymore, but this function
# is checking the server version
min_version = "2.0" min_version = "2.0"
current_version = "2.0" current_version = "2.0"
@ -128,22 +128,37 @@ def get_server_version(url, insecure=False, cacert=None, cert=None):
current_version = version['version'] current_version = version['version']
break break
else: else:
# Set the values, but don't break out the loop here in case v3 # keep looking in case this cloud is running v2 and
# comes later # we haven't seen v3 yet
min_version = '2.0' continue
current_version = '2.0'
except exceptions.ClientException as e: except exceptions.ClientException as e:
# NOTE: logging the warning but returning the lowest server API version
# supported in this OpenStack release is the legacy behavior, so that's
# what we do here
min_version = '3.0'
current_version = '3.0'
logger.warning("Error in server version query:%s\n" logger.warning("Error in server version query:%s\n"
"Returning APIVersion 2.0", str(e.message)) "Returning APIVersion 3.0", str(e.message))
return (api_versions.APIVersion(min_version), return (api_versions.APIVersion(min_version),
api_versions.APIVersion(current_version)) api_versions.APIVersion(current_version))
def get_highest_client_server_version(url, insecure=False, def get_highest_client_server_version(url, insecure=False,
cacert=None, cert=None): cacert=None, cert=None):
"""Returns highest supported version by client and server as a string.""" """Returns highest supported version by client and server as a string.
:raises: UnsupportedVersion if the maximum supported by the server
is less than the minimum supported by the client
"""
min_server, max_server = get_server_version(url, insecure, cacert, cert) min_server, max_server = get_server_version(url, insecure, cacert, cert)
max_client = api_versions.APIVersion(api_versions.MAX_VERSION) max_client = api_versions.APIVersion(api_versions.MAX_VERSION)
min_client = api_versions.APIVersion(api_versions.MIN_VERSION)
if max_server < min_client:
msg = _("The maximum version supported by the server (%(srv)s) does "
"not meet the minimum version supported by this client "
"(%(cli)s)") % {"srv": str(max_server),
"cli": api_versions.MIN_VERSION}
raise exceptions.UnsupportedVersion(msg)
return min(max_server, max_client).get_string() return min(max_server, max_client).get_string()
@ -769,7 +784,6 @@ def _get_client_class_and_version(version):
def get_client_class(version): def get_client_class(version):
version_map = { version_map = {
'2': 'cinderclient.v2.client.Client',
'3': 'cinderclient.v3.client.Client', '3': 'cinderclient.v3.client.Client',
} }
try: try:
@ -797,10 +811,6 @@ def discover_extensions(version):
def _discover_via_python_path(): def _discover_via_python_path():
for (module_loader, name, ispkg) in pkgutil.iter_modules(): for (module_loader, name, ispkg) in pkgutil.iter_modules():
if name.endswith('cinderclient_ext'): if name.endswith('cinderclient_ext'):
if not hasattr(module_loader, 'load_module'):
# Python 2.6 compat: actually get an ImpImporter obj
module_loader = module_loader.find_module(name)
module = module_loader.load_module(name) module = module_loader.load_module(name)
yield name, module yield name, module
@ -845,7 +855,7 @@ def Client(version, *args, **kwargs):
Here ``VERSION`` can be a string or Here ``VERSION`` can be a string or
``cinderclient.api_versions.APIVersion`` obj. If you prefer string value, ``cinderclient.api_versions.APIVersion`` obj. If you prefer string value,
you can use ``2`` (deprecated now) or ``3.X`` (where X is a microversion). you can use ``3`` or ``3.X`` (where X is a microversion).
Alternatively, you can create a client instance using the keystoneclient Alternatively, you can create a client instance using the keystoneclient

View File

@ -48,7 +48,6 @@ except Exception:
DEFAULT_MAJOR_OS_VOLUME_API_VERSION = "3" DEFAULT_MAJOR_OS_VOLUME_API_VERSION = "3"
DEFAULT_CINDER_ENDPOINT_TYPE = 'publicURL' DEFAULT_CINDER_ENDPOINT_TYPE = 'publicURL'
V2_SHELL = 'cinderclient.v2.shell'
V3_SHELL = 'cinderclient.v3.shell' V3_SHELL = 'cinderclient.v3.shell'
HINT_HELP_MSG = (" [hint: use '--os-volume-api-version' flag to show help " HINT_HELP_MSG = (" [hint: use '--os-volume-api-version' flag to show help "
"message for proper version]") "message for proper version]")
@ -202,7 +201,8 @@ class OpenStackCinderShell(object):
default=None), default=None),
help=_('Block Storage API version. ' help=_('Block Storage API version. '
'Accepts X, X.Y (where X is major and Y is minor ' 'Accepts X, X.Y (where X is major and Y is minor '
'part).' 'part). NOTE: this client accepts only \'3\' for '
'the major version. '
'Default=env[OS_VOLUME_API_VERSION].')) 'Default=env[OS_VOLUME_API_VERSION].'))
parser.add_argument('--os_volume_api_version', parser.add_argument('--os_volume_api_version',
help=argparse.SUPPRESS) help=argparse.SUPPRESS)
@ -356,10 +356,7 @@ class OpenStackCinderShell(object):
self.subcommands = {} self.subcommands = {}
subparsers = parser.add_subparsers(metavar='<subcommand>') subparsers = parser.add_subparsers(metavar='<subcommand>')
if version.ver_major == 3: actions_module = importutils.import_module(V3_SHELL)
actions_module = importutils.import_module(V3_SHELL)
else:
actions_module = importutils.import_module(V2_SHELL)
self._find_actions(subparsers, actions_module, version, do_help, self._find_actions(subparsers, actions_module, version, do_help,
input_args) input_args)
@ -740,6 +737,10 @@ class OpenStackCinderShell(object):
except exc.AuthorizationFailure: except exc.AuthorizationFailure:
raise exc.CommandError("Unable to authorize user.") raise exc.CommandError("Unable to authorize user.")
# FIXME: this section figuring out the api version could use
# analysis and refactoring. See
# https://review.opendev.org/c/openstack/python-cinderclient/+/766882/
# for some ideas.
endpoint_api_version = None endpoint_api_version = None
# Try to get the API version from the endpoint URL. If that fails fall # Try to get the API version from the endpoint URL. If that fails fall
# back to trying to use what the user specified via # back to trying to use what the user specified via
@ -750,18 +751,26 @@ class OpenStackCinderShell(object):
self.cs.get_volume_api_version_from_endpoint() self.cs.get_volume_api_version_from_endpoint()
except exc.UnsupportedVersion: except exc.UnsupportedVersion:
endpoint_api_version = options.os_volume_api_version endpoint_api_version = options.os_volume_api_version
if api_version_input: # FIXME: api_version_input is initialized as True at the beginning
# of this function and never modified
if api_version_input and endpoint_api_version:
logger.warning("Cannot determine the API version from " logger.warning("Cannot determine the API version from "
"the endpoint URL. Falling back to the " "the endpoint URL. Falling back to the "
"user-specified version: %s", "user-specified version: %s",
endpoint_api_version) endpoint_api_version)
else: elif endpoint_api_version:
logger.warning("Cannot determine the API version from the " logger.warning("Cannot determine the API version from the "
"endpoint URL or user input. Falling back " "endpoint URL or user input. Falling back "
"to the default API version: %s", "to the default API version: %s",
endpoint_api_version) endpoint_api_version)
else:
msg = _("Cannot determine API version. Please specify by "
"using --os-volume-api-version option.")
raise exc.UnsupportedVersion(msg)
API_MAX_VERSION = api_versions.APIVersion(api_versions.MAX_VERSION) API_MAX_VERSION = api_versions.APIVersion(api_versions.MAX_VERSION)
# FIXME: the endpoint_api_version[0] can ONLY be '3' now, so the
# above line should probably be ripped out and this condition removed
if endpoint_api_version[0] == '3': if endpoint_api_version[0] == '3':
disc_client = client.Client(API_MAX_VERSION, disc_client = client.Client(API_MAX_VERSION,
os_username, os_username,
@ -807,14 +816,9 @@ class OpenStackCinderShell(object):
os_auth_url, os_auth_url,
client_args): client_args):
if (os_api_version.get_major_version() in discovered_version = api_versions.discover_version(
api_versions.DEPRECATED_VERSIONS): current_client,
discovered_version = api_versions.DEPRECATED_VERSION os_api_version)
os_service_type = 'volume'
else:
discovered_version = api_versions.discover_version(
current_client,
os_api_version)
if not os_endpoint_type: if not os_endpoint_type:
os_endpoint_type = DEFAULT_CINDER_ENDPOINT_TYPE os_endpoint_type = DEFAULT_CINDER_ENDPOINT_TYPE
@ -841,6 +845,11 @@ class OpenStackCinderShell(object):
return current_client, discovered_version return current_client, discovered_version
def _discover_service_type(self, discovered_version): def _discover_service_type(self, discovered_version):
# FIXME: this function is either no longer needed or could use a
# refactoring. The official service type is 'block-storage',
# which isn't even present here. (Devstack creates 2 service
# types which it maps to v3: 'block-storage' and 'volumev3'.
# The default 'catalog_type' in tempest is 'volumev3'.)
SERVICE_TYPES = {'1': 'volume', '2': 'volumev2', '3': 'volumev3'} SERVICE_TYPES = {'1': 'volume', '2': 'volumev2', '3': 'volumev3'}
major_version = discovered_version.get_major_version() major_version = discovered_version.get_major_version()
service_type = SERVICE_TYPES[major_version] service_type = SERVICE_TYPES[major_version]

View File

@ -14,6 +14,7 @@ from keystoneauth1 import fixture
from cinderclient.tests.unit.fixture_data import base from cinderclient.tests.unit.fixture_data import base
from cinderclient.v2 import client as v2client from cinderclient.v2 import client as v2client
from cinderclient.v3 import client as v3client
class Base(base.Fixture): class Base(base.Fixture):
@ -46,3 +47,18 @@ class V2(Base):
api_key='xx', api_key='xx',
project_id='xx', project_id='xx',
auth_url=self.identity_url) auth_url=self.identity_url)
class V3(Base):
def __init__(self, *args, **kwargs):
super(V3, self).__init__(*args, **kwargs)
svc = self.token.add_service('volumev3')
svc.add_endpoint(self.volume_url)
def new_client(self):
return v3client.Client(username='xx',
api_key='xx',
project_id='xx',
auth_url=self.identity_url)

View File

@ -153,7 +153,7 @@ def generate_v2_project_scoped_token(**kwargs):
], ],
'endpoints_links': [], 'endpoints_links': [],
'name': None, 'name': None,
'type': 'volumev2' 'type': 'volumev3'
} }
# Add multiple Cinder endpoints # Add multiple Cinder endpoints
@ -163,7 +163,7 @@ def generate_v2_project_scoped_token(**kwargs):
name = "cinder%i" % count name = "cinder%i" % count
# Assign the service name and a unique endpoint # Assign the service name and a unique endpoint
endpoint_copy['endpoints'][0]['publicURL'] = \ endpoint_copy['endpoints'][0]['publicURL'] = \
'http://%s.api.com/v2' % name 'http://%s.api.com/v3' % name
endpoint_copy['name'] = name endpoint_copy['name'] = name
o['access']['serviceCatalog'].append(endpoint_copy) o['access']['serviceCatalog'].append(endpoint_copy)

View File

@ -18,7 +18,6 @@ from unittest import mock
import ddt import ddt
from cinderclient import api_versions from cinderclient import api_versions
from cinderclient import client as base_client
from cinderclient import exceptions from cinderclient import exceptions
from cinderclient.tests.unit import test_utils from cinderclient.tests.unit import test_utils
from cinderclient.tests.unit import utils from cinderclient.tests.unit import utils
@ -212,6 +211,14 @@ class DiscoverVersionTestCase(utils.TestCase):
self.fake_client.services.server_api_version.return_value = val self.fake_client.services.server_api_version.return_value = val
@ddt.data( @ddt.data(
# what the data mean:
# items 1, 2: client min, max
# items 3, 4: server min, max
# item 5: user's requested API version
# item 6: should this raise an exception?
# item 7: version that should be returned when no exception
# item 8: what client.services.server_api_version should return
# when called by _get_server_version_range in discover_version
("3.1", "3.3", "3.4", "3.7", "3.3", True), # Server too new ("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.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.3", "3.9", "3.7", "3.17", "3.9", False), # Requested < server
@ -222,9 +229,8 @@ class DiscoverVersionTestCase(utils.TestCase):
# downgraded because of both: # downgraded because of both:
("3.5", "3.7", "3.0", "3.8", "3.9", False, "3.7"), ("3.5", "3.7", "3.0", "3.8", "3.9", False, "3.7"),
("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), # Server & client same
("3.5", "3.5", "3.0", "3.5", "3.5", False, "2.0", []), # Pre-micro ("3.5", "3.5", None, None, "3.5", True, None, []), # Pre-micro
("3.1", "3.11", "3.4", "3.7", "3.7", False), # Requested in range ("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 ("3.5", "3.5", "3.0", "3.5", "1.0", True) # Requested too old
) )
@ddt.unpack @ddt.unpack
@ -240,21 +246,23 @@ class DiscoverVersionTestCase(utils.TestCase):
api_versions.MIN_VERSION = client_min api_versions.MIN_VERSION = client_min
if exp_range: if exp_range:
self.assertRaisesRegex(exceptions.UnsupportedVersion, exc = self.assertRaises(exceptions.UnsupportedVersion,
".*range is '%s' to '%s'.*" % api_versions.discover_version,
(server_min, server_max), self.fake_client,
api_versions.discover_version, api_versions.APIVersion(requested_version))
self.fake_client, if ret_val is not None:
api_versions.APIVersion(requested_version)) self.assertIn("Server does not support microversions",
str(exc))
else:
self.assertIn("range is '%s' to '%s'" %
(server_min, server_max), str(exc))
else: else:
discovered_version = api_versions.discover_version( discovered_version = api_versions.discover_version(
self.fake_client, self.fake_client,
api_versions.APIVersion(requested_version)) api_versions.APIVersion(requested_version))
version = requested_version version = requested_version
if server_min is None and server_max is None: if end_version is not None:
version = api_versions.DEPRECATED_VERSION
elif end_version is not None:
version = end_version version = end_version
self.assertEqual(version, self.assertEqual(version,
discovered_version.get_string()) discovered_version.get_string())
@ -266,10 +274,3 @@ class DiscoverVersionTestCase(utils.TestCase):
highest_version = api_versions.get_highest_version(self.fake_client) highest_version = api_versions.get_highest_version(self.fake_client)
self.assertEqual("3.14", highest_version.get_string()) self.assertEqual("3.14", highest_version.get_string())
self.assertTrue(self.fake_client.services.server_api_version.called) self.assertTrue(self.fake_client.services.server_api_version.called)
def test_get_highest_version_bad_client(self):
"""Tests that we gracefully handle the wrong version of client."""
v2_client = base_client.Client('2.0')
ex = self.assertRaises(exceptions.UnsupportedVersion,
api_versions.get_highest_version, v2_client)
self.assertIn('Invalid client version 2.0 to get', str(ex))

View File

@ -33,8 +33,9 @@ import cinderclient.v2.client
class ClientTest(utils.TestCase): class ClientTest(utils.TestCase):
def test_get_client_class_v2(self): def test_get_client_class_v2(self):
output = cinderclient.client.get_client_class('2') self.assertRaises(cinderclient.exceptions.UnsupportedVersion,
self.assertEqual(cinderclient.v2.client.Client, output) cinderclient.client.get_client_class,
'2')
def test_get_client_class_unknown(self): def test_get_client_class_unknown(self):
self.assertRaises(cinderclient.exceptions.UnsupportedVersion, self.assertRaises(cinderclient.exceptions.UnsupportedVersion,
@ -81,10 +82,14 @@ class ClientTest(utils.TestCase):
def test_versions(self): def test_versions(self):
v2_url = 'http://fakeurl/v2/tenants' v2_url = 'http://fakeurl/v2/tenants'
v3_url = 'http://fakeurl/v3/tenants'
unknown_url = 'http://fakeurl/v9/tenants' unknown_url = 'http://fakeurl/v9/tenants'
self.assertEqual('2', self.assertRaises(cinderclient.exceptions.UnsupportedVersion,
cinderclient.client.get_volume_api_from_url(v2_url)) cinderclient.client.get_volume_api_from_url,
v2_url)
self.assertEqual('3',
cinderclient.client.get_volume_api_from_url(v3_url))
self.assertRaises(cinderclient.exceptions.UnsupportedVersion, self.assertRaises(cinderclient.exceptions.UnsupportedVersion,
cinderclient.client.get_volume_api_from_url, cinderclient.client.get_volume_api_from_url,
unknown_url) unknown_url)
@ -318,6 +323,7 @@ class GetAPIVersionTestCase(utils.TestCase):
@mock.patch('cinderclient.client.requests.get') @mock.patch('cinderclient.client.requests.get')
def test_get_server_version_v2(self, mock_request): def test_get_server_version_v2(self, mock_request):
# Why are we testing this? Because we can!
mock_response = utils.TestResponse({ mock_response = utils.TestResponse({
"status_code": 200, "status_code": 200,
@ -329,6 +335,7 @@ class GetAPIVersionTestCase(utils.TestCase):
url = "http://192.168.122.127:8776/v2/e5526285ebd741b1819393f772f11fc3" url = "http://192.168.122.127:8776/v2/e5526285ebd741b1819393f772f11fc3"
min_version, max_version = cinderclient.client.get_server_version(url) min_version, max_version = cinderclient.client.get_server_version(url)
self.assertEqual(api_versions.APIVersion('2.0'), min_version) self.assertEqual(api_versions.APIVersion('2.0'), min_version)
self.assertEqual(api_versions.APIVersion('2.0'), max_version) self.assertEqual(api_versions.APIVersion('2.0'), max_version)
@ -427,3 +434,21 @@ class GetAPIVersionTestCase(utils.TestCase):
cinderclient.client.get_highest_client_server_version(url)) cinderclient.client.get_highest_client_server_version(url))
expected = version if version == '3.12' else '3.16' expected = version if version == '3.12' else '3.16'
self.assertEqual(expected, highest) self.assertEqual(expected, highest)
@mock.patch('cinderclient.client.requests.get')
def test_get_highest_client_server_version_negative(self,
mock_request):
mock_response = utils.TestResponse({
"status_code": 200,
"text": json.dumps(fakes.fake_request_get_no_v3())
})
mock_request.return_value = mock_response
url = "http://192.168.122.127:8776/v3/e5526285ebd741b1819393f772f11fc3"
self.assertRaises(exceptions.UnsupportedVersion,
cinderclient.client.
get_highest_client_server_version,
url)

View File

@ -13,9 +13,9 @@
import argparse import argparse
import io import io
import json
import re import re
import sys import sys
import unittest
from unittest import mock from unittest import mock
import ddt import ddt
@ -35,6 +35,7 @@ from cinderclient import shell
from cinderclient.tests.unit import fake_actions_module from cinderclient.tests.unit import fake_actions_module
from cinderclient.tests.unit.fixture_data import keystone_client from cinderclient.tests.unit.fixture_data import keystone_client
from cinderclient.tests.unit import utils from cinderclient.tests.unit import utils
from cinderclient.tests.unit.v3 import fakes
@ddt.ddt @ddt.ddt
@ -205,8 +206,13 @@ class ShellTest(utils.TestCase):
os_auth_url = "http://multiple.service.names/v2.0" os_auth_url = "http://multiple.service.names/v2.0"
mocker.register_uri('POST', os_auth_url + "/tokens", mocker.register_uri('POST', os_auth_url + "/tokens",
text=keystone_client.keystone_request_callback) text=keystone_client.keystone_request_callback)
# microversion support requires us to make a versions request
# to the endpoint to see exactly what is supported by the server
mocker.register_uri('GET', mocker.register_uri('GET',
"http://cinder%i.api.com/v2/volumes/detail" "http://cinder%i.api.com/"
% count, text=json.dumps(fakes.fake_request_get()))
mocker.register_uri('GET',
"http://cinder%i.api.com/v3/volumes/detail"
% count, text='{"volumes": []}') % count, text='{"volumes": []}')
self.make_env(include={'OS_AUTH_URL': os_auth_url, self.make_env(include={'OS_AUTH_URL': os_auth_url,
'CINDER_SERVICE_NAME': 'cinder%i' % count}) 'CINDER_SERVICE_NAME': 'cinder%i' % count})
@ -219,7 +225,6 @@ class ShellTest(utils.TestCase):
_shell.main, _shell.main,
['list', '--name', 'abc', '--filters', 'name=xyz']) ['list', '--name', 'abc', '--filters', 'name=xyz'])
@unittest.skip("Skip cuz I broke it")
def test_cinder_service_name(self): def test_cinder_service_name(self):
# Failing with 'No mock address' means we are not # Failing with 'No mock address' means we are not
# choosing the correct endpoint # choosing the correct endpoint
@ -248,14 +253,19 @@ class ShellTest(utils.TestCase):
tenant_name=self.FAKE_ENV['OS_PROJECT_NAME'], tenant_name=self.FAKE_ENV['OS_PROJECT_NAME'],
username=self.FAKE_ENV['OS_USERNAME']) username=self.FAKE_ENV['OS_USERNAME'])
@mock.patch('cinderclient.api_versions.discover_version',
return_value=api_versions.APIVersion("3.0"))
@requests_mock.Mocker() @requests_mock.Mocker()
def test_noauth_plugin(self, mocker): def test_noauth_plugin(self, mock_disco, mocker):
os_auth_url = "http://example.com/v2" # just to prove i'm not crazy about the mock parameter ordering
self.assertTrue(requests_mock.mocker.Mocker, type(mocker))
os_volume_url = "http://example.com/volumes/v3"
mocker.register_uri('GET', mocker.register_uri('GET',
"%s/volumes/detail" "%s/volumes/detail"
% os_auth_url, text='{"volumes": []}') % os_volume_url, text='{"volumes": []}')
_shell = shell.OpenStackCinderShell() _shell = shell.OpenStackCinderShell()
args = ['--os-endpoint', os_auth_url, args = ['--os-endpoint', os_volume_url,
'--os-auth-type', 'noauth', '--os-user-id', '--os-auth-type', 'noauth', '--os-user-id',
'admin', '--os-project-id', 'admin', 'list'] 'admin', '--os-project-id', 'admin', 'list']
_shell.main(args) _shell.main(args)

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from cinderclient.v2 import availability_zones from cinderclient.v3 import availability_zones
from cinderclient.v2 import shell from cinderclient.v3 import shell
from cinderclient.tests.unit.fixture_data import availability_zones as azfixture # noqa from cinderclient.tests.unit.fixture_data import availability_zones as azfixture # noqa
from cinderclient.tests.unit.fixture_data import client from cinderclient.tests.unit.fixture_data import client
@ -24,7 +24,7 @@ from cinderclient.tests.unit import utils
class AvailabilityZoneTest(utils.FixturedTestCase): class AvailabilityZoneTest(utils.FixturedTestCase):
client_fixture_class = client.V2 client_fixture_class = client.V3
data_fixture_class = azfixture.Fixture data_fixture_class = azfixture.Fixture
def _assertZone(self, zone, name, status): def _assertZone(self, zone, name, status):

View File

@ -16,4 +16,27 @@
"""Availability Zone interface (v3 extension)""" """Availability Zone interface (v3 extension)"""
from cinderclient.v2.availability_zones import * # noqa from cinderclient import base
class AvailabilityZone(base.Resource):
NAME_ATTR = 'display_name'
def __repr__(self):
return "<AvailabilityZone: %s>" % self.zoneName
class AvailabilityZoneManager(base.ManagerWithFind):
"""Manage :class:`AvailabilityZone` resources."""
resource_class = AvailabilityZone
def list(self, detailed=False):
"""Lists all availability zones.
:rtype: list of :class:`AvailabilityZone`
"""
if detailed is True:
return self._list("/os-availability-zone/detail",
"availabilityZoneInfo")
else:
return self._list("/os-availability-zone", "availabilityZoneInfo")

View File

@ -27,8 +27,8 @@ from cinderclient import exceptions
from cinderclient import shell_utils from cinderclient import shell_utils
from cinderclient import utils from cinderclient import utils
from cinderclient.v2.shell import * # noqa from cinderclient.v3.shell_base import * # noqa
from cinderclient.v2.shell import CheckSizeArgForCreate from cinderclient.v3.shell_base import CheckSizeArgForCreate
FILTER_DEPRECATED = ("This option is deprecated and will be removed in " FILTER_DEPRECATED = ("This option is deprecated and will be removed in "
"newer release. Please use '--filters' option which " "newer release. Please use '--filters' option which "