From 61ef35fe79e2a3a76987a92f9ee2db0bf1f6e651 Mon Sep 17 00:00:00 2001 From: Andrey Kurilin Date: Tue, 31 Mar 2015 18:09:36 +0300 Subject: [PATCH] Deprecate v1.1 and remove v3 Module novaclient.v1_1 is already deprecated, so it's time to stop using it inside novaclient. Since support of v3 nova is undocumented feature, which uses v2 implementation, we can remove code related to it. Also, this patch removes redundant check for compute api version != 1.0. Change-Id: I06b349f704d5ae2c592d8d286da268870f2a69e9 --- novaclient/client.py | 37 ++++++++++++----- novaclient/shell.py | 56 ++++---------------------- novaclient/tests/unit/test_client.py | 4 -- novaclient/tests/unit/test_shell.py | 4 -- novaclient/tests/unit/v2/test_shell.py | 11 ----- 5 files changed, 34 insertions(+), 78 deletions(-) diff --git a/novaclient/client.py b/novaclient/client.py index 85d618da1..d7656dab7 100644 --- a/novaclient/client.py +++ b/novaclient/client.py @@ -24,8 +24,10 @@ import copy import functools import hashlib import logging +import pkgutil import re import socket +import warnings from keystoneclient import adapter from oslo_utils import importutils @@ -41,11 +43,15 @@ except ImportError: from six.moves.urllib import parse from novaclient import exceptions -from novaclient.i18n import _ +from novaclient.i18n import _, _LW from novaclient import service_catalog from novaclient import utils +# key is a deprecated version and value is an alternative version. +DEPRECATED_VERSIONS = {"1.1": "2"} + + class TCPKeepAliveAdapter(adapters.HTTPAdapter): """The custom adapter used to set TCP Keep-Alive on all connections.""" def init_poolmanager(self, *args, **kwargs): @@ -712,21 +718,30 @@ def _construct_http_client(username=None, password=None, project_id=None, def get_client_class(version): - version_map = { - '1.1': 'novaclient.v2.client.Client', - '2': 'novaclient.v2.client.Client', - '3': 'novaclient.v2.client.Client', - } + version = str(version) + if version in DEPRECATED_VERSIONS: + warnings.warn(_LW( + "Version %(deprecated_version)s is deprecated, using " + "alternative version %(alternative)s instead.") % + {"deprecated_version": version, + "alternative": DEPRECATED_VERSIONS[version]}) + version = DEPRECATED_VERSIONS[version] try: - client_path = version_map[str(version)] - except (KeyError, ValueError): + return importutils.import_class( + "novaclient.v%s.client.Client" % version) + except ImportError: + # NOTE(andreykurilin): available clients version should not be + # hardcoded, so let's discover them. + matcher = re.compile(r"v[0-9_]*$") + submodules = pkgutil.iter_modules(['novaclient']) + available_versions = [ + name[1:].replace("_", ".") for loader, name, ispkg in submodules + if matcher.search(name)] msg = _("Invalid client version '%(version)s'. must be one of: " "%(keys)s") % {'version': version, - 'keys': ', '.join(version_map.keys())} + 'keys': ', '.join(available_versions)} raise exceptions.UnsupportedVersion(msg) - return importutils.import_class(client_path) - def Client(version, *args, **kwargs): client_class = get_client_class(version) diff --git a/novaclient/shell.py b/novaclient/shell.py index 4e7b5c96c..515163533 100644 --- a/novaclient/shell.py +++ b/novaclient/shell.py @@ -58,13 +58,7 @@ from novaclient.v2 import shell as shell_v2 DEFAULT_OS_COMPUTE_API_VERSION = "2" DEFAULT_NOVA_ENDPOINT_TYPE = 'publicURL' -# NOTE(cyeoh): Having the service type dependent on the API version -# is pretty ugly, but we have to do this because traditionally the -# catalog entry for compute points directly to the V2 API rather than -# the root, and then doing version discovery. -DEFAULT_NOVA_SERVICE_TYPE_MAP = {'1.1': 'compute', - '2': 'compute', - '3': 'computev3'} +DEFAULT_NOVA_SERVICE_TYPE = "compute" logger = logging.getLogger(__name__) @@ -414,7 +408,7 @@ class OpenStackComputeShell(object): metavar='', default=cliutils.env('OS_COMPUTE_API_VERSION', default=DEFAULT_OS_COMPUTE_API_VERSION), - help=_('Accepts 1.1 or 3, ' + help=_('Accepts number of API version, ' 'defaults to env[OS_COMPUTE_API_VERSION].')) parser.add_argument( '--os_compute_api_version', @@ -490,9 +484,9 @@ class OpenStackComputeShell(object): def _discover_via_contrib_path(self, version): module_path = os.path.dirname(os.path.abspath(__file__)) version_str = "v%s" % version.replace('.', '_') - # NOTE(akurilin): v1.1, v2 and v3 have one implementation, so - # we should discover contrib modules in one place. - if version_str in ["v1_1", "v3"]: + # NOTE(andreykurilin): v1.1 uses implementation of v2, so we should + # discover contrib modules in novaclient.v2 dir. + if version_str == "v1_1": version_str = "v2" ext_path = os.path.join(module_path, version_str, 'contrib') ext_glob = os.path.join(ext_path, "*.py") @@ -656,15 +650,8 @@ class OpenStackComputeShell(object): endpoint_type += 'URL' if not service_type: - os_compute_api_version = (options.os_compute_api_version or - DEFAULT_OS_COMPUTE_API_VERSION) - try: - service_type = DEFAULT_NOVA_SERVICE_TYPE_MAP[ - os_compute_api_version] - except KeyError: - service_type = DEFAULT_NOVA_SERVICE_TYPE_MAP[ - DEFAULT_OS_COMPUTE_API_VERSION] - service_type = cliutils.get_service_type(args.func) or service_type + service_type = (cliutils.get_service_type(args.func) or + DEFAULT_NOVA_SERVICE_TYPE) # If we have an auth token but no management_url, we must auth anyway. # Expired tokens are handled by client.py:_cs_request @@ -734,8 +721,7 @@ class OpenStackComputeShell(object): project_domain_id=args.os_project_domain_id, project_domain_name=args.os_project_domain_name) - if (options.os_compute_api_version and - options.os_compute_api_version != '1.0'): + if options.os_compute_api_version: if not any([args.os_tenant_id, args.os_tenant_name, args.os_project_id, args.os_project_name]): raise exc.CommandError(_("You must provide a project name or" @@ -806,32 +792,6 @@ class OpenStackComputeShell(object): except exc.AuthorizationFailure: raise exc.CommandError(_("Unable to authorize user")) - if options.os_compute_api_version == "3" and service_type != 'image': - # NOTE(cyeoh): create an image based client because the - # images api is no longer proxied by the V3 API and we - # sometimes need to be able to look up images information - # via glance when connected to the nova api. - image_service_type = 'image' - # NOTE(hdd): the password is needed again because creating a new - # Client without specifying bypass_url will force authentication. - # We can't reuse self.cs's bypass_url, because that's the URL for - # the nova service; we need to get glance's URL for this Client - if not os_password: - os_password = helper.password - self.cs.image_cs = client.Client( - options.os_compute_api_version, os_username, - os_password, os_tenant_name, tenant_id=os_tenant_id, - auth_url=os_auth_url, insecure=insecure, - region_name=os_region_name, endpoint_type=endpoint_type, - extensions=self.extensions, service_type=image_service_type, - service_name=service_name, auth_system=os_auth_system, - auth_plugin=auth_plugin, - volume_service_name=volume_service_name, - timings=args.timings, bypass_url=bypass_url, - os_cache=os_cache, http_log_debug=options.debug, - session=keystone_session, auth=keystone_auth, - cacert=cacert, timeout=timeout) - args.func(self.cs, args) if args.timings: diff --git a/novaclient/tests/unit/test_client.py b/novaclient/tests/unit/test_client.py index 805278cca..a828503e1 100644 --- a/novaclient/tests/unit/test_client.py +++ b/novaclient/tests/unit/test_client.py @@ -161,10 +161,6 @@ class ClientTest(utils.TestCase): self._check_version_url('http://foo.com/nova/v2/%s', 'http://foo.com/nova/') - def test_get_client_class_v3(self): - output = novaclient.client.get_client_class('3') - self.assertEqual(output, novaclient.v2.client.Client) - def test_get_client_class_v2(self): output = novaclient.client.get_client_class('2') self.assertEqual(output, novaclient.v2.client.Client) diff --git a/novaclient/tests/unit/test_shell.py b/novaclient/tests/unit/test_shell.py index f284eb88e..a8826deb5 100644 --- a/novaclient/tests/unit/test_shell.py +++ b/novaclient/tests/unit/test_shell.py @@ -342,10 +342,6 @@ class ShellTest(utils.TestCase): def test_v2_service_type(self, mock_client): self._test_service_type('2', 'compute', mock_client) - @mock.patch('novaclient.client.Client') - def test_v3_service_type(self, mock_client): - self._test_service_type('3', 'computev3', mock_client) - @mock.patch('novaclient.client.Client') def test_v_unknown_service_type(self, mock_client): self._test_service_type('unknown', 'compute', mock_client) diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py index 139ea18e5..0abc345d1 100644 --- a/novaclient/tests/unit/v2/test_shell.py +++ b/novaclient/tests/unit/v2/test_shell.py @@ -2374,17 +2374,6 @@ class ShellTestV11(ShellTest): } -class ShellTestV3(ShellTest): - FAKE_ENV = { - 'NOVA_USERNAME': 'username', - 'NOVA_PASSWORD': 'password', - 'NOVA_PROJECT_ID': 'project_id', - 'OS_COMPUTE_API_VERSION': '3', - 'NOVA_URL': 'http://no.where', - 'OS_AUTH_URL': 'http://no.where/v2.0', - } - - class ShellWithSessionClientTest(ShellTest): def setUp(self):