Check which glance client version to use
Nova is working toward supporting the glance v2 API which will
allow disabling the glance v1 API in glance in a deployment and
configuring Nova to only use the glance v2 API.
The existing API and scenario tests are setting up a base test image
using the glance v1 client regardless of whether or not the glance v1
API is enabled in tempest.conf.
This adds a check to the tests to see which glance client version
to use depending on the config.
Change-Id: I1b1dc2911698d4e4d1a2727902ba457688d88752
Closes-Bug: #1589093
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 0724566..427a748 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -19,6 +19,7 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
+from tempest import exceptions
from tempest import test
CONF = config.CONF
@@ -36,7 +37,17 @@
@classmethod
def setup_clients(cls):
super(ImagesMetadataTestJSON, cls).setup_clients()
- cls.glance_client = cls.os.image_client
+ # Check if glance v1 is available to determine which client to use. We
+ # prefer glance v1 for the compute API tests since the compute image
+ # API proxy was written for glance v1.
+ if CONF.image_feature_enabled.api_v1:
+ cls.glance_client = cls.os.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ cls.glance_client = cls.os.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
cls.client = cls.compute_images_client
@classmethod
@@ -45,14 +56,22 @@
cls.image_id = None
name = data_utils.rand_name('image')
+ if CONF.image_feature_enabled.api_v1:
+ kwargs = dict(is_public=False)
+ else:
+ kwargs = dict(visibility='private')
body = cls.glance_client.create_image(name=name,
container_format='bare',
disk_format='raw',
- is_public=False)['image']
+ **kwargs)
+ body = body['image'] if 'image' in body else body
cls.image_id = body['id']
cls.images.append(cls.image_id)
image_file = six.StringIO(('*' * 1024))
- cls.glance_client.update_image(cls.image_id, data=image_file)
+ if CONF.image_feature_enabled.api_v1:
+ cls.glance_client.update_image(cls.image_id, data=image_file)
+ else:
+ cls.glance_client.store_image_file(cls.image_id, data=image_file)
waiters.wait_for_image_status(cls.client, cls.image_id, 'ACTIVE')
def setUp(self):
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index af840cc..e74ca67 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -22,6 +22,7 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
+from tempest import exceptions
from tempest import test
CONF = config.CONF
@@ -40,7 +41,17 @@
def setup_clients(cls):
super(ListImageFiltersTestJSON, cls).setup_clients()
cls.client = cls.compute_images_client
- cls.glance_client = cls.os.image_client
+ # Check if glance v1 is available to determine which client to use. We
+ # prefer glance v1 for the compute API tests since the compute image
+ # API proxy was written for glance v1.
+ if CONF.image_feature_enabled.api_v1:
+ cls.glance_client = cls.os.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ cls.glance_client = cls.os.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
@classmethod
def resource_setup(cls):
@@ -48,17 +59,25 @@
def _create_image():
name = data_utils.rand_name('image')
+ if CONF.image_feature_enabled.api_v1:
+ kwargs = dict(is_public=False)
+ else:
+ kwargs = dict(visibility='private')
body = cls.glance_client.create_image(name=name,
container_format='bare',
disk_format='raw',
- is_public=False)['image']
+ **kwargs)
+ body = body['image'] if 'image' in body else body
image_id = body['id']
cls.images.append(image_id)
# Wait 1 second between creation and upload to ensure a delta
# between created_at and updated_at.
time.sleep(1)
image_file = six.StringIO(('*' * 1024))
- cls.glance_client.update_image(image_id, data=image_file)
+ if CONF.image_feature_enabled.api_v1:
+ cls.glance_client.update_image(image_id, data=image_file)
+ else:
+ cls.glance_client.store_image_file(image_id, data=image_file)
waiters.wait_for_image_status(cls.client, image_id, 'ACTIVE')
body = cls.client.show_image(image_id)['image']
return body
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 66aec84..3a4428a 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -24,6 +24,7 @@
from tempest.common.utils.linux import remote_client
from tempest.common import waiters
from tempest import config
+from tempest import exceptions
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from tempest import test
@@ -320,6 +321,19 @@
def test_create_backup(self):
# Positive test:create backup successfully and rotate backups correctly
# create the first and the second backup
+
+ # Check if glance v1 is available to determine which client to use. We
+ # prefer glance v1 for the compute API tests since the compute image
+ # API proxy was written for glance v1.
+ if CONF.image_feature_enabled.api_v1:
+ glance_client = self.os.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ glance_client = self.os.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
+
backup1 = data_utils.rand_name('backup-1')
resp = self.client.create_backup(self.server_id,
backup_type='daily',
@@ -331,7 +345,7 @@
def _clean_oldest_backup(oldest_backup):
if oldest_backup_exist:
try:
- self.os.image_client.delete_image(oldest_backup)
+ glance_client.delete_image(oldest_backup)
except lib_exc.NotFound:
pass
else:
@@ -341,7 +355,7 @@
image1_id = data_utils.parse_image_id(resp['location'])
self.addCleanup(_clean_oldest_backup, image1_id)
- waiters.wait_for_image_status(self.os.image_client,
+ waiters.wait_for_image_status(glance_client,
image1_id, 'active')
backup2 = data_utils.rand_name('backup-2')
@@ -351,8 +365,8 @@
rotation=2,
name=backup2).response
image2_id = data_utils.parse_image_id(resp['location'])
- self.addCleanup(self.os.image_client.delete_image, image2_id)
- waiters.wait_for_image_status(self.os.image_client,
+ self.addCleanup(glance_client.delete_image, image2_id)
+ waiters.wait_for_image_status(glance_client,
image2_id, 'active')
# verify they have been created
@@ -361,12 +375,20 @@
'backup_type': "daily",
'instance_uuid': self.server_id,
}
- image_list = self.os.image_client.list_images(
- detail=True,
- properties=properties,
- status='active',
- sort_key='created_at',
- sort_dir='asc')['images']
+ if CONF.image_feature_enabled.api_v1:
+ params = dict(
+ properties=properties, status='active',
+ sort_key='created_at', sort_dir='asc',)
+ image_list = glance_client.list_images(
+ detail=True,
+ **params)['images']
+ else:
+ # Additional properties are flattened in glance v2.
+ params = dict(
+ status='active', sort_key='created_at', sort_dir='asc')
+ params.update(properties)
+ image_list = glance_client.list_images(params)['images']
+
self.assertEqual(2, len(image_list))
self.assertEqual((backup1, backup2),
(image_list[0]['name'], image_list[1]['name']))
@@ -380,17 +402,16 @@
rotation=2,
name=backup3).response
image3_id = data_utils.parse_image_id(resp['location'])
- self.addCleanup(self.os.image_client.delete_image, image3_id)
+ self.addCleanup(glance_client.delete_image, image3_id)
# the first back up should be deleted
waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
- self.os.image_client.wait_for_resource_deletion(image1_id)
+ glance_client.wait_for_resource_deletion(image1_id)
oldest_backup_exist = False
- image_list = self.os.image_client.list_images(
- detail=True,
- properties=properties,
- status='active',
- sort_key='created_at',
- sort_dir='asc')['images']
+ if CONF.image_feature_enabled.api_v1:
+ image_list = glance_client.list_images(
+ detail=True, **params)['images']
+ else:
+ image_list = glance_client.list_images(params)['images']
self.assertEqual(2, len(image_list),
'Unexpected number of images for '
'v2:test_create_backup; was the oldest backup not '
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 38913ce..76cd36c 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -18,6 +18,7 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
+from tempest import exceptions
from tempest.lib.common.utils import test_utils
from tempest import test
@@ -30,7 +31,16 @@
def setup_clients(cls):
super(VolumesV2ActionsTest, cls).setup_clients()
cls.client = cls.volumes_client
- cls.image_client = cls.os.image_client
+ if CONF.service_available.glance:
+ # Check if glance v1 is available to determine which client to use.
+ if CONF.image_feature_enabled.api_v1:
+ cls.image_client = cls.os.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ cls.image_client = cls.os.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
@classmethod
def resource_setup(cls):
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 8d0f2f6..bab875d 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -50,8 +50,15 @@
cls.compute_floating_ips_client = (
cls.manager.compute_floating_ips_client)
if CONF.service_available.glance:
- # Glance image client v1
- cls.image_client = cls.manager.image_client
+ # Check if glance v1 is available to determine which client to use.
+ if CONF.image_feature_enabled.api_v1:
+ cls.image_client = cls.manager.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ cls.image_client = cls.manager.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
# Compute image client
cls.compute_images_client = cls.manager.compute_images_client
cls.keypairs_client = cls.manager.keypairs_client
@@ -376,14 +383,23 @@
'name': name,
'container_format': fmt,
'disk_format': disk_format or fmt,
- 'is_public': 'False',
}
- params['properties'] = properties
- image = self.image_client.create_image(**params)['image']
+ if CONF.image_feature_enabled.api_v1:
+ params['is_public'] = 'False'
+ params['properties'] = properties
+ else:
+ params['visibility'] = 'private'
+ # Additional properties are flattened out in the v2 API.
+ params.update(properties)
+ body = self.image_client.create_image(**params)
+ image = body['image'] if 'image' in body else body
self.addCleanup(self.image_client.delete_image, image['id'])
self.assertEqual("queued", image['status'])
with open(path, 'rb') as image_file:
- self.image_client.update_image(image['id'], data=image_file)
+ if CONF.image_feature_enabled.api_v1:
+ self.image_client.update_image(image['id'], data=image_file)
+ else:
+ self.image_client.store_image_file(image['id'], image_file)
return image['id']
def glance_image_create(self):
@@ -450,9 +466,16 @@
thing_id=image_id, thing_id_param='id',
cleanup_callable=test_utils.call_and_ignore_notfound_exc,
cleanup_args=[_image_client.delete_image, image_id])
- snapshot_image = _image_client.check_image(image_id)
+ if CONF.image_feature_enabled.api_v1:
+ # In glance v1 the additional properties are stored in the headers.
+ snapshot_image = _image_client.check_image(image_id)
+ image_props = snapshot_image.get('properties', {})
+ else:
+ # In glance v2 the additional properties are flattened.
+ snapshot_image = _image_client.show_image(image_id)
+ image_props = snapshot_image
- bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
+ bdm = image_props.get('block_device_mapping')
if bdm:
bdm = json.loads(bdm)
if bdm and 'snapshot_id' in bdm[0]: