Fix ImportError when providing a meaningless API version.

Ironicclient parses subcommand by API version. When providing a
meaningless (e.g 0.9) API version, the error message like 'No
module named v0.shell' is not humanized. This patch provides
the error more friendly.

Change-Id: I1d5130cde8fd60234523701b97b9d29f27380e93
Closes-Bug: #1654186
This commit is contained in:
ericxiett
2017-01-20 23:18:15 +08:00
parent 808a4cbfa4
commit 97f82c5a46
2 changed files with 28 additions and 2 deletions

View File

@@ -19,6 +19,9 @@ from __future__ import print_function
import argparse import argparse
import getpass import getpass
import logging import logging
import os
import pkgutil
import re
import sys import sys
from keystoneauth1.loading import session as kasession from keystoneauth1.loading import session as kasession
@@ -27,6 +30,7 @@ from oslo_utils import importutils
import six import six
import ironicclient import ironicclient
from ironicclient.common.apiclient import exceptions
from ironicclient.common import cliutils from ironicclient.common import cliutils
from ironicclient.common import http from ironicclient.common import http
from ironicclient.common.i18n import _ from ironicclient.common.i18n import _
@@ -235,14 +239,31 @@ class IronicShell(object):
return parser return parser
def get_available_major_versions(self):
matcher = re.compile(r"^v[0-9]+$")
submodules = pkgutil.iter_modules([os.path.dirname(__file__)])
available_versions = [name[1:] for loader, name, ispkg in submodules
if matcher.search(name)]
return available_versions
def get_subcommand_parser(self, version): def get_subcommand_parser(self, version):
parser = self.get_base_parser() parser = self.get_base_parser()
self.subcommands = {} self.subcommands = {}
subparsers = parser.add_subparsers(metavar='<subcommand>', subparsers = parser.add_subparsers(metavar='<subcommand>',
dest='subparser_name') dest='subparser_name')
submodule = importutils.import_versioned_module('ironicclient', try:
version, 'shell') submodule = importutils.import_versioned_module('ironicclient',
version, 'shell')
except ImportError as e:
msg = _("Invalid client version '%(version)s'. "
"Major part must be one of: '%(major)s'") % {
"version": version,
"major": ", ".join(self.get_available_major_versions())}
raise exceptions.UnsupportedVersion(
_('%(message)s, error was: %(error)s') %
{'message': msg, 'error': e})
submodule.enhance_parser(parser, subparsers, self.subcommands) submodule.enhance_parser(parser, subparsers, self.subcommands)
utils.define_commands_from_module(subparsers, self, self.subcommands) utils.define_commands_from_module(subparsers, self, self.subcommands)
return parser return parser

View File

@@ -24,6 +24,7 @@ import testtools
from testtools import matchers from testtools import matchers
from ironicclient import client from ironicclient import client
from ironicclient.common.apiclient import exceptions
from ironicclient.common import http from ironicclient.common import http
from ironicclient import exc from ironicclient import exc
from ironicclient import shell as ironic_shell from ironicclient import shell as ironic_shell
@@ -251,6 +252,10 @@ class ShellTest(utils.BaseTestCase):
self.assertRaises(exc.CommandError, self.assertRaises(exc.CommandError,
self.shell, '--ironic-api-version 1.2.1 help') self.shell, '--ironic-api-version 1.2.1 help')
def test_invalid_ironic_api_version(self):
self.assertRaises(exceptions.UnsupportedVersion,
self.shell, '--ironic-api-version 0.8 help')
class TestCase(testtools.TestCase): class TestCase(testtools.TestCase):