Merge "Use API v2 as default"

This commit is contained in:
Jenkins 2015-08-13 23:43:59 +00:00 committed by Gerrit Code Review
commit 13af690396
3 changed files with 107 additions and 29 deletions

View File

@ -22,6 +22,7 @@ from __future__ import print_function
import argparse
import copy
import getpass
import hashlib
import json
import logging
import os
@ -263,7 +264,7 @@ class OpenStackImagesShell(object):
parser.add_argument('--os-image-api-version',
default=utils.env('OS_IMAGE_API_VERSION',
default=None),
help='Defaults to env[OS_IMAGE_API_VERSION] or 1.')
help='Defaults to env[OS_IMAGE_API_VERSION] or 2.')
parser.add_argument('--os_image_api_version',
help=argparse.SUPPRESS)
@ -551,9 +552,13 @@ class OpenStackImagesShell(object):
def _cache_schemas(self, options, home_dir='~/.glanceclient'):
homedir = os.path.expanduser(home_dir)
if not os.path.exists(homedir):
path_prefix = homedir
if options.os_auth_url:
hash_host = hashlib.sha1(options.os_auth_url.encode('utf-8'))
path_prefix = os.path.join(path_prefix, hash_host.hexdigest())
if not os.path.exists(path_prefix):
try:
os.makedirs(homedir)
os.makedirs(path_prefix)
except OSError as e:
# This avoids glanceclient to crash if it can't write to
# ~/.glanceclient, which may happen on some env (for me,
@ -561,12 +566,12 @@ class OpenStackImagesShell(object):
# /var/lib/jenkins).
msg = '%s' % e
print(encodeutils.safe_decode(msg), file=sys.stderr)
resources = ['image', 'metadefs/namespace', 'metadefs/resource_type']
schema_file_paths = [homedir + os.sep + x + '_schema.json'
schema_file_paths = [os.path.join(path_prefix, x + '_schema.json')
for x in ['image', 'namespace', 'resource_type']]
client = None
failed_download_schema = 0
for resource, schema_file_path in zip(resources, schema_file_paths):
if (not os.path.exists(schema_file_path)) or options.get_schema:
try:
@ -580,8 +585,11 @@ class OpenStackImagesShell(object):
except Exception:
# NOTE(esheffield) do nothing here, we'll get a message
# later if the schema is missing
failed_download_schema += 1
pass
return failed_download_schema >= len(resources)
def main(self, argv):
# Parse args once to find version
@ -605,7 +613,7 @@ class OpenStackImagesShell(object):
# build available subcommands based on version
try:
api_version = int(options.os_image_api_version or url_version or 1)
api_version = int(options.os_image_api_version or url_version or 2)
if api_version not in SUPPORTED_VERSIONS:
raise ValueError
except ValueError:
@ -614,7 +622,12 @@ class OpenStackImagesShell(object):
utils.exit(msg=msg)
if api_version == 2:
self._cache_schemas(options)
switch_version = self._cache_schemas(options)
if switch_version:
print('WARNING: The client is falling back to v1 because'
' the accessing to v2 failed. This behavior will'
' be removed in future versions')
api_version = 1
try:
subcommand_parser = self.get_subcommand_parser(api_version)

View File

@ -24,26 +24,61 @@ class SimpleReadOnlyGlanceClientTest(base.ClientTestBase):
This only exercises client commands that are read only.
"""
def test_list(self):
out = self.glance('image-list')
def test_list_v1(self):
out = self.glance('--os-image-api-version 1 image-list')
endpoints = self.parser.listing(out)
self.assertTableStruct(endpoints, [
'ID', 'Name', 'Disk Format', 'Container Format',
'Size', 'Status'])
def test_list_v2(self):
out = self.glance('--os-image-api-version 2 image-list')
endpoints = self.parser.listing(out)
self.assertTableStruct(endpoints, ['ID', 'Name'])
def test_fake_action(self):
self.assertRaises(exceptions.CommandFailed,
self.glance,
'this-does-not-exist')
def test_member_list(self):
def test_member_list_v1(self):
tenant_name = '--tenant-id %s' % self.tenant_name
out = self.glance('member-list',
out = self.glance('--os-image-api-version 1 member-list',
params=tenant_name)
endpoints = self.parser.listing(out)
self.assertTableStruct(endpoints,
['Image ID', 'Member ID', 'Can Share'])
def test_member_list_v2(self):
try:
# NOTE(flwang): If set disk-format and container-format, Jenkins
# will raise an error said can't recognize the params, thouhg it
# works fine at local. Without the two params, Glance will
# complain. So we just catch the exception can skip it.
self.glance('--os-image-api-version 2 image-create --name temp')
except Exception:
pass
out = self.glance('--os-image-api-version 2 image-list'
' --visibility private')
image_list = self.parser.listing(out)
# NOTE(flwang): Because the member-list command of v2 is using
# image-id as required parameter, so we have to get a valid image id
# based on current environment. If there is no valid image id, we will
# pass in a fake one and expect a 404 error.
if len(image_list) > 0:
param_image_id = '--image-id %s' % image_list[0]['ID']
out = self.glance('--os-image-api-version 2 member-list',
params=param_image_id)
endpoints = self.parser.listing(out)
self.assertTableStruct(endpoints,
['Image ID', 'Member ID', 'Status'])
else:
param_image_id = '--image-id fake_image_id'
self.assertRaises(exceptions.CommandFailed,
self.glance,
'--os-image-api-version 2 member-list',
params=param_image_id)
def test_help(self):
help_text = self.glance('help')
lines = help_text.split('\n')

View File

@ -19,6 +19,7 @@ try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
import hashlib
import os
import sys
import uuid
@ -204,8 +205,8 @@ class ShellTest(testutils.TestCase):
def test_no_auth_with_token_and_image_url_with_v1(self, v1_client):
# test no authentication is required if both token and endpoint url
# are specified
args = ('--os-auth-token mytoken --os-image-url https://image:1234/v1 '
'image-list')
args = ('--os-image-api-version 1 --os-auth-token mytoken'
' --os-image-url https://image:1234/v1 image-list')
glance_shell = openstack_shell.OpenStackImagesShell()
glance_shell.main(args.split())
assert v1_client.called
@ -213,7 +214,8 @@ class ShellTest(testutils.TestCase):
self.assertEqual('mytoken', kwargs['token'])
self.assertEqual('https://image:1234', args[0])
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
return_value=False)
def test_no_auth_with_token_and_image_url_with_v2(self,
cache_schemas):
with mock.patch('glanceclient.v2.client.Client') as v2_client:
@ -244,13 +246,14 @@ class ShellTest(testutils.TestCase):
@mock.patch('glanceclient.v1.client.Client')
def test_auth_plugin_invocation_with_v1(self, v1_client):
args = 'image-list'
args = '--os-image-api-version 1 image-list'
glance_shell = openstack_shell.OpenStackImagesShell()
glance_shell.main(args.split())
self._assert_auth_plugin_args()
@mock.patch('glanceclient.v2.client.Client')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
return_value=False)
def test_auth_plugin_invocation_with_v2(self,
v2_client,
cache_schemas):
@ -262,13 +265,15 @@ class ShellTest(testutils.TestCase):
@mock.patch('glanceclient.v1.client.Client')
def test_auth_plugin_invocation_with_unversioned_auth_url_with_v1(
self, v1_client):
args = '--os-auth-url %s image-list' % DEFAULT_UNVERSIONED_AUTH_URL
args = ('--os-image-api-version 1 --os-auth-url %s image-list' %
DEFAULT_UNVERSIONED_AUTH_URL)
glance_shell = openstack_shell.OpenStackImagesShell()
glance_shell.main(args.split())
self._assert_auth_plugin_args()
@mock.patch('glanceclient.v2.client.Client')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
return_value=False)
def test_auth_plugin_invocation_with_unversioned_auth_url_with_v2(
self, v2_client, cache_schemas):
args = ('--os-auth-url %s --os-image-api-version 2 '
@ -300,7 +305,8 @@ class ShellTest(testutils.TestCase):
@mock.patch(
'glanceclient.shell.OpenStackImagesShell._get_keystone_session')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
return_value=False)
def test_no_auth_with_proj_name(self, cache_schemas, session):
with mock.patch('glanceclient.v2.client.Client'):
args = ('--os-project-name myname '
@ -414,7 +420,10 @@ class ShellTest(testutils.TestCase):
self.assertRaises(exc.CommandError, glance_shell.main, args.split())
@mock.patch('glanceclient.v2.client.Client')
def test_auth_plugin_invocation_without_tenant_with_v2(self, v2_client):
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
return_value=False)
def test_auth_plugin_invocation_without_tenant_with_v2(self, v2_client,
cache_schemas):
if 'OS_TENANT_NAME' in os.environ:
self.make_env(exclude='OS_TENANT_NAME')
if 'OS_PROJECT_ID' in os.environ:
@ -445,13 +454,14 @@ class ShellTestWithKeystoneV3Auth(ShellTest):
@mock.patch('glanceclient.v1.client.Client')
def test_auth_plugin_invocation_with_v1(self, v1_client):
args = 'image-list'
args = '--os-image-api-version 1 image-list'
glance_shell = openstack_shell.OpenStackImagesShell()
glance_shell.main(args.split())
self._assert_auth_plugin_args()
@mock.patch('glanceclient.v2.client.Client')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
return_value=False)
def test_auth_plugin_invocation_with_v2(self, v2_client, cache_schemas):
args = '--os-image-api-version 2 image-list'
glance_shell = openstack_shell.OpenStackImagesShell()
@ -489,9 +499,12 @@ class ShellCacheSchemaTest(testutils.TestCase):
self._mock_client_setup()
self._mock_shell_setup()
self.cache_dir = '/dir_for_cached_schema'
self.cache_files = [self.cache_dir + '/image_schema.json',
self.cache_dir + '/namespace_schema.json',
self.cache_dir + '/resource_type_schema.json']
self.os_auth_url = 'http://localhost:5000/v2'
url_hex = hashlib.sha1(self.os_auth_url.encode('utf-8')).hexdigest()
self.prefix_path = (self.cache_dir + '/' + url_hex)
self.cache_files = [self.prefix_path + '/image_schema.json',
self.prefix_path + '/namespace_schema.json',
self.prefix_path + '/resource_type_schema.json']
def tearDown(self):
super(ShellCacheSchemaTest, self).tearDown()
@ -524,7 +537,8 @@ class ShellCacheSchemaTest(testutils.TestCase):
@mock.patch('os.path.exists', return_value=True)
def test_cache_schemas_gets_when_forced(self, exists_mock):
options = {
'get_schema': True
'get_schema': True,
'os_auth_url': self.os_auth_url
}
schema_odict = OrderedDict(self.schema_dict)
@ -545,7 +559,8 @@ class ShellCacheSchemaTest(testutils.TestCase):
@mock.patch('os.path.exists', side_effect=[True, False, False, False])
def test_cache_schemas_gets_when_not_exists(self, exists_mock):
options = {
'get_schema': False
'get_schema': False,
'os_auth_url': self.os_auth_url
}
schema_odict = OrderedDict(self.schema_dict)
@ -566,14 +581,29 @@ class ShellCacheSchemaTest(testutils.TestCase):
@mock.patch('os.path.exists', return_value=True)
def test_cache_schemas_leaves_when_present_not_forced(self, exists_mock):
options = {
'get_schema': False
'get_schema': False,
'os_auth_url': self.os_auth_url
}
self.shell._cache_schemas(self._make_args(options),
home_dir=self.cache_dir)
os.path.exists.assert_any_call(self.cache_dir)
os.path.exists.assert_any_call(self.prefix_path)
os.path.exists.assert_any_call(self.cache_files[0])
os.path.exists.assert_any_call(self.cache_files[1])
self.assertEqual(4, exists_mock.call_count)
self.assertEqual(0, open.mock_calls.__len__())
@mock.patch('six.moves.builtins.open', new=mock.mock_open(), create=True)
@mock.patch('os.path.exists', return_value=True)
def test_cache_schemas_leaves_auto_switch(self, exists_mock):
options = {
'get_schema': True,
'os_auth_url': self.os_auth_url
}
self.client.schemas.get.return_value = Exception()
switch_version = self.shell._cache_schemas(self._make_args(options),
home_dir=self.cache_dir)
self.assertEqual(switch_version, True)