Enable ironicclient with --ironic-api-version 1.x

python-ironic-client doesn't recognize API micro-version parameter.
Reuse --ironic-api-version to recognize this.

1. The client accepts '1.x' or 'latest' as valid API version and send
corresponding headers to Ironic.
2. If the user does not specify a version, client will not sent any
extra headers to Ironic. It will use the minimum version.

Closes-Bug: #1417430
Change-Id: I1db6e2f4e57d6d47d86f068018f143d0044b7211
This commit is contained in:
Lin Tan 2015-02-13 10:47:16 +08:00
parent 17018ce723
commit 53095aaa8f
5 changed files with 76 additions and 13 deletions

View File

@ -111,6 +111,7 @@ def get_client(api_version, **kwargs):
'cert_file': kwargs.get('cert_file'),
'key_file': kwargs.get('key_file'),
'auth_ref': auth_ref,
'os_ironic_api_version': kwargs.get('os_ironic_api_version'),
}
return Client(api_version, endpoint, **cli_kwargs)

View File

@ -62,6 +62,7 @@ class HTTPClient(object):
self.endpoint_trimmed = _trim_endpoint_api_version(endpoint)
self.auth_token = kwargs.get('token')
self.auth_ref = kwargs.get('auth_ref')
self.os_ironic_api_version = kwargs.get('os_ironic_api_version')
self.connection_params = self.get_connection_params(endpoint, **kwargs)
@staticmethod
@ -146,6 +147,9 @@ class HTTPClient(object):
# Copy the kwargs so we can reuse the original in case of redirects
kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
kwargs['headers'].setdefault('User-Agent', USER_AGENT)
if self.os_ironic_api_version:
kwargs['headers'].setdefault('X-OpenStack-Ironic-API-Version',
self.os_ironic_api_version)
if self.auth_token:
kwargs['headers'].setdefault('X-Auth-Token', self.auth_token)
@ -293,6 +297,9 @@ class SessionClient(adapter.LegacyJsonAdapter):
def _http_request(self, url, method, **kwargs):
kwargs.setdefault('user_agent', USER_AGENT)
kwargs.setdefault('auth', self.auth)
if getattr(self, 'os_ironic_api_version', None):
kwargs['headers'].setdefault('X-OpenStack-Ironic-API-Version',
self.os_ironic_api_version)
endpoint_filter = kwargs.setdefault('endpoint_filter', {})
endpoint_filter.setdefault('interface', self.interface)
@ -301,7 +308,6 @@ class SessionClient(adapter.LegacyJsonAdapter):
resp = self.session.request(url, method,
raise_exc=False, **kwargs)
if 400 <= resp.status_code < 600:
error_json = _extract_error_json(resp.content)
raise exc.from_response(resp, error_json.get('faultstring'),
@ -371,12 +377,16 @@ def _construct_http_client(*args, **kwargs):
service_type = kwargs.pop('service_type', 'baremetal')
interface = kwargs.pop('endpoint_type', None)
region_name = kwargs.pop('region_name', None)
return SessionClient(session=session,
auth=auth,
interface=interface,
service_type=service_type,
region_name=region_name,
service_name=None,
user_agent='python-ironicclient')
os_ironic_api_version = kwargs.pop('os_ironic_api_version', None)
session_client = SessionClient(session=session,
auth=auth,
interface=interface,
service_type=service_type,
region_name=region_name,
service_name=None,
user_agent='python-ironicclient')
# Append an ironic specific variable to session
session_client.os_ironic_api_version = os_ironic_api_version
return session_client
else:
return HTTPClient(*args, **kwargs)

View File

@ -42,6 +42,9 @@ from ironicclient.openstack.common import gettextutils
gettextutils.install('ironicclient')
LATEST_API_VERSION = ('1', 'latest')
class IronicShell(object):
def _append_global_identity_args(self, parser):
@ -187,8 +190,9 @@ class IronicShell(object):
parser.add_argument('--ironic-api-version',
default=cliutils.env(
'IRONIC_API_VERSION', default='1'),
help='Defaults to env[IRONIC_API_VERSION] '
'or 1')
help='Accepts 1.x (where "x" is microversion) '
'or "latest", Defaults to '
'env[IRONIC_API_VERSION] or 1')
parser.add_argument('--ironic_api_version',
help=argparse.SUPPRESS)
@ -349,6 +353,30 @@ class IronicShell(object):
return auth
def _check_version(self, api_version):
if api_version == 'latest':
return LATEST_API_VERSION
else:
try:
versions = tuple(int(i) for i in api_version.split('.'))
except ValueError:
versions = ()
if len(versions) == 1:
# Default value of ironic_api_version is '1'.
# If user not specify the value of api version, not passing
# headers at all.
os_ironic_api_version = None
elif len(versions) == 2:
os_ironic_api_version = api_version
# In the case of '1.0'
if versions[1] == 0:
os_ironic_api_version = None
else:
raise exc.CommandError("Incorrect API version %s, expect "
"value ike X.Y" % api_version)
api_major_version = versions[0]
return (api_major_version, os_ironic_api_version)
def main(self, argv):
# Parse args once to find version
parser = self.get_base_parser()
@ -356,8 +384,10 @@ class IronicShell(object):
self._setup_debugging(options.debug)
# build available subcommands based on version
api_version = options.ironic_api_version
subcommand_parser = self.get_subcommand_parser(api_version)
(api_major_version, os_ironic_api_version) = (
self._check_version(options.ironic_api_version))
subcommand_parser = self.get_subcommand_parser(api_major_version)
self.parser = subcommand_parser
# Handle top-level --help/-h before attempting to parse
@ -466,7 +496,8 @@ class IronicShell(object):
'username': args.os_username,
'password': args.os_password,
}
client = iroclient.Client(api_version, endpoint, **kwargs)
kwargs['os_ironic_api_version'] = os_ironic_api_version
client = iroclient.Client(api_major_version, endpoint, **kwargs)
try:
args.func(client, args)

View File

@ -140,3 +140,18 @@ class ClientTest(utils.BaseTestCase):
client = get_client('1', **kwargs)
self.assertEqual(ksclient().auth_ref, client.http_client.auth_ref)
def test_get_client_with_api_version(self):
self.useFixture(fixtures.MonkeyPatch(
'ironicclient.client._get_ksclient', fake_get_ksclient))
kwargs = {
'os_tenant_name': 'TENANT_NAME',
'os_username': 'USERNAME',
'os_password': 'PASSWORD',
'os_auth_url': 'http://localhost:35357/v2.0',
'os_auth_token': '',
'os_ironic_api_version': 'latest',
}
client = get_client('1', **kwargs)
self.assertEqual('latest', client.http_client.os_ironic_api_version)

View File

@ -170,6 +170,12 @@ class ShellTest(utils.BaseTestCase):
self.assertThat(stdout,
matchers.MatchesRegex(r, self.re_options))
def test_ironic_api_version(self):
self.shell('--ironic-api-version 1.2 help')
self.shell('--ironic-api-version latest help')
self.assertRaises(exc.CommandError,
self.shell, '--ironic-api-version 1.2.1 help')
class TestCase(testtools.TestCase):