Merge "Use configured upper-constraints for non-master Tempest run"
diff --git a/releasenotes/notes/add-alt-project-dynamic-creds-1a3bc543e65d9433.yaml b/releasenotes/notes/add-alt-project-dynamic-creds-1a3bc543e65d9433.yaml
new file mode 100644
index 0000000..de81b2b
--- /dev/null
+++ b/releasenotes/notes/add-alt-project-dynamic-creds-1a3bc543e65d9433.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Add project alternate admin, member and reader role for dynamic credentials.
diff --git a/releasenotes/notes/image-client-add-versions-and-tasks-ac289dbfe1c899cc.yaml b/releasenotes/notes/image-client-add-versions-and-tasks-ac289dbfe1c899cc.yaml
new file mode 100644
index 0000000..fde6193
--- /dev/null
+++ b/releasenotes/notes/image-client-add-versions-and-tasks-ac289dbfe1c899cc.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Adds a method to images_client to get tasks relevant to a given image. Also adds
+ has_version() method to image versions_client to probe for availability of a given
+ API version.
diff --git a/releasenotes/notes/intermediate-wallaby-release-55a0b31b1dee7b23.yaml b/releasenotes/notes/intermediate-wallaby-release-55a0b31b1dee7b23.yaml
new file mode 100644
index 0000000..cda3b89
--- /dev/null
+++ b/releasenotes/notes/intermediate-wallaby-release-55a0b31b1dee7b23.yaml
@@ -0,0 +1,4 @@
+---
+prelude: >
+ This is an intermediate release during the Wallaby development cycle to
+ make new functionality available to plugins and other consumers.
diff --git a/releasenotes/notes/remove-deprecated-volume-config-options-4b7ea93b88e5b982.yaml b/releasenotes/notes/remove-deprecated-volume-config-options-4b7ea93b88e5b982.yaml
new file mode 100644
index 0000000..f3002f9
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-volume-config-options-4b7ea93b88e5b982.yaml
@@ -0,0 +1,9 @@
+---
+upgrade:
+ - |
+ Deprecated config options to select the Volume API version have been
+ removed. Use ``CONF.volume.catalog_type`` to run volume tests under v3
+ or v2 APIs.
+
+ * ``CONF.volume-feature-enabled.api_v2``
+ * ``CONF.volume-feature-enabled.api_v3``
\ No newline at end of file
diff --git a/releasenotes/notes/support-scope-in-get-roles-dynamic-creds-90bfab163c1c289a.yaml b/releasenotes/notes/support-scope-in-get-roles-dynamic-creds-90bfab163c1c289a.yaml
new file mode 100644
index 0000000..26282f0
--- /dev/null
+++ b/releasenotes/notes/support-scope-in-get-roles-dynamic-creds-90bfab163c1c289a.yaml
@@ -0,0 +1,36 @@
+---
+features:
+ - |
+ Dynamic credentials now support the scope type for specific roles
+ too along with ``admin``, ``member``, ``reader`` role.
+ Test can specify the scope in the prefix of ``cls.credentials`` name.
+ If ``system`` is prefix in ``cls.credentials`` name then creds will
+ be created with scope as ``system``. If ``domain`` is prefix in
+ ``cls.credentials`` name then creds will be created with scope as
+ ``domain`` otherwise default ``project`` scope will be used.
+ For Example::
+
+ credentials = [['my_role', 'role1'], # this will be old style and project scoped
+ ['project_my_role', 'role1'], # this will be project scoped
+ ['domain_my_role', 'role1'], # this will be domain scoped
+ ['system_my_role', 'role1']] # this will be system scoped
+
+ And below is how test can access the credential manager of respective
+ credentials type::
+
+ cls.os_my_role.any_client
+ cls.os_project_my_role.any_client
+ cls.os_domain_my_role.any_client
+ cls.os_system_my_role.any_client
+
+
+ For backward compatibility, we set the credentials manager class attribute
+ in old style form too which is prefix with ``os_roles_*``, example
+ ``cls.os_roles_my_role`` but we recommend to use the new style attribute
+ as shown above.
+issues:
+ - |
+ Scope support for specific role is not yet added for pre-provisioned credentials.
+fixes:
+ - |
+ Fixes the `bug# 1917168 <https://bugs.launchpad.net/tempest/+bug/1917168>`_
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 941315e..52ccea7 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -169,8 +169,13 @@
block_migrate_cinder_iscsi,
'Block Live migration not configured for iSCSI')
@utils.services('volume')
- def test_iscsi_volume(self):
- """Test live migrating a server with volume attached"""
+ def test_live_block_migration_with_attached_volume(self):
+ """Test the live-migration of an instance with an attached volume.
+
+ This tests the live-migration of an instance with both a local disk and
+ attach volume. This differs from test_volume_backed_live_migration
+ above that tests live-migration with only an attached volume.
+ """
server = self.create_test_server(wait_until="ACTIVE")
server_id = server['id']
if not CONF.compute_feature_enabled.can_migrate_between_any_hosts:
diff --git a/tempest/api/compute/admin/test_volume.py b/tempest/api/compute/admin/test_volume.py
index 342380e..cf8c560 100644
--- a/tempest/api/compute/admin/test_volume.py
+++ b/tempest/api/compute/admin/test_volume.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
+import io
from tempest.api.compute import base
from tempest.common import waiters
@@ -51,7 +51,7 @@
image = self.image_client.show_image(CONF.compute.image_ref)
image_data = self.image_client.show_image_file(
CONF.compute.image_ref).data
- image_file = six.BytesIO(image_data)
+ image_file = io.BytesIO(image_data)
create_dict = {
'container_format': image['container_format'],
'disk_format': image['disk_format'],
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
index 235049a..5d6a7d7 100644
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -13,10 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+import io
import random
-import six
-
from tempest.api.compute import base
from tempest.common import image as common_image
from tempest.common import utils
@@ -44,7 +43,7 @@
CONF.compute.flavor_ref)['flavor']
min_img_ram = flavor['ram'] + 1
size = random.randint(1024, 4096)
- image_file = six.BytesIO(data_utils.random_bytes(size))
+ image_file = io.BytesIO(data_utils.random_bytes(size))
params = {
'name': data_utils.rand_name('image'),
'container_format': CONF.image.container_formats[0],
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 561265f..ece983d 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
+import io
from tempest.api.compute import base
from tempest.common import image as common_image
@@ -77,7 +77,7 @@
cls.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc,
cls.glance_client.delete_image,
cls.image_id)
- image_file = six.BytesIO((b'*' * 1024))
+ image_file = io.BytesIO((b'*' * 1024))
if CONF.image_feature_enabled.api_v1:
cls.glance_client.update_image(cls.image_id, data=image_file)
else:
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 7930c67..15b8a00 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -15,7 +15,7 @@
import time
-import six
+import io
import testtools
from tempest.api.compute import base
@@ -85,7 +85,7 @@
# Wait 1 second between creation and upload to ensure a delta
# between created_at and updated_at.
time.sleep(1)
- image_file = six.BytesIO((b'*' * 1024))
+ image_file = io.BytesIO((b'*' * 1024))
if CONF.image_feature_enabled.api_v1:
cls.glance_client.update_image(image_id, data=image_file)
else:
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 102792e..ac18442 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -16,7 +16,6 @@
import time
from oslo_log import log
-import six
from tempest.api.compute import base
from tempest.common import compute
@@ -241,7 +240,7 @@
except lib_exc.BadRequest as e:
msg = ('Multiple possible networks found, use a Network ID to be '
'more specific.')
- if not CONF.compute.fixed_network_name and six.text_type(e) == msg:
+ if not CONF.compute.fixed_network_name and str(e) == msg:
raise
else:
ifs.append(iface)
@@ -450,7 +449,7 @@
except lib_exc.BadRequest as e:
msg = ('Multiple possible networks found, use a Network ID to be '
'more specific.')
- if not CONF.compute.fixed_network_name and six.text_type(e) == msg:
+ if not CONF.compute.fixed_network_name and str(e) == msg:
raise
else:
# just to check the response schema
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 34b3146..a9c0e56 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -69,7 +69,7 @@
resp = urllib3.PoolManager().request('GET', vnc_url)
# Make sure that the GET request was accepted by the novncproxy
self.assertEqual(resp.status, 200, 'Got a Bad HTTP Response on the '
- 'initial call: ' + six.text_type(resp.status))
+ 'initial call: ' + str(resp.status))
# Do some basic validation to make sure it is an expected HTML document
resp_data = resp.data.decode()
# This is needed in the case of example: <html lang="en">
@@ -165,11 +165,11 @@
self._websocket.response.startswith(b'HTTP/1.1 101 Switching '
b'Protocols'),
'Incorrect HTTP return status code: {}'.format(
- six.text_type(self._websocket.response)
+ str(self._websocket.response)
)
)
_required_header = 'upgrade: websocket'
- _response = six.text_type(self._websocket.response).lower()
+ _response = str(self._websocket.response).lower()
self.assertIn(
_required_header,
_response,
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index f3a7471..5bbd65c 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
-
from tempest.api.identity import base
from tempest import config
from tempest.lib.common.utils import data_utils
@@ -70,8 +68,8 @@
orig_expires_at = token_auth['token']['expires_at']
orig_user = token_auth['token']['user']
- self.assertIsInstance(token_auth['token']['expires_at'], six.text_type)
- self.assertIsInstance(token_auth['token']['issued_at'], six.text_type)
+ self.assertIsInstance(token_auth['token']['expires_at'], str)
+ self.assertIsInstance(token_auth['token']['issued_at'], str)
self.assertEqual(['password'], token_auth['token']['methods'])
self.assertEqual(user['id'], token_auth['token']['user']['id'])
self.assertEqual(user['name'], token_auth['token']['user']['name'])
@@ -91,7 +89,7 @@
self.assertEqual(orig_expires_at, token_auth['token']['expires_at'],
'Expiration time should match original token')
- self.assertIsInstance(token_auth['token']['issued_at'], six.text_type)
+ self.assertIsInstance(token_auth['token']['issued_at'], str)
self.assertEqual(set(['password', 'token']),
set(token_auth['token']['methods']))
self.assertEqual(orig_user, token_auth['token']['user'],
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index d3dc19a..d0d64a5 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
+import io
from tempest.common import image as common_image
from tempest import config
@@ -113,7 +113,7 @@
cls.alt_tenant_id = cls.alt_image_member_client.tenant_id
def _create_image(self):
- image_file = six.BytesIO(data_utils.random_bytes())
+ image_file = io.BytesIO(data_utils.random_bytes())
image = self.create_image(container_format='bare',
disk_format='raw',
is_public=False,
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index 595717e..6fd6c4e 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
+import io
from tempest.api.image import base
from tempest.common import image as common_image
@@ -72,7 +72,7 @@
self.assertEqual(val, image.get('properties')[key])
# Now try uploading an image file
- image_file = six.BytesIO(data_utils.random_bytes())
+ image_file = io.BytesIO(data_utils.random_bytes())
body = self.client.update_image(image['id'], data=image_file)['image']
self.assertIn('size', body)
self.assertEqual(1024, body.get('size'))
@@ -204,7 +204,7 @@
Note that the size of the new image is a random number between
1024 and 4096
"""
- image_file = six.BytesIO(data_utils.random_bytes(size))
+ image_file = io.BytesIO(data_utils.random_bytes(size))
name = 'New Standard Image %s' % name
image = cls.create_image(name=name,
container_format=container_format,
@@ -306,7 +306,7 @@
disk_format, size):
"""Create a new standard image and return newly-registered image-id"""
- image_file = six.BytesIO(data_utils.random_bytes(size))
+ image_file = io.BytesIO(data_utils.random_bytes(size))
name = 'New Standard Image %s' % name
image = cls.create_image(name=name,
container_format=container_format,
diff --git a/tempest/api/image/v2/admin/test_images.py b/tempest/api/image/v2/admin/test_images.py
index ad68d82..733c778 100644
--- a/tempest/api/image/v2/admin/test_images.py
+++ b/tempest/api/image/v2/admin/test_images.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
+import io
from tempest.api.image import base
from tempest.common import waiters
@@ -99,7 +99,7 @@
self.assertEqual('queued', image['status'])
file_content = data_utils.random_bytes()
- image_file = six.BytesIO(file_content)
+ image_file = io.BytesIO(file_content)
self.client.store_image_file(image['id'], image_file)
body = self.client.show_image(image['id'])
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index ca72388..efa23bb 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -14,10 +14,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+import io
import random
-import six
-
from oslo_log import log as logging
from tempest.api.image import base
from tempest.common import waiters
@@ -69,6 +68,23 @@
self.assertEqual('queued', image['status'])
return image
+ def _require_import_method(self, method):
+ if method not in self.available_import_methods:
+ raise self.skipException('Server does not support '
+ '%s import method' % method)
+
+ def _stage_and_check(self):
+ image = self._create_image()
+ # Stage image data
+ file_content = data_utils.random_bytes()
+ image_file = io.BytesIO(file_content)
+ self.client.stage_image_file(image['id'], image_file)
+ # Check image status is 'uploading'
+ body = self.client.show_image(image['id'])
+ self.assertEqual(image['id'], body['id'])
+ self.assertEqual('uploading', body['status'])
+ return image['id']
+
@decorators.idempotent_id('32ca0c20-e16f-44ac-8590-07869c9b4cc2')
def test_image_glance_direct_import(self):
"""Test 'glance-direct' import functionalities
@@ -76,21 +92,29 @@
Create image, stage image data, import image and verify
that import succeeded.
"""
- if 'glance-direct' not in self.available_import_methods:
- raise self.skipException('Server does not support '
- 'glance-direct import method')
- image = self._create_image()
- # Stage image data
- file_content = data_utils.random_bytes()
- image_file = six.BytesIO(file_content)
- self.client.stage_image_file(image['id'], image_file)
- # Check image status is 'uploading'
- body = self.client.show_image(image['id'])
- self.assertEqual(image['id'], body['id'])
- self.assertEqual('uploading', body['status'])
+ self._require_import_method('glance-direct')
+
+ image_id = self._stage_and_check()
# import image from staging to backend
- self.client.image_import(image['id'], method='glance-direct')
- waiters.wait_for_image_imported_to_stores(self.client, image['id'])
+ resp = self.client.image_import(image_id, method='glance-direct')
+ waiters.wait_for_image_imported_to_stores(self.client, image_id)
+
+ if not self.versions_client.has_version('2.12'):
+ # API is not new enough to support image/tasks API
+ LOG.info('Glance does not support v2.12, so I am unable to '
+ 'validate the image/tasks API.')
+ return
+
+ # Make sure we can access the task and that some of the key
+ # fields look legit.
+ tasks = self.client.show_image_tasks(image_id)
+ self.assertEqual(1, len(tasks['tasks']))
+ task = tasks['tasks'][0]
+ self.assertEqual('success', task['status'])
+ self.assertEqual(resp.response['x-openstack-request-id'],
+ task['request_id'])
+ self.assertEqual('glance-direct',
+ task['input']['import_req']['method']['name'])
@decorators.idempotent_id('f6feb7a4-b04f-4706-a011-206129f83e62')
def test_image_web_download_import(self):
@@ -99,9 +123,8 @@
Create image, import image and verify that import
succeeded.
"""
- if 'web-download' not in self.available_import_methods:
- raise self.skipException('Server does not support '
- 'web-download import method')
+ self._require_import_method('web-download')
+
image = self._create_image()
# Now try to get image details
body = self.client.show_image(image['id'])
@@ -113,6 +136,47 @@
image_uri=image_uri)
waiters.wait_for_image_imported_to_stores(self.client, image['id'])
+ @decorators.idempotent_id('e04761a1-22af-42c2-b8bc-a34a3f12b585')
+ def test_remote_import(self):
+ """Test image import against a different worker than stage.
+
+ This creates and stages an image against the primary API worker,
+ but then calls import on a secondary worker (if available) to
+ test that distributed image import works (i.e. proxies the import
+ request to the proper worker).
+ """
+ self._require_import_method('glance-direct')
+
+ if not CONF.image.alternate_image_endpoint:
+ raise self.skipException('No image_remote service to test '
+ 'against')
+
+ image_id = self._stage_and_check()
+ # import image from staging to backend, but on the alternate worker
+ self.os_primary.image_client_remote.image_import(
+ image_id, method='glance-direct')
+ waiters.wait_for_image_imported_to_stores(self.client, image_id)
+
+ @decorators.idempotent_id('44d60544-1524-42f7-8899-315301105dd8')
+ def test_remote_delete(self):
+ """Test image delete against a different worker than stage.
+
+ This creates and stages an image against the primary API worker,
+ but then calls delete on a secondary worker (if available) to
+ test that distributed image import works (i.e. proxies the delete
+ request to the proper worker).
+ """
+ self._require_import_method('glance-direct')
+
+ if not CONF.image.alternate_image_endpoint:
+ raise self.skipException('No image_remote service to test '
+ 'against')
+
+ image_id = self._stage_and_check()
+ # delete image from staging to backend, but on the alternate worker
+ self.os_primary.image_client_remote.delete_image(image_id)
+ self.client.wait_for_resource_deletion(image_id)
+
class MultiStoresImportImagesTest(base.BaseV2ImageTest):
"""Test importing image in multiple stores"""
@@ -158,7 +222,7 @@
self.client.stage_image_file(
image['id'],
- six.BytesIO(data_utils.random_bytes()))
+ io.BytesIO(data_utils.random_bytes()))
# Check image status is 'uploading'
body = self.client.show_image(image['id'])
self.assertEqual(image['id'], body['id'])
@@ -240,7 +304,7 @@
# Now try uploading an image file
file_content = data_utils.random_bytes()
- image_file = six.BytesIO(file_content)
+ image_file = io.BytesIO(file_content)
self.client.store_image_file(image['id'], image_file)
# Now try to get image details
@@ -317,7 +381,7 @@
# Upload an image file
content = data_utils.random_bytes()
- image_file = six.BytesIO(content)
+ image_file = io.BytesIO(content)
self.client.store_image_file(image['id'], image_file)
# Deactivate image
@@ -367,7 +431,7 @@
1024 and 4096
"""
size = random.randint(1024, 4096)
- image_file = six.BytesIO(data_utils.random_bytes(size))
+ image_file = io.BytesIO(data_utils.random_bytes(size))
tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')]
image = cls.create_image(container_format=container_format,
disk_format=disk_format,
@@ -550,7 +614,7 @@
def test_list_images_param_member_status(self):
"""Test listing images by member_status and visibility"""
# Create an image to be shared using default visibility
- image_file = six.BytesIO(data_utils.random_bytes(2048))
+ image_file = io.BytesIO(data_utils.random_bytes(2048))
container_format = CONF.image.container_formats[0]
disk_format = CONF.image.disk_formats[0]
image = self.create_image(container_format=container_format,
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
index 810c37c..a3802a9 100644
--- a/tempest/api/image/v2/test_images_negative.py
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -14,6 +14,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import time
+
from tempest.api.image import base
from tempest import config
from tempest.lib.common.utils import data_utils
@@ -156,3 +158,63 @@
container_format='bare',
disk_format='raw',
os_glance_foo='bar')
+
+
+class ImportImagesNegativeTest(base.BaseV2ImageTest):
+ """Here we test the import operations for image"""
+
+ @classmethod
+ def skip_checks(cls):
+ super(ImportImagesNegativeTest, cls).skip_checks()
+ if not CONF.image_feature_enabled.import_image:
+ skip_msg = (
+ "%s skipped as image import is not available" % cls.__name__)
+ raise cls.skipException(skip_msg)
+
+ @classmethod
+ def resource_setup(cls):
+ super(ImportImagesNegativeTest, cls).resource_setup()
+ cls.available_import_methods = cls.client.info_import()[
+ 'import-methods']['value']
+ if not cls.available_import_methods:
+ raise cls.skipException('Server does not support '
+ 'any import method')
+
+ cls.available_stores = cls.get_available_stores()
+ if not len(cls.available_stores) > 0:
+ raise cls.skipException(
+ 'No stores configured %s' % cls.available_stores)
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('c52f6a77-f522-4411-8dbe-9d14f2b1ba6b')
+ def test_image_web_download_import_with_bad_url(self):
+ """Test 'web-download' import functionalities
+
+ Make sure that web-download with invalid URL fails properly.
+ """
+ if 'web-download' not in self.available_import_methods:
+ raise self.skipException('Server does not support '
+ 'web-download import method')
+ image = self.client.create_image(name='test',
+ container_format='bare',
+ disk_format='raw')
+ # Now try to get image details
+ body = self.client.show_image(image['id'])
+ self.assertEqual(image['id'], body['id'])
+ self.assertEqual('queued', body['status'])
+ stores = self.get_available_stores()
+ # import image from web to backend
+ image_uri = 'http://does-not.exist/no/possible/way'
+ self.client.image_import(image['id'], method='web-download',
+ image_uri=image_uri,
+ stores=[stores[0]['id']])
+
+ start_time = int(time.time())
+ while int(time.time()) - start_time < self.client.build_timeout:
+ body = self.client.show_image(image['id'])
+ if body.get('os_glance_failed_import'):
+ # Store ended up in failed list, which is good
+ return
+ time.sleep(self.client.build_interval)
+
+ self.fail('Image never reported failed store')
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 479578d..63078cd 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -16,7 +16,6 @@
import ipaddress
import netaddr
-import six
import testtools
from tempest.api.network import base_security_groups as sec_base
@@ -234,15 +233,15 @@
# Get two IP addresses
ip_address_1 = None
ip_address_2 = None
- ip_network = ipaddress.ip_network(six.text_type(subnet['cidr']))
+ ip_network = ipaddress.ip_network(str(subnet['cidr']))
for ip in ip_network:
if ip == ip_network.network_address:
continue
if ip_address_1 is None:
- ip_address_1 = six.text_type(ip)
+ ip_address_1 = str(ip)
else:
ip_address_2 = ip_address_1
- ip_address_1 = six.text_type(ip)
+ ip_address_1 = str(ip)
# Make sure these two IP addresses have different substring
if ip_address_1[:-1] != ip_address_2[:-1]:
break
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index e8f3f8b..478a834 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -13,12 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-import time
-
from tempest.common import custom_matchers
from tempest import config
from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
from tempest.lib import exceptions as lib_exc
import tempest.test
@@ -50,12 +47,11 @@
_, objlist = container_client.list_container_objects(cont, params)
# delete every object in the container
for obj in objlist:
- test_utils.call_and_ignore_notfound_exc(
- object_client.delete_object, cont, obj['name'])
- # sleep 2 seconds to sync the deletion of the objects
- # in HA deployment
- time.sleep(2)
+ object_client.delete_object(cont, obj['name'])
+ object_client.wait_for_resource_deletion(obj['name'], cont)
+ # Verify resource deletion
container_client.delete_container(cont)
+ container_client.wait_for_resource_deletion(cont)
except lib_exc.NotFound:
pass
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index da8ad66..ffea6f6 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -62,7 +62,7 @@
self.assertIsNotNone(container_list)
for container_name in self.containers:
- self.assertIn(six.text_type(container_name).encode('utf-8'),
+ self.assertIn(str(container_name).encode('utf-8'),
container_list)
@decorators.idempotent_id('884ec421-fbad-4fcc-916b-0580f2699565')
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index fc9b1a2..93f6fdb 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -13,12 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-import hashlib
import random
import re
import time
import zlib
+from oslo_utils.secretutils import md5
from tempest.api.object_storage import base
from tempest.common import custom_matchers
from tempest import config
@@ -151,8 +151,8 @@
"""Test creating object with Etag"""
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.random_bytes()
- md5 = hashlib.md5(data).hexdigest()
- metadata = {'Etag': md5}
+ create_md5 = md5(data, usedforsecurity=False).hexdigest()
+ metadata = {'Etag': create_md5}
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
@@ -641,7 +641,7 @@
"""Test getting object with if_match"""
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.random_bytes(10)
- create_md5 = hashlib.md5(data).hexdigest()
+ create_md5 = md5(data, usedforsecurity=False).hexdigest()
create_metadata = {'Etag': create_md5}
self.object_client.create_object(self.container_name,
object_name,
@@ -681,7 +681,7 @@
"""Test getting object with if_none_match"""
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.random_bytes()
- create_md5 = hashlib.md5(data).hexdigest()
+ create_md5 = md5(data, usedforsecurity=False).hexdigest()
create_metadata = {'Etag': create_md5}
self.object_client.create_object(self.container_name,
object_name,
@@ -689,7 +689,7 @@
metadata=create_metadata)
list_data = data_utils.random_bytes()
- list_md5 = hashlib.md5(list_data).hexdigest()
+ list_md5 = md5(list_data, usedforsecurity=False).hexdigest()
list_metadata = {'If-None-Match': list_md5}
resp, body = self.object_client.get_object(
self.container_name,
@@ -978,8 +978,8 @@
"""
object_name, data = self.create_object(self.container_name)
# local copy is identical, no download
- md5 = hashlib.md5(data).hexdigest()
- headers = {'If-None-Match': md5}
+ object_md5 = md5(data, usedforsecurity=False).hexdigest()
+ headers = {'If-None-Match': object_md5}
url = "%s/%s" % (self.container_name, object_name)
resp, _ = self.object_client.get(url, headers=headers)
self.assertEqual(resp['status'], '304')
@@ -993,8 +993,8 @@
# local copy is different, download
local_data = "something different"
- md5 = hashlib.md5(local_data.encode()).hexdigest()
- headers = {'If-None-Match': md5}
+ other_md5 = md5(local_data.encode(), usedforsecurity=False).hexdigest()
+ headers = {'If-None-Match': other_md5}
resp, _ = self.object_client.get(url, headers=headers)
self.assertHeaders(resp, 'Object', 'GET')
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 664bbc8..0c84357 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -12,10 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-import hashlib
-
from oslo_serialization import jsonutils as json
+from oslo_utils.secretutils import md5
from tempest.api.object_storage import base
from tempest.common import utils
from tempest.lib.common.utils import data_utils
@@ -70,10 +69,12 @@
path_object_2 = '/%s/%s' % (self.container_name,
object_name_base_2)
data_manifest = [{'path': path_object_1,
- 'etag': hashlib.md5(self.content).hexdigest(),
+ 'etag': md5(self.content,
+ usedforsecurity=False).hexdigest(),
'size_bytes': data_size},
{'path': path_object_2,
- 'etag': hashlib.md5(self.content).hexdigest(),
+ 'etag': md5(self.content,
+ usedforsecurity=False).hexdigest(),
'size_bytes': data_size}]
return json.dumps(data_manifest)
diff --git a/tempest/api/volume/admin/test_group_snapshots.py b/tempest/api/volume/admin/test_group_snapshots.py
index 0a8b56d..659e2c4 100644
--- a/tempest/api/volume/admin/test_group_snapshots.py
+++ b/tempest/api/volume/admin/test_group_snapshots.py
@@ -64,7 +64,6 @@
class GroupSnapshotsTest(BaseGroupSnapshotsTest):
"""Test group snapshot"""
- _api_version = 3
min_microversion = '3.14'
max_microversion = 'latest'
@@ -253,7 +252,6 @@
class GroupSnapshotsV319Test(BaseGroupSnapshotsTest):
"""Test group snapshot with volume microversion greater than 3.18"""
- _api_version = 3
min_microversion = '3.19'
max_microversion = 'latest'
diff --git a/tempest/api/volume/admin/test_group_type_specs.py b/tempest/api/volume/admin/test_group_type_specs.py
index 159c6fb..5c5913e 100644
--- a/tempest/api/volume/admin/test_group_type_specs.py
+++ b/tempest/api/volume/admin/test_group_type_specs.py
@@ -21,7 +21,6 @@
class GroupTypeSpecsTest(base.BaseVolumeAdminTest):
"""Test group type specs"""
- _api_version = 3
min_microversion = '3.11'
max_microversion = 'latest'
diff --git a/tempest/api/volume/admin/test_group_types.py b/tempest/api/volume/admin/test_group_types.py
index 3993020..a7a5d6f 100644
--- a/tempest/api/volume/admin/test_group_types.py
+++ b/tempest/api/volume/admin/test_group_types.py
@@ -21,7 +21,6 @@
class GroupTypesTest(base.BaseVolumeAdminTest):
"""Test group types"""
- _api_version = 3
min_microversion = '3.11'
max_microversion = 'latest'
diff --git a/tempest/api/volume/admin/test_groups.py b/tempest/api/volume/admin/test_groups.py
index e67b985..747a194 100644
--- a/tempest/api/volume/admin/test_groups.py
+++ b/tempest/api/volume/admin/test_groups.py
@@ -25,7 +25,6 @@
class GroupsTest(base.BaseVolumeAdminTest):
"""Tests of volume groups with microversion greater than 3.12"""
- _api_version = 3
min_microversion = '3.13'
max_microversion = 'latest'
@@ -156,7 +155,6 @@
class GroupsV314Test(base.BaseVolumeAdminTest):
"""Tests of volume groups with microversion greater than 3.13"""
- _api_version = 3
min_microversion = '3.14'
max_microversion = 'latest'
@@ -194,7 +192,6 @@
class GroupsV320Test(base.BaseVolumeAdminTest):
"""Tests of volume groups with microversion greater than 3.19"""
- _api_version = 3
min_microversion = '3.20'
max_microversion = 'latest'
diff --git a/tempest/api/volume/admin/test_user_messages.py b/tempest/api/volume/admin/test_user_messages.py
index 096709c..768c129 100644
--- a/tempest/api/volume/admin/test_user_messages.py
+++ b/tempest/api/volume/admin/test_user_messages.py
@@ -24,7 +24,6 @@
class UserMessagesTest(base.BaseVolumeAdminTest):
"""Test volume messages with microversion greater than 3.2"""
- _api_version = 3
min_microversion = '3.3'
max_microversion = 'latest'
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index c538e60..9f9fc3b 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -20,7 +20,6 @@
from tempest.lib.common import api_version_utils
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
-from tempest.lib import exceptions
import tempest.test
CONF = config.CONF
@@ -33,12 +32,6 @@
# Set this to True in subclasses to create a default network. See
# https://bugs.launchpad.net/tempest/+bug/1844568
create_default_network = False
- _api_version = 2
- # if api_v2 is not enabled while api_v3 is enabled, the volume v2 classes
- # should be transferred to volume v3 classes.
- if (not CONF.volume_feature_enabled.api_v2 and
- CONF.volume_feature_enabled.api_v3):
- _api_version = 3
credentials = ['primary']
@classmethod
@@ -48,17 +41,6 @@
if not CONF.service_available.cinder:
skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
raise cls.skipException(skip_msg)
- if cls._api_version == 2:
- if not CONF.volume_feature_enabled.api_v2:
- msg = "Volume API v2 is disabled"
- raise cls.skipException(msg)
- elif cls._api_version == 3:
- if not CONF.volume_feature_enabled.api_v3:
- msg = "Volume API v3 is disabled"
- raise cls.skipException(msg)
- else:
- msg = ("Invalid Cinder API version (%s)" % cls._api_version)
- raise exceptions.InvalidConfiguration(msg)
api_version_utils.check_skip_with_microversion(
cls.min_microversion, cls.max_microversion,
@@ -129,6 +111,13 @@
name = data_utils.rand_name(cls.__name__ + '-Volume')
kwargs['name'] = name
+ if CONF.volume.volume_type and 'volume_type' not in kwargs:
+ # If volume_type is not provided in config then no need to
+ # add a volume type and
+ # if volume_type has already been added by child class then
+ # no need to override.
+ kwargs['volume_type'] = CONF.volume.volume_type
+
if CONF.compute.compute_volume_common_az:
kwargs.setdefault('availability_zone',
CONF.compute.compute_volume_common_az)
diff --git a/tempest/api/volume/test_versions.py b/tempest/api/volume/test_versions.py
index e065bdf..578be58 100644
--- a/tempest/api/volume/test_versions.py
+++ b/tempest/api/volume/test_versions.py
@@ -19,8 +19,6 @@
class VersionsTest(base.BaseVolumeTest):
"""Test volume versions"""
- _api_version = 3
-
@decorators.idempotent_id('77838fc4-b49b-4c64-9533-166762517369')
@decorators.attr(type='smoke')
def test_list_versions(self):
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 2e78114..fff6a44 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -164,7 +164,6 @@
class VolumesBackupsV39Test(base.BaseVolumeTest):
"""Test volumes backup with volume microversion greater than 3.8"""
- _api_version = 3
min_microversion = '3.9'
max_microversion = 'latest'
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index 7441f1d..d9790f3 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -77,7 +77,6 @@
# details once that microversion is available in Nova.
credentials = ['primary', 'admin']
- _api_version = 3
# NOTE(mriedem): The minimum required volume API version is 3.42 and the
# minimum required compute API microversion is 2.51, but the compute call
# is implicit - Cinder calls Nova at that microversion, Tempest does not.
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 91728ab..28e41bf 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -143,7 +143,6 @@
class VolumesSummaryTest(base.BaseVolumeTest):
"""Test volume summary"""
- _api_version = 3
min_microversion = '3.12'
max_microversion = 'latest'
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index 389d3be..35dd0ca 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
+import io
from tempest.api.volume import base
from tempest.common import utils
@@ -50,7 +50,7 @@
self.images_client.delete_image, image['id'])
# Upload image with 1KB data
- image_file = six.BytesIO(data_utils.random_bytes())
+ image_file = io.BytesIO(data_utils.random_bytes())
self.images_client.store_image_file(image['id'], image_file)
waiters.wait_for_image_status(self.images_client,
image['id'], 'active')
diff --git a/tempest/clients.py b/tempest/clients.py
index 6d19a0c..d2fb3eb 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -88,6 +88,13 @@
self.image_v2.NamespacePropertiesClient()
self.namespace_tags_client = self.image_v2.NamespaceTagsClient()
self.image_versions_client = self.image_v2.VersionsClient()
+ # NOTE(danms): If no alternate endpoint is configured,
+ # this client will work the same as the base self.images_client.
+ # If your test needs to know if these are different, check the
+ # config option to see if the alternate_image_endpoint is set.
+ self.image_client_remote = self.image_v2.ImagesClient(
+ service=CONF.image.alternate_image_endpoint,
+ endpoint_type=CONF.image.alternate_image_endpoint_type)
def _set_compute_clients(self):
self.agents_client = self.compute.AgentsClient()
@@ -231,89 +238,85 @@
def _set_volume_clients(self):
- # if only api_v3 is enabled, all these clients should be available
- if (CONF.volume_feature_enabled.api_v2 or
- CONF.volume_feature_enabled.api_v3):
- self.backups_client_latest = self.volume_v3.BackupsClient()
- self.encryption_types_client_latest = \
- self.volume_v3.EncryptionTypesClient()
- self.snapshot_manage_client_latest = \
- self.volume_v3.SnapshotManageClient()
- self.snapshots_client_latest = self.volume_v3.SnapshotsClient()
- self.volume_capabilities_client_latest = \
- self.volume_v3.CapabilitiesClient()
- self.volume_manage_client_latest = (
- self.volume_v3.VolumeManageClient())
- self.volume_qos_client_latest = self.volume_v3.QosSpecsClient()
- self.volume_services_client_latest = (
- self.volume_v3.ServicesClient())
- self.volume_types_client_latest = self.volume_v3.TypesClient()
- self.volume_hosts_client_latest = self.volume_v3.HostsClient()
- self.volume_quotas_client_latest = self.volume_v3.QuotasClient()
- self.volume_quota_classes_client_latest = \
- self.volume_v3.QuotaClassesClient()
- self.volume_scheduler_stats_client_latest = \
- self.volume_v3.SchedulerStatsClient()
- self.volume_transfers_client_latest = \
- self.volume_v3.TransfersClient()
- self.volume_availability_zone_client_latest = \
- self.volume_v3.AvailabilityZoneClient()
- self.volume_limits_client_latest = self.volume_v3.LimitsClient()
- self.volumes_client_latest = self.volume_v3.VolumesClient()
- self.volumes_extension_client_latest = \
- self.volume_v3.ExtensionsClient()
- self.group_types_client_latest = self.volume_v3.GroupTypesClient()
- self.groups_client_latest = self.volume_v3.GroupsClient()
- self.group_snapshots_client_latest = \
- self.volume_v3.GroupSnapshotsClient()
- self.volume_messages_client_latest = (
- self.volume_v3.MessagesClient())
- self.volume_versions_client_latest = (
- self.volume_v3.VersionsClient())
- self.attachments_client_latest = (
- self.volume_v3.AttachmentsClient())
+ self.backups_client_latest = self.volume_v3.BackupsClient()
+ self.encryption_types_client_latest = \
+ self.volume_v3.EncryptionTypesClient()
+ self.snapshot_manage_client_latest = \
+ self.volume_v3.SnapshotManageClient()
+ self.snapshots_client_latest = self.volume_v3.SnapshotsClient()
+ self.volume_capabilities_client_latest = \
+ self.volume_v3.CapabilitiesClient()
+ self.volume_manage_client_latest = (
+ self.volume_v3.VolumeManageClient())
+ self.volume_qos_client_latest = self.volume_v3.QosSpecsClient()
+ self.volume_services_client_latest = (
+ self.volume_v3.ServicesClient())
+ self.volume_types_client_latest = self.volume_v3.TypesClient()
+ self.volume_hosts_client_latest = self.volume_v3.HostsClient()
+ self.volume_quotas_client_latest = self.volume_v3.QuotasClient()
+ self.volume_quota_classes_client_latest = \
+ self.volume_v3.QuotaClassesClient()
+ self.volume_scheduler_stats_client_latest = \
+ self.volume_v3.SchedulerStatsClient()
+ self.volume_transfers_client_latest = \
+ self.volume_v3.TransfersClient()
+ self.volume_availability_zone_client_latest = \
+ self.volume_v3.AvailabilityZoneClient()
+ self.volume_limits_client_latest = self.volume_v3.LimitsClient()
+ self.volumes_client_latest = self.volume_v3.VolumesClient()
+ self.volumes_extension_client_latest = \
+ self.volume_v3.ExtensionsClient()
+ self.group_types_client_latest = self.volume_v3.GroupTypesClient()
+ self.groups_client_latest = self.volume_v3.GroupsClient()
+ self.group_snapshots_client_latest = \
+ self.volume_v3.GroupSnapshotsClient()
+ self.volume_messages_client_latest = (
+ self.volume_v3.MessagesClient())
+ self.volume_versions_client_latest = (
+ self.volume_v3.VersionsClient())
+ self.attachments_client_latest = (
+ self.volume_v3.AttachmentsClient())
- # TODO(gmann): Below alias for service clients have been
- # deprecated and will be removed in future. Start using the alias
- # defined above with suffix _latest.
- # ****************Deprecated alias start from here***************
- self.backups_v2_client = self.volume_v3.BackupsClient()
- self.encryption_types_v2_client = \
- self.volume_v3.EncryptionTypesClient()
- self.snapshot_manage_v2_client = \
- self.volume_v3.SnapshotManageClient()
- self.snapshots_v2_client = self.volume_v3.SnapshotsClient()
- self.volume_capabilities_v2_client = \
- self.volume_v3.CapabilitiesClient()
- self.volume_manage_v2_client = self.volume_v3.VolumeManageClient()
- self.volume_qos_v2_client = self.volume_v3.QosSpecsClient()
- self.volume_services_v2_client = self.volume_v3.ServicesClient()
- self.volume_types_v2_client = self.volume_v3.TypesClient()
- self.volume_hosts_v2_client = self.volume_v3.HostsClient()
- self.volume_quotas_v2_client = self.volume_v3.QuotasClient()
- self.volume_quota_classes_v2_client = \
- self.volume_v3.QuotaClassesClient()
- self.volume_scheduler_stats_v2_client = \
- self.volume_v3.SchedulerStatsClient()
- self.volume_transfers_v2_client = self.volume_v3.TransfersClient()
- self.volume_v2_availability_zone_client = \
- self.volume_v3.AvailabilityZoneClient()
- self.volume_v2_limits_client = self.volume_v3.LimitsClient()
- self.volumes_v2_client = self.volume_v3.VolumesClient()
- self.volumes_v2_extension_client = \
- self.volume_v3.ExtensionsClient()
+ # TODO(gmann): Below alias for service clients have been
+ # deprecated and will be removed in future. Start using the alias
+ # defined above with suffix _latest.
+ # ****************Deprecated alias start from here***************
+ self.backups_v2_client = self.volume_v3.BackupsClient()
+ self.encryption_types_v2_client = \
+ self.volume_v3.EncryptionTypesClient()
+ self.snapshot_manage_v2_client = \
+ self.volume_v3.SnapshotManageClient()
+ self.snapshots_v2_client = self.volume_v3.SnapshotsClient()
+ self.volume_capabilities_v2_client = \
+ self.volume_v3.CapabilitiesClient()
+ self.volume_manage_v2_client = self.volume_v3.VolumeManageClient()
+ self.volume_qos_v2_client = self.volume_v3.QosSpecsClient()
+ self.volume_services_v2_client = self.volume_v3.ServicesClient()
+ self.volume_types_v2_client = self.volume_v3.TypesClient()
+ self.volume_hosts_v2_client = self.volume_v3.HostsClient()
+ self.volume_quotas_v2_client = self.volume_v3.QuotasClient()
+ self.volume_quota_classes_v2_client = \
+ self.volume_v3.QuotaClassesClient()
+ self.volume_scheduler_stats_v2_client = \
+ self.volume_v3.SchedulerStatsClient()
+ self.volume_transfers_v2_client = self.volume_v3.TransfersClient()
+ self.volume_v2_availability_zone_client = \
+ self.volume_v3.AvailabilityZoneClient()
+ self.volume_v2_limits_client = self.volume_v3.LimitsClient()
+ self.volumes_v2_client = self.volume_v3.VolumesClient()
+ self.volumes_v2_extension_client = \
+ self.volume_v3.ExtensionsClient()
- if CONF.volume_feature_enabled.api_v3:
- self.backups_v3_client = self.volume_v3.BackupsClient()
- self.group_types_v3_client = self.volume_v3.GroupTypesClient()
- self.groups_v3_client = self.volume_v3.GroupsClient()
- self.group_snapshots_v3_client = \
- self.volume_v3.GroupSnapshotsClient()
- self.snapshots_v3_client = self.volume_v3.SnapshotsClient()
- self.volume_v3_messages_client = self.volume_v3.MessagesClient()
- self.volume_v3_versions_client = self.volume_v3.VersionsClient()
- self.volumes_v3_client = self.volume_v3.VolumesClient()
- # ****************Deprecated alias end here***********************
+ self.backups_v3_client = self.volume_v3.BackupsClient()
+ self.group_types_v3_client = self.volume_v3.GroupTypesClient()
+ self.groups_v3_client = self.volume_v3.GroupsClient()
+ self.group_snapshots_v3_client = \
+ self.volume_v3.GroupSnapshotsClient()
+ self.snapshots_v3_client = self.volume_v3.SnapshotsClient()
+ self.volume_v3_messages_client = self.volume_v3.MessagesClient()
+ self.volume_v3_versions_client = self.volume_v3.VersionsClient()
+ self.volumes_v3_client = self.volume_v3.VolumesClient()
+ # ****************Deprecated alias end here***********************
def _set_object_storage_clients(self):
self.account_client = self.object_storage.AccountClient()
diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py
index 172fbaa..6c36d82 100644
--- a/tempest/cmd/subunit_describe_calls.py
+++ b/tempest/cmd/subunit_describe_calls.py
@@ -40,12 +40,14 @@
subunit-describe-calls will take in either stdin subunit v1 or v2 stream or a
file path which contains either a subunit v1 or v2 stream passed via the
---subunit parameter. This is then parsed checking for details contained in the
-file_bytes of the --non-subunit-name parameter (the default is pythonlogging
-which is what Tempest uses to store logs). By default the OpenStack Kilo
-release port defaults (http://bit.ly/22jpF5P) are used unless a file is
-provided via the --ports option. The resulting output is dumped in JSON output
-to the path provided in the --output-file option.
+``--subunit`` parameter. This is then parsed checking for details contained in
+the file_bytes of the ``--non-subunit-name`` parameter (the default is
+pythonlogging which is what Tempest uses to store logs). By default `the
+OpenStack default ports
+<https://docs.openstack.org/install-guide/firewalls-default-ports.html>`_
+are used unless a file is provided via the ``--ports`` option. The resulting
+output is dumped in JSON output to the path provided in the ``--output-file``
+option.
Ports file JSON structure
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -110,9 +112,8 @@
response_re = re.compile(r'.* Response - Headers: (?P<headers>.*)')
body_re = re.compile(r'.*Body: (?P<body>.*)')
- # Based on newton defaults:
- # http://docs.openstack.org/newton/config-reference/
- # firewalls-default-ports.html
+ # Based on OpenStack default ports:
+ # https://docs.openstack.org/install-guide/firewalls-default-ports.html
services = {
"8776": "Block Storage",
"8774": "Nova",
@@ -131,7 +132,10 @@
"3260": "iSCSI",
"3306": "MySQL",
"5672": "AMQP",
- "8082": "murano"}
+ "8082": "murano",
+ "8778": "Clustering",
+ "8999": "Vitrage",
+ "8989": "Mistral"}
def __init__(self, services=None):
super(UrlParser, self).__init__()
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 235d8e3..0db1ab1 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -202,22 +202,8 @@
not CONF.identity_feature_enabled.api_v3, update)
-def verify_cinder_api_versions(os, update):
- # Check cinder api versions
- versions = _get_api_versions(os, 'cinder')
- if (CONF.volume_feature_enabled.api_v2 !=
- contains_version('v2.', versions)):
- print_and_or_update('api_v2', 'volume-feature-enabled',
- not CONF.volume_feature_enabled.api_v2, update)
- if (CONF.volume_feature_enabled.api_v3 !=
- contains_version('v3.', versions)):
- print_and_or_update('api_v3', 'volume-feature-enabled',
- not CONF.volume_feature_enabled.api_v3, update)
-
-
def verify_api_versions(os, service, update):
verify = {
- 'cinder': verify_cinder_api_versions,
'glance': verify_glance_api_versions,
'keystone': verify_keystone_api_versions,
}
diff --git a/tempest/config.py b/tempest/config.py
index 1367678..e7dca38 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -657,6 +657,15 @@
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
help="The endpoint type to use for the image service."),
+ cfg.StrOpt('alternate_image_endpoint',
+ default=None,
+ help="Alternate endpoint name for cross-worker testing"),
+ cfg.StrOpt('alternate_image_endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help=("The endpoint type to use for the alternate image "
+ "service.")),
cfg.StrOpt('http_image',
default='http://download.cirros-cloud.net/0.3.1/'
'cirros-0.3.1-x86_64-uec.tar.gz',
@@ -972,6 +981,9 @@
default=['BACKEND_1', 'BACKEND_2'],
help='A list of backend names separated by comma. '
'The backend name must be declared in cinder.conf'),
+ cfg.StrOpt('volume_type',
+ default='',
+ help='Volume type to be used while creating volume.'),
cfg.StrOpt('storage_protocol',
default='iSCSI',
help='Backend protocol to target when creating volume types'),
@@ -1043,31 +1055,6 @@
help='A list of enabled volume extensions with a special '
'entry all which indicates every extension is enabled. '
'Empty list indicates all extensions are disabled'),
- cfg.BoolOpt('api_v2',
- default=True,
- help="Is the v2 volume API enabled",
- deprecated_for_removal=True,
- deprecated_reason="The v2 volume API has been deprecated "
- "since Pike release. Now Tempest run all "
- "the volume tests against v2 or v3 API "
- "based on CONF.volume.catalog_type which "
- "makes this config option unusable. If "
- "catalog_type is volumev2, then all the "
- "volume tests will run against v2 API. "
- "Use ``CONF.volume.catalog_type`` to run "
- "the Tempest against volume v2 or v3 API"),
- cfg.BoolOpt('api_v3',
- default=True,
- help="Is the v3 volume API enabled",
- deprecated_for_removal=True,
- deprecated_reason="Tempest run all the volume tests against "
- "v2 or v3 API based on "
- "CONF.volume.catalog_type which makes this "
- "config option unusable. If catalog_type is "
- "volumev3 which is default, then all the "
- "volume tests will run against v3 API. "
- "Use ``CONF.volume.catalog_type`` to run "
- "the Tempest against volume v2 or v3 API"),
cfg.BoolOpt('extend_attached_volume',
default=False,
help='Does the cloud support extending the size of a volume '
diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py
index ab9860e..8bdf98e 100644
--- a/tempest/lib/auth.py
+++ b/tempest/lib/auth.py
@@ -21,7 +21,6 @@
from urllib import parse as urlparse
from oslo_log import log as logging
-import six
from tempest.lib import exceptions
from tempest.lib.services.identity.v2 import token_client as json_v2id
@@ -65,8 +64,7 @@
return url
-@six.add_metaclass(abc.ABCMeta)
-class AuthProvider(object):
+class AuthProvider(object, metaclass=abc.ABCMeta):
"""Provide authentication"""
SCOPES = set(['project'])
diff --git a/tempest/lib/common/cred_client.py b/tempest/lib/common/cred_client.py
index f6e9b49..f13d6d0 100644
--- a/tempest/lib/common/cred_client.py
+++ b/tempest/lib/common/cred_client.py
@@ -13,7 +13,6 @@
import abc
from oslo_log import log as logging
-import six
from tempest.lib import auth
from tempest.lib import exceptions as lib_exc
@@ -22,8 +21,7 @@
LOG = logging.getLogger(__name__)
-@six.add_metaclass(abc.ABCMeta)
-class CredsClient(object):
+class CredsClient(object, metaclass=abc.ABCMeta):
"""This class is a wrapper around the identity clients
to provide a single interface for managing credentials in both v2 and v3
diff --git a/tempest/lib/common/cred_provider.py b/tempest/lib/common/cred_provider.py
index d0fccbc..069172a 100644
--- a/tempest/lib/common/cred_provider.py
+++ b/tempest/lib/common/cred_provider.py
@@ -14,14 +14,12 @@
import abc
-import six
from tempest.lib import auth
from tempest.lib import exceptions
-@six.add_metaclass(abc.ABCMeta)
-class CredentialProvider(object):
+class CredentialProvider(object, metaclass=abc.ABCMeta):
def __init__(self, identity_version, name=None,
network_resources=None, credentials_domain=None,
admin_role=None, identity_uri=None):
@@ -88,14 +86,26 @@
return
@abc.abstractmethod
+ def get_project_alt_admin_creds(self):
+ return
+
+ @abc.abstractmethod
def get_project_member_creds(self):
return
@abc.abstractmethod
+ def get_project_alt_member_creds(self):
+ return
+
+ @abc.abstractmethod
def get_project_reader_creds(self):
return
@abc.abstractmethod
+ def get_project_alt_reader_creds(self):
+ return
+
+ @abc.abstractmethod
def clear_creds(self):
return
@@ -108,7 +118,7 @@
return
@abc.abstractmethod
- def get_creds_by_roles(self, roles, force_new=False):
+ def get_creds_by_roles(self, roles, force_new=False, scope=None):
return
@abc.abstractmethod
diff --git a/tempest/lib/common/dynamic_creds.py b/tempest/lib/common/dynamic_creds.py
index 0244128..f334c36 100644
--- a/tempest/lib/common/dynamic_creds.py
+++ b/tempest/lib/common/dynamic_creds.py
@@ -228,8 +228,9 @@
roles_to_assign = [r for r in roles]
if admin:
roles_to_assign.append(self.admin_role)
- self.creds_client.assign_user_role(
- user, project, self.identity_admin_role)
+ if scope == 'project':
+ self.creds_client.assign_user_role(
+ user, project, self.identity_admin_role)
if (self.identity_version == 'v3' and
self.identity_admin_domain_scope):
self.creds_client.assign_user_role_on_domain(
@@ -341,7 +342,7 @@
tenant_id=tenant_id,
enable_dhcp=self.network_resources['dhcp'],
ip_version=(ipaddress.ip_network(
- six.text_type(subnet_cidr)).version))
+ str(subnet_cidr)).version))
else:
resp_body = self.subnets_admin_client.\
create_subnet(network_id=network_id,
@@ -349,7 +350,7 @@
name=subnet_name,
tenant_id=tenant_id,
ip_version=(ipaddress.ip_network(
- six.text_type(subnet_cidr)).version))
+ str(subnet_cidr)).version))
break
except lib_exc.BadRequest as e:
if 'overlaps with another subnet' not in str(e):
@@ -375,13 +376,22 @@
def get_credentials(self, credential_type, scope=None):
if not scope and self._creds.get(str(credential_type)):
credentials = self._creds[str(credential_type)]
- elif scope and self._creds.get("%s_%s" % (scope, credential_type[0])):
- credentials = self._creds["%s_%s" % (scope, credential_type[0])]
+ elif scope and (
+ self._creds.get("%s_%s" % (scope, str(credential_type)))):
+ credentials = self._creds["%s_%s" % (scope, str(credential_type))]
else:
+ LOG.debug("Creating new dynamic creds for scope: %s and "
+ "credential_type: %s", scope, credential_type)
if scope:
- if credential_type == 'admin':
+ if credential_type in [['admin'], ['alt_admin']]:
credentials = self._create_creds(
admin=True, scope=scope)
+ elif credential_type in [['alt_member'], ['alt_reader']]:
+ cred_type = credential_type[0][4:]
+ if isinstance(cred_type, str):
+ cred_type = [cred_type]
+ credentials = self._create_creds(
+ roles=cred_type, scope=scope)
else:
credentials = self._create_creds(
roles=credential_type, scope=scope)
@@ -392,7 +402,7 @@
credentials = self._create_creds(roles=credential_type)
if scope:
self._creds["%s_%s" %
- (scope, credential_type[0])] = credentials
+ (scope, str(credential_type))] = credentials
else:
self._creds[str(credential_type)] = credentials
# Maintained until tests are ported
@@ -443,25 +453,37 @@
def get_project_admin_creds(self):
return self.get_credentials(['admin'], scope='project')
+ def get_project_alt_admin_creds(self):
+ return self.get_credentials(['alt_admin'], scope='project')
+
def get_project_member_creds(self):
return self.get_credentials(['member'], scope='project')
+ def get_project_alt_member_creds(self):
+ return self.get_credentials(['alt_member'], scope='project')
+
def get_project_reader_creds(self):
return self.get_credentials(['reader'], scope='project')
- def get_creds_by_roles(self, roles, force_new=False):
+ def get_project_alt_reader_creds(self):
+ return self.get_credentials(['alt_reader'], scope='project')
+
+ def get_creds_by_roles(self, roles, force_new=False, scope=None):
roles = list(set(roles))
# The roles list as a str will become the index as the dict key for
# the created credentials set in the dynamic_creds dict.
- exist_creds = self._creds.get(str(roles))
+ creds_name = str(roles)
+ if scope:
+ creds_name = "%s_%s" % (scope, str(roles))
+ exist_creds = self._creds.get(creds_name)
# If force_new flag is True 2 cred sets with the same roles are needed
# handle this by creating a separate index for old one to store it
# separately for cleanup
if exist_creds and force_new:
- new_index = str(roles) + '-' + str(len(self._creds))
+ new_index = creds_name + '-' + str(len(self._creds))
self._creds[new_index] = exist_creds
- del self._creds[str(roles)]
- return self.get_credentials(roles)
+ del self._creds[creds_name]
+ return self.get_credentials(roles, scope=scope)
def _clear_isolated_router(self, router_id, router_name):
client = self.routers_admin_client
diff --git a/tempest/lib/common/jsonschema_validator.py b/tempest/lib/common/jsonschema_validator.py
index bbf5e89..0ac757d 100644
--- a/tempest/lib/common/jsonschema_validator.py
+++ b/tempest/lib/common/jsonschema_validator.py
@@ -15,7 +15,6 @@
import jsonschema
from oslo_serialization import base64
from oslo_utils import timeutils
-import six
# JSON Schema validator and format checker used for JSON Schema validation
JSONSCHEMA_VALIDATOR = jsonschema.Draft4Validator
@@ -43,7 +42,7 @@
@jsonschema.FormatChecker.cls_checks('base64')
def _validate_base64_format(instance):
try:
- if isinstance(instance, six.text_type):
+ if isinstance(instance, str):
instance = instance.encode('utf-8')
base64.decode_as_bytes(instance)
except TypeError:
diff --git a/tempest/lib/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py
index 9784a1f..6d948cf 100644
--- a/tempest/lib/common/preprov_creds.py
+++ b/tempest/lib/common/preprov_creds.py
@@ -12,12 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-import hashlib
import os
from oslo_concurrency import lockutils
from oslo_log import log as logging
-import six
+from oslo_utils.secretutils import md5
import yaml
from tempest.lib import auth
@@ -135,10 +134,10 @@
scope = 'domain'
elif 'system' in account:
scope = 'system'
- temp_hash = hashlib.md5()
+ temp_hash = md5(usedforsecurity=False)
account_for_hash = dict((k, v) for (k, v) in account.items()
if k in cls.HASH_CRED_FIELDS)
- temp_hash.update(six.text_type(account_for_hash).encode('utf-8'))
+ temp_hash.update(str(account_for_hash).encode('utf-8'))
temp_hash_key = temp_hash.hexdigest()
hash_dict['creds'][temp_hash_key] = account
for role in roles:
@@ -375,6 +374,10 @@
self._creds['project_admin'] = project_admin
return project_admin
+ def get_project_alt_admin_creds(self):
+ # TODO(gmann): Implement alt admin hash.
+ return
+
def get_project_member_creds(self):
if self._creds.get('project_member'):
return self._creds.get('project_member')
@@ -382,6 +385,10 @@
self._creds['project_member'] = project_member
return project_member
+ def get_project_alt_member_creds(self):
+ # TODO(gmann): Implement alt member hash.
+ return
+
def get_project_reader_creds(self):
if self._creds.get('project_reader'):
return self._creds.get('project_reader')
@@ -389,9 +396,13 @@
self._creds['project_reader'] = project_reader
return project_reader
- def get_creds_by_roles(self, roles, force_new=False):
+ def get_project_alt_reader_creds(self):
+ # TODO(gmann): Implement alt reader hash.
+ return
+
+ def get_creds_by_roles(self, roles, force_new=False, scope=None):
roles = list(set(roles))
- exist_creds = self._creds.get(six.text_type(roles).encode(
+ exist_creds = self._creds.get(str(roles).encode(
'utf-8'), None)
# The force kwarg is used to allocate an additional set of creds with
# the same role list. The index used for the previously allocation
@@ -401,11 +412,11 @@
elif exist_creds and force_new:
# NOTE(andreaf) In py3.x encode returns bytes, and b'' is bytes
# In py2.7 encode returns strings, and b'' is still string
- new_index = six.text_type(roles).encode('utf-8') + b'-' + \
- six.text_type(len(self._creds)).encode('utf-8')
+ new_index = str(roles).encode('utf-8') + b'-' + \
+ str(len(self._creds)).encode('utf-8')
self._creds[new_index] = exist_creds
net_creds = self._get_creds(roles=roles)
- self._creds[six.text_type(roles).encode('utf-8')] = net_creds
+ self._creds[str(roles).encode('utf-8')] = net_creds
return net_creds
def clear_creds(self):
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index c950f63..00f2aeb 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -418,7 +418,7 @@
def _safe_body(self, body, maxlen=4096):
# convert a structure into a string safely
try:
- text = six.text_type(body)
+ text = str(body)
except UnicodeDecodeError:
# if this isn't actually text, return marker that
return "<BinaryData: removed>"
@@ -890,7 +890,7 @@
return True
return 'exceed' in resp_body.get('message', 'blabla')
- def wait_for_resource_deletion(self, id):
+ def wait_for_resource_deletion(self, id, *args, **kwargs):
"""Waits for a resource to be deleted
This method will loop over is_resource_deleted until either
@@ -903,7 +903,7 @@
"""
start_time = int(time.time())
while True:
- if self.is_resource_deleted(id):
+ if self.is_resource_deleted(id, *args, **kwargs):
return
if int(time.time()) - start_time >= self.build_timeout:
message = ('Failed to delete %(resource_type)s %(id)s within '
diff --git a/tempest/lib/services/identity/v3/oauth_token_client.py b/tempest/lib/services/identity/v3/oauth_token_client.py
index 3336094..236b224 100644
--- a/tempest/lib/services/identity/v3/oauth_token_client.py
+++ b/tempest/lib/services/identity/v3/oauth_token_client.py
@@ -33,7 +33,7 @@
def _escape(self, s):
"""Escape a unicode string in an OAuth-compatible fashion."""
safe = b'~'
- s = s.encode('utf-8') if isinstance(s, six.text_type) else s
+ s = s.encode('utf-8') if isinstance(s, str) else s
s = urlparse.quote(s, safe)
if isinstance(s, six.binary_type):
s = s.decode('utf-8')
@@ -47,8 +47,8 @@
verifier=None,
http_method='GET'):
"""Generate OAUTH params along with signature."""
- timestamp = six.text_type(int(time.time()))
- nonce = six.text_type(random.getrandbits(64)) + timestamp
+ timestamp = str(int(time.time()))
+ nonce = str(random.getrandbits(64)) + timestamp
oauth_params = [
('oauth_nonce', nonce),
('oauth_timestamp', timestamp),
diff --git a/tempest/lib/services/image/v2/images_client.py b/tempest/lib/services/image/v2/images_client.py
index fa3bb8c..abf427c 100644
--- a/tempest/lib/services/image/v2/images_client.py
+++ b/tempest/lib/services/image/v2/images_client.py
@@ -121,6 +121,14 @@
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+ def show_image_tasks(self, image_id):
+ """Show image tasks."""
+ url = 'images/%s/tasks' % image_id
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
def is_resource_deleted(self, id):
try:
self.show_image(id)
diff --git a/tempest/lib/services/image/v2/versions_client.py b/tempest/lib/services/image/v2/versions_client.py
index 1b7f806..98b4fb6 100644
--- a/tempest/lib/services/image/v2/versions_client.py
+++ b/tempest/lib/services/image/v2/versions_client.py
@@ -30,3 +30,13 @@
self.expected_success(300, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+
+ def has_version(self, version):
+ """Return True if a version is supported."""
+ version = 'v%s' % version
+ supported = ['SUPPORTED', 'CURRENT']
+ versions = self.list_versions()
+ for version_struct in versions['versions']:
+ if version_struct['id'] == version:
+ return version_struct['status'] in supported
+ return False
diff --git a/tempest/lib/services/object_storage/container_client.py b/tempest/lib/services/object_storage/container_client.py
index 8472a97..6d07ec1 100644
--- a/tempest/lib/services/object_storage/container_client.py
+++ b/tempest/lib/services/object_storage/container_client.py
@@ -20,10 +20,18 @@
from oslo_serialization import jsonutils as json
from tempest.lib.common import rest_client
+from tempest.lib import exceptions
class ContainerClient(rest_client.RestClient):
+ def is_resource_deleted(self, container):
+ try:
+ self.list_container_metadata(container)
+ except exceptions.NotFound:
+ return True
+ return False
+
def update_container(self, container_name, **headers):
"""Creates or Updates a container
diff --git a/tempest/lib/services/object_storage/object_client.py b/tempest/lib/services/object_storage/object_client.py
index 8845d79..bb82975 100644
--- a/tempest/lib/services/object_storage/object_client.py
+++ b/tempest/lib/services/object_storage/object_client.py
@@ -23,6 +23,13 @@
class ObjectClient(rest_client.RestClient):
+ def is_resource_deleted(self, object_name, container):
+ try:
+ self.get_object(container, object_name)
+ except exceptions.NotFound:
+ return True
+ return False
+
def create_object(self, container, object_name, data,
params=None, metadata=None, headers=None,
chunked=False):
diff --git a/tempest/lib/services/placement/resource_providers_client.py b/tempest/lib/services/placement/resource_providers_client.py
index fcd220f..e6fbcb2 100644
--- a/tempest/lib/services/placement/resource_providers_client.py
+++ b/tempest/lib/services/placement/resource_providers_client.py
@@ -81,3 +81,29 @@
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+
+ def update_resource_providers_inventories(self, rp_uuid, **kwargs):
+ """Update resource providers inventories.
+
+ For full list of available parameters, please refer to the official
+ API reference:
+ https://docs.openstack.org/api-ref/placement/#update-resource-provider-inventories
+ """
+ url = '/resource_providers/{}/inventories'.format(rp_uuid)
+ data = json.dumps(kwargs)
+ resp, body = self.put(url, data)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_resource_providers_inventories(self, rp_uuid):
+ """Delete resource providers inventories.
+
+ For full list of available parameters, please refer to the official
+ API reference:
+ https://docs.openstack.org/api-ref/placement/#delete-resource-provider-inventories
+ """
+ url = '/resource_providers/{}/inventories'.format(rp_uuid)
+ resp, body = self.delete(url)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 4652af4..22d0fd2 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -18,6 +18,7 @@
import subprocess
import netaddr
+
from oslo_log import log
from oslo_serialization import jsonutils as json
from oslo_utils import netutils
@@ -486,7 +487,7 @@
snapshot['id'])['snapshot']
return snapshot
- def _cleanup_volume_type(self, volume_type):
+ def cleanup_volume_type(self, volume_type):
"""Clean up a given volume type.
Ensuring all volumes associated to a type are first removed before
@@ -542,7 +543,7 @@
volume_type = volume_type_resp['volume_type']
self.assertIn('id', volume_type)
- self.addCleanup(self._cleanup_volume_type, volume_type)
+ self.addCleanup(self.cleanup_volume_type, volume_type)
return volume_type
def create_loginable_secgroup_rule(self, secgroup_id=None, rulesets=None):
@@ -589,7 +590,7 @@
rules.append(sg_rule)
return rules
- def _create_security_group(self, **kwargs):
+ def create_security_group(self, **kwargs):
"""Create security group and add rules to security group"""
if not kwargs.get('name'):
kwargs['name'] = data_utils.rand_name(self.__class__.__name__)
@@ -1060,10 +1061,10 @@
if not CONF.service_available.neutron:
raise cls.skipException('Neutron not available')
- def _create_network(self, networks_client=None,
- project_id=None,
- namestart='network-smoke-',
- port_security_enabled=True, **net_dict):
+ def create_network(self, networks_client=None,
+ project_id=None,
+ namestart='network-smoke-',
+ port_security_enabled=True, **net_dict):
if not networks_client:
networks_client = self.networks_client
if not project_id:
@@ -1098,6 +1099,8 @@
:Keyword Arguments:
* *ip_version = ip version of the given network,
+ use_default_subnetpool = default subnetpool to
+ manage IPv6 addresses range.
"""
if not subnets_client:
@@ -1120,51 +1123,73 @@
network_id=ext_net['id'], cidr=cidr)['subnets'])
return len(tenant_subnets + external_subnets) != 0
- ip_version = kwargs.pop('ip_version', 4)
-
- if ip_version == 6:
- tenant_cidr = netaddr.IPNetwork(
- CONF.network.project_network_v6_cidr)
- num_bits = CONF.network.project_network_v6_mask_bits
- else:
- tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
- num_bits = CONF.network.project_network_mask_bits
-
- result = None
- str_cidr = None
- # Repeatedly attempt subnet creation with sequential cidr
- # blocks until an unallocated block is found.
- for subnet_cidr in tenant_cidr.subnet(num_bits):
- str_cidr = str(subnet_cidr)
- if cidr_in_use(str_cidr, project_id=network['project_id']):
- continue
+ def _make_create_subnet_request(namestart, network,
+ ip_version, subnets_client, **kwargs):
subnet = dict(
name=data_utils.rand_name(namestart),
network_id=network['id'],
project_id=network['project_id'],
- cidr=str_cidr,
ip_version=ip_version,
**kwargs
)
+
+ if ip_version == 6:
+ subnet['ipv6_address_mode'] = 'slaac'
+ subnet['ipv6_ra_mode'] = 'slaac'
+
try:
- result = subnets_client.create_subnet(**subnet)
- break
+ return subnets_client.create_subnet(**subnet)
except lib_exc.Conflict as e:
- is_overlapping_cidr = 'overlaps with another subnet' in str(e)
- if not is_overlapping_cidr:
+ if 'overlaps with another subnet' not in str(e):
raise
+
+ result = None
+ str_cidr = None
+
+ use_default_subnetpool = kwargs.get('use_default_subnetpool', False)
+ ip_version = kwargs.pop('ip_version', 4)
+
+ if not use_default_subnetpool:
+
+ if ip_version == 6:
+ tenant_cidr = netaddr.IPNetwork(
+ CONF.network.project_network_v6_cidr)
+ num_bits = CONF.network.project_network_v6_mask_bits
+ else:
+ tenant_cidr = netaddr.IPNetwork(
+ CONF.network.project_network_cidr)
+ num_bits = CONF.network.project_network_mask_bits
+
+ # Repeatedly attempt subnet creation with sequential cidr
+ # blocks until an unallocated block is found.
+ for subnet_cidr in tenant_cidr.subnet(num_bits):
+ str_cidr = str(subnet_cidr)
+ if cidr_in_use(str_cidr, project_id=network['project_id']):
+ continue
+ result = _make_create_subnet_request(
+ namestart, network, ip_version, subnets_client,
+ cidr=str_cidr, **kwargs)
+
+ if result is not None:
+ break
+
+ else:
+ result = _make_create_subnet_request(
+ namestart, network, ip_version, subnets_client,
+ **kwargs)
self.assertIsNotNone(result, 'Unable to allocate tenant network')
subnet = result['subnet']
- self.assertEqual(subnet['cidr'], str_cidr)
+ if str_cidr is not None:
+ self.assertEqual(subnet['cidr'], str_cidr)
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
subnets_client.delete_subnet, subnet['id'])
return subnet
- def _get_server_port_id_and_ip4(self, server, ip_addr=None, **kwargs):
+ def get_server_port_id_and_ip4(self, server, ip_addr=None, **kwargs):
if ip_addr and not kwargs.get('fixed_ips'):
kwargs['fixed_ips'] = 'ip_address=%s' % ip_addr
@@ -1201,7 +1226,7 @@
% port_map)
return port_map[0]
- def _get_network_by_name(self, network_name):
+ def get_network_by_name(self, network_name):
net = self.os_admin.networks_client.list_networks(
name=network_name)['networks']
self.assertNotEmpty(net,
@@ -1217,7 +1242,7 @@
if not client:
client = self.floating_ips_client
if not port_id:
- port_id, ip4 = self._get_server_port_id_and_ip4(server)
+ port_id, ip4 = self.get_server_port_id_and_ip4(server)
else:
ip4 = None
@@ -1245,7 +1270,7 @@
This wrapper utility attaches the floating_ip for
the respective port_id of server
"""
- port_id, _ = self._get_server_port_id_and_ip4(server)
+ port_id, _ = self.get_server_port_id_and_ip4(server)
kwargs = dict(port_id=port_id)
floating_ip = self.floating_ips_client.update_floatingip(
floating_ip['id'], **kwargs)['floatingip']
@@ -1361,17 +1386,17 @@
self.log_console_output()
self.fail(msg)
- def _create_security_group(self, security_group_rules_client=None,
- project_id=None,
- namestart='secgroup-smoke',
- security_groups_client=None):
+ def create_security_group(self, security_group_rules_client=None,
+ project_id=None,
+ namestart='secgroup-smoke',
+ security_groups_client=None):
if security_group_rules_client is None:
security_group_rules_client = self.security_group_rules_client
if security_groups_client is None:
security_groups_client = self.security_groups_client
if project_id is None:
project_id = security_groups_client.project_id
- secgroup = self._create_empty_security_group(
+ secgroup = self.create_empty_security_group(
namestart=namestart, client=security_groups_client,
project_id=project_id)
@@ -1385,8 +1410,8 @@
self.assertEqual(secgroup['id'], rule['security_group_id'])
return secgroup
- def _create_empty_security_group(self, client=None, project_id=None,
- namestart='secgroup-smoke'):
+ def create_empty_security_group(self, client=None, project_id=None,
+ namestart='secgroup-smoke'):
"""Create a security group without rules.
Default rules will be created:
@@ -1520,7 +1545,7 @@
return rules
- def _get_router(self, client=None, project_id=None, **kwargs):
+ def get_router(self, client=None, project_id=None, **kwargs):
"""Retrieve a router for the given tenant id.
If a public router has been configured, it will be returned.
@@ -1589,18 +1614,18 @@
if not CONF.compute.fixed_network_name:
m = 'fixed_network_name must be specified in config'
raise lib_exc.InvalidConfiguration(m)
- network = self._get_network_by_name(
+ network = self.get_network_by_name(
CONF.compute.fixed_network_name)
router = None
subnet = None
else:
- network = self._create_network(
+ network = self.create_network(
networks_client=networks_client,
project_id=project_id,
port_security_enabled=port_security_enabled,
**net_dict)
- router = self._get_router(client=routers_client,
- project_id=project_id)
+ router = self.get_router(client=routers_client,
+ project_id=project_id)
subnet_kwargs = dict(network=network,
subnets_client=subnets_client)
# use explicit check because empty list is a valid option
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index fe42583..5201315 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -78,7 +78,7 @@
self.assertEqual(1, disks.count(CONF.compute.volume_device_name))
def create_and_add_security_group_to_server(self, server):
- secgroup = self._create_security_group()
+ secgroup = self.create_security_group()
self.servers_client.add_security_group(server['id'],
name=secgroup['name'])
self.addCleanup(self.servers_client.remove_security_group,
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index dbab212..20d2e80 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -60,7 +60,7 @@
def _setup_server(self, keypair):
security_groups = []
if utils.is_extension_enabled('security-group', 'network'):
- security_group = self._create_security_group()
+ security_group = self.create_security_group()
security_groups = [{'name': security_group['name']}]
network, _, _ = self.create_networks()
server = self.create_server(
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 6c1b3fa..e359c71 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -159,7 +159,7 @@
keypair = self.create_keypair()
self.keypairs[keypair['name']] = keypair
security_groups = [
- {'name': self._create_security_group()['name']}
+ {'name': self.create_security_group()['name']}
]
network = {'uuid': network['id']}
if port_id is not None:
@@ -223,14 +223,14 @@
floating_ip, server = self.floating_ip_tuple
# create a new server for the floating ip
server = self._create_server(self.network)
- port_id, _ = self._get_server_port_id_and_ip4(server)
+ port_id, _ = self.get_server_port_id_and_ip4(server)
floating_ip = self.floating_ips_client.update_floatingip(
floating_ip['id'], port_id=port_id)['floatingip']
self.assertEqual(port_id, floating_ip['port_id'])
self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
def _create_new_network(self, create_gateway=False):
- self.new_net = self._create_network()
+ self.new_net = self.create_network()
if create_gateway:
self.new_subnet = self.create_subnet(
network=self.new_net)
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 9be28c4..4f5118b 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -66,7 +66,7 @@
def setUp(self):
super(TestGettingAddress, self).setUp()
self.keypair = self.create_keypair()
- self.sec_grp = self._create_security_group()
+ self.sec_grp = self.create_security_group()
def prepare_network(self, address6_mode, n_subnets6=1, dualnet=False):
"""Prepare network
@@ -77,15 +77,15 @@
if dualnet - create IPv6 subnets on a different network
:return: list of created networks
"""
- network = self._create_network()
+ network = self.create_network()
if dualnet:
- network_v6 = self._create_network()
+ network_v6 = self.create_network()
sub4 = self.create_subnet(network=network,
namestart='sub4',
ip_version=4)
- router = self._get_router()
+ router = self.get_router()
self.routers_client.add_router_interface(router['id'],
subnet_id=sub4['id'])
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 496a371..e078f23 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -197,14 +197,14 @@
tenant.keypair = keypair
def _create_tenant_security_groups(self, tenant):
- access_sg = self._create_empty_security_group(
+ access_sg = self.create_empty_security_group(
namestart='secgroup_access-',
project_id=tenant.creds.project_id,
client=tenant.manager.security_groups_client
)
# don't use default secgroup since it allows in-project traffic
- def_sg = self._create_empty_security_group(
+ def_sg = self.create_empty_security_group(
namestart='secgroup_general-',
project_id=tenant.creds.project_id,
client=tenant.manager.security_groups_client
@@ -534,7 +534,7 @@
new_tenant = self.primary_tenant
# Create empty security group and add icmp rule in it
- new_sg = self._create_empty_security_group(
+ new_sg = self.create_empty_security_group(
namestart='secgroup_new-',
project_id=new_tenant.creds.project_id,
client=new_tenant.manager.security_groups_client)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 60242d5..4c82d84 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -128,7 +128,7 @@
@utils.services('compute', 'network')
def test_server_basic_ops(self):
keypair = self.create_keypair()
- security_group = self._create_security_group()
+ security_group = self.create_security_group()
self.md = {'meta1': 'data1', 'meta2': 'data2', 'metaN': 'dataN'}
self.instance = self.create_server(
key_name=keypair['name'],
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
index ed06898..29612ec 100644
--- a/tempest/scenario/test_shelve_instance.py
+++ b/tempest/scenario/test_shelve_instance.py
@@ -76,7 +76,7 @@
cold_migrate=False):
keypair = self.create_keypair()
- security_group = self._create_security_group()
+ security_group = self.create_security_group()
security_groups = [{'name': security_group['name']}]
server = self.create_server(
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index a062d40..d04cb9a 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -50,7 +50,7 @@
def test_snapshot_pattern(self):
# prepare for booting an instance
keypair = self.create_keypair()
- security_group = self._create_security_group()
+ security_group = self.create_security_group()
# boot an instance and create a timestamp file in it
server = self.create_server(
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index a8e4c30..4b81b9e 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -81,7 +81,7 @@
def test_stamp_pattern(self):
# prepare for booting an instance
keypair = self.create_keypair()
- security_group = self._create_security_group()
+ security_group = self.create_security_group()
# boot an instance and create a timestamp file in it
volume = self.create_volume()
diff --git a/tempest/scenario/test_volume_backup_restore.py b/tempest/scenario/test_volume_backup_restore.py
index 8a8c54e..71e6b53 100644
--- a/tempest/scenario/test_volume_backup_restore.py
+++ b/tempest/scenario/test_volume_backup_restore.py
@@ -70,7 +70,7 @@
# Create keypair and security group
keypair = self.create_keypair()
- security_group = self._create_security_group()
+ security_group = self.create_security_group()
# Boot a server from the restored backup
bd_map_v2 = [{
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 3b4bbda..5a5cc27 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -64,7 +64,7 @@
LOG.info("Creating keypair and security group")
keypair = self.create_keypair()
- security_group = self._create_security_group()
+ security_group = self.create_security_group()
# create an instance from volume
LOG.info("Booting instance 1 from volume")
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index 106500e..57d2a1a 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -100,7 +100,7 @@
def test_volume_retype_attached(self):
LOG.info("Creating keypair and security group")
keypair = self.create_keypair()
- security_group = self._create_security_group()
+ security_group = self.create_security_group()
# create volume types
LOG.info("Creating Volume types")
@@ -156,7 +156,7 @@
def test_volume_migrate_attached(self):
LOG.info("Creating keypair and security group")
keypair = self.create_keypair()
- security_group = self._create_security_group()
+ security_group = self.create_security_group()
LOG.info("Creating volume")
# Create a unique volume type to avoid using the backend default
diff --git a/tempest/test.py b/tempest/test.py
index 68602d6..655b9a4 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -296,6 +296,7 @@
identity_version = cls.get_identity_version()
# setting force_tenant_isolation to True also needs admin credentials.
if ('admin' in cls.credentials or
+ 'alt_admin' in cls.credentials or
getattr(cls, 'force_tenant_isolation', False)):
if not credentials.is_admin_available(
identity_version=identity_version):
@@ -414,8 +415,18 @@
'alt_manager', 'os_alt', version='Pike',
removal_version='Queens')
elif isinstance(credentials_type, list):
+ scope = 'project'
+ if credentials_type[0].startswith('system'):
+ scope = 'system'
+ elif credentials_type[0].startswith('domain'):
+ scope = 'domain'
manager = cls.get_client_manager(roles=credentials_type[1:],
- force_new=True)
+ force_new=True,
+ scope=scope)
+ setattr(cls, 'os_%s' % credentials_type[0], manager)
+ # TODO(gmann): Setting the old style attribute too for
+ # backward compatibility but at some point we should
+ # remove this.
setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
@classmethod
@@ -657,7 +668,7 @@
@classmethod
def get_client_manager(cls, credential_type=None, roles=None,
- force_new=None):
+ force_new=None, scope=None):
"""Returns an OpenStack client manager
Returns an OpenStack client manager based on either credential_type
@@ -665,6 +676,7 @@
credential_type 'primary'
:param credential_type: string - primary, alt or admin
:param roles: list of roles
+ :param scope: scope for the test user
:returns: the created client manager
:raises skipException: if the requested credentials are not available
@@ -683,7 +695,7 @@
" is not able to provide credentials with the %s role "
"assigned." % (cls.__name__, role))
raise cls.skipException(skip_msg)
- params = dict(roles=roles)
+ params = dict(roles=roles, scope=scope)
if force_new is not None:
params.update(force_new=force_new)
creds = cred_provider.get_creds_by_roles(**params)
@@ -850,7 +862,13 @@
if isinstance(credentials_type, six.string_types):
manager = cls.get_client_manager(credential_type=credentials_type)
elif isinstance(credentials_type, list):
- manager = cls.get_client_manager(roles=credentials_type[1:])
+ scope = 'project'
+ if credentials_type[0].startswith('system'):
+ scope = 'system'
+ elif credentials_type[0].startswith('domain'):
+ scope = 'domain'
+ manager = cls.get_client_manager(roles=credentials_type[1:],
+ scope=scope)
else:
manager = cls.get_client_manager()
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index b20b60e..1d69d9d 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -15,7 +15,6 @@
import abc
from oslo_log import log as logging
-import six
import stevedore
from tempest.lib.common.utils import misc
@@ -24,8 +23,7 @@
LOG = logging.getLogger(__name__)
-@six.add_metaclass(abc.ABCMeta)
-class TempestPlugin(object):
+class TempestPlugin(object, metaclass=abc.ABCMeta):
"""Provide basic hooks for an external plugin
To provide tempest the necessary information to run the plugin.
diff --git a/tempest/tests/api/compute/test_base.py b/tempest/tests/api/compute/test_base.py
index 74d2625..8a1873b 100644
--- a/tempest/tests/api/compute/test_base.py
+++ b/tempest/tests/api/compute/test_base.py
@@ -15,7 +15,6 @@
from unittest import mock
from oslo_utils import uuidutils
-import six
from tempest.api.compute import base as compute_base
from tempest.common import waiters
@@ -128,9 +127,9 @@
mock.sentinel.server_id, wait_until='active')
# make our assertions
if fault:
- self.assertIn(fault, six.text_type(ex))
+ self.assertIn(fault, str(ex))
else:
- self.assertNotIn(fault, six.text_type(ex))
+ self.assertNotIn(fault, str(ex))
if compute_base.BaseV2ComputeTest.is_requested_microversion_compatible(
'2.35'):
status = 'ACTIVE'
diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py
index ec7b760..3b5e901 100644
--- a/tempest/tests/cmd/test_run.py
+++ b/tempest/tests/cmd/test_run.py
@@ -21,7 +21,6 @@
from unittest import mock
import fixtures
-import six
from tempest.cmd import run
from tempest.cmd import workspace
@@ -153,12 +152,12 @@
subprocess.call(['stestr', 'init'])
out, err = self.assertRunExit(['tempest', 'run', '-l'], 0)
tests = out.split()
- tests = sorted([six.text_type(x.rstrip()) for x in tests if x])
+ tests = sorted([str(x.rstrip()) for x in tests if x])
result = [
- six.text_type('tests.test_failing.FakeTestClass.test_pass'),
- six.text_type('tests.test_failing.FakeTestClass.test_pass_list'),
- six.text_type('tests.test_passing.FakeTestClass.test_pass'),
- six.text_type('tests.test_passing.FakeTestClass.test_pass_list'),
+ str('tests.test_failing.FakeTestClass.test_pass'),
+ str('tests.test_failing.FakeTestClass.test_pass_list'),
+ str('tests.test_passing.FakeTestClass.test_pass'),
+ str('tests.test_passing.FakeTestClass.test_pass_list'),
]
# NOTE(mtreinish): on python 3 the subprocess prints b'' around
# stdout.
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 277e049..a8a4c0f 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -18,12 +18,9 @@
import fixtures
from oslo_serialization import jsonutils as json
-from tempest import clients
from tempest.cmd import init
from tempest.cmd import verify_tempest_config
-from tempest.common import credentials_factory
from tempest import config
-from tempest.lib.common import rest_client
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
from tempest.tests import base
@@ -97,15 +94,15 @@
self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
- fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v2.0'}]}
+ fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]}
fake_resp = json.dumps(fake_resp)
self.useFixture(fixtures.MockPatch(
'tempest.lib.common.http.ClosingHttp.request',
return_value=(None, fake_resp)))
fake_os = mock.MagicMock()
versions = verify_tempest_config._get_api_versions(fake_os, 'cinder')
- self.assertIn('v1.0', versions)
self.assertIn('v2.0', versions)
+ self.assertIn('v3.0', versions)
def test_get_nova_versions(self):
self.useFixture(fixtures.MockPatchObject(
@@ -145,7 +142,7 @@
self.assertTrue(mock_log_error.called)
def test_verify_api_versions(self):
- api_services = ['cinder', 'glance', 'keystone']
+ api_services = ['glance', 'keystone']
fake_os = mock.MagicMock()
for svc in api_services:
m = 'verify_%s_api_versions' % svc
@@ -154,7 +151,7 @@
verify_mock.assert_called_once_with(fake_os, True)
def test_verify_api_versions_not_implemented(self):
- api_services = ['cinder', 'glance', 'keystone']
+ api_services = ['glance', 'keystone']
fake_os = mock.MagicMock()
for svc in api_services:
m = 'verify_%s_api_versions' % svc
@@ -178,52 +175,6 @@
'identity-feature-enabled',
False, True)
- @mock.patch('tempest.lib.common.http.ClosingHttp.request')
- def test_verify_cinder_api_versions_no_v3(self, mock_request):
- self.useFixture(fixtures.MockPatchObject(
- verify_tempest_config, '_get_unversioned_endpoint',
- return_value='http://fake_endpoint:5000'))
- fake_resp = {'versions': [{'id': 'v2.0'}]}
- fake_resp = json.dumps(fake_resp)
- mock_request.return_value = (None, fake_resp)
- fake_os = mock.MagicMock()
- with mock.patch.object(verify_tempest_config,
- 'print_and_or_update') as print_mock:
- verify_tempest_config.verify_cinder_api_versions(fake_os, True)
- print_mock.assert_any_call('api_v3', 'volume-feature-enabled',
- False, True)
- self.assertEqual(1, print_mock.call_count)
-
- @mock.patch('tempest.lib.common.http.ClosingHttp.request')
- def test_verify_cinder_api_versions_no_v2(self, mock_request):
- self.useFixture(fixtures.MockPatchObject(
- verify_tempest_config, '_get_unversioned_endpoint',
- return_value='http://fake_endpoint:5000'))
- fake_resp = {'versions': [{'id': 'v3.0'}]}
- fake_resp = json.dumps(fake_resp)
- mock_request.return_value = (None, fake_resp)
- fake_os = mock.MagicMock()
- with mock.patch.object(verify_tempest_config,
- 'print_and_or_update') as print_mock:
- verify_tempest_config.verify_cinder_api_versions(fake_os, True)
- print_mock.assert_any_call('api_v2', 'volume-feature-enabled',
- False, True)
- self.assertEqual(1, print_mock.call_count)
-
- @mock.patch('tempest.lib.common.http.ClosingHttp.request')
- def test_verify_cinder_api_versions_no_v1(self, mock_request):
- self.useFixture(fixtures.MockPatchObject(
- verify_tempest_config, '_get_unversioned_endpoint',
- return_value='http://fake_endpoint:5000'))
- fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]}
- fake_resp = json.dumps(fake_resp)
- mock_request.return_value = (None, fake_resp)
- fake_os = mock.MagicMock()
- with mock.patch.object(verify_tempest_config,
- 'print_and_or_update') as print_mock:
- verify_tempest_config.verify_cinder_api_versions(fake_os, True)
- print_mock.assert_not_called()
-
def test_verify_glance_version_no_v2_with_v1_1(self):
# This test verifies that wrong config api_v2 = True is detected
class FakeClient(object):
@@ -560,23 +511,24 @@
self.assertEqual([], results['swift']['extensions'])
def test_get_extension_client(self):
- creds = credentials_factory.get_credentials(
- fill_in=False, username='fake_user', project_name='fake_project',
- password='fake_password')
- os = clients.Manager(creds)
- for service in ['nova', 'neutron', 'swift', 'cinder']:
+ fake_os = mock.MagicMock()
+ services = {
+ 'nova': fake_os.compute.ExtensionsClient(),
+ 'neutron': fake_os.network.ExtensionsClient(),
+ 'swift': fake_os.object_storage.CapabilitiesClient(),
+ 'cinder': fake_os.volume_v2.ExtensionsClient(),
+ }
+ for service in services.keys():
extensions_client = verify_tempest_config.get_extension_client(
- os, service)
- self.assertIsInstance(extensions_client, rest_client.RestClient)
+ fake_os, service)
+ self.assertIsInstance(extensions_client, mock.MagicMock)
+ self.assertEqual(extensions_client, services[service])
def test_get_extension_client_sysexit(self):
- creds = credentials_factory.get_credentials(
- fill_in=False, username='fake_user', project_name='fake_project',
- password='fake_password')
- os = clients.Manager(creds)
+ fake_os = mock.MagicMock()
self.assertRaises(SystemExit,
verify_tempest_config.get_extension_client,
- os, 'fakeservice')
+ fake_os, 'fakeservice')
def test_get_config_file(self):
conf_dir = os.path.join(os.getcwd(), 'etc')
diff --git a/tempest/tests/lib/cmd/test_check_uuid.py b/tempest/tests/lib/cmd/test_check_uuid.py
index 428e047..5d63dec 100644
--- a/tempest/tests/lib/cmd/test_check_uuid.py
+++ b/tempest/tests/lib/cmd/test_check_uuid.py
@@ -13,13 +13,13 @@
import ast
import importlib
import os
+import shutil
import sys
import tempfile
from unittest import mock
-import fixtures
-
from tempest.lib.cmd import check_uuid
+from tempest.lib import decorators
from tempest.tests import base
@@ -40,23 +40,24 @@
return tests_file
def test_fix_argument_no(self):
- temp_dir = self.useFixture(fixtures.TempDir(rootdir="."))
- tests_file = self.create_tests_file(temp_dir.path)
-
+ temp_dir = tempfile.mkdtemp(prefix='check-uuid-no', dir=".")
+ self.addCleanup(shutil.rmtree, temp_dir, ignore_errors=True)
+ tests_file = self.create_tests_file(temp_dir)
sys.argv = [sys.argv[0]] + ["--package",
- os.path.relpath(temp_dir.path)]
+ os.path.relpath(temp_dir)]
self.assertRaises(SystemExit, check_uuid.run)
with open(tests_file, "r") as f:
self.assertTrue(TestCLInterface.CODE == f.read())
+ @decorators.skip_because(bug='1918316')
def test_fix_argument_yes(self):
- temp_dir = self.useFixture(fixtures.TempDir(rootdir="."))
- tests_file = self.create_tests_file(temp_dir.path)
+ temp_dir = tempfile.mkdtemp(prefix='check-uuid-yes', dir=".")
+ self.addCleanup(shutil.rmtree, temp_dir, ignore_errors=True)
+ tests_file = self.create_tests_file(temp_dir)
sys.argv = [sys.argv[0]] + ["--fix", "--package",
- os.path.relpath(temp_dir.path)]
-
+ os.path.relpath(temp_dir)]
check_uuid.run()
with open(tests_file, "r") as f:
self.assertTrue(TestCLInterface.CODE != f.read())
diff --git a/tempest/tests/lib/common/test_api_version_utils.py b/tempest/tests/lib/common/test_api_version_utils.py
index b99e8d4..8d5de09 100644
--- a/tempest/tests/lib/common/test_api_version_utils.py
+++ b/tempest/tests/lib/common/test_api_version_utils.py
@@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
import testtools
from tempest.lib.common import api_version_utils
@@ -31,7 +30,7 @@
cfg_max_version)
except testtools.TestCase.skipException as e:
if not expected_skip:
- raise testtools.TestCase.failureException(six.text_type(e))
+ raise testtools.TestCase.failureException(str(e))
def test_version_min_in_range(self):
self._test_version('2.2', '2.10', '2.1', '2.7')
diff --git a/tempest/tests/lib/common/test_dynamic_creds.py b/tempest/tests/lib/common/test_dynamic_creds.py
index e9073cc..b4b1b91 100644
--- a/tempest/tests/lib/common/test_dynamic_creds.py
+++ b/tempest/tests/lib/common/test_dynamic_creds.py
@@ -214,6 +214,56 @@
self.assertEqual(admin_creds.user_id, '1234')
@mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_project_alt_admin_creds(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_roles('1234', 'admin')
+ self._mock_user_create('1234', 'fake_alt_admin_user')
+ self._mock_tenant_create('1234', 'fake_alt_admin')
+
+ user_mock = mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_project')
+ user_mock.start()
+ self.addCleanup(user_mock.stop)
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_project') as user_mock:
+ alt_admin_creds = creds.get_project_alt_admin_creds()
+ user_mock.assert_has_calls([
+ mock.call('1234', '1234', '1234')])
+ self.assertEqual(alt_admin_creds.username, 'fake_alt_admin_user')
+ self.assertEqual(alt_admin_creds.project_name, 'fake_alt_admin')
+ # Verify IDs
+ self.assertEqual(alt_admin_creds.project_id, '1234')
+ self.assertEqual(alt_admin_creds.user_id, '1234')
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_project_alt_member_creds(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_assign_user_role()
+ self._mock_list_role()
+ self._mock_tenant_create('1234', 'fake_alt_member')
+ self._mock_user_create('1234', 'fake_alt_user')
+ alt_member_creds = creds.get_project_alt_member_creds()
+ self.assertEqual(alt_member_creds.username, 'fake_alt_user')
+ self.assertEqual(alt_member_creds.project_name, 'fake_alt_member')
+ # Verify IDs
+ self.assertEqual(alt_member_creds.project_id, '1234')
+ self.assertEqual(alt_member_creds.user_id, '1234')
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_project_alt_reader_creds(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_assign_user_role()
+ self._mock_list_roles('1234', 'reader')
+ self._mock_tenant_create('1234', 'fake_alt_reader')
+ self._mock_user_create('1234', 'fake_alt_user')
+ alt_reader_creds = creds.get_project_alt_reader_creds()
+ self.assertEqual(alt_reader_creds.username, 'fake_alt_user')
+ self.assertEqual(alt_reader_creds.project_name, 'fake_alt_reader')
+ # Verify IDs
+ self.assertEqual(alt_reader_creds.project_id, '1234')
+ self.assertEqual(alt_reader_creds.user_id, '1234')
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
def test_role_creds(self, MockRestClient):
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
self._mock_list_2_roles()
@@ -242,6 +292,100 @@
self.assertEqual(role_creds.user_id, '1234')
@mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_role_creds_with_project_scope(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+ self._mock_tenant_create('1234', 'fake_role_project')
+
+ user_mock = mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_project')
+ user_mock.start()
+ self.addCleanup(user_mock.stop)
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_project') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='project')
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+ args = map(lambda x: x[1], calls)
+ args = list(args)
+ self.assertIn(('1234', '1234', '1234'), args)
+ self.assertIn(('1234', '1234', '12345'), args)
+ self.assertEqual(role_creds.username, 'fake_role_user')
+ self.assertEqual(role_creds.project_name, 'fake_role_project')
+ # Verify IDs
+ self.assertEqual(role_creds.project_id, '1234')
+ self.assertEqual(role_creds.user_id, '1234')
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def _test_get_same_role_creds_with_project_scope(self, MockRestClient,
+ scope=None):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+ self._mock_tenant_create('1234', 'fake_role_project')
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_project') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope=scope)
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+
+ # Fetch the same creds again
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_project') as user_mock1:
+ role_creds_new = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope=scope)
+ calls = user_mock1.mock_calls
+ # Assert that previously created creds are return and no call to
+ # role creation.
+ self.assertEqual(len(calls), 0)
+ # Check if previously created creds are returned.
+ self.assertEqual(role_creds, role_creds_new)
+
+ def test_get_same_role_creds_with_project_scope(self):
+ self._test_get_same_role_creds_with_project_scope(scope='project')
+
+ def test_get_same_role_creds_with_default_scope(self):
+ self._test_get_same_role_creds_with_project_scope()
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def _test_get_different_role_creds_with_project_scope(
+ self, MockRestClient, scope=None):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+ self._mock_tenant_create('1234', 'fake_role_project')
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_project') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope=scope)
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+ # Fetch the creds with one role different
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_project') as user_mock1:
+ role_creds_new = creds.get_creds_by_roles(
+ roles=['role1'], scope=scope)
+ calls = user_mock1.mock_calls
+ # Because one role is different, assert that the role creation
+ # is called with the 1 specified roles
+ self.assertEqual(len(calls), 1)
+ # Check new creds is created for new roles.
+ self.assertNotEqual(role_creds, role_creds_new)
+
+ def test_get_different_role_creds_with_project_scope(self):
+ self._test_get_different_role_creds_with_project_scope(
+ scope='project')
+
+ def test_get_different_role_creds_with_default_scope(self):
+ self._test_get_different_role_creds_with_project_scope()
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
def test_all_cred_cleanup(self, MockRestClient):
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
self._mock_assign_user_role()
@@ -658,6 +802,232 @@
return project_fix
@mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_role_creds_with_system_scope(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_system') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='system')
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+ args = map(lambda x: x[1], calls)
+ args = list(args)
+ self.assertIn(('1234', '1234'), args)
+ self.assertIn(('1234', '12345'), args)
+ self.assertEqual(role_creds.username, 'fake_role_user')
+ self.assertEqual(role_creds.user_id, '1234')
+ # Verify system scope
+ self.assertEqual(role_creds.system, 'all')
+ # Verify domain is default
+ self.assertEqual(role_creds.domain_id, 'default')
+ self.assertEqual(role_creds.domain_name, 'Default')
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_get_same_role_creds_with_system_scope(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_system') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='system')
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+
+ # Fetch the same creds again
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_system') as user_mock1:
+ role_creds_new = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='system')
+ calls = user_mock1.mock_calls
+ # Assert that previously created creds are return and no call to
+ # role creation.
+ self.assertEqual(len(calls), 0)
+ # Verify system scope
+ self.assertEqual(role_creds_new.system, 'all')
+ # Check if previously created creds are returned.
+ self.assertEqual(role_creds, role_creds_new)
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_get_different_role_creds_with_system_scope(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_system') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='system')
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+ # Verify system scope
+ self.assertEqual(role_creds.system, 'all')
+ # Fetch the creds with one role different
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_system') as user_mock1:
+ role_creds_new = creds.get_creds_by_roles(
+ roles=['role1'], scope='system')
+ calls = user_mock1.mock_calls
+ # Because one role is different, assert that the role creation
+ # is called with the 1 specified roles
+ self.assertEqual(len(calls), 1)
+ # Verify Scope
+ self.assertEqual(role_creds_new.system, 'all')
+ # Check new creds is created for new roles.
+ self.assertNotEqual(role_creds, role_creds_new)
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_role_creds_with_domain_scope(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+
+ domain = {
+ "id": '12',
+ "enabled": True,
+ "name": "TestDomain"
+ }
+
+ self.useFixture(fixtures.MockPatch(
+ 'tempest.lib.common.cred_client.V3CredsClient.create_domain',
+ return_value=domain))
+
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_domain') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='domain')
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+ args = map(lambda x: x[1], calls)
+ args = list(args)
+ self.assertIn((domain['id'], '1234', '1234'), args)
+ self.assertIn((domain['id'], '1234', '12345'), args)
+ self.assertEqual(role_creds.username, 'fake_role_user')
+ self.assertEqual(role_creds.user_id, '1234')
+ # Verify creds are under new created domain
+ self.assertEqual(role_creds.domain_id, domain['id'])
+ self.assertEqual(role_creds.domain_name, domain['name'])
+ # Verify that Scope is None
+ self.assertIsNone(role_creds.system)
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_get_same_role_creds_with_domain_scope(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+
+ domain = {
+ "id": '12',
+ "enabled": True,
+ "name": "TestDomain"
+ }
+
+ self.useFixture(fixtures.MockPatch(
+ 'tempest.lib.common.cred_client.V3CredsClient.create_domain',
+ return_value=domain))
+
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_domain') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='domain')
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+ self.assertEqual(role_creds.user_id, '1234')
+ # Verify Scope
+ self.assertIsNone(role_creds.system)
+ # Fetch the same creds again
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_domain') as user_mock1:
+ role_creds_new = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='domain')
+ calls = user_mock1.mock_calls
+ # Assert that previously created creds are return and no call to
+ # role creation.
+ self.assertEqual(len(calls), 0)
+ # Verify Scope
+ self.assertIsNone(role_creds_new.system)
+ # Check if previously created creds are returned.
+ self.assertEqual(role_creds, role_creds_new)
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_get_different_role_creds_with_domain_scope(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+
+ domain = {
+ "id": '12',
+ "enabled": True,
+ "name": "TestDomain"
+ }
+
+ self.useFixture(fixtures.MockPatch(
+ 'tempest.lib.common.cred_client.V3CredsClient.create_domain',
+ return_value=domain))
+
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_domain') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='domain')
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+ self.assertEqual(role_creds.user_id, '1234')
+ # Verify Scope
+ self.assertIsNone(role_creds.system)
+ # Fetch the same creds again
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_domain') as user_mock1:
+ role_creds_new = creds.get_creds_by_roles(
+ roles=['role1'], scope='domain')
+ calls = user_mock1.mock_calls
+ # Because one role is different, assert that the role creation
+ # is called with the 1 specified roles
+ self.assertEqual(len(calls), 1)
+ # Verify Scope
+ self.assertIsNone(role_creds_new.system)
+ # Check new creds is created for new roles.
+ self.assertNotEqual(role_creds, role_creds_new)
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
+ def test_get_role_creds_with_different_scope(self, MockRestClient):
+ creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+ self._mock_tenant_create('1234', 'fake_role_project')
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_system') as user_mock:
+ role_creds = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='system')
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+ # Verify Scope
+ self.assertEqual(role_creds.system, 'all')
+
+ # Fetch the same role creds but with different scope
+ with mock.patch.object(self.roles_client.RolesClient,
+ 'create_user_role_on_project') as user_mock1:
+ role_creds_new = creds.get_creds_by_roles(
+ roles=['role1', 'role2'], scope='project')
+ calls = user_mock1.mock_calls
+ # Because scope is different, assert that the role creation
+ # is called with the 2 specified roles
+ self.assertEqual(len(calls), 2)
+ # Verify Scope
+ self.assertIsNone(role_creds_new.system)
+ # Check that created creds are different
+ self.assertNotEqual(role_creds, role_creds_new)
+
+ @mock.patch('tempest.lib.common.rest_client.RestClient')
def test_member_role_creation_with_duplicate(self, rest_client_mock):
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
creds.creds_client = mock.MagicMock()
diff --git a/tempest/tests/lib/common/test_preprov_creds.py b/tempest/tests/lib/common/test_preprov_creds.py
index 579363e..fe7fcd2 100644
--- a/tempest/tests/lib/common/test_preprov_creds.py
+++ b/tempest/tests/lib/common/test_preprov_creds.py
@@ -12,17 +12,16 @@
# License for the specific language governing permissions and limitations
# under the License.
-import hashlib
import os
import shutil
from unittest import mock
-import six
import testtools
import fixtures
from oslo_concurrency.fixture import lockutils as lockutils_fixtures
from oslo_config import cfg
+from oslo_utils.secretutils import md5
from tempest import config
from tempest.lib import auth
@@ -106,10 +105,10 @@
hash_fields = (
preprov_creds.PreProvisionedCredentialProvider.HASH_CRED_FIELDS)
for account in accounts_list:
- hash = hashlib.md5()
+ hash = md5(usedforsecurity=False)
account_for_hash = dict((k, v) for (k, v) in account.items()
if k in hash_fields)
- hash.update(six.text_type(account_for_hash).encode('utf-8'))
+ hash.update(str(account_for_hash).encode('utf-8'))
temp_hash = hash.hexdigest()
hash_list.append(temp_hash)
return hash_list
diff --git a/tempest/tests/lib/services/image/v2/test_images_client.py b/tempest/tests/lib/services/image/v2/test_images_client.py
index fe671bd..5b162f8 100644
--- a/tempest/tests/lib/services/image/v2/test_images_client.py
+++ b/tempest/tests/lib/services/image/v2/test_images_client.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
+import io
from tempest.lib.common.utils import data_utils
from tempest.lib.services.image.v2 import images_client
@@ -105,6 +105,44 @@
"first": "/v2/images"
}
+ FAKE_SHOW_IMAGE_TASKS = {
+ "tasks": [
+ {
+ "id": "ee22890e-8948-4ea6-9668-831f973c84f5",
+ "image_id": "dddddddd-dddd-dddd-dddd-dddddddddddd",
+ "request-id": "rrrrrrr-rrrr-rrrr-rrrr-rrrrrrrrrrrr",
+ "user": "uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu",
+ "type": "api_image_import",
+ "status": "processing",
+ "owner": "64f0efc9955145aeb06f297a8a6fe402",
+ "expires_at": None,
+ "created_at": "2020-12-18T05:20:38.000000",
+ "updated_at": "2020-12-18T05:25:39.000000",
+ "deleted_at": None,
+ "deleted": False,
+ "input": {
+ "image_id": "829c729b-ebc4-4cc7-a164-6f43f1149b17",
+ "import_req": {
+ "method": {
+ "name": "copy-image",
+ },
+ "all_stores": True,
+ "all_stores_must_succeed": False,
+ },
+ "backend": [
+ "fast",
+ "cheap",
+ "slow",
+ "reliable",
+ "common",
+ ]
+ },
+ "result": None,
+ "message": "Copied 15 MiB",
+ }
+ ]
+ }
+
FAKE_TAG_NAME = "fake tag"
def setUp(self):
@@ -178,7 +216,7 @@
{}, image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8", status=204)
def test_store_image_file(self):
- data = six.BytesIO(data_utils.random_bytes())
+ data = io.BytesIO(data_utils.random_bytes())
self.check_service_client_function(
self.client.store_image_file,
@@ -230,3 +268,11 @@
def test_list_images_with_bytes_body(self):
self._test_list_images(bytes_body=True)
+
+ def test_show_image_tasks(self):
+ self.check_service_client_function(
+ self.client.show_image_tasks,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SHOW_IMAGE_TASKS,
+ True,
+ image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8")
diff --git a/tempest/tests/lib/services/image/v2/test_versions_client.py b/tempest/tests/lib/services/image/v2/test_versions_client.py
index 6234b06..98c558a 100644
--- a/tempest/tests/lib/services/image/v2/test_versions_client.py
+++ b/tempest/tests/lib/services/image/v2/test_versions_client.py
@@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import fixtures
+
from tempest.lib.services.image.v2 import versions_client
from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib.services import base
@@ -92,3 +94,13 @@
def test_list_versions_with_bytes_body(self):
self._test_list_versions(bytes_body=True)
+
+ def test_has_version(self):
+ mocked_r = self.create_response(self.FAKE_VERSIONS_INFO, False,
+ 300, None)
+ self.useFixture(fixtures.MockPatch(
+ 'tempest.lib.common.rest_client.RestClient.raw_request',
+ return_value=mocked_r))
+
+ self.assertTrue(self.client.has_version('2.1'))
+ self.assertFalse(self.client.has_version('9.9'))
diff --git a/tempest/tests/lib/services/placement/test_resource_providers_client.py b/tempest/tests/lib/services/placement/test_resource_providers_client.py
index 11aeaf2..485f584 100644
--- a/tempest/tests/lib/services/placement/test_resource_providers_client.py
+++ b/tempest/tests/lib/services/placement/test_resource_providers_client.py
@@ -48,6 +48,43 @@
FAKE_RESOURCE_PROVIDER_AGGREGATES = {
'aggregates': [FAKE_AGGREGATE_UUID]
}
+ FAKE_RESOURCE_UPDATE_INVENTORIES_RESPONSE = {
+ "inventories": {
+ "MEMORY_MB": {
+ "allocation_ratio": 2.0,
+ "max_unit": 16,
+ "min_unit": 1,
+ "reserved": 0,
+ "step_size": 4,
+ "total": 128
+ },
+ "VCPU": {
+ "allocation_ratio": 10.0,
+ "max_unit": 2147483647,
+ "min_unit": 1,
+ "reserved": 2,
+ "step_size": 1,
+ "total": 64
+ }
+ },
+ "resource_provider_generation": 2
+ }
+ FAKE_RESOURCE_UPDATE_INVENTORIES_REQUEST = {
+ "inventories": {
+ "MEMORY_MB": {
+ "allocation_ratio": 2.0,
+ "max_unit": 16,
+ "step_size": 4,
+ "total": 128
+ },
+ "VCPU": {
+ "allocation_ratio": 10.0,
+ "reserved": 2,
+ "total": 64
+ }
+ },
+ "resource_provider_generation": 1
+ }
def setUp(self):
super(TestResourceProvidersClient, self).setUp()
@@ -102,6 +139,32 @@
def test_list_resource_provider_inventories_with_bytes_body(self):
self._test_list_resource_provider_inventories(bytes_body=True)
+ def _test_update_resource_providers_inventories(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_resource_providers_inventories,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_RESOURCE_UPDATE_INVENTORIES_RESPONSE,
+ to_utf=bytes_body,
+ status=200,
+ rp_uuid=self.FAKE_RESOURCE_PROVIDER_UUID,
+ **self.FAKE_RESOURCE_UPDATE_INVENTORIES_REQUEST
+ )
+
+ def test_update_resource_providers_inventories_with_str_body(self):
+ self._test_update_resource_providers_inventories()
+
+ def test_update_resource_providers_inventories_with_bytes_body(self):
+ self._test_update_resource_providers_inventories(bytes_body=True)
+
+ def test_delete_resource_providers_inventories(self):
+ self.check_service_client_function(
+ self.client.delete_resource_providers_inventories,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ status=204,
+ rp_uuid=self.FAKE_RESOURCE_PROVIDER_UUID,
+ )
+
def _test_list_resource_provider_aggregates(self, bytes_body=False):
self.check_service_client_function(
self.client.list_resource_provider_aggregates,
diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py
index e3c17e8..fc93f76 100644
--- a/tempest/tests/lib/test_decorators.py
+++ b/tempest/tests/lib/test_decorators.py
@@ -16,7 +16,6 @@
import abc
from unittest import mock
-import six
import testtools
from tempest.lib import base as test
@@ -69,8 +68,7 @@
condition=True)
-@six.add_metaclass(abc.ABCMeta)
-class BaseSkipDecoratorTests(object):
+class BaseSkipDecoratorTests(object, metaclass=abc.ABCMeta):
@abc.abstractmethod
def _test_skip_helper(self, raise_exception=True, expected_to_skip=True,
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
index 0ec9262..035bdb0 100644
--- a/tempest/tests/lib/test_ssh.py
+++ b/tempest/tests/lib/test_ssh.py
@@ -274,7 +274,7 @@
client = ssh.Client('localhost', 'root', timeout=2)
exc = self.assertRaises(exceptions.SSHExecCommandFailed,
client.exec_command, "test")
- self.assertIn('R' + self._utf8_string, six.text_type(exc))
+ self.assertIn('R' + self._utf8_string, str(exc))
def test_exec_command_no_select(self):
gsc_mock = self.patch('tempest.lib.common.ssh.Client.'
diff --git a/tempest/tests/test_base_test.py b/tempest/tests/test_base_test.py
index b154cd5..88c28bf 100644
--- a/tempest/tests/test_base_test.py
+++ b/tempest/tests/test_base_test.py
@@ -109,7 +109,7 @@
test.BaseTestCase.get_tenant_network(credentials_type=creds)
- mock_gcm.assert_called_once_with(roles=['role1'])
+ mock_gcm.assert_called_once_with(roles=['role1'], scope='project')
mock_gprov.assert_called_once_with()
mock_gtn.assert_called_once_with(mock_prov, net_client,
self.fixed_network_name)
diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py
index 1cc9c9a..fe44ef6 100644
--- a/tempest/tests/test_list_tests.py
+++ b/tempest/tests/test_list_tests.py
@@ -16,8 +16,6 @@
import re
import subprocess
-import six
-
from tempest.tests import base
@@ -32,7 +30,7 @@
self.assertEqual(0, p.returncode,
"test discovery failed, one or more files cause an "
"error on import %s" % ids)
- ids = six.text_type(ids).split('\n')
+ ids = str(ids).split('\n')
for test_id in ids:
if re.match(r'(\w+\.){3}\w+', test_id):
if not test_id.startswith('tempest.'):
diff --git a/tempest/tests/test_microversions.py b/tempest/tests/test_microversions.py
index ee6db71..835f51c 100644
--- a/tempest/tests/test_microversions.py
+++ b/tempest/tests/test_microversions.py
@@ -13,7 +13,6 @@
# under the License.
from oslo_config import cfg
-import six
import testtools
from tempest.api.compute import base as compute_base
@@ -75,7 +74,7 @@
self.assertRaises(testtools.TestCase.skipException,
test_class.skip_checks)
except testtools.TestCase.skipException as e:
- raise testtools.TestCase.failureException(six.text_type(e))
+ raise testtools.TestCase.failureException(str(e))
def test_config_version_none_none(self):
expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2]
diff --git a/tempest/tests/test_test.py b/tempest/tests/test_test.py
index 72e8b6d..9aeedb3 100644
--- a/tempest/tests/test_test.py
+++ b/tempest/tests/test_test.py
@@ -453,6 +453,130 @@
expected_creds[1][1:],
mock_get_client_manager.mock_calls[1][2]['roles'])
+ def test_setup_credentials_with_role_and_system_scope(self):
+ expected_creds = [['system_my_role', 'role1', 'role2']]
+
+ class SystemRoleCredentials(self.parent_test):
+ credentials = expected_creds
+
+ expected_clients = 'clients'
+ with mock.patch.object(
+ SystemRoleCredentials,
+ 'get_client_manager') as mock_get_client_manager:
+ mock_get_client_manager.return_value = expected_clients
+ sys_creds = SystemRoleCredentials()
+ sys_creds.setup_credentials()
+ self.assertTrue(hasattr(sys_creds, 'os_system_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_system_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role)
+ self.assertEqual(1, mock_get_client_manager.call_count)
+ self.assertEqual(
+ expected_creds[0][1:],
+ mock_get_client_manager.mock_calls[0][2]['roles'])
+ self.assertEqual(
+ 'system',
+ mock_get_client_manager.mock_calls[0][2]['scope'])
+
+ def test_setup_credentials_with_multiple_role_and_system_scope(self):
+ expected_creds = [['system_my_role', 'role1', 'role2'],
+ ['system_my_role2', 'role1', 'role2'],
+ ['system_my_role3', 'role3']]
+
+ class SystemRoleCredentials(self.parent_test):
+ credentials = expected_creds
+
+ expected_clients = 'clients'
+ with mock.patch.object(
+ SystemRoleCredentials,
+ 'get_client_manager') as mock_get_client_manager:
+ mock_get_client_manager.return_value = expected_clients
+ sys_creds = SystemRoleCredentials()
+ sys_creds.setup_credentials()
+ self.assertTrue(hasattr(sys_creds, 'os_system_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_system_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_system_my_role2'))
+ self.assertEqual(expected_clients, sys_creds.os_system_my_role2)
+ self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role2'))
+ self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role2)
+ self.assertTrue(hasattr(sys_creds, 'os_system_my_role3'))
+ self.assertEqual(expected_clients, sys_creds.os_system_my_role3)
+ self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role3'))
+ self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role3)
+ self.assertEqual(3, mock_get_client_manager.call_count)
+ self.assertEqual(
+ expected_creds[0][1:],
+ mock_get_client_manager.mock_calls[0][2]['roles'])
+ self.assertEqual(
+ 'system', mock_get_client_manager.mock_calls[0][2]['scope'])
+ self.assertEqual(
+ expected_creds[1][1:],
+ mock_get_client_manager.mock_calls[1][2]['roles'])
+ self.assertEqual(
+ 'system', mock_get_client_manager.mock_calls[1][2]['scope'])
+ self.assertEqual(
+ expected_creds[2][1:],
+ mock_get_client_manager.mock_calls[2][2]['roles'])
+ self.assertEqual(
+ 'system', mock_get_client_manager.mock_calls[2][2]['scope'])
+
+ def test_setup_credentials_with_role_and_multiple_scope(self):
+ expected_creds = [['my_role', 'role1', 'role2'],
+ ['project_my_role', 'role1', 'role2'],
+ ['domain_my_role', 'role1', 'role2'],
+ ['system_my_role', 'role1', 'role2']]
+
+ class SystemRoleCredentials(self.parent_test):
+ credentials = expected_creds
+
+ expected_clients = 'clients'
+ with mock.patch.object(
+ SystemRoleCredentials,
+ 'get_client_manager') as mock_get_client_manager:
+ mock_get_client_manager.return_value = expected_clients
+ sys_creds = SystemRoleCredentials()
+ sys_creds.setup_credentials()
+ self.assertTrue(hasattr(sys_creds, 'os_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_roles_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_roles_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_project_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_project_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_roles_project_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_roles_project_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_domain_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_domain_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_roles_domain_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_roles_domain_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_system_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_system_my_role)
+ self.assertTrue(hasattr(sys_creds, 'os_roles_system_my_role'))
+ self.assertEqual(expected_clients, sys_creds.os_roles_system_my_role)
+
+ self.assertEqual(4, mock_get_client_manager.call_count)
+ self.assertEqual(
+ expected_creds[0][1:],
+ mock_get_client_manager.mock_calls[0][2]['roles'])
+ self.assertEqual(
+ 'project', mock_get_client_manager.mock_calls[0][2]['scope'])
+ self.assertEqual(
+ expected_creds[1][1:],
+ mock_get_client_manager.mock_calls[1][2]['roles'])
+ self.assertEqual(
+ 'project', mock_get_client_manager.mock_calls[1][2]['scope'])
+ self.assertEqual(
+ expected_creds[2][1:],
+ mock_get_client_manager.mock_calls[2][2]['roles'])
+ self.assertEqual(
+ 'domain', mock_get_client_manager.mock_calls[2][2]['scope'])
+ self.assertEqual(
+ expected_creds[3][1:],
+ mock_get_client_manager.mock_calls[3][2]['roles'])
+ self.assertEqual(
+ 'system', mock_get_client_manager.mock_calls[3][2]['scope'])
+
def test_setup_class_overwritten(self):
class OverridesSetup(self.parent_test):
diff --git a/zuul.d/integrated-gate.yaml b/zuul.d/integrated-gate.yaml
index 0a9fb71..4e62d67 100644
--- a/zuul.d/integrated-gate.yaml
+++ b/zuul.d/integrated-gate.yaml
@@ -306,6 +306,12 @@
subnode:
devstack_localrc:
USE_PYTHON3: true
+ devstack_local_conf:
+ post-config:
+ "/$NEUTRON_CORE_PLUGIN_CONF":
+ ovs:
+ bridge_mappings: public:br-ex
+ resource_provider_bandwidths: br-ex:1000000:1000000
- job:
name: tempest-slow