Merge "Remove unused babel.cfg"
diff --git a/.zuul.yaml b/.zuul.yaml
index 986b1ce..03bf740 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -21,13 +21,11 @@
- cinder-tempest-plugin-cbak-ceph
- cinder-tempest-plugin-cbak-s3
# As per the Tempest "Stable Branch Support Policy", Tempest will only
- # support the "Maintained" stable branches and not the "Extended Maintained"
- # branches. That is what we need to do for all tempest plugins. Only jobs
- # for the current releasable ("Maintained") stable branches should be listed
- # here.
- - cinder-tempest-plugin-basic-zed
- - cinder-tempest-plugin-basic-yoga
- - cinder-tempest-plugin-basic-xena
+ # support the "Maintained" stable branches, so only jobs for the
+ # current stable branches should be listed here.
+ - cinder-tempest-plugin-basic-2024-1
+ - cinder-tempest-plugin-basic-2023-2
+ - cinder-tempest-plugin-basic-2023-1
- cinder-tempest-plugin-protection-functional
gate:
jobs:
@@ -38,9 +36,9 @@
- cinder-tempest-plugin-cbak-ceph
experimental:
jobs:
- - cinder-tempest-plugin-cbak-ceph-zed
- - cinder-tempest-plugin-cbak-ceph-yoga
- - cinder-tempest-plugin-cbak-ceph-xena
+ - cinder-tempest-plugin-cbak-ceph-2024-1
+ - cinder-tempest-plugin-cbak-ceph-2023-2
+ - cinder-tempest-plugin-cbak-ceph-2023-1
- job:
name: cinder-tempest-plugin-protection-functional
@@ -51,10 +49,13 @@
vars:
tox_envlist: all
tempest_test_regex: 'cinder_tempest_plugin.rbac'
+ devstack_localrc:
+ KEYSTONE_ENFORCE_SCOPE: True
devstack_local_conf:
test-config:
$CINDER_CONF:
oslo_policy:
+ enforce_scope: True
enforce_new_defaults: True
$TEMPEST_CONFIG:
enforce_scope:
@@ -72,6 +73,7 @@
- opendev.org/openstack/cinder-tempest-plugin
- opendev.org/openstack/cinder
vars:
+ configure_swap_size: 8192
tempest_test_regex: '(^tempest\.(api|scenario)|(^cinder_tempest_plugin))'
tempest_test_exclude_list: '{{ ansible_user_dir }}/{{ zuul.projects["opendev.org/openstack/tempest"].src_dir }}/tools/tempest-integrated-gate-storage-exclude-list.txt'
# Temporarily exclude TestMultiAttachVolumeSwap until LP bug #1980816 is resolved.
@@ -106,6 +108,7 @@
devstack_plugins:
barbican: https://opendev.org/openstack/barbican
vars:
+ configure_swap_size: 8192
tempest_test_regex: '(^tempest\.(api|scenario)|(^cinder_tempest_plugin))'
tox_envlist: all
devstack_localrc:
@@ -134,9 +137,22 @@
- job:
name: cinder-tempest-plugin-lvm-barbican-base
description: |
+ This is a base job for lvm with lio & tgt targets.
+ No cinderlib testing beginning with 2024.1 development.
+ # FIXME: the following RE2 expression won't work after the 9999.2 release.
+ # If you are reading this during the 9999.2 development cycle, greetings
+ # from the 21st century!
+ branches: ^(master|(stable/(202[4-9]|20[3-9]\d|2[1-9]\d\d|[3-9]\d\d\d))\.[12])$
+ parent: cinder-tempest-plugin-lvm-barbican-base-abstract
+ vars:
+ tempest_test_exclude_list: '{{ ansible_user_dir }}/{{ zuul.projects["opendev.org/openstack/tempest"].src_dir }}/tools/tempest-integrated-gate-storage-exclude-list.txt'
+
+- job:
+ name: cinder-tempest-plugin-lvm-barbican-base
+ description: |
This is a base job for lvm with lio & tgt targets
with cinderlib tests.
- branches: ^(?!stable/(ocata|pike|queens|rocky|stein|train|ussuri|victoria|wallaby)).*$
+ branches: ^(stable/(xena|yoga|zed|2023\.[12]))$
parent: cinder-tempest-plugin-lvm-barbican-base-abstract
roles:
- zuul: opendev.org/openstack/cinderlib
@@ -214,7 +230,6 @@
- stable/ussuri
parent: cinder-tempest-plugin-lvm-barbican-base-abstract
required-projects:
- - opendev.org/openstack/cinderlib
- name: opendev.org/openstack/cinder-tempest-plugin
override-checkout: 1.3.0
vars:
@@ -224,7 +239,7 @@
name: cinder-tempest-plugin-lvm-barbican-base
description: |
This is a base job for lvm with lio & tgt targets
- branches: ^(?=stable/(ocata|pike|queens|rocky|stein)).*$
+ branches: ^stable/(ocata|pike|queens|rocky|stein).*$
parent: cinder-tempest-plugin-lvm-barbican-base-abstract
required-projects:
- name: opendev.org/openstack/cinder-tempest-plugin
@@ -239,6 +254,11 @@
Integration tests that runs with the ceph devstack plugin, py3
and enable the backup service.
vars:
+ # FIXME: change I29b1af0a4034decad to tempest added image format tests that
+ # cannot pass in this job because the image data takes a optimized path that
+ # bypasses nova's checks. Until the nova team decides on a strategy to handle
+ # this issue, we skip these tests.
+ tempest_exclude_regex: (tempest.api.image.v2.test_images_formats.ImagesFormatTest.test_compute_rejects)
configure_swap_size: 4096
devstack_local_conf:
test-config:
@@ -252,34 +272,28 @@
timeout: 10800
- job:
- name: cinder-tempest-plugin-cbak-ceph-zed
+ name: cinder-tempest-plugin-cbak-ceph-2024-1
parent: cinder-tempest-plugin-cbak-ceph
- nodeset: openstack-single-node-focal
- override-checkout: stable/zed
+ nodeset: openstack-single-node-jammy
+ override-checkout: stable/2024.1
- job:
- name: cinder-tempest-plugin-cbak-ceph-yoga
+ name: cinder-tempest-plugin-cbak-ceph-2023-2
parent: cinder-tempest-plugin-cbak-ceph
- nodeset: openstack-single-node-focal
- override-checkout: stable/yoga
+ nodeset: openstack-single-node-jammy
+ override-checkout: stable/2023.2
- job:
- name: cinder-tempest-plugin-cbak-ceph-xena
+ name: cinder-tempest-plugin-cbak-ceph-2023-1
parent: cinder-tempest-plugin-cbak-ceph
- nodeset: openstack-single-node-focal
- override-checkout: stable/xena
-
-- job:
- name: cinder-tempest-plugin-cbak-ceph-wallaby
- parent: cinder-tempest-plugin-cbak-ceph
- nodeset: openstack-single-node-focal
- override-checkout: stable/wallaby
+ nodeset: openstack-single-node-jammy
+ override-checkout: stable/2023.1
# variant for pre-Ussuri branches (no volume revert for Ceph),
# should this job be used on those branches
- job:
name: cinder-tempest-plugin-cbak-ceph
- branches: ^(?=stable/(ocata|pike|queens|rocky|stein|train)).*$
+ branches: ^stable/(ocata|pike|queens|rocky|stein|train).*$
vars:
devstack_local_conf:
test-config:
@@ -295,7 +309,7 @@
parent: cinder-tempest-plugin-lvm-barbican-base
vars:
devstack_localrc:
- CINDER_ISCSI_HELPER: lioadm
+ CINDER_TARGET_HELPER: lioadm
- job:
name: cinder-tempest-plugin-lvm-lio-barbican-centos-8-stream
@@ -322,7 +336,6 @@
under FIPS mode
pre-run: playbooks/enable-fips.yaml
vars:
- configure_swap_size: 4096
nslookup_target: 'opendev.org'
tempest_exclude_regex: 'test_encrypted_cinder_volumes_cryptsetup'
@@ -368,7 +381,7 @@
parent: cinder-tempest-plugin-lvm-barbican-base
vars:
devstack_localrc:
- CINDER_ISCSI_HELPER: tgtadm
+ CINDER_TARGET_HELPER: tgtadm
- job:
name: cinder-tempest-plugin-cbak-s3
@@ -406,19 +419,19 @@
- ^releasenotes/.*$
- job:
- name: cinder-tempest-plugin-basic-zed
+ name: cinder-tempest-plugin-basic-2024-1
parent: cinder-tempest-plugin-basic
- nodeset: openstack-single-node-focal
- override-checkout: stable/zed
+ nodeset: openstack-single-node-jammy
+ override-checkout: stable/2024.1
- job:
- name: cinder-tempest-plugin-basic-yoga
+ name: cinder-tempest-plugin-basic-2023-2
parent: cinder-tempest-plugin-basic
- nodeset: openstack-single-node-focal
- override-checkout: stable/yoga
+ nodeset: openstack-single-node-jammy
+ override-checkout: stable/2023.2
- job:
- name: cinder-tempest-plugin-basic-xena
+ name: cinder-tempest-plugin-basic-2023-1
parent: cinder-tempest-plugin-basic
- nodeset: openstack-single-node-focal
- override-checkout: stable/xena
+ nodeset: openstack-single-node-jammy
+ override-checkout: stable/2023.1
diff --git a/cinder_tempest_plugin/api/volume/admin/test_consistencygroups.py b/cinder_tempest_plugin/api/volume/admin/test_consistencygroups.py
index 7dff494..42c78f1 100644
--- a/cinder_tempest_plugin/api/volume/admin/test_consistencygroups.py
+++ b/cinder_tempest_plugin/api/volume/admin/test_consistencygroups.py
@@ -28,9 +28,7 @@
class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
@classmethod
def setup_clients(cls):
- cls._api_version = 2
super(ConsistencyGroupsV2Test, cls).setup_clients()
- cls.admin_volume_client = cls.os_admin.volumes_v2_client
manager = cinder_clients.Manager(cls.os_admin)
cls.consistencygroups_adm_client = manager.consistencygroups_adm_client
diff --git a/cinder_tempest_plugin/api/volume/admin/test_volume_backup.py b/cinder_tempest_plugin/api/volume/admin/test_volume_backup.py
index e5ded52..41cfc91 100644
--- a/cinder_tempest_plugin/api/volume/admin/test_volume_backup.py
+++ b/cinder_tempest_plugin/api/volume/admin/test_volume_backup.py
@@ -24,13 +24,6 @@
class VolumesBackupsTest(base.BaseVolumeAdminTest):
@classmethod
- def setup_clients(cls):
- super(VolumesBackupsTest, cls).setup_clients()
- cls.admin_volume_client = cls.os_admin.volumes_client_latest
- cls.backups_client = cls.os_primary.backups_client_latest
- cls.volumes_client = cls.os_primary.volumes_client_latest
-
- @classmethod
def skip_checks(cls):
super(VolumesBackupsTest, cls).skip_checks()
if not CONF.volume_feature_enabled.backup:
diff --git a/cinder_tempest_plugin/api/volume/base.py b/cinder_tempest_plugin/api/volume/base.py
index ea6bd2e..c0f53bd 100644
--- a/cinder_tempest_plugin/api/volume/base.py
+++ b/cinder_tempest_plugin/api/volume/base.py
@@ -13,10 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import io
+
from tempest.common import compute
from tempest.common import waiters
from tempest import config
-from tempest.lib.common import api_microversion_fixture
from tempest.lib.common import api_version_utils
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@@ -57,8 +58,6 @@
def setUp(self):
super(BaseVolumeTest, self).setUp()
- self.useFixture(api_microversion_fixture.APIMicroversionFixture(
- volume_microversion=self.request_microversion))
@classmethod
def resource_setup(cls):
@@ -67,6 +66,8 @@
api_version_utils.select_request_microversion(
cls.min_microversion,
CONF.volume.min_microversion))
+ cls.setup_api_microversion_fixture(
+ volume_microversion=cls.request_microversion)
@classmethod
def create_volume(cls, wait_until='available', **kwargs):
@@ -159,6 +160,29 @@
body['id'])
return body
+ @classmethod
+ def create_image_with_data(cls, **kwargs):
+ # we do this as a class method so we can use the
+ # addClassResourceCleanup functionality of tempest.test.BaseTestCase
+ images_client = cls.os_primary.image_client_v2
+ if 'min_disk' not in kwargs:
+ kwargs['min_disk'] = 1
+ response = images_client.create_image(**kwargs)
+ image_id = response['id']
+ cls.addClassResourceCleanup(
+ images_client.wait_for_resource_deletion, image_id)
+ cls.addClassResourceCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ images_client.delete_image, image_id)
+
+ # upload "data" to image
+ image_file = io.BytesIO(data_utils.random_bytes(size=1024))
+ images_client.store_image_file(image_id, image_file)
+
+ waiters.wait_for_image_status(images_client, image_id, 'active')
+ image = images_client.show_image(image_id)
+ return image
+
class BaseVolumeAdminTest(BaseVolumeTest):
"""Base test case class for all Volume Admin API tests."""
@@ -171,7 +195,7 @@
cls.admin_volume_types_client = cls.os_admin.volume_types_client_latest
cls.admin_backups_client = cls.os_admin.backups_client_latest
- cls.admin_volumes_client = cls.os_admin.volumes_client_latest
+ cls.admin_volume_client = cls.os_admin.volumes_client_latest
@classmethod
def create_volume_type(cls, name=None, **kwargs):
@@ -194,12 +218,12 @@
type_id = volume_type['id']
type_name = volume_type['name']
- volumes = cls.admin_volumes_client.list_volumes(
+ volumes = cls.admin_volume_client.list_volumes(
detail=True, params={'all_tenants': 1})['volumes']
for volume in [v for v in volumes if v['volume_type'] == type_name]:
test_utils.call_and_ignore_notfound_exc(
- cls.admin_volumes_client.delete_volume, volume['id'])
- cls.admin_volumes_client.wait_for_resource_deletion(volume['id'])
+ cls.admin_volume_client.delete_volume, volume['id'])
+ cls.admin_volume_client.wait_for_resource_deletion(volume['id'])
test_utils.call_and_ignore_notfound_exc(
cls.admin_volume_types_client.delete_volume_type, type_id)
diff --git a/cinder_tempest_plugin/api/volume/test_create_from_image.py b/cinder_tempest_plugin/api/volume/test_create_from_image.py
index acb1943..f44f630 100644
--- a/cinder_tempest_plugin/api/volume/test_create_from_image.py
+++ b/cinder_tempest_plugin/api/volume/test_create_from_image.py
@@ -10,12 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import io
-
-from tempest.common import waiters
from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from cinder_tempest_plugin.api.volume import base
@@ -32,29 +27,6 @@
if not CONF.service_available.glance:
raise cls.skipException("Glance service is disabled")
- @classmethod
- def create_image_with_data(cls, **kwargs):
- # we do this as a class method so we can use the
- # addClassResourceCleanup functionality of tempest.test.BaseTestCase
- images_client = cls.os_primary.image_client_v2
- if 'min_disk' not in kwargs:
- kwargs['min_disk'] = 1
- response = images_client.create_image(**kwargs)
- image_id = response['id']
- cls.addClassResourceCleanup(
- images_client.wait_for_resource_deletion, image_id)
- cls.addClassResourceCleanup(
- test_utils.call_and_ignore_notfound_exc,
- images_client.delete_image, image_id)
-
- # upload "data" to image
- image_file = io.BytesIO(data_utils.random_bytes(size=1024))
- images_client.store_image_file(image_id, image_file)
-
- waiters.wait_for_image_status(images_client, image_id, 'active')
- image = images_client.show_image(image_id)
- return image
-
@decorators.idempotent_id('6e9266ff-a917-4dd5-aa4a-c36e59e7a2a6')
def test_create_from_image_with_volume_type_image_property(self):
"""Verify that the cinder_img_volume_type image property works.
diff --git a/cinder_tempest_plugin/api/volume/test_volume_dependency.py b/cinder_tempest_plugin/api/volume/test_volume_dependency.py
new file mode 100644
index 0000000..5ea067f
--- /dev/null
+++ b/cinder_tempest_plugin/api/volume/test_volume_dependency.py
@@ -0,0 +1,255 @@
+# Copyright 2022 Red Hat, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+from tempest.common import utils
+from tempest.common import waiters
+from tempest import config
+from tempest.lib import decorators
+import testtools
+
+from cinder_tempest_plugin.api.volume import base
+
+CONF = config.CONF
+
+
+class VolumeDependencyTests(base.BaseVolumeTest):
+ min_microversion = '3.40'
+
+ @classmethod
+ def setup_clients(cls):
+ super(VolumeDependencyTests, cls).setup_clients()
+
+ @decorators.idempotent_id('42e9df95-854b-4840-9d55-ae62f65e9b8e')
+ def test_delete_source_volume(self):
+ """Test basic dependency deletion
+
+ * Create a volume with source_volid
+ * Delete the source volume
+ """
+ source_volume = self.create_volume()
+ kwargs = {'source_volid': source_volume['id']}
+ cloned_volume = self.create_volume(**kwargs)
+ self.assertEqual(source_volume['id'], cloned_volume['source_volid'])
+ self.volumes_client.delete_volume(source_volume['id'])
+ self.volumes_client.wait_for_resource_deletion(source_volume['id'])
+
+ @decorators.idempotent_id('900d8ea5-2afd-4fe5-a0c3-fab4744f0d40')
+ def test_delete_source_snapshot(self):
+ """Test basic dependency deletion with snapshot
+
+ * Create a snapshot from source volume
+ * Create a volume from that snapshot
+ * Delete the source snapshot
+ * Delete the source volume
+ """
+ source_volume = self.create_volume()
+ snapshot_source_volume = self.create_snapshot(source_volume['id'])
+ kwargs = {'snapshot_id': snapshot_source_volume['id']}
+ volume_from_snapshot = self.create_volume(**kwargs)
+ self.assertEqual(volume_from_snapshot['snapshot_id'],
+ snapshot_source_volume['id'])
+
+ self.snapshots_client.delete_snapshot(snapshot_source_volume['id'])
+ self.snapshots_client.wait_for_resource_deletion(
+ snapshot_source_volume['id'])
+ self.volumes_client.delete_volume(source_volume['id'])
+ self.volumes_client.wait_for_resource_deletion(source_volume['id'])
+
+ def _delete_vol_and_wait(self, vol_id):
+ self.volumes_client.delete_volume(vol_id)
+
+ self.volumes_client.wait_for_resource_deletion(vol_id)
+
+ def _delete_snap_and_wait(self, snap_id):
+ self.snapshots_client.delete_snapshot(snap_id)
+
+ self.snapshots_client.wait_for_resource_deletion(snap_id)
+
+ @decorators.idempotent_id('f8278e5c-50ff-4a1d-8670-3ca0866d411a')
+ def test_delete_dep_chain(self):
+ """Test a complex chain of volume and snapshot dependency deletion."""
+ volume_1 = self.create_volume()['id']
+ snapshot_of_vol_1 = self.create_snapshot(volume_1)['id']
+
+ volume_2_args = {'snapshot_id': snapshot_of_vol_1}
+ volume_2 = self.create_volume(**volume_2_args)['id']
+
+ snapshot_of_vol_2 = self.create_snapshot(volume_2)['id']
+
+ volume_3_args = {'snapshot_id': snapshot_of_vol_2}
+ volume_3 = self.create_volume(**volume_3_args)['id']
+
+ volume_4_args = {'source_volid': volume_3}
+ volume_4 = self.create_volume(**volume_4_args)['id']
+
+ self._delete_snap_and_wait(snapshot_of_vol_1)
+ self._delete_snap_and_wait(snapshot_of_vol_2)
+
+ self._delete_vol_and_wait(volume_3)
+ self._delete_vol_and_wait(volume_1)
+ self._delete_vol_and_wait(volume_2)
+ self._delete_vol_and_wait(volume_4)
+
+ @decorators.idempotent_id('63447ef8-e667-4796-ba66-1b9b883af1f1')
+ def test_delete_dep_chain_2(self):
+ """Test a different chain of volume/snapshot dependency deletion."""
+ volume_1 = self.create_volume()['id']
+ snapshot_of_vol_1 = self.create_snapshot(volume_1)['id']
+
+ volume_2_args = {'snapshot_id': snapshot_of_vol_1}
+ volume_2 = self.create_volume(**volume_2_args)['id']
+
+ snapshot_of_vol_2 = self.create_snapshot(volume_2)['id']
+
+ volume_3_args = {'snapshot_id': snapshot_of_vol_2}
+ volume_3 = self.create_volume(**volume_3_args)['id']
+
+ self._delete_snap_and_wait(snapshot_of_vol_1)
+ self._delete_snap_and_wait(snapshot_of_vol_2)
+
+ self._delete_vol_and_wait(volume_1)
+ self._delete_vol_and_wait(volume_2)
+ self._delete_vol_and_wait(volume_3)
+
+
+class VolumeImageDependencyTests(base.BaseVolumeTest):
+ """Volume<->image dependency tests.
+
+ These tests perform clones to/from volumes and images,
+ deleting images/volumes that other volumes were cloned from.
+
+ Images and volumes are expected to be independent at the OpenStack
+ level, but in some configurations (i.e. when using Ceph as storage
+ for both Cinder and Glance) it was possible to end up with images
+ or volumes that could not be deleted. This was fixed for RBD in
+ Cinder 2024.1 change I009d0748f.
+
+ """
+
+ min_microversion = '3.40'
+
+ @classmethod
+ def del_image(cls, image_id):
+ images_client = cls.os_primary.image_client_v2
+ images_client.delete_image(image_id)
+ images_client.wait_for_resource_deletion(image_id)
+
+ @testtools.skipUnless(CONF.volume_feature_enabled.volume_image_dep_tests,
+ reason='Volume/image dependency tests not enabled.')
+ @utils.services('image', 'volume')
+ @decorators.idempotent_id('7a9fba78-2e4b-42b1-9898-bb4a60685320')
+ def test_image_volume_dependencies_1(self):
+ # image -> volume
+ image_args = {
+ 'disk_format': 'raw',
+ 'container_format': 'bare',
+ 'name': 'image-for-test-7a9fba78-2e4b-42b1-9898-bb4a60685320'
+ }
+ image = self.create_image_with_data(**image_args)
+
+ # create a volume from the image
+ vol_args = {'name': ('volume1-for-test'
+ '7a9fba78-2e4b-42b1-9898-bb4a60685320'),
+ 'imageRef': image['id']}
+ volume1 = self.create_volume(**vol_args)
+ waiters.wait_for_volume_resource_status(self.volumes_client,
+ volume1['id'],
+ 'available')
+
+ self.volumes_client.delete_volume(volume1['id'])
+ self.volumes_client.wait_for_resource_deletion(volume1['id'])
+
+ self.del_image(image['id'])
+
+ @testtools.skipUnless(CONF.volume_feature_enabled.volume_image_dep_tests,
+ reason='Volume/image dependency tests not enabled.')
+ @utils.services('image', 'volume')
+ @decorators.idempotent_id('0e20bd6e-440f-41d8-9b5d-fc047ac00423')
+ def test_image_volume_dependencies_2(self):
+ # image -> volume -> volume
+
+ image_args = {
+ 'disk_format': 'raw',
+ 'container_format': 'bare',
+ 'name': 'image-for-test-0e20bd6e-440f-41d8-9b5d-fc047ac00423'
+ }
+ image = self.create_image_with_data(**image_args)
+
+ # create a volume from the image
+ vol_args = {'name': ('volume1-for-test'
+ '0e20bd6e-440f-41d8-9b5d-fc047ac00423'),
+ 'imageRef': image['id']}
+ volume1 = self.create_volume(**vol_args)
+ waiters.wait_for_volume_resource_status(self.volumes_client,
+ volume1['id'],
+ 'available')
+
+ vol2_args = {'name': ('volume2-for-test-'
+ '0e20bd6e-440f-41d8-9b5d-fc047ac00423'),
+ 'source_volid': volume1['id']}
+ volume2 = self.create_volume(**vol2_args)
+ waiters.wait_for_volume_resource_status(self.volumes_client,
+ volume2['id'],
+ 'available')
+
+ self.volumes_client.delete_volume(volume1['id'])
+ self.volumes_client.wait_for_resource_deletion(volume1['id'])
+
+ self.del_image(image['id'])
+
+ @testtools.skipUnless(CONF.volume_feature_enabled.volume_image_dep_tests,
+ reason='Volume/image dependency tests not enabled.')
+ @decorators.idempotent_id('e6050452-06bd-4c7f-9912-45178c83e379')
+ @utils.services('image', 'volume')
+ def test_image_volume_dependencies_3(self):
+ # image -> volume -> snap -> volume
+
+ image_args = {
+ 'disk_format': 'raw',
+ 'container_format': 'bare',
+ 'name': 'image-for-test-e6050452-06bd-4c7f-9912-45178c83e379'
+ }
+ image = self.create_image_with_data(**image_args)
+
+ # create a volume from the image
+ vol_args = {'name': ('volume1-for-test'
+ 'e6050452-06bd-4c7f-9912-45178c83e379'),
+ 'imageRef': image['id']}
+ volume1 = self.create_volume(**vol_args)
+ waiters.wait_for_volume_resource_status(self.volumes_client,
+ volume1['id'],
+ 'available')
+
+ snapshot1 = self.create_snapshot(volume1['id'])
+
+ vol2_args = {'name': ('volume2-for-test-'
+ 'e6050452-06bd-4c7f-9912-45178c83e379'),
+ 'snapshot_id': snapshot1['id']}
+ volume2 = self.create_volume(**vol2_args)
+ waiters.wait_for_volume_resource_status(self.volumes_client,
+ volume2['id'],
+ 'available')
+
+ self.snapshots_client.delete_snapshot(snapshot1['id'])
+ self.snapshots_client.wait_for_resource_deletion(snapshot1['id'])
+
+ self.volumes_client.delete_volume(volume2['id'])
+ self.volumes_client.wait_for_resource_deletion(volume2['id'])
+
+ self.del_image(image['id'])
+
+ self.volumes_client.delete_volume(volume1['id'])
+ self.volumes_client.wait_for_resource_deletion(volume1['id'])
diff --git a/cinder_tempest_plugin/api/volume/test_volume_revert.py b/cinder_tempest_plugin/api/volume/test_volume_revert.py
index bf3d806..2c4d6bd 100644
--- a/cinder_tempest_plugin/api/volume/test_volume_revert.py
+++ b/cinder_tempest_plugin/api/volume/test_volume_revert.py
@@ -35,7 +35,6 @@
@classmethod
def setup_clients(cls):
- cls._api_version = 3
super(VolumeRevertTests, cls).setup_clients()
manager = cinder_clients.Manager(cls.os_primary)
diff --git a/cinder_tempest_plugin/config.py b/cinder_tempest_plugin/config.py
index 78dd6ea..53222b8 100644
--- a/cinder_tempest_plugin/config.py
+++ b/cinder_tempest_plugin/config.py
@@ -22,6 +22,9 @@
cfg.BoolOpt('volume_revert',
default=False,
help='Enable to run Cinder volume revert tests'),
+ cfg.BoolOpt('volume_image_dep_tests',
+ default=True,
+ help='Run tests for dependencies between images and volumes')
]
# The barbican service is discovered by config_tempest [1], and will appear
diff --git a/cinder_tempest_plugin/rbac/v3/base.py b/cinder_tempest_plugin/rbac/v3/base.py
index af724a3..6fc6be5 100644
--- a/cinder_tempest_plugin/rbac/v3/base.py
+++ b/cinder_tempest_plugin/rbac/v3/base.py
@@ -13,7 +13,6 @@
from tempest.common import waiters
from tempest import config
-from tempest.lib.common import api_microversion_fixture
from tempest.lib.common import api_version_utils
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@@ -51,8 +50,6 @@
def setUp(self):
super(VolumeV3RbacBaseTests, self).setUp()
- self.useFixture(api_microversion_fixture.APIMicroversionFixture(
- volume_microversion=self.request_microversion))
@classmethod
def resource_setup(cls):
@@ -61,6 +58,8 @@
api_version_utils.select_request_microversion(
cls.min_microversion,
CONF.volume.min_microversion))
+ cls.setup_api_microversion_fixture(
+ volume_microversion=cls.request_microversion)
def do_request(self, method, expected_status=200, client=None, **payload):
"""Perform API call
diff --git a/cinder_tempest_plugin/rbac/v3/test_snapshots.py b/cinder_tempest_plugin/rbac/v3/test_snapshots.py
index f11da42..14377a9 100644
--- a/cinder_tempest_plugin/rbac/v3/test_snapshots.py
+++ b/cinder_tempest_plugin/rbac/v3/test_snapshots.py
@@ -17,6 +17,8 @@
from tempest.lib import decorators
from tempest.lib import exceptions
+import testtools
+
from cinder_tempest_plugin.rbac.v3 import base as rbac_base
CONF = config.CONF
@@ -309,10 +311,15 @@
def test_force_delete_snapshot(self):
self._force_delete_snapshot(expected_status=exceptions.Forbidden)
+ # We don't need to skip the unmanage because the failure should happen at
+ # the API level, so it should fail regardless of the driver support for
+ # unmanaging snapshots.
@decorators.idempotent_id('35495666-b663-4c68-ba44-0695e30a6838')
def test_unmanage_snapshot(self):
self._unmanage_snapshot(expected_status=exceptions.Forbidden)
+ @testtools.skipUnless(CONF.volume_feature_enabled.manage_snapshot,
+ 'manage snapshots are disabled')
@decorators.idempotent_id('d2d1326d-fb47-4448-a1e1-2d1219d30fd5')
def test_manage_snapshot(self):
self._manage_snapshot(
@@ -362,10 +369,15 @@
def test_force_delete_snapshot(self):
self._force_delete_snapshot(expected_status=exceptions.Forbidden)
+ # We don't need to skip the unmanage because the failure should happen at
+ # the API level, so it should fail regardless of the driver support for
+ # unmanaging snapshots.
@decorators.idempotent_id('dd7da3da-68ef-42f5-af1d-29803a4a04fd')
def test_unmanage_snapshot(self):
self._unmanage_snapshot(expected_status=exceptions.Forbidden)
+ @testtools.skipUnless(CONF.volume_feature_enabled.manage_snapshot,
+ 'manage snapshots are disabled')
@decorators.idempotent_id('c2501d05-9bca-42d7-9ab5-c0d9133e762f')
def test_manage_snapshot(self):
self._manage_snapshot(
diff --git a/cinder_tempest_plugin/scenario/manager.py b/cinder_tempest_plugin/scenario/manager.py
index 8598ade..cffa044 100644
--- a/cinder_tempest_plugin/scenario/manager.py
+++ b/cinder_tempest_plugin/scenario/manager.py
@@ -110,7 +110,6 @@
(mount_path, filename))
md5 = ssh_client.exec_command(
'sudo md5sum -b %s/%s|cut -c 1-32' % (mount_path, filename))
- ssh_client.exec_command('sudo sync')
return md5
def get_md5_from_file(self, instance, instance_ip, filename,
diff --git a/cinder_tempest_plugin/scenario/test_snapshots.py b/cinder_tempest_plugin/scenario/test_snapshots.py
index f376954..02cd6bd 100644
--- a/cinder_tempest_plugin/scenario/test_snapshots.py
+++ b/cinder_tempest_plugin/scenario/test_snapshots.py
@@ -14,10 +14,16 @@
# under the License.
from tempest.common import utils
+from tempest.common import waiters
+from tempest import config
from tempest.lib import decorators
+import testtools
+
from cinder_tempest_plugin.scenario import manager
+CONF = config.CONF
+
class SnapshotDataIntegrityTests(manager.ScenarioTest):
@@ -121,3 +127,33 @@
self.assertEqual(count_snap, i)
self.assertEqual(file_map[i], md5_file)
+
+
+class SnapshotDependencyTests(manager.ScenarioTest):
+ @testtools.skipUnless(CONF.volume_feature_enabled.volume_image_dep_tests,
+ 'dependency tests not enabled')
+ @decorators.idempotent_id('e7028f52-f6d4-479c-8809-6f6cf96cfe0f')
+ @utils.services('image', 'volume')
+ def test_snapshot_removal(self):
+ volume_1 = self.create_volume()
+
+ snapshot_1 = self.create_volume_snapshot(volume_1['id'], force=True)
+ waiters.wait_for_volume_resource_status(
+ self.snapshots_client, snapshot_1['id'], 'available')
+
+ clone_kwargs = {'snapshot_id': snapshot_1['id'],
+ 'size': volume_1['size']}
+ volume_2 = self.volumes_client.create_volume(**clone_kwargs)['volume']
+
+ waiters.wait_for_volume_resource_status(
+ self.volumes_client, volume_2['id'], 'available')
+ volume_2 = self.volumes_client.show_volume(volume_2['id'])['volume']
+
+ self.snapshots_client.delete_snapshot(snapshot_1['id'])
+ self.snapshots_client.wait_for_resource_deletion(snapshot_1['id'])
+
+ self.volumes_client.delete_volume(volume_1['id'])
+ self.volumes_client.wait_for_resource_deletion(volume_1['id'])
+
+ self.volumes_client.delete_volume(volume_2['id'])
+ self.volumes_client.wait_for_resource_deletion(volume_2['id'])
diff --git a/cinder_tempest_plugin/scenario/test_volume_multiattach.py b/cinder_tempest_plugin/scenario/test_volume_multiattach.py
index e04610f..4fb266e 100644
--- a/cinder_tempest_plugin/scenario/test_volume_multiattach.py
+++ b/cinder_tempest_plugin/scenario/test_volume_multiattach.py
@@ -71,18 +71,25 @@
# Create a multiattach volume
volume = self.create_volume(volume_type=multiattach_vol_type['id'])
- # Create encrypted volume
- encrypted_volume = self.create_encrypted_volume(
- 'luks', volume_type='luks')
+ # Create a volume with the default volume type
+ default_volume = self.create_volume()
- # Create a normal volume
- simple_volume = self.create_volume()
+ # Create other volume
+ if CONF.compute_feature_enabled.attach_encrypted_volume:
+ other_volume = self.create_encrypted_volume(
+ 'luks', volume_type='luks')
+ else:
+ # Create secondary volume type
+ second_vol_type = self.create_volume_type()
- # Attach normal and encrypted volumes (These volumes are not used in
+ other_volume = self.create_volume(
+ volume_type=second_vol_type['id'])
+
+ # Attach default and secondary volumes (These volumes are not used in
# the current test but is used to emulate a real world scenario
# where different types of volumes will be attached to the server)
- self.attach_volume(server_1, simple_volume)
- self.attach_volume(server_1, encrypted_volume)
+ self.attach_volume(server_1, default_volume)
+ self.attach_volume(server_1, other_volume)
instance_ip = self.get_server_ip(server_1)
diff --git a/setup.cfg b/setup.cfg
index f224c5c..3d74cb9 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -20,6 +20,7 @@
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
+ Programming Language :: Python :: 3.11
[files]
packages =
diff --git a/test-requirements.txt b/test-requirements.txt
index 905ad51..cb279bc 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -2,7 +2,7 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-hacking>=3.0.1,<3.1 # Apache-2.0
+hacking>=6.1.0,<7.0 # Apache-2.0
coverage!=4.4,>=4.0 # Apache-2.0
python-subunit>=1.0.0 # Apache-2.0/BSD