Merge "Add access rules restriction tests"
diff --git a/babel.cfg b/babel.cfg
deleted file mode 100644
index 15cd6cb..0000000
--- a/babel.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[python: **.py]
-
diff --git a/manila_tempest_tests/common/constants.py b/manila_tempest_tests/common/constants.py
index 3488bc5..416de56 100644
--- a/manila_tempest_tests/common/constants.py
+++ b/manila_tempest_tests/common/constants.py
@@ -108,3 +108,6 @@
SERVER_STATE_UNMANAGE_STARTING = 'unmanage_starting'
STATUS_SERVER_MIGRATING = 'server_migrating'
STATUS_SERVER_MIGRATING_TO = 'server_migrating_to'
+
+# Share transfer
+SHARE_TRANSFER_VERSION = "2.77"
diff --git a/manila_tempest_tests/common/waiters.py b/manila_tempest_tests/common/waiters.py
index 8a97c8e..a11b620 100644
--- a/manila_tempest_tests/common/waiters.py
+++ b/manila_tempest_tests/common/waiters.py
@@ -45,7 +45,8 @@
resource_name='share', rule_id=None,
status_attr='status',
raise_rule_in_error_state=True,
- version=LATEST_MICROVERSION):
+ version=LATEST_MICROVERSION,
+ timeout=None):
"""Waits for a resource to reach a given status."""
get_resource_action = {
@@ -59,6 +60,7 @@
'share_group': 'get_share_group',
'share_group_snapshot': 'get_share_group_snapshot',
'share_replica': 'get_share_replica',
+ 'share_backup': 'get_share_backup'
}
action_name = get_resource_action[resource_name]
@@ -86,6 +88,9 @@
start = int(time.time())
exp_status = status if isinstance(status, list) else [status]
+ resource_status_check_time_out = client.build_timeout
+ if timeout is not None:
+ resource_status_check_time_out = timeout
while resource_status not in exp_status:
time.sleep(client.build_interval)
body = resource_action(*method_args, **method_kwargs)[rn]
@@ -102,11 +107,11 @@
raise_method = _get_name_of_raise_method(resource_name)
resource_exception = getattr(share_exceptions, raise_method)
raise resource_exception(resource_id=resource_id)
- if int(time.time()) - start >= client.build_timeout:
+ if int(time.time()) - start >= resource_status_check_time_out:
message = ('%s %s failed to reach %s status (current %s) '
'within the required time (%s s).' %
(resource_name.replace('_', ' '), resource_id, status,
- resource_status, client.build_timeout))
+ resource_status, resource_status_check_time_out))
raise exceptions.TimeoutException(message)
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index 91d03d9..0a98ad5 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -265,6 +265,9 @@
default=False,
help="Enable or disable migration with "
"preserve_snapshots tests set to True."),
+ cfg.BoolOpt("run_driver_assisted_backup_tests",
+ default=False,
+ help="Enable or disable share backup tests."),
cfg.BoolOpt("run_manage_unmanage_tests",
default=False,
help="Defines whether to run manage/unmanage tests or not. "
@@ -314,6 +317,10 @@
default=1500,
help="Time to wait for share migration before "
"timing out (seconds)."),
+ cfg.IntOpt("share_backup_timeout",
+ default=1500,
+ help="Time to wait for share backup before "
+ "timing out (seconds)."),
cfg.IntOpt("share_server_migration_timeout",
default="1500",
help="Time to wait for share server migration before "
@@ -336,4 +343,20 @@
"attempt to create an IPv6 subnet on the project network "
"they create for ping and SSH to the client test VM "
"where data path testing is performed."),
+ cfg.StrOpt("dd_input_file",
+ default="/dev/zero",
+ help="The input file (if) in the dd command specifies the "
+ "source of data that dd will read and process, which can "
+ "be a device, a regular file, or even standard input "
+ "(stdin). dd copies, transforms, or performs actions on "
+ "this data based on provided options and then writes it "
+ "to an output file or device (of). When using /dev/zero "
+ "in storage systems with default compression, although "
+ "it generates highly compressible null bytes (zeros), "
+ "writing data from /dev/zero might not yield significant "
+ "space savings as these systems are already optimized for "
+ "efficient compression."),
+ cfg.DictOpt("driver_assisted_backup_test_driver_options",
+ default={'dummy': True},
+ help="Share backup driver options specified as dict."),
]
diff --git a/manila_tempest_tests/services/share/json/shares_client.py b/manila_tempest_tests/services/share/json/shares_client.py
index 6871eda..fb03afc 100644
--- a/manila_tempest_tests/services/share/json/shares_client.py
+++ b/manila_tempest_tests/services/share/json/shares_client.py
@@ -323,6 +323,9 @@
elif "server_id" in kwargs:
return self._is_resource_deleted(
self.show_share_server, kwargs.get("server_id"))
+ elif "backup_id" in kwargs:
+ return self._is_resource_deleted(
+ self.get_share_backup, kwargs.get("backup_id"))
else:
raise share_exceptions.InvalidResource(
message=str(kwargs))
diff --git a/manila_tempest_tests/services/share/v2/json/shares_client.py b/manila_tempest_tests/services/share/v2/json/shares_client.py
index 5dd5793..e3a022e 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -373,6 +373,61 @@
return rest_client.ResponseBody(resp, body)
###############
+ def create_share_transfer(self, share_id, name=None,
+ version=LATEST_MICROVERSION):
+ if name is None:
+ name = data_utils.rand_name("tempest-created-share-transfer")
+ post_body = {
+ "transfer": {
+ "share_id": share_id,
+ "name": name
+ }
+ }
+ body = json.dumps(post_body)
+ resp, body = self.post("share-transfers", body, version=version)
+ self.expected_success(202, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_share_transfer(self, transfer_id, version=LATEST_MICROVERSION):
+ resp, body = self.delete("share-transfers/%s" % transfer_id,
+ version=version)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_share_transfers(self, detailed=False, params=None,
+ version=LATEST_MICROVERSION):
+ """Get list of share transfers w/o filters."""
+ uri = 'share-transfers/detail' if detailed else 'share-transfers'
+ uri += '?%s' % parse.urlencode(params) if params else ''
+ resp, body = self.get(uri, version=version)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def get_share_transfer(self, transfer_id, version=LATEST_MICROVERSION):
+ resp, body = self.get("share-transfers/%s" % transfer_id,
+ version=version)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def accept_share_transfer(self, transfer_id, auth_key,
+ clear_access_rules=False,
+ version=LATEST_MICROVERSION):
+ post_body = {
+ "accept": {
+ "auth_key": auth_key,
+ "clear_access_rules": clear_access_rules
+ }
+ }
+ body = json.dumps(post_body)
+ resp, body = self.post("share-transfers/%s/accept" % transfer_id,
+ body, version=version)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+###############
def get_instances_of_share(self, share_id, version=LATEST_MICROVERSION):
resp, body = self.get("shares/%s/instances" % share_id,
@@ -1789,6 +1844,109 @@
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+###############
+
+ def get_share_backup(self, backup_id, version=LATEST_MICROVERSION):
+ """Returns the details of a single backup."""
+ resp, body = self.get("share-backups/%s" % backup_id,
+ headers=EXPERIMENTAL,
+ extra_headers=True,
+ version=version)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_share_backups(self, share_id=None, version=LATEST_MICROVERSION):
+ """Get list of backups."""
+ uri = "share-backups/detail"
+ if share_id:
+ uri += (f'?share_id={share_id}')
+ resp, body = self.get(uri, headers=EXPERIMENTAL,
+ extra_headers=True, version=version)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def create_share_backup(self, share_id, name=None, description=None,
+ backup_options=None, version=LATEST_MICROVERSION):
+ """Create a share backup."""
+ if name is None:
+ name = data_utils.rand_name("tempest-created-share-backup")
+ if description is None:
+ description = data_utils.rand_name(
+ "tempest-created-share-backup-desc")
+ post_body = {
+ 'share_backup': {
+ 'name': name,
+ 'description': description,
+ 'share_id': share_id,
+ 'backup_options': backup_options,
+ }
+ }
+ body = json.dumps(post_body)
+ resp, body = self.post('share-backups', body,
+ headers=EXPERIMENTAL,
+ extra_headers=True,
+ version=version)
+
+ self.expected_success(202, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_share_backup(self, backup_id, version=LATEST_MICROVERSION):
+ """Delete share backup."""
+ uri = "share-backups/%s" % backup_id
+ resp, body = self.delete(uri,
+ headers=EXPERIMENTAL,
+ extra_headers=True,
+ version=version)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def restore_share_backup(self, backup_id, version=LATEST_MICROVERSION):
+ """Restore share backup."""
+ uri = "share-backups/%s/action" % backup_id
+ body = {'restore': None}
+ resp, body = self.post(uri, json.dumps(body),
+ headers=EXPERIMENTAL,
+ extra_headers=True,
+ version=version)
+ self.expected_success(202, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def update_share_backup(self, backup_id, name=None, description=None,
+ version=LATEST_MICROVERSION):
+ """Update share backup."""
+ uri = "share-backups/%s" % backup_id
+ post_body = {}
+ if name:
+ post_body['name'] = name
+ if description:
+ post_body['description'] = description
+
+ body = json.dumps({'share_backup': post_body})
+ resp, body = self.put(uri, body,
+ headers=EXPERIMENTAL,
+ extra_headers=True,
+ version=version)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def reset_state_share_backup(self, backup_id,
+ status=constants.STATUS_AVAILABLE,
+ version=LATEST_MICROVERSION):
+
+ uri = "share-backups/%s/action" % backup_id
+ body = {'reset_status': {'status': status}}
+ resp, body = self.post(uri, json.dumps(body),
+ headers=EXPERIMENTAL,
+ extra_headers=True,
+ version=LATEST_MICROVERSION)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
################
def create_snapshot_access_rule(self, snapshot_id, access_type="ip",
diff --git a/manila_tempest_tests/share_exceptions.py b/manila_tempest_tests/share_exceptions.py
index efa61b5..7620109 100644
--- a/manila_tempest_tests/share_exceptions.py
+++ b/manila_tempest_tests/share_exceptions.py
@@ -86,3 +86,7 @@
class ShareServerMigrationException(exceptions.TempestException):
message = ("Share server %(server_id)s failed to migrate and is in ERROR "
"status")
+
+
+class ShareBackupBuildErrorException(exceptions.TempestException):
+ message = ("Share backup %(backup_id)s failed and is in ERROR status")
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers_manage_negative.py b/manila_tempest_tests/tests/api/admin/test_share_servers_manage_negative.py
index 1e9073d..09a40d9 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers_manage_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers_manage_negative.py
@@ -333,7 +333,8 @@
invalid_params)
# try with part of the identifier
- invalid_params['identifier'] = share_server['identifier'].split("-")[2]
+ invalid_params['identifier'] = (
+ share_server['identifier'].split("-")[-1])
self.assertRaises(
lib_exc.BadRequest,
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers_migration.py b/manila_tempest_tests/tests/api/admin/test_share_servers_migration.py
index 2535745..d3ec3f1 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers_migration.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers_migration.py
@@ -282,10 +282,11 @@
src_server_id, dest_host, preserve_snapshots=preserve_snapshots)
expected_state = constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE
+ timeout = CONF.share.share_server_migration_timeout
waiters.wait_for_resource_status(
self.shares_v2_client, src_server_id,
expected_state, resource_name='share_server',
- status_attr='task_state'
+ status_attr='task_state', timeout=timeout
)
# Get for the destination share server.
@@ -352,10 +353,11 @@
preserve_snapshots=preserve_snapshots)
expected_state = constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE
+ timeout = CONF.share.share_server_migration_timeout
waiters.wait_for_resource_status(
self.shares_v2_client, src_server_id,
expected_state, resource_name='share_server',
- status_attr='task_state'
+ status_attr='task_state', timeout=timeout
)
# Get for the destination share server.
dest_server_id = self._get_share_server_destination_for_migration(
diff --git a/manila_tempest_tests/tests/api/admin/test_share_types.py b/manila_tempest_tests/tests/api/admin/test_share_types.py
index 3d46c9e..d23171a 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_types.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_types.py
@@ -113,22 +113,26 @@
@utils.skip_if_microversion_not_supported("2.50")
@decorators.idempotent_id('a9af19e1-e789-4c4f-a39b-dd8df6ed00b1')
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
- @ddt.data(
- ('2.50', data_utils.rand_name("type_updated"),
+ @ddt.named_data(
+ ('2_50_name_description_public', '2.50',
+ data_utils.rand_name("type_updated"), 'description_updated', True),
+ ('2_50_name', '2.50', data_utils.rand_name("type_updated"), None,
+ None),
+ ('2_50_description_public', '2.50', None, 'description_updated',
+ None),
+ ('2_50_public', '2.50', None, None, True),
+ ('2_50', '2.50', None, None, False),
+ (f'{LATEST_MICROVERSION}_name_description_public',
+ LATEST_MICROVERSION, data_utils.rand_name("type_updated"),
'description_updated', True),
- ('2.50', data_utils.rand_name("type_updated"), None, None),
- ('2.50', None, 'description_updated', None),
- ('2.50', None, None, True),
- ('2.50', None, None, False),
- (LATEST_MICROVERSION, data_utils.rand_name("type_updated"),
- 'description_updated', True),
- (LATEST_MICROVERSION, data_utils.rand_name("type_updated"),
- None, None),
- (LATEST_MICROVERSION, None, 'description_updated', None),
- (LATEST_MICROVERSION, None, None, True),
- (LATEST_MICROVERSION, None, None, False),
+ (f'{LATEST_MICROVERSION}_name', LATEST_MICROVERSION,
+ data_utils.rand_name("type_updated"), None, None),
+ (f'{LATEST_MICROVERSION}_description', LATEST_MICROVERSION, None,
+ 'description_updated', None),
+ (f'{LATEST_MICROVERSION}_public', LATEST_MICROVERSION, None, None,
+ True),
+ (LATEST_MICROVERSION, LATEST_MICROVERSION, None, None, False),
)
- @ddt.unpack
def test_share_type_create_update(self, version, st_name,
st_description, st_is_public):
name = data_utils.rand_name("tempest-manila")
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index 9bd32a9..2db2353 100755
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -705,6 +705,31 @@
return replica
@classmethod
+ def create_backup_wait_for_active(cls, share_id, client=None,
+ cleanup_in_class=False, cleanup=True,
+ version=CONF.share.max_api_microversion):
+ client = client or cls.shares_v2_client
+ backup_name = data_utils.rand_name('Backup')
+ backup_options = CONF.share.driver_assisted_backup_test_driver_options
+ backup = client.create_share_backup(
+ share_id,
+ name=backup_name,
+ backup_options=backup_options)['share_backup']
+ resource = {
+ "type": "share_backup",
+ "id": backup["id"],
+ "client": client,
+ }
+ if cleanup:
+ if cleanup_in_class:
+ cls.class_resources.insert(0, resource)
+ else:
+ cls.method_resources.insert(0, resource)
+ waiters.wait_for_resource_status(client, backup["id"], "available",
+ resource_name='share_backup')
+ return client.get_share_backup(backup['id'])['share_backup']
+
+ @classmethod
def delete_share_replica(cls, replica_id, client=None,
version=CONF.share.max_api_microversion):
client = client or cls.shares_v2_client
@@ -760,7 +785,7 @@
share_network_subnet = client.create_subnet(
**kwargs)['share_network_subnet']
resource = {
- "type": "share-network-subnet",
+ "type": "share_network_subnet",
"id": share_network_subnet["id"],
"extra_params": {
"share_network_id": share_network_subnet["share_network_id"]
@@ -919,6 +944,9 @@
elif res["type"] == "share_replica":
client.delete_share_replica(res_id)
client.wait_for_resource_deletion(replica_id=res_id)
+ elif res["type"] == "share_backup":
+ client.delete_share_backup(res_id)
+ client.wait_for_resource_deletion(backup_id=res_id)
elif res["type"] == "share_network_subnet":
sn_id = res["extra_params"]["share_network_id"]
client.delete_subnet(sn_id, res_id)
diff --git a/manila_tempest_tests/tests/api/test_backup.py b/manila_tempest_tests/tests/api/test_backup.py
new file mode 100644
index 0000000..f443802
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_backup.py
@@ -0,0 +1,117 @@
+# Copyright 2024 Cloudification GmbH
+# 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 import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import waiters
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+
+CONF = config.CONF
+_MIN_SUPPORTED_MICROVERSION = '2.80'
+
+
+class ShareBackupTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareBackupTest, cls).skip_checks()
+ if not CONF.share.run_driver_assisted_backup_tests:
+ raise cls.skipException("Share backup tests are disabled.")
+ utils.check_skip_if_microversion_not_supported(
+ _MIN_SUPPORTED_MICROVERSION)
+
+ def setUp(self):
+ super(ShareBackupTest, self).setUp()
+ extra_specs = {
+ 'snapshot_support': True,
+ 'mount_snapshot_support': True,
+ }
+ share_type = self.create_share_type(extra_specs=extra_specs)
+ share = self.create_share(self.shares_v2_client.share_protocol,
+ share_type_id=share_type['id'])
+ self.share_id = share["id"]
+
+ @decorators.idempotent_id('12c36c97-faf4-4fec-9a9b-7cff0d2035cd')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ def test_create_share_backup(self):
+ backup = self.create_backup_wait_for_active(self.share_id)
+
+ # Verify backup create API response
+ expected_keys = ["id", "share_id", "status",
+ "availability_zone", "created_at", "updated_at",
+ "size", "progress", "restore_progress",
+ "name", "description"]
+
+ # Strict key check
+ actual_backup = self.shares_v2_client.get_share_backup(
+ backup['id'])['share_backup']
+ actual_keys = actual_backup.keys()
+ self.assertEqual(backup['id'], actual_backup['id'])
+ self.assertEqual(set(expected_keys), set(actual_keys))
+
+ @decorators.idempotent_id('34c36c97-faf4-4fec-9a9b-7cff0d2035cd')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ def test_delete_share_backup(self):
+ backup = self.create_backup_wait_for_active(
+ self.share_id, cleanup=False)
+
+ # Delete share backup
+ self.shares_v2_client.delete_share_backup(backup['id'])
+ self.shares_v2_client.wait_for_resource_deletion(
+ backup_id=backup['id'])
+ self.assertRaises(
+ lib_exc.NotFound,
+ self.shares_v2_client.get_share_backup,
+ backup['id'])
+
+ @decorators.idempotent_id('56c36c97-faf4-4fec-9a9b-7cff0d2035cd')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ def test_restore_share_backup(self):
+ backup = self.create_backup_wait_for_active(self.share_id)
+
+ # Restore share backup
+ restore = self.shares_v2_client.restore_share_backup(
+ backup['id'])['restore']
+ waiters.wait_for_resource_status(
+ self.shares_v2_client, backup['id'], 'available',
+ resource_name='share_backup')
+
+ self.assertEqual(restore['share_id'], self.share_id)
+
+ @decorators.idempotent_id('78c36c97-faf4-4fec-9a9b-7cff0d2035cd')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ def test_update_share_backup(self):
+ backup = self.create_backup_wait_for_active(self.share_id)
+
+ # Update share backup name
+ backup_name2 = data_utils.rand_name('Backup')
+ backup = self.shares_v2_client.update_share_backup(
+ backup['id'], name=backup_name2)['share_backup']
+ updated_backup = self.shares_v2_client.get_share_backup(
+ backup['id'])['share_backup']
+ self.assertEqual(backup_name2, updated_backup['name'])
+
+ @decorators.idempotent_id('19c36c97-faf4-4fec-9a9b-7cff0d2045af')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ def test_list_share_backups(self):
+ self.create_backup_wait_for_active(self.share_id)
+ backups = self.shares_v2_client.list_share_backups()
+ self.assertEqual(1, len(backups))
diff --git a/manila_tempest_tests/tests/api/test_backup_negative.py b/manila_tempest_tests/tests/api/test_backup_negative.py
new file mode 100644
index 0000000..743c195
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_backup_negative.py
@@ -0,0 +1,153 @@
+# Copyright 2024 Cloudification GmbH
+# 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 import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import waiters
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+
+CONF = config.CONF
+_MIN_SUPPORTED_MICROVERSION = '2.80'
+
+
+class ShareBackupNegativeTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareBackupNegativeTest, cls).skip_checks()
+ if not CONF.share.run_driver_assisted_backup_tests:
+ raise cls.skipException("Share backup tests are disabled.")
+ utils.check_skip_if_microversion_not_supported(
+ _MIN_SUPPORTED_MICROVERSION)
+
+ def setUp(self):
+ super(ShareBackupNegativeTest, self).setUp()
+ extra_specs = {
+ 'snapshot_support': True,
+ 'mount_snapshot_support': True,
+ }
+ share_type = self.create_share_type(extra_specs=extra_specs)
+ share = self.create_share(self.shares_v2_client.share_protocol,
+ share_type_id=share_type['id'])
+ self.share_id = share["id"]
+ self.backup_options = (
+ CONF.share.driver_assisted_backup_test_driver_options)
+
+ @decorators.idempotent_id('58c36c97-faf4-4fec-9a9b-7cff0d2035ab')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_BACKEND)
+ def test_create_backup_when_share_is_in_backup_creating_state(self):
+ backup_name1 = data_utils.rand_name('Backup')
+ backup1 = self.shares_v2_client.create_share_backup(
+ self.share_id,
+ name=backup_name1,
+ backup_options=self.backup_options)['share_backup']
+
+ # try create backup when share state is busy
+ backup_name2 = data_utils.rand_name('Backup')
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.create_share_backup,
+ self.share_id,
+ name=backup_name2,
+ backup_options=self.backup_options)
+ waiters.wait_for_resource_status(
+ self.shares_v2_client, backup1['id'], "available",
+ resource_name='share_backup')
+
+ # delete the share backup
+ self.shares_v2_client.delete_share_backup(backup1['id'])
+ self.shares_v2_client.wait_for_resource_deletion(
+ backup_id=backup1['id'])
+
+ @decorators.idempotent_id('58c36c97-faf4-4fec-9a9b-7cff0d2012ab')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_BACKEND)
+ def test_create_backup_when_share_is_in_error_state(self):
+ self.admin_shares_v2_client.reset_state(self.share_id,
+ status='error')
+
+ # try create backup when share is not available
+ backup_name = data_utils.rand_name('Backup')
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.create_share_backup,
+ self.share_id,
+ name=backup_name,
+ backup_options=self.backup_options)
+
+ self.admin_shares_v2_client.reset_state(self.share_id,
+ status='available')
+
+ @decorators.idempotent_id('58c36c97-faf4-4fec-9a9b-7cff0d2012de')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_BACKEND)
+ def test_create_backup_when_share_has_snapshots(self):
+ self.create_snapshot_wait_for_active(self.share_id,
+ cleanup_in_class=False)
+
+ # try create backup when share has snapshots
+ backup_name = data_utils.rand_name('Backup')
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.create_share_backup,
+ self.share_id,
+ name=backup_name,
+ backup_options=self.backup_options)
+
+ @decorators.idempotent_id('58c12c97-faf4-4fec-9a9b-7cff0d2012de')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_BACKEND)
+ def test_delete_backup_when_backup_is_not_available(self):
+ backup = self.create_backup_wait_for_active(self.share_id)
+ self.admin_shares_v2_client.reset_state_share_backup(
+ backup['id'], status='creating')
+
+ # try delete backup when share backup is not available
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.delete_share_backup,
+ backup['id'])
+
+ self.admin_shares_v2_client.reset_state_share_backup(
+ backup['id'], status='available')
+
+ @decorators.idempotent_id('58c56c97-faf4-4fec-9a9b-7cff0d2012de')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_BACKEND)
+ def test_restore_backup_when_share_is_not_available(self):
+ backup = self.create_backup_wait_for_active(self.share_id)
+ self.admin_shares_v2_client.reset_state(self.share_id,
+ status='error')
+
+ # try restore backup when share is not available
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.restore_share_backup,
+ backup['id'])
+
+ self.admin_shares_v2_client.reset_state(self.share_id,
+ status='available')
+
+ @decorators.idempotent_id('58c12998-faf4-4fec-9a9b-7cff0d2012de')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_BACKEND)
+ def test_restore_backup_when_backup_is_not_available(self):
+ backup = self.create_backup_wait_for_active(self.share_id)
+ self.admin_shares_v2_client.reset_state_share_backup(
+ backup['id'], status='creating')
+
+ # try restore backup when backup is not available
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.restore_share_backup,
+ backup['id'])
+
+ self.admin_shares_v2_client.reset_state_share_backup(
+ backup['id'], status='available')
diff --git a/manila_tempest_tests/tests/api/test_metadata.py b/manila_tempest_tests/tests/api/test_metadata.py
index bd73963..862de50 100644
--- a/manila_tempest_tests/tests/api/test_metadata.py
+++ b/manila_tempest_tests/tests/api/test_metadata.py
@@ -33,12 +33,6 @@
def _verify_share_metadata(self, share, md):
- # get metadata of share
- metadata = self.shares_v2_client.get_metadata(share["id"])['metadata']
-
- # verify metadata
- self.assertEqual(md, metadata)
-
# verify metadata items
for key in md:
get_value = self.shares_v2_client.get_metadata_item(
@@ -82,7 +76,8 @@
# verify deletion of metadata
get_metadata = self.shares_v2_client.get_metadata(share["id"])[
'metadata']
- self.assertEmpty(get_metadata)
+ for key in md.keys():
+ self.assertNotIn(key, list(get_metadata.keys()))
@decorators.idempotent_id('4e5f8159-62b6-4d5c-f729-d8b1f029d7de')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -117,7 +112,8 @@
# verify deletion of metadata
get_metadata = self.shares_v2_client.get_metadata(
share["id"])['metadata']
- self.assertEmpty(get_metadata)
+ for key in md.keys():
+ self.assertNotIn(key, list(get_metadata.keys()))
@decorators.idempotent_id('2ec70ba5-050b-3b17-c862-c149e53543c0')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -150,7 +146,8 @@
# verify deletion of metadata
get_metadata = self.shares_v2_client.get_metadata(
share["id"])['metadata']
- self.assertEmpty(get_metadata)
+ for key in md.keys():
+ self.assertNotIn(key, list(get_metadata.keys()))
@decorators.idempotent_id('c94851f4-2559-4712-9297-9912db1da7ff')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -228,7 +225,7 @@
body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
- self.assertEqual(data, body_get)
+ self.assertEqual(data["k"], body_get["k"])
@decorators.idempotent_id('5eff5619-b7cd-42f1-85e0-47d3d47098dd')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -240,7 +237,9 @@
body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
- self.assertEqual(data, body_get)
+ body_get_keys = list(body_get.keys())
+ self.assertIn(max_key, body_get_keys)
+ self.assertEqual(data[max_key], body_get[max_key])
@decorators.idempotent_id('44a572f1-6b5c-49d0-8f2e-1583ec3428d8')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -251,7 +250,7 @@
body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
- self.assertEqual(data, body_get)
+ self.assertEqual(data["key"], body_get["key"])
@decorators.idempotent_id('694d95e1-ba8c-49fc-a888-6f9f0d51d77d')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -263,4 +262,4 @@
body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
- self.assertEqual(data, body_get)
+ self.assertEqual(max_value, body_get["key"])
diff --git a/manila_tempest_tests/tests/api/test_revert_to_snapshot.py b/manila_tempest_tests/tests/api/test_revert_to_snapshot.py
index dca394a..5eb6915 100644
--- a/manila_tempest_tests/tests/api/test_revert_to_snapshot.py
+++ b/manila_tempest_tests/tests/api/test_revert_to_snapshot.py
@@ -109,8 +109,8 @@
@decorators.idempotent_id('196f2bc5-e13a-4730-ac51-61e339068a06')
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@ddt.data(
- *{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
- CONF.share.max_api_microversion}
+ *utils.deduplicate([constants.REVERT_TO_SNAPSHOT_MICROVERSION,
+ CONF.share.max_api_microversion])
)
def test_revert_to_latest_snapshot(self, version):
snapshot = self.create_snapshot_wait_for_active(self.share['id'],
@@ -129,8 +129,8 @@
@decorators.idempotent_id('09bd9942-7ef9-4d24-b2dd-f83bdda27b50')
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@ddt.data(
- *{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
- CONF.share.max_api_microversion}
+ *utils.deduplicate([constants.REVERT_TO_SNAPSHOT_MICROVERSION,
+ CONF.share.max_api_microversion])
)
def test_revert_to_previous_snapshot(self, version):
snapshot1 = self.create_snapshot_wait_for_active(
@@ -157,8 +157,8 @@
@tc.skipUnless(CONF.share.run_replication_tests,
'Replication tests are disabled.')
@ddt.data(
- *{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
- CONF.share.max_api_microversion}
+ *utils.deduplicate([constants.REVERT_TO_SNAPSHOT_MICROVERSION,
+ CONF.share.max_api_microversion])
)
def test_revert_to_replicated_snapshot(self, version):
"""Test reverting to a replicated snapshot."""
diff --git a/manila_tempest_tests/tests/api/test_revert_to_snapshot_negative.py b/manila_tempest_tests/tests/api/test_revert_to_snapshot_negative.py
index 96d7f04..95e2c72 100644
--- a/manila_tempest_tests/tests/api/test_revert_to_snapshot_negative.py
+++ b/manila_tempest_tests/tests/api/test_revert_to_snapshot_negative.py
@@ -80,8 +80,8 @@
@decorators.idempotent_id('21dd8561-8913-42a2-a95c-74b536964c94')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@ddt.data(
- *{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
- CONF.share.max_api_microversion}
+ *utils.deduplicate([constants.REVERT_TO_SNAPSHOT_MICROVERSION,
+ CONF.share.max_api_microversion])
)
def test_revert_to_second_latest_snapshot(self, version):
snapshot1 = self.create_snapshot_wait_for_active(
@@ -98,8 +98,8 @@
@decorators.idempotent_id('7360ee16-ac7d-46ce-9c81-251d64fb7434')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@ddt.data(
- *{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
- CONF.share.max_api_microversion}
+ *utils.deduplicate([constants.REVERT_TO_SNAPSHOT_MICROVERSION,
+ CONF.share.max_api_microversion])
)
def test_revert_to_error_snapshot(self, version):
snapshot = self.create_snapshot_wait_for_active(self.share['id'],
@@ -118,8 +118,8 @@
@decorators.idempotent_id('108a451e-a8e9-450f-8f75-53883d58c6be')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@ddt.data(
- *{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
- CONF.share.max_api_microversion}
+ *utils.deduplicate([constants.REVERT_TO_SNAPSHOT_MICROVERSION,
+ CONF.share.max_api_microversion])
)
def test_revert_error_share_to_snapshot(self, version):
snapshot = self.create_snapshot_wait_for_active(self.share['id'],
@@ -143,8 +143,8 @@
@decorators.idempotent_id('29024057-dbbd-4cf6-a796-207dfbd4c3ff')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@ddt.data(
- *{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
- CONF.share.max_api_microversion}
+ *utils.deduplicate([constants.REVERT_TO_SNAPSHOT_MICROVERSION,
+ CONF.share.max_api_microversion])
)
def test_revert_to_missing_snapshot(self, version):
self.assertRaises(exceptions.BadRequest,
@@ -156,8 +156,8 @@
@decorators.idempotent_id('ef706fad-5ac4-41dc-af81-5aa0331560cf')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@ddt.data(
- *{constants.REVERT_TO_SNAPSHOT_MICROVERSION,
- CONF.share.max_api_microversion}
+ *utils.deduplicate([constants.REVERT_TO_SNAPSHOT_MICROVERSION,
+ CONF.share.max_api_microversion])
)
def test_revert_to_invalid_snapshot(self, version):
snapshot = self.create_snapshot_wait_for_active(
diff --git a/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet_negative.py b/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet_negative.py
index 522f34e..a230163 100644
--- a/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet_negative.py
+++ b/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet_negative.py
@@ -32,13 +32,17 @@
super(ShareServerMultipleSubNegativeTest, cls).skip_checks()
if not CONF.share.multitenancy_enabled:
raise cls.skipException('Multitenancy tests are disabled.')
+ if not CONF.share.run_share_server_multiple_subnet_tests:
+ raise cls.skipException(
+ 'Share server multiple subnets and network allocation '
+ 'update tests are disabled.')
utils.check_skip_if_microversion_not_supported("2.70")
@classmethod
def resource_setup(cls):
super(ShareServerMultipleSubNegativeTest, cls).resource_setup()
- cls.share_network = cls.alt_shares_v2_client.get_share_network(
- cls.alt_shares_v2_client.share_network_id)['share_network']
+ cls.share_network = cls.shares_v2_client.get_share_network(
+ cls.shares_v2_client.share_network_id)['share_network']
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@decorators.idempotent_id('1e2a9415-b02f-4c02-812d-bedc361f92ce')
@@ -53,9 +57,9 @@
zones = self.get_availability_zones_matching_share_type(
share_type)
if not pools or not zones:
- raise self.skipException("At least one backend that supports "
- "adding multiple subnets into a share "
- "network is needed for this test.")
+ raise self.skipException("At least one backend that does not "
+ "support adding multiple subnets into a "
+ "share network is needed for this test.")
extra_specs = {'pool_name': pools[0]['pool'],
'availability_zone': zones[0]}
self.admin_shares_v2_client.update_share_type_extra_specs(
diff --git a/manila_tempest_tests/tests/api/test_share_transfers.py b/manila_tempest_tests/tests/api/test_share_transfers.py
new file mode 100644
index 0000000..56f8e0c
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_transfers.py
@@ -0,0 +1,107 @@
+# Copyright (C) 2022 China Telecom Digital Intelligence.
+# 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 import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.common import waiters
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+
+
+class ShareTransferTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareTransferTest, cls).skip_checks()
+ utils.check_skip_if_microversion_not_supported(
+ constants.SHARE_TRANSFER_VERSION)
+ if CONF.share.multitenancy_enabled:
+ raise cls.skipException(
+ 'Only for driver_handles_share_servers = False driver mode.')
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareTransferTest, cls).resource_setup()
+ # create share_type with dhss=False
+ extra_specs = cls.add_extra_specs_to_dict()
+ cls.share_type = cls.create_share_type(extra_specs=extra_specs)
+ cls.share_type_id = cls.share_type['id']
+
+ @decorators.idempotent_id('716e71a0-8265-4410-9170-08714095d9e8')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ def test_create_and_delete_share_transfer(self):
+ # create share
+ share_name = data_utils.rand_name("tempest-share-name")
+ share = self.create_share(name=share_name,
+ share_type_id=self.share_type_id,
+ cleanup_in_class=False)
+
+ # create share transfer
+ transfer = self.shares_v2_client.create_share_transfer(
+ share['id'], name='tempest_share_transfer')['transfer']
+ waiters.wait_for_resource_status(
+ self.shares_client, share['id'], 'awaiting_transfer')
+
+ # check transfer exists and show transfer
+ transfer_show = self.shares_v2_client.get_share_transfer(
+ transfer['id'])['transfer']
+ self.assertEqual(transfer_show['name'], 'tempest_share_transfer')
+
+ # delete share transfer
+ self.shares_v2_client.delete_share_transfer(transfer['id'])
+ waiters.wait_for_resource_status(
+ self.shares_client, share['id'], 'available')
+
+ # check transfer not in transfer list
+ transfers = self.shares_v2_client.list_share_transfers()['transfers']
+ transfer_ids = [tf['id'] for tf in transfers]
+ self.assertNotIn(transfer['id'], transfer_ids)
+
+ @decorators.idempotent_id('3c2622ab-3368-4693-afb6-e60bd27e61ef')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ def test_create_and_accept_share_transfer(self):
+ # create share
+ share_name = data_utils.rand_name("tempest-share-name")
+ share = self.create_share(name=share_name,
+ share_type_id=self.share_type_id)
+
+ # create share transfer
+ transfer = self.shares_v2_client.create_share_transfer(
+ share['id'])['transfer']
+ waiters.wait_for_resource_status(
+ self.shares_client, share['id'], 'awaiting_transfer')
+
+ # accept share transfer by alt project
+ self.alt_shares_v2_client.accept_share_transfer(transfer['id'],
+ transfer['auth_key'])
+ waiters.wait_for_resource_status(
+ self.alt_shares_client, share['id'], 'available')
+
+ # check share in alt project
+ shares = self.alt_shares_v2_client.list_shares(
+ detailed=True)['shares']
+ share_ids = [sh['id'] for sh in shares] if shares else []
+ self.assertIn(share['id'], share_ids)
+
+ # delete the share
+ self.alt_shares_v2_client.delete_share(share['id'])
+ self.alt_shares_v2_client.wait_for_resource_deletion(
+ share_id=share["id"])
diff --git a/manila_tempest_tests/tests/api/test_share_transfers_negative.py b/manila_tempest_tests/tests/api/test_share_transfers_negative.py
new file mode 100644
index 0000000..0672459
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_transfers_negative.py
@@ -0,0 +1,137 @@
+# Copyright (C) 2022 China Telecom Digital Intelligence.
+# 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 oslo_utils import uuidutils
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.common import waiters
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+
+
+class ShareTransferNegativeTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareTransferNegativeTest, cls).skip_checks()
+ utils.check_skip_if_microversion_not_supported(
+ constants.SHARE_TRANSFER_VERSION)
+ if CONF.share.multitenancy_enabled:
+ raise cls.skipException(
+ 'Only for driver_handles_share_servers = False driver mode.')
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareTransferNegativeTest, cls).resource_setup()
+ # create share_type with dhss=False
+ extra_specs = cls.add_extra_specs_to_dict()
+ cls.share_type = cls.create_share_type(extra_specs=extra_specs)
+ cls.share_type_id = cls.share_type['id']
+
+ def _create_share_transfer(self, share):
+ transfer = self.shares_v2_client.create_share_transfer(
+ share['id'])['transfer']
+ waiters.wait_for_resource_status(
+ self.shares_client, share['id'], 'awaiting_transfer')
+ self.addCleanup(waiters.wait_for_resource_status, self.shares_client,
+ share['id'], 'available')
+ self.addCleanup(self.shares_v2_client.delete_share_transfer,
+ transfer['id'])
+ return transfer
+
+ @decorators.idempotent_id('baf66f62-253e-40dd-a6a9-109bc7613e52')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ def test_show_transfer_of_other_tenants(self):
+ # create share
+ share_name = data_utils.rand_name("tempest-share-name")
+ share = self.create_share(
+ name=share_name,
+ share_type_id=self.share_type_id)
+
+ # create share transfer
+ transfer = self._create_share_transfer(share)
+
+ self.assertRaises(lib_exc.NotFound,
+ self.alt_shares_v2_client.get_share_transfer,
+ transfer['id'])
+
+ @decorators.idempotent_id('4b9e75b1-4ac6-4111-b09e-e6dacd0ac2c3')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_show_nonexistent_transfer(self):
+ self.assertRaises(lib_exc.NotFound,
+ self.shares_v2_client.get_share_transfer,
+ str(uuidutils.generate_uuid()))
+
+ @decorators.idempotent_id('b3e26356-5eb0-4f73-b5a7-d3594cc2f30e')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ def test_delete_transfer_of_other_tenants(self):
+ # create share
+ share_name = data_utils.rand_name("tempest-share-name")
+ share = self.create_share(
+ name=share_name,
+ share_type_id=self.share_type_id)
+
+ # create share transfer
+ transfer = self._create_share_transfer(share)
+
+ self.assertRaises(lib_exc.NotFound,
+ self.alt_shares_v2_client.delete_share_transfer,
+ transfer['id'])
+
+ @decorators.idempotent_id('085d5971-fe6e-4497-93cb-f1eb176a10da')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_delete_nonexistent_transfer(self):
+ self.assertRaises(lib_exc.NotFound,
+ self.shares_v2_client.delete_share_transfer,
+ str(uuidutils.generate_uuid()))
+
+ @decorators.idempotent_id('cc7af032-0504-417e-8ab9-73b37bed7f85')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ def test_accept_transfer_without_auth_key(self):
+ # create share
+ share_name = data_utils.rand_name("tempest-share-name")
+ share = self.create_share(
+ name=share_name,
+ share_type_id=self.share_type_id)
+
+ # create share transfer
+ transfer = self._create_share_transfer(share)
+
+ self.assertRaises(lib_exc.BadRequest,
+ self.alt_shares_v2_client.accept_share_transfer,
+ transfer['id'], "")
+
+ @decorators.idempotent_id('05a6a345-7609-421f-be21-d79041970674')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_accept_transfer_with_incorrect_auth_key(self):
+ # create share
+ share_name = data_utils.rand_name("tempest-share-name")
+ share = self.create_share(
+ name=share_name,
+ share_type_id=self.share_type_id)
+
+ # create share transfer
+ transfer = self._create_share_transfer(share)
+
+ self.assertRaises(lib_exc.BadRequest,
+ self.alt_shares_v2_client.accept_share_transfer,
+ transfer['id'], "incorrect_auth_key")
diff --git a/manila_tempest_tests/tests/api/test_share_types_negative.py b/manila_tempest_tests/tests/api/test_share_types_negative.py
index 046af45..af4815f 100644
--- a/manila_tempest_tests/tests/api/test_share_types_negative.py
+++ b/manila_tempest_tests/tests/api/test_share_types_negative.py
@@ -83,15 +83,17 @@
@utils.skip_if_microversion_not_supported("2.50")
@decorators.idempotent_id('4a22945c-8988-43a1-88c9-eb86e6abcd8e')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
- @ddt.data(
- ('2.50', '', None, None),
- (LATEST_MICROVERSION, '', None, None),
- ('2.50', None, None, 'not_bool'),
- (LATEST_MICROVERSION, None, None, 'not_bool'),
- ('2.50', None, generate_long_description(256), None),
- (LATEST_MICROVERSION, None, generate_long_description(256), None),
+ @ddt.named_data(
+ ('2_50', '2.50', '', None, None),
+ (LATEST_MICROVERSION, LATEST_MICROVERSION, '', None, None),
+ ('2_50_bad_public', '2.50', None, None, 'not_bool'),
+ (f'{LATEST_MICROVERSION}_bad_public', LATEST_MICROVERSION, None, None,
+ 'not_bool'),
+ ('2_50_description', '2.50', None, generate_long_description(256),
+ None),
+ (f'{LATEST_MICROVERSION}_description', LATEST_MICROVERSION, None,
+ generate_long_description(256), None),
)
- @ddt.unpack
def test_share_type_update_bad_request(
self, version, st_name, st_description, st_is_public):
st_id = self.st['id']
diff --git a/manila_tempest_tests/tests/api/test_shares_actions_negative.py b/manila_tempest_tests/tests/api/test_shares_actions_negative.py
index 977d9a1..da85f2e 100644
--- a/manila_tempest_tests/tests/api/test_shares_actions_negative.py
+++ b/manila_tempest_tests/tests/api/test_shares_actions_negative.py
@@ -288,7 +288,6 @@
self.assertEqual(0, len(shares))
- @decorators.skip_because(bug='1914363')
@decorators.idempotent_id('e8f857f1-ec32-4f81-9e09-26065891dc93')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_get_share_from_other_project(self):
diff --git a/manila_tempest_tests/tests/rbac/base.py b/manila_tempest_tests/tests/rbac/base.py
index b1eba9b..d3c63de 100644
--- a/manila_tempest_tests/tests/rbac/base.py
+++ b/manila_tempest_tests/tests/rbac/base.py
@@ -53,7 +53,7 @@
'sn': 'share_network',
}
key, resource_id = list(kwargs.items())[0]
- key = key.split('_')[0]
+ key = key.rsplit('_', 1)[0]
resource_name = key_names[key] if key in key_names else key
del_action = getattr(client, 'delete_{}'.format(resource_name))
@@ -116,6 +116,33 @@
return share_type
@classmethod
+ def create_share_group_type(cls, share_types, is_public=True,
+ group_specs=None):
+ name = data_utils.rand_name('share-group-type')
+ share_group_type = (
+ cls.admin_shares_v2_client.create_share_group_type(
+ name=name, share_types=share_types, is_public=is_public,
+ group_specs=group_specs))['share_group_type']
+ cls.addClassResourceCleanup(
+ cls.delete_resource, cls.admin_shares_v2_client,
+ share_group_type_id=share_group_type['id'])
+ return share_group_type
+
+ @classmethod
+ def create_share_group(cls, client, share_group_type_id, share_type_ids):
+ name = data_utils.rand_name('share-group')
+ share_group = client.create_share_group(
+ name=name, share_group_type_id=share_group_type_id,
+ share_type_ids=share_type_ids)['share_group']
+ waiters.wait_for_resource_status(
+ client, share_group['id'], 'available',
+ resource_name='share_group')
+ cls.addClassResourceCleanup(
+ cls.delete_resource, client,
+ share_group_id=share_group['id'])
+ return share_group
+
+ @classmethod
def get_share_type(cls):
return cls.shares_v2_client.get_default_share_type()['share_type']
diff --git a/manila_tempest_tests/tests/rbac/test_share_group_types.py b/manila_tempest_tests/tests/rbac/test_share_group_types.py
new file mode 100644
index 0000000..ac2f54b
--- /dev/null
+++ b/manila_tempest_tests/tests/rbac/test_share_group_types.py
@@ -0,0 +1,372 @@
+# 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.
+
+import abc
+
+from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests.tests.rbac import base as rbac_base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+
+
+class ShareRbacShareGroupTypesTests(rbac_base.ShareRbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(ShareRbacShareGroupTypesTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.share_v2.SharesV2Client()
+ cls.admin_shares_v2_client = (
+ cls.os_project_admin.share_v2.SharesV2Client())
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareRbacShareGroupTypesTests, cls).skip_checks()
+ if not CONF.share.run_share_group_tests:
+ raise cls.skipException('Share Group tests disabled.')
+
+ utils.check_skip_if_microversion_not_supported(
+ constants.MIN_SHARE_GROUP_MICROVERSION)
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareRbacShareGroupTypesTests, cls).resource_setup()
+ cls.group_specs1 = {u'key1': u'value1'}
+ cls.group_specs2 = {u'key2': u'value2'}
+ cls.share_type = cls.create_share_type()
+ cls.share_group_type = cls.create_share_group_type(
+ cls.share_type['id'], group_specs=cls.group_specs1)
+ cls.private_share_group_type = cls.create_share_group_type(
+ cls.share_type['id'], is_public=False)
+
+ @abc.abstractmethod
+ def test_create_share_group_type(self):
+ pass
+
+ @abc.abstractmethod
+ def test_get_share_group_type(self):
+ pass
+
+ @abc.abstractmethod
+ def test_list_share_group_types(self):
+ pass
+
+ @abc.abstractmethod
+ def test_delete_share_group_type(self):
+ pass
+
+ @abc.abstractmethod
+ def test_create_share_group_type_extra_specs(self):
+ pass
+
+ @abc.abstractmethod
+ def test_update_share_group_type_extra_spec(self):
+ pass
+
+ @abc.abstractmethod
+ def test_delete_share_group_type_extra_spec(self):
+ pass
+
+ @abc.abstractmethod
+ def test_add_share_group_type_access(self):
+ pass
+
+ @abc.abstractmethod
+ def test_list_share_group_type_access(self):
+ pass
+
+ @abc.abstractmethod
+ def test_remove_share_group_type_access(self):
+ pass
+
+
+class ProjectAdminTests(ShareRbacShareGroupTypesTests, base.BaseSharesTest):
+
+ credentials = ['project_admin']
+
+ @decorators.idempotent_id('9ea9954a-ae09-4d02-a082-9a72b80009fc')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_create_share_group_type(self):
+ share_group_type = self.do_request(
+ 'create_share_group_type', expected_status=200,
+ name='gt', share_types=self.share_type['id'])['share_group_type']
+ self.addCleanup(self.delete_resource, self.client,
+ share_group_type_id=share_group_type['id'])
+
+ @decorators.idempotent_id('fcad2b86-ca43-42b0-82bd-37e6f760e4d2')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_get_share_group_type(self):
+ self.do_request(
+ 'get_share_group_type', expected_status=200,
+ share_group_type_id=self.share_group_type['id'])
+
+ @decorators.idempotent_id('7871b1b5-610a-425c-9363-d0bcf2beff72')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_list_share_group_types(self):
+ share_group_type_list = self.do_request(
+ 'list_share_group_types', expected_status=200)['share_group_types']
+ share_group_type_id_list = [
+ sgt['id'] for sgt in share_group_type_list
+ ]
+ self.assertIn(self.share_group_type['id'], share_group_type_id_list)
+
+ @decorators.idempotent_id('c23da121-8b1f-4443-80cc-11881745a1c3')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_delete_share_group_type(self):
+ share_group_type = self.create_share_group_type(
+ share_types=self.share_type['id'])
+ self.do_request(
+ 'delete_share_group_type', expected_status=204,
+ share_group_type_id=share_group_type['id'])
+
+ @decorators.idempotent_id('80eb22cb-846a-4b51-a71d-ceef0b804901')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_create_share_group_type_extra_specs(self):
+ self.do_request(
+ 'create_share_group_type_specs', expected_status=200,
+ share_group_type_id=self.share_group_type['id'],
+ group_specs_dict=self.group_specs2)
+ self.addCleanup(
+ self.admin_shares_v2_client.delete_share_group_type_spec,
+ self.share_group_type['id'], group_spec_key='key2')
+
+ @decorators.idempotent_id('fe29877d-2226-42ca-b492-4be0dacd6eaf')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_update_share_group_type_extra_spec(self):
+ self.do_request(
+ 'update_share_group_type_spec', expected_status=200,
+ share_group_type_id=self.share_group_type['id'],
+ group_spec_key='key', group_spec_value='value_updated')
+
+ @decorators.idempotent_id('743c18dc-8c3a-4934-9ef8-8b342daffe7c')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_delete_share_group_type_extra_spec(self):
+ self.admin_shares_v2_client.create_share_group_type_specs(
+ self.share_group_type['id'], self.group_specs2)
+ self.do_request(
+ 'delete_share_group_type_spec', expected_status=204,
+ share_group_type_id=self.share_group_type['id'],
+ group_spec_key='key2')
+
+ @decorators.idempotent_id('89876c46-1167-450d-8b98-746d97fff388')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_add_share_group_type_access(self):
+ self.do_request(
+ 'add_access_to_share_group_type', expected_status=202,
+ share_group_type_id=self.private_share_group_type['id'],
+ project_id=self.client.project_id)
+ self.addCleanup(
+ self.client.remove_access_from_share_group_type,
+ share_group_type_id=self.private_share_group_type['id'],
+ project_id=self.client.project_id)
+
+ @decorators.idempotent_id('64a7be53-d1af-40c3-950b-743a2704ac97')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_list_share_group_type_access(self):
+ self.client.add_access_to_share_group_type(
+ self.private_share_group_type['id'], self.client.project_id)
+ self.addCleanup(
+ self.client.remove_access_from_share_group_type,
+ share_group_type_id=self.private_share_group_type['id'],
+ project_id=self.client.project_id)
+ access_list = self.do_request(
+ 'list_access_to_share_group_type', expected_status=200,
+ share_group_type_id=self.private_share_group_type['id']
+ )['share_group_type_access']
+
+ project_id_list = [
+ access['project_id'] for access in access_list
+ ]
+
+ self.assertIn(self.client.project_id, project_id_list)
+
+ @decorators.idempotent_id('fc67ba18-78e9-4c02-9b37-2bd49c8a4470')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_remove_share_group_type_access(self):
+ self.client.add_access_to_share_group_type(
+ self.private_share_group_type['id'], self.client.project_id)
+ self.do_request(
+ 'remove_access_from_share_group_type', expected_status=202,
+ share_group_type_id=self.private_share_group_type['id'],
+ project_id=self.client.project_id)
+
+
+class ProjectMemberTests(ShareRbacShareGroupTypesTests, base.BaseSharesTest):
+
+ credentials = ['project_member', 'project_admin']
+
+ @decorators.idempotent_id('f9e6f2fd-7c1a-4eee-817c-bf1988904515')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_create_share_group_type(self):
+ self.do_request(
+ 'create_share_group_type', expected_status=lib_exc.Forbidden,
+ name='gt', share_types=self.share_type['id'])
+
+ @decorators.idempotent_id('8eaf4a99-9706-41c9-8b12-40856d0900f4')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_get_share_group_type(self):
+ self.do_request(
+ 'get_share_group_type', expected_status=200,
+ share_group_type_id=self.share_group_type['id'])
+
+ @decorators.idempotent_id('d2dd61f4-c763-49f9-9c93-8b587879f554')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_list_share_group_types(self):
+ share_group_type_list = self.do_request(
+ 'list_share_group_types', expected_status=200)['share_group_types']
+ share_group_type_id_list = [
+ sgt['id'] for sgt in share_group_type_list
+ ]
+ self.assertIn(self.share_group_type['id'], share_group_type_id_list)
+
+ @decorators.idempotent_id('8f45798f-717d-41b0-acba-a80dd647cddf')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_delete_share_group_type(self):
+ share_group_type = self.create_share_group_type(
+ share_types=self.share_type['id'])
+ self.do_request(
+ 'delete_share_group_type', expected_status=lib_exc.Forbidden,
+ share_group_type_id=share_group_type['id'])
+
+ @decorators.idempotent_id('2fa2f953-f068-4c60-ab52-eeb1bd69a7a4')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_create_share_group_type_extra_specs(self):
+ self.do_request(
+ 'create_share_group_type_specs', expected_status=lib_exc.Forbidden,
+ share_group_type_id=self.share_group_type['id'],
+ group_specs_dict=self.group_specs2)
+
+ @decorators.idempotent_id('30c73c94-b7bc-4e1f-8172-192335997879')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_update_share_group_type_extra_spec(self):
+ self.do_request(
+ 'update_share_group_type_spec', expected_status=lib_exc.Forbidden,
+ share_group_type_id=self.share_group_type['id'],
+ group_spec_key='key', group_spec_value='value_updated')
+
+ @decorators.idempotent_id('95aa1fbf-3eaf-4d65-96b5-4554b0fb0937')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_delete_share_group_type_extra_spec(self):
+ self.admin_shares_v2_client.create_share_group_type_specs(
+ self.share_group_type['id'], self.group_specs2)
+ self.do_request(
+ 'delete_share_group_type_spec', expected_status=lib_exc.Forbidden,
+ share_group_type_id=self.share_group_type['id'],
+ group_spec_key='key2')
+
+ @decorators.idempotent_id('85b69e26-9c67-45c4-80e0-2ce212977c2a')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_add_share_group_type_access(self):
+ self.do_request(
+ 'add_access_to_share_group_type',
+ expected_status=lib_exc.Forbidden,
+ share_group_type_id=self.private_share_group_type['id'],
+ project_id=self.client.project_id)
+
+ @decorators.idempotent_id('027314a9-6b14-4ae9-83f2-471e84ccaa01')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_list_share_group_type_access(self):
+ self.admin_shares_v2_client.add_access_to_share_group_type(
+ self.private_share_group_type['id'], self.client.project_id)
+ self.addCleanup(
+ self.admin_shares_v2_client.remove_access_from_share_group_type,
+ share_group_type_id=self.private_share_group_type['id'],
+ project_id=self.client.project_id)
+ self.do_request(
+ 'list_access_to_share_group_type',
+ expected_status=lib_exc.Forbidden,
+ share_group_type_id=self.private_share_group_type['id'])
+
+ @decorators.idempotent_id('d8518122-dabd-4d2d-8b6a-4eed975e19ee')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_remove_share_group_type_access(self):
+ self.admin_shares_v2_client.add_access_to_share_group_type(
+ self.private_share_group_type['id'], self.client.project_id)
+ self.addCleanup(
+ self.admin_shares_v2_client.remove_access_from_share_group_type,
+ share_group_type_id=self.private_share_group_type['id'],
+ project_id=self.client.project_id)
+ self.do_request(
+ 'remove_access_from_share_group_type',
+ expected_status=lib_exc.Forbidden,
+ share_group_type_id=self.private_share_group_type['id'],
+ project_id=self.client.project_id)
+
+
+class ProjectReaderTests(ProjectMemberTests):
+
+ credentials = ['project_reader', 'project_member', 'project_admin']
+
+ @decorators.idempotent_id('8c47bbe9-f3f1-419e-b00b-97c9c942a48a')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_create_share_group_type(self):
+ super(ProjectReaderTests, self).test_create_share_group_type()
+
+ @decorators.idempotent_id('fe3b28a3-6980-4782-8eaa-518bbd3913d1')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_get_share_group_type(self):
+ super(ProjectReaderTests, self).test_get_share_group_type()
+
+ @decorators.idempotent_id('47f92f0b-424e-4685-a742-8a4e00cc6901')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_list_share_group_types(self):
+ super(ProjectReaderTests, self).test_list_share_group_types()
+
+ @decorators.idempotent_id('e853fd60-8906-4e38-b0b4-ec5723696518')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_delete_share_group_type(self):
+ super(ProjectReaderTests, self).test_delete_share_group_type()
+
+ @decorators.idempotent_id('caa6d960-4f34-4dff-9cc0-9a0cde44c2ae')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_create_share_group_type_extra_specs(self):
+ super(
+ ProjectReaderTests,
+ self).test_create_share_group_type_extra_specs()
+
+ @decorators.idempotent_id('2782c329-2447-49f7-95e7-0c4c766cfda3')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_update_share_group_type_extra_spec(self):
+ super(
+ ProjectReaderTests, self).test_update_share_group_type_extra_spec()
+
+ @decorators.idempotent_id('003a0eee-0075-47b0-ba8a-8e57e958c1d3')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_delete_share_group_type_extra_spec(self):
+ super(
+ ProjectReaderTests, self).test_delete_share_group_type_extra_spec()
+
+ @decorators.idempotent_id('93bba264-104c-48af-af91-5a79ec3e695e')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_add_share_group_type_access(self):
+ super(ProjectReaderTests, self).test_add_share_group_type_access()
+
+ @decorators.idempotent_id('176b280c-7a46-43ae-8164-3bdd945d2dd4')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_list_share_group_type_access(self):
+ super(ProjectReaderTests, self).test_list_share_group_type_access()
+
+ @decorators.idempotent_id('00caa020-3805-4322-aac1-86d4552268a2')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_remove_share_group_type_access(self):
+ super(ProjectReaderTests, self).test_remove_share_group_type_access()
diff --git a/manila_tempest_tests/tests/rbac/test_share_groups.py b/manila_tempest_tests/tests/rbac/test_share_groups.py
new file mode 100644
index 0000000..b09a5e4
--- /dev/null
+++ b/manila_tempest_tests/tests/rbac/test_share_groups.py
@@ -0,0 +1,474 @@
+# 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.
+
+import abc
+
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import waiters
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests.tests.rbac import base as rbac_base
+
+CONF = config.CONF
+
+
+class ShareRbacShareGroupsTests(rbac_base.ShareRbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareRbacShareGroupsTests, cls).skip_checks()
+ if cls.protocol not in CONF.share.enable_protocols:
+ message = "%s tests are disabled" % cls.protocol
+ raise cls.skipException(message)
+
+ @classmethod
+ def setup_clients(cls):
+ super(ShareRbacShareGroupsTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.share_v2.SharesV2Client()
+ cls.admin_shares_v2_client = (
+ cls.os_project_admin.share_v2.SharesV2Client())
+ cls.alt_project_share_v2_client = (
+ cls.os_project_alt_member.share_v2.SharesV2Client())
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareRbacShareGroupsTests, cls).resource_setup()
+ cls.share_type = cls.create_share_type()
+ cls.share_group_type = cls.create_share_group_type(
+ cls.share_type['id'])
+
+ def share_group(self, share_group_type_id, share_type_ids):
+ share_group = {}
+ share_group['name'] = data_utils.rand_name('share_group')
+ share_group['share_group_type_id'] = share_group_type_id
+ share_group['share_type_ids'] = [share_type_ids]
+ return share_group
+
+ @abc.abstractmethod
+ def test_get_share_group(self):
+ pass
+
+ @abc.abstractmethod
+ def test_list_share_groups(self):
+ pass
+
+ @abc.abstractmethod
+ def test_create_share_group(self):
+ pass
+
+ @abc.abstractmethod
+ def test_delete_share_group(self):
+ pass
+
+ @abc.abstractmethod
+ def test_force_delete_share_group(self):
+ pass
+
+ @abc.abstractmethod
+ def test_update_share_group(self):
+ pass
+
+ @abc.abstractmethod
+ def test_reset_share_group(self):
+ pass
+
+
+class TestProjectAdminTestsNFS(ShareRbacShareGroupsTests, base.BaseSharesTest):
+
+ credentials = ['project_admin', 'project_alt_member']
+ protocol = 'nfs'
+
+ @classmethod
+ def setup_clients(cls):
+ super(TestProjectAdminTestsNFS, cls).setup_clients()
+ project_member = cls.setup_user_client(
+ cls.persona, project_id=cls.persona.credentials.project_id)
+ cls.share_member_client = project_member.share_v2.SharesV2Client()
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('0de993c5-8389-4997-8f7f-345e27f563f1')
+ def test_get_share_group(self):
+ share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'get_share_group', expected_status=200,
+ share_group_id=share_group['id'])
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'get_share_group', expected_status=200,
+ share_group_id=alt_share_group['id'])
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('3b277a44-dcae-46da-a58c-f5281d8abc84')
+ def test_list_share_groups(self):
+ share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+
+ params = {"all_tenants": 1}
+ share_group_list = self.do_request(
+ 'list_share_groups', expected_status=200,
+ params=params)['share_groups']
+ share_group_id_list = [
+ s['id'] for s in share_group_list
+ ]
+
+ self.assertIn(share_group['id'], share_group_id_list)
+ self.assertIn(alt_share_group['id'], share_group_id_list)
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('d060996e-c5f2-4dff-820b-6892a096a425')
+ def test_create_share_group(self):
+ share_group = self.do_request(
+ 'create_share_group', expected_status=202,
+ **self.share_group(self.share_group_type['id'],
+ self.share_type['id']))['share_group']
+ waiters.wait_for_resource_status(
+ self.client, share_group['id'], 'available',
+ resource_name='share_group')
+ self.addCleanup(self.client.wait_for_resource_deletion,
+ share_group_id=share_group['id'])
+ self.addCleanup(self.client.delete_share_group, share_group['id'])
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('ea6cbb78-057e-4fbc-86bf-125b033cb76f')
+ def test_delete_share_group(self):
+ share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'delete_share_group', expected_status=202,
+ share_group_id=share_group['id'])
+ self.client.wait_for_resource_deletion(
+ share_group_id=share_group['id'])
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'delete_share_group', expected_status=202,
+ share_group_id=alt_share_group['id'])
+ self.client.wait_for_resource_deletion(
+ share_group_id=alt_share_group['id'])
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('2cb00ffb-47e3-495e-853c-007752c9e679')
+ def test_force_delete_share_group(self):
+ share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'share_group_force_delete', expected_status=202,
+ share_group_id=share_group['id'])
+ self.client.wait_for_resource_deletion(
+ share_group_id=share_group['id'])
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'share_group_force_delete', expected_status=202,
+ share_group_id=alt_share_group['id'])
+ self.client.wait_for_resource_deletion(
+ share_group_id=alt_share_group['id'])
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('1bab40d5-bdba-4a23-9300-807fe513bf15')
+ def test_update_share_group(self):
+ share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ name = data_utils.rand_name('rename_share')
+ self.do_request(
+ 'update_share_group', expected_status=200,
+ share_group_id=share_group['id'], name=name)
+
+ alt_share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ name = data_utils.rand_name('rename_share')
+ self.do_request(
+ 'update_share_group', expected_status=200,
+ share_group_id=alt_share_group['id'], name=name)
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('069bc68e-6411-44b8-abe9-399885f0eee5')
+ def test_reset_share_group(self):
+ share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'share_group_reset_state', expected_status=202,
+ share_group_id=share_group['id'], status='error')
+
+ alt_share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'share_group_reset_state', expected_status=202,
+ share_group_id=alt_share_group['id'], status='error')
+
+
+class TestProjectMemberTestsNFS(ShareRbacShareGroupsTests,
+ base.BaseSharesTest):
+
+ credentials = ['project_member', 'project_admin', 'project_alt_member']
+ protocol = 'nfs'
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('a29e1a68-220e-40fc-98ea-9092fd256d07')
+ def test_get_share_group(self):
+ share_client = getattr(self, 'share_member_client', self.client)
+ share_group = self.create_share_group(
+ share_client, self.share_group_type['id'], [self.share_type['id']])
+ self.do_request(
+ 'get_share_group', expected_status=200,
+ share_group_id=share_group['id'])
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'get_share_group', expected_status=lib_exc.NotFound,
+ share_group_id=alt_share_group['id'])
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('d9c04932-c47e-46e0-bfcf-79c2af32c4c7')
+ def test_list_share_groups(self):
+ share_client = getattr(self, 'share_member_client', self.client)
+ share_group = self.create_share_group(
+ share_client, self.share_group_type['id'], [self.share_type['id']])
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+
+ params = {"all_tenants": 1}
+ share_group_list = self.do_request(
+ 'list_share_groups', expected_status=200,
+ params=params)['share_groups']
+ share_group_id_list = [
+ s['id'] for s in share_group_list
+ ]
+
+ self.assertIn(share_group['id'], share_group_id_list)
+ self.assertNotIn(alt_share_group['id'], share_group_id_list)
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('ebad2242-1fb5-4d99-9a5a-281c1944e03d')
+ def test_create_share_group(self):
+ share_group = self.do_request(
+ 'create_share_group', expected_status=202,
+ **self.share_group(self.share_group_type['id'],
+ self.share_type['id']))['share_group']
+ waiters.wait_for_resource_status(
+ self.client, share_group['id'], 'available',
+ resource_name='share_group')
+ self.addCleanup(self.client.wait_for_resource_deletion,
+ share_group_id=share_group['id'])
+ self.addCleanup(self.client.delete_share_group, share_group['id'])
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('f5c243e4-5128-4a1c-9a15-8c9f0a44437e')
+ def test_delete_share_group(self):
+ share_group = self.create_share_group(
+ self.client, self.share_group_type['id'], [self.share_type['id']])
+ self.do_request(
+ 'delete_share_group', expected_status=202,
+ share_group_id=share_group['id'])
+ self.client.wait_for_resource_deletion(
+ share_group_id=share_group['id'])
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'delete_share_group', expected_status=lib_exc.NotFound,
+ share_group_id=alt_share_group['id'])
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('36a58d50-1257-479f-80a2-f9b7a00814e2')
+ def test_force_delete_share_group(self):
+ share_client = getattr(self, 'share_member_client', self.client)
+ share_group = self.create_share_group(
+ share_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'share_group_force_delete', expected_status=lib_exc.Forbidden,
+ share_group_id=share_group['id'])
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'share_group_force_delete', expected_status=lib_exc.Forbidden,
+ share_group_id=alt_share_group['id'])
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('cf9e34b6-6c04-4920-a811-2dbcf07ba14e')
+ def test_update_share_group(self):
+ share_group = self.create_share_group(
+ self.client, self.share_group_type['id'], [self.share_type['id']])
+ name = data_utils.rand_name('rename_share')
+ self.do_request(
+ 'update_share_group', expected_status=200,
+ share_group_id=share_group['id'], name=name)
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ name = data_utils.rand_name('rename_share')
+ self.do_request(
+ 'update_share_group', expected_status=lib_exc.NotFound,
+ share_group_id=alt_share_group['id'], name=name)
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('2108c4cd-74e0-467f-823a-e44cf8686afa')
+ def test_reset_share_group(self):
+ share_client = getattr(self, 'share_member_client', self.client)
+ share_group = self.create_share_group(
+ share_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'share_group_reset_state', expected_status=lib_exc.Forbidden,
+ share_group_id=share_group['id'], status='error')
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'share_group_reset_state', expected_status=lib_exc.Forbidden,
+ share_group_id=alt_share_group['id'], status='error')
+
+
+class TestProjectReaderTestsNFS(TestProjectMemberTestsNFS):
+ """Test suite for basic share group operations by reader user
+
+ In order to test certain share operations we must create a share group
+ resource for this. Since reader user is limited in resources creation, we
+ are forced to use admin credentials, so we can test other share operations.
+ In this class we use admin user to create a member user within reader
+ project. That way we can perform a reader actions on this resource.
+ """
+
+ credentials = ['project_reader', 'project_admin', 'project_alt_member']
+
+ @classmethod
+ def setup_clients(cls):
+ super(TestProjectReaderTestsNFS, cls).setup_clients()
+ project_member = cls.setup_user_client(
+ cls.os_project_admin,
+ project_id=cls.persona.credentials.project_id)
+ cls.share_member_client = project_member.share_v2.SharesV2Client()
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('ec0ecbb0-5d45-4624-bb26-8b2e140e2ea9')
+ def test_get_share_group(self):
+ super(TestProjectReaderTestsNFS, self).test_get_share_group()
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('4ac87837-5bdf-4253-ab50-dd6efdcea285')
+ def test_list_share_groups(self):
+ super(TestProjectReaderTestsNFS, self).test_list_share_groups()
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('526dcd91-e789-48f8-b209-c384d77e5803')
+ def test_create_share_group(self):
+ self.do_request(
+ 'create_share_group', expected_status=lib_exc.Forbidden,
+ **self.share_group(self.share_group_type['id'],
+ self.share_type['id']))
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('fdf4d49e-a576-441f-9a3c-e2d58c0d8679')
+ def test_delete_share_group(self):
+ share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'delete_share_group', expected_status=lib_exc.Forbidden,
+ share_group_id=share_group['id'])
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ self.do_request(
+ 'delete_share_group', expected_status=lib_exc.Forbidden,
+ share_group_id=alt_share_group['id'])
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('eddca093-e3a1-4a79-a8c7-8fd04c77b02f')
+ def test_force_delete_share_group(self):
+ super(TestProjectReaderTestsNFS, self).test_force_delete_share_group()
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('4530c19d-0aa5-402e-ac83-a3f2333f6c71')
+ def test_update_share_group(self):
+ share_group = self.create_share_group(
+ self.share_member_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ name = data_utils.rand_name('rename_share')
+ self.do_request(
+ 'update_share_group', expected_status=lib_exc.Forbidden,
+ share_group_id=share_group['id'], name=name)
+
+ alt_share_group = self.create_share_group(
+ self.alt_project_share_v2_client, self.share_group_type['id'],
+ [self.share_type['id']])
+ name = data_utils.rand_name('rename_share')
+ self.do_request(
+ 'update_share_group', expected_status=lib_exc.Forbidden,
+ share_group_id=alt_share_group['id'], name=name)
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('37f23531-69b5-418d-bd91-7913341586ec')
+ def test_reset_share_group(self):
+ super(TestProjectReaderTestsNFS, self).test_reset_share_group()
+
+
+class TestProjectAdminTestsCEPHFS(TestProjectAdminTestsNFS):
+ protocol = 'cephfs'
+
+
+class TestProjectMemberTestsCEPHFS(TestProjectMemberTestsNFS):
+ protocol = 'cephfs'
+
+
+class TestProjectReaderTestsCEPHFS(TestProjectReaderTestsNFS):
+ protocol = 'cephfs'
+
+
+class TestProjectAdminTestsCIFS(TestProjectAdminTestsNFS):
+ protocol = 'cifs'
+
+
+class TestProjectMemberTestsCIFS(TestProjectMemberTestsNFS):
+ protocol = 'cifs'
+
+
+class TestProjectReaderTestsCIFS(TestProjectReaderTestsNFS):
+ protocol = 'cifs'
diff --git a/manila_tempest_tests/tests/rbac/test_shares.py b/manila_tempest_tests/tests/rbac/test_shares.py
index 2ca3c92..b5ea7d9 100644
--- a/manila_tempest_tests/tests/rbac/test_shares.py
+++ b/manila_tempest_tests/tests/rbac/test_shares.py
@@ -420,7 +420,7 @@
alt_share = self.create_share(
self.alt_project_share_v2_client, self.share_type['id'])
self.do_request(
- 'reset_state', expected_status=lib_exc.NotFound,
+ 'reset_state', expected_status=lib_exc.Forbidden,
s_id=alt_share['id'], status="error")
@decorators.idempotent_id('56a07567-d0a9-460a-9267-fcd82306a371')
@@ -465,7 +465,7 @@
alt_share = self.create_share(
self.alt_project_share_v2_client, self.share_type['id'])
self.do_request(
- 'set_metadata', expected_status=lib_exc.Forbidden,
+ 'set_metadata', expected_status=lib_exc.NotFound,
resource_id=alt_share['id'], metadata={'key': 'value'})
@decorators.idempotent_id('a69a2b85-3374-4621-83a9-89937ddb520b')
@@ -482,7 +482,7 @@
self.alt_project_share_v2_client, self.share_type['id'],
metadata=metadata)
self.do_request(
- 'get_metadata', expected_status=lib_exc.Forbidden,
+ 'get_metadata', expected_status=lib_exc.NotFound,
resource_id=alt_share['id'])
@decorators.idempotent_id('bea5518a-338e-494d-9034-1d03658ed58b')
@@ -498,7 +498,7 @@
self.alt_project_share_v2_client, self.share_type['id'],
metadata={'key': 'value'})
self.do_request(
- 'delete_metadata', expected_status=lib_exc.Forbidden,
+ 'delete_metadata', expected_status=lib_exc.NotFound,
resource_id=alt_share['id'], key='key')
@@ -551,7 +551,7 @@
alt_share = self.create_share(
self.alt_project_share_v2_client, self.share_type['id'])
self.do_request(
- 'delete_share', expected_status=lib_exc.NotFound,
+ 'delete_share', expected_status=lib_exc.Forbidden,
share_id=alt_share['id'])
@decorators.idempotent_id('cb040955-5897-409f-aea0-84b6ae16b77e')
@@ -596,7 +596,7 @@
self.alt_project_share_v2_client, self.share_type['id'],
size=CONF.share.share_size + 1)
self.do_request(
- 'shrink_share', expected_status=lib_exc.NotFound,
+ 'shrink_share', expected_status=lib_exc.Forbidden,
share_id=alt_share['id'], new_size=CONF.share.share_size)
@decorators.idempotent_id('0b57aedb-6b68-498f-814e-173c47e6c307')
@@ -612,7 +612,7 @@
alt_share = self.create_share(
self.alt_project_share_v2_client, self.share_type['id'])
self.do_request(
- 'extend_share', expected_status=lib_exc.NotFound,
+ 'extend_share', expected_status=lib_exc.Forbidden,
share_id=alt_share['id'], new_size=CONF.share.share_size + 1)
@decorators.idempotent_id('3def3f4e-33fc-4726-8818-6cffbc2cab51')
diff --git a/manila_tempest_tests/tests/rbac/test_snapshots.py b/manila_tempest_tests/tests/rbac/test_snapshots.py
index 810ba9b..1978415 100644
--- a/manila_tempest_tests/tests/rbac/test_snapshots.py
+++ b/manila_tempest_tests/tests/rbac/test_snapshots.py
@@ -497,7 +497,7 @@
alt_snap = self.create_snapshot(
self.alt_project_share_v2_client, self.alt_share['id'])
self.do_request(
- 'delete_snapshot', expected_status=lib_exc.NotFound,
+ 'delete_snapshot', expected_status=lib_exc.Forbidden,
snap_id=alt_snap['id'])
@decorators.idempotent_id('ed0af390-e3d0-432b-9147-c0d569181b92')
@@ -517,7 +517,7 @@
alt_snap = self.create_snapshot(
self.alt_project_share_v2_client, self.alt_share['id'])
self.do_request(
- 'rename_snapshot', expected_status=lib_exc.NotFound,
+ 'rename_snapshot', expected_status=lib_exc.Forbidden,
snapshot_id=alt_snap['id'], name=name)
@decorators.idempotent_id('b8c9c9a4-3b2a-4b1c-80d8-2ec87d708111')
diff --git a/manila_tempest_tests/tests/scenario/manager.py b/manila_tempest_tests/tests/scenario/manager.py
index a73ab44..fe2833a 100644
--- a/manila_tempest_tests/tests/scenario/manager.py
+++ b/manila_tempest_tests/tests/scenario/manager.py
@@ -16,7 +16,6 @@
from oslo_log import log
from oslo_utils import uuidutils
-from tempest.common import image as common_image
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@@ -45,24 +44,16 @@
'name': name,
'container_format': fmt,
'disk_format': disk_format or fmt,
+ 'visibility': 'private'
}
- if CONF.image_feature_enabled.api_v1:
- params['is_public'] = 'False'
- params['properties'] = properties
- params = {'headers': common_image.image_meta_to_headers(**params)}
- else:
- params['visibility'] = 'private'
- # Additional properties are flattened out in the v2 API.
- params.update(properties)
+ # Additional properties are flattened out in the v2 API.
+ params.update(properties)
body = self.image_client.create_image(**params)
image = body['image'] if 'image' in body else body
self.addCleanup(self.image_client.delete_image, image['id'])
self.assertEqual("queued", image['status'])
with open(path, 'rb') as image_file:
- if CONF.image_feature_enabled.api_v1:
- self.image_client.update_image(image['id'], data=image_file)
- else:
- self.image_client.store_image_file(image['id'], image_file)
+ self.image_client.store_image_file(image['id'], image_file)
return image['id']
def glance_image_create(self):
diff --git a/manila_tempest_tests/tests/scenario/manager_share.py b/manila_tempest_tests/tests/scenario/manager_share.py
index a847217..3e06323 100644
--- a/manila_tempest_tests/tests/scenario/manager_share.py
+++ b/manila_tempest_tests/tests/scenario/manager_share.py
@@ -84,7 +84,7 @@
if CONF.share.image_with_share_tools == 'centos':
self.image_ref = self._create_centos_based_glance_image()
elif CONF.share.image_with_share_tools:
- images = self.compute_images_client.list_images()["images"]
+ images = self.image_client.list_images()["images"]
for img in images:
if img["name"] == CONF.share.image_with_share_tools:
self.image_id = img['id']
@@ -186,8 +186,7 @@
storage_net_nic[0]['addr']
)
# Attach a floating IP
- self.compute_floating_ips_client.associate_floating_ip_to_server(
- floating_ip['floating_ip_address'], instance['id'])
+ self.associate_floating_ip(floating_ip, instance)
self.assertIsNotNone(server_ip)
# Check ssh
@@ -230,8 +229,7 @@
def write_data_to_mounted_share_using_dd(self, remote_client,
output_file,
block_size,
- block_count,
- input_file='/dev/zero'):
+ block_count):
"""Writes data to mounted share using dd command
Example Usage for writing 512Mb to a file on /mnt/
@@ -244,13 +242,12 @@
:param block_size: The size of an individual block in bytes
:param block_count: The number of blocks to write
:param output_file: Path to the file to be written
- :param input_file: Path to the file to read from
"""
block_count = int(block_count)
remote_client.exec_command(
- "sudo sh -c \"dd bs={} count={} if={} of={} conv=fsync"
- " iflag=fullblock\""
- .format(block_size, block_count, input_file, output_file))
+ "sudo sh -c \"dd bs={} count={} if={} of={} iflag=fullblock\""
+ .format(block_size, block_count, CONF.share.dd_input_file,
+ output_file))
def read_data_from_mounted_share(self,
remote_client,
diff --git a/manila_tempest_tests/tests/scenario/test_share_extend.py b/manila_tempest_tests/tests/scenario/test_share_extend.py
index 595ddd4..450d2d4 100644
--- a/manila_tempest_tests/tests/scenario/test_share_extend.py
+++ b/manila_tempest_tests/tests/scenario/test_share_extend.py
@@ -76,8 +76,7 @@
.format(three_quarter_blocks))
self.write_data_to_mounted_share_using_dd(remote_client,
'/mnt/t1', '64M',
- three_quarter_blocks,
- '/dev/urandom')
+ three_quarter_blocks)
ls_result = remote_client.exec_command("sudo ls -lAh /mnt/")
LOG.debug(ls_result)
@@ -86,8 +85,7 @@
self.assertRaises(
exceptions.SSHExecCommandFailed,
self.write_data_to_mounted_share_using_dd,
- remote_client, '/mnt/t2', '64M', over_one_quarter_blocks,
- '/dev/urandom')
+ remote_client, '/mnt/t2', '64M', over_one_quarter_blocks)
ls_result = remote_client.exec_command("sudo ls -lAh /mnt/")
LOG.debug(ls_result)
@@ -129,8 +127,7 @@
self.write_data_to_mounted_share_using_dd(remote_client,
output_file,
block_size,
- block_count,
- '/dev/urandom')
+ block_count)
except exceptions.SSHExecCommandFailed as e:
if 'stale file handle' in str(e).lower():
LOG.warning("Client was disconnected during extend process")
@@ -139,8 +136,7 @@
self.write_data_to_mounted_share_using_dd(remote_client,
output_file,
block_size,
- block_count,
- '/dev/urandom')
+ block_count)
else:
raise
diff --git a/manila_tempest_tests/tests/scenario/test_share_manage_unmanage.py b/manila_tempest_tests/tests/scenario/test_share_manage_unmanage.py
index ef2a6af..bbf5ba6 100644
--- a/manila_tempest_tests/tests/scenario/test_share_manage_unmanage.py
+++ b/manila_tempest_tests/tests/scenario/test_share_manage_unmanage.py
@@ -105,7 +105,7 @@
LOG.debug('Step 6b - writing 640mb')
self.write_data_to_mounted_share_using_dd(remote_client,
'/mnt/t1', 1024,
- 2048, '/dev/zero')
+ 2048)
ls_result = remote_client.exec_command("sudo ls -lA /mnt/")
LOG.debug(ls_result)
diff --git a/manila_tempest_tests/tests/scenario/test_share_shrink.py b/manila_tempest_tests/tests/scenario/test_share_shrink.py
index a4e59e8..fab7e0a 100644
--- a/manila_tempest_tests/tests/scenario/test_share_shrink.py
+++ b/manila_tempest_tests/tests/scenario/test_share_shrink.py
@@ -79,7 +79,7 @@
LOG.debug('Step 6 - writing {} * 64MB blocks'.format(blocks))
self.write_data_to_mounted_share_using_dd(remote_client,
'/mnt/t1', '64M',
- blocks, '/dev/urandom')
+ blocks)
ls_result = remote_client.exec_command("sudo ls -lAh /mnt/")
LOG.debug(ls_result)
@@ -120,7 +120,7 @@
self.assertRaises(
exceptions.SSHExecCommandFailed,
self.write_data_to_mounted_share_using_dd,
- remote_client, '/mnt/t1', '64M', blocks, '/dev/urandom')
+ remote_client, '/mnt/t1', '64M', blocks)
LOG.debug('Step 12 - unmount')
self.unmount_share(remote_client)
diff --git a/playbooks/manila-tempest-plugin-standalone/run.yaml b/playbooks/manila-tempest-plugin-standalone/run.yaml
index 8df9205..26ad69a 100644
--- a/playbooks/manila-tempest-plugin-standalone/run.yaml
+++ b/playbooks/manila-tempest-plugin-standalone/run.yaml
@@ -5,7 +5,6 @@
- hosts: tempest
roles:
- setup-tempest-run-dir
- - set-tempest-config
- setup-tempest-data-dir
- acl-devstack-files
- run-tempest
diff --git a/requirements.txt b/requirements.txt
index 95ad247..108bbee 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,6 +4,6 @@
pbr!=2.1.0,>=2.0.0 # Apache-2.0
-ddt>=1.0.1 # MIT
+ddt>=1.6.0 # MIT
oslo.log>=3.36.0 # Apache-2.0
tempest>=31.1.0 # Apache-2.0
diff --git a/roles/set-tempest-config/README.rst b/roles/set-tempest-config/README.rst
deleted file mode 100644
index 9402d3c..0000000
--- a/roles/set-tempest-config/README.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-set-tempest-config
-==================
-
-This is a workaround for the `merge_config_file <https://opendev
-.org/openstack/devstack/src/commit/76d7d7c90c3979c72404fddd31ee884c8bfdb1ec
-/inc/meta-config#L82>`_ routine that doesn't working correctly on jobs based on
-the "devstack-minimal" profile.
-
-**Role Variables**
-
-.. zuul:rolevar:: devstack_base_dir
- :default: /opt/stack
-
- The devstack base directory.
-
-.. zuul:rolevar:: devstack_local_conf_path
- :default: "{{ devstack_base_dir }}/devstack/local.conf"
-
- Where to find the local.conf file
diff --git a/roles/set-tempest-config/defaults/main.yml b/roles/set-tempest-config/defaults/main.yml
deleted file mode 100644
index 5cc7ca6..0000000
--- a/roles/set-tempest-config/defaults/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-devstack_base_dir: /opt/stack
-devstack_local_conf_path: "{{ devstack_base_dir }}/devstack/local.conf"
diff --git a/roles/set-tempest-config/tasks/main.yml b/roles/set-tempest-config/tasks/main.yml
deleted file mode 100644
index 3572ff5..0000000
--- a/roles/set-tempest-config/tasks/main.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-- name: Install required pip packages
- pip:
- name: devstack-tools
- state: "latest"
- virtualenv: /var/tmp/venv
-
-- name: Copy tempest config
- shell: >-
- . /var/tmp/venv/bin/activate && \
- dsconf extract {{ devstack_local_conf_path }} \
- test-config \
- '$TEMPEST_CONFIG' \
- {{ devstack_base_dir }}/tempest/etc/tempest.conf
- become: yes
diff --git a/setup.py b/setup.py
index 566d844..cd35c3c 100644
--- a/setup.py
+++ b/setup.py
@@ -13,17 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
-# In python < 2.7.4, a lazy loading of package `pbr` will break
-# setuptools if some other modules registered functions in `atexit`.
-# solution from: http://bugs.python.org/issue15881#msg170215
-try:
- import multiprocessing # noqa
-except ImportError:
- pass
-
setuptools.setup(
setup_requires=['pbr>=2.0.0'],
pbr=True)
diff --git a/zuul.d/manila-tempest-jobs.yaml b/zuul.d/manila-tempest-jobs.yaml
index 690b8bc..702dcf8 100644
--- a/zuul.d/manila-tempest-jobs.yaml
+++ b/zuul.d/manila-tempest-jobs.yaml
@@ -157,16 +157,18 @@
backend_names: LONDON,PARIS
multi_backend: true
image_password: manila
+ dd_input_file: /dev/urandom
- job:
name: manila-tempest-plugin-zfsonlinux
description: Test ZFSOnLinux multibackend (DHSS=False) with postgresql db
parent: manila-tempest-plugin-zfsonlinux-base
- branches: &ubuntu_jammy_test_image_branches ^(?!stable/(yoga|xena|wallaby|victoria|ussuri)).*$
+ branches: &ubuntu_jammy_test_image_branches
+ regex: ^stable/(yoga|xena|wallaby|victoria|ussuri)$
+ negate: true
- job:
name: manila-tempest-plugin-lvm-base
- nodeset: openstack-single-node-focal
description: |
Test LVM multibackend (DHSS=False) in a 4+6 (dual-stack) devstack
environment with IPv6 control plane endpoints.
@@ -237,6 +239,14 @@
environment with IPv6 control plane endpoints.
branches: *ubuntu_jammy_test_image_branches
parent: manila-tempest-plugin-lvm-base
+ vars:
+ # TODO(gouthamr): some tests are disabled due to bugs
+ # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
+ # drop these overrides once we address that bug.
+ tempest_exclude_regex: '(^manila_tempest_tests.tests.scenario.*IPv6.*)'
+ devstack_localrc:
+ MANILA_SETUP_IPV6: false
+ NEUTRON_CREATE_INITIAL_NETWORKS: true
- job:
name: manila-tempest-plugin-container
@@ -307,6 +317,7 @@
MANILA_USE_SERVICE_INSTANCE_PASSWORD: true
MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS: 'snapshot_support=True create_share_from_snapshot_support=True'
TEMPEST_USE_TEST_ACCOUNTS: true
+ GLANCE_ENFORCE_SCOPE: false
devstack_services:
cinder: true
devstack_local_conf:
@@ -393,7 +404,6 @@
- job:
name: manila-tempest-plugin-cephfs-native
- nodeset: openstack-single-node-focal
description: Test CephFS Native (DHSS=False)
parent: manila-tempest-plugin-cephfs-native-base
branches: *ubuntu_jammy_test_image_branches
@@ -408,7 +418,6 @@
tempest_exclude_regex: '(^manila_tempest_tests.tests.scenario.*ceph_fuse.*)'
devstack_localrc:
ENABLE_CEPH_NOVA: false
- CONTAINER_IMAGE: 'quay.io/ceph/ceph:v17.2.5'
CEPHADM_DEPLOY: true
CEPHADM_DEV_OSD: true
TARGET_DEV_OSD_DIR: /opt/stack
@@ -481,10 +490,7 @@
vars:
# TODO(gouthamr): some tests are disabled due to bugs
# IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
- # snapshot clone fs sync: https://bugs.launchpad.net/manila/+bug/1989273
- tempest_exclude_regex: "\
- (^manila_tempest_tests.tests.scenario.*IPv6.*)|\
- (^manila_tempest_tests.tests.scenario.test_share_basic_ops.TestShareBasicOpsNFS.test_write_data_to_share_created_from_snapshot)"
+ tempest_exclude_regex: "(^manila_tempest_tests.tests.scenario.*IPv6.*)"
devstack_localrc:
MANILA_OPTGROUP_cephfsnfs_cephfs_ganesha_server_ip: "{{ hostvars[inventory_hostname]['nodepool']['private_ipv4'] }}"
CEPH_RELEASE: "quincy"
@@ -493,6 +499,102 @@
IP_VERSION: 4
- job:
+ name: manila-tempest-plugin-multinode-base
+ abstract: true
+ description: |
+ Base job for testing multinode with Manila. Manila is enabled in
+ the controller node; and we have an additional compute node.
+ parent: tempest-multinode-full-py3
+ timeout: 10800
+ irrelevant-files: *irrelevant-files
+ required-projects: *manila-tempest-required-projects
+ vars:
+ tox_envlist: all
+ tempest_test_regex: manila_tempest_tests
+ tempest_plugins:
+ - manila-tempest-plugin
+ tempest_concurrency: 8
+ devstack_services:
+ cinder: false
+ c-bak: false
+ s-account: false
+ s-container: false
+ s-object: false
+ s-proxy: false
+ horizon: false
+ tls-proxy: true
+ devstack_localrc:
+ MANILA_USE_DOWNGRADE_MIGRATIONS: false
+ MANILA_INSTALL_TEMPEST_PLUGIN_SYSTEMWIDE: false
+ MANILA_ALLOW_NAS_SERVER_PORTS_ON_HOST: true
+ MANILA_SHARE_MIGRATION_PERIOD_TASK_INTERVAL: 1
+ MANILA_SERVER_MIGRATION_PERIOD_TASK_INTERVAL: 10
+ MANILA_REPLICA_STATE_UPDATE_INTERVAL: 10
+ group-vars:
+ tempest:
+ devstack_plugins:
+ manila: https://opendev.org/openstack/manila
+ subnode:
+ devstack_services:
+ cinder: false
+ c-bak: false
+
+- job:
+ name: manila-tempest-plugin-multinode-cephfs-nfs-cephadm
+ description: Test CephFS NFS (DHSS=False) in a Multinode devstack env
+ parent: manila-tempest-plugin-multinode-base
+ required-projects:
+ - openstack/devstack-plugin-ceph
+ vars:
+ configure_swap_size: 8192
+ tempest_concurrency: 2
+ # TODO(gouthamr): some tests are disabled due to bugs
+ # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
+ tempest_exclude_regex: "(^manila_tempest_tests.tests.scenario.*IPv6.*)"
+ devstack_localrc:
+ MYSQL_REDUCE_MEMORY: True
+ CEPHADM_DEPLOY: True
+ CEPHADM_DEV_OSD: true
+ CEPH_LOOPBACK_DISK_SIZE: 40GB
+ ENABLED_SHARE_PROTOCOLS: NFS
+ ENABLE_CEPH_MANILA: True
+ ENABLE_CEPH_NOVA: False
+ MANILA_CEPH_DRIVER: cephfsnfs
+ MANILA_CONFIGURE_DEFAULT_TYPES: true
+ MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS: 'snapshot_support=True create_share_from_snapshot_support=True'
+ MANILA_ENABLED_BACKENDS: cephfsnfs
+ MANILA_OPTGROUP_cephfsnfs_cephfs_auth_id: manila
+ MANILA_OPTGROUP_cephfsnfs_cephfs_conf_path: /etc/ceph/ceph.conf
+ MANILA_OPTGROUP_cephfsnfs_cephfs_nfs_cluster_id: cephfs
+ MANILA_OPTGROUP_cephfsnfs_cephfs_protocol_helper_type: NFS
+ MANILA_OPTGROUP_cephfsnfs_driver_handles_share_servers: false
+ MANILA_OPTGROUP_cephfsnfs_share_driver: manila.share.drivers.cephfs.driver.CephFSDriver
+ MANILA_SERVICE_IMAGE_ENABLED: True
+ MANILA_SETUP_IPV6: false
+ SHARE_DRIVER: manila.share.drivers.cephfs.driver.CephFSDriver
+ TARGET_DEV_OSD_DIR: /opt/stack
+ devstack_local_conf:
+ test-config:
+ $TEMPEST_CONFIG:
+ share:
+ backend_names: cephfsnfs
+ capability_storage_protocol: NFS
+ default_share_type_name: default
+ enable_protocols: nfs
+ image_password: manila
+ multitenancy_enabled: false
+ run_share_group_tests: false
+ group-vars:
+ subnode:
+ devstack_plugins:
+ devstack-plugin-ceph: https://opendev.org/openstack/devstack-plugin-ceph
+ devstack_localrc:
+ REMOTE_CEPH: True
+ tempest:
+ devstack_plugins:
+ devstack-plugin-ceph: https://opendev.org/openstack/devstack-plugin-ceph
+
+- job:
name: manila-tempest-plugin-dummy-no-dhss
description: Test the Dummy driver with DHSS=False
parent: manila-tempest-plugin-standalone-base
@@ -524,6 +626,8 @@
MANILA_OPTGROUP_membernet_standalone_network_plugin_mask: 24
MANILA_OPTGROUP_membernet_standalone_network_plugin_network_type: vlan
MANILA_OPTGROUP_membernet_standalone_network_plugin_segmentation_id: 1010
+ MANILA_CREATE_BACKUP_CONTINUE_TASK_INTERVAL: 30
+ MANILA_RESTORE_BACKUP_CONTINUE_TASK_INTERVAL: 30
devstack_local_conf:
test-config:
"$TEMPEST_CONFIG":
@@ -537,6 +641,7 @@
enable_user_rules_for_protocols: cifs
multi_backend: true
multitenancy_enabled: false
+ run_driver_assisted_backup_tests: true
run_driver_assisted_migration_tests: true
run_manage_unmanage_snapshot_tests: true
run_manage_unmanage_tests: true
@@ -619,7 +724,6 @@
description: |
Test the GlusterFS driver (DHSS=False) with the native GlusterFS protocol
parent: manila-tempest-plugin-standalone-base
- nodeset: openstack-single-node-focal
required-projects:
- x/devstack-plugin-glusterfs
vars:
@@ -652,7 +756,6 @@
description: |
Test the GlusterFS driver (DHSS=False) with the native NFS protocol
parent: manila-tempest-plugin-standalone-base
- nodeset: openstack-single-node-focal
required-projects:
- x/devstack-plugin-glusterfs
vars:
@@ -723,7 +826,9 @@
- job:
name: manila-tempest-plugin-lvm-fips
parent: manila-tempest-plugin-lvm-fips-base
- branches: ^(?!stable/(yoga|xena|wallaby|victoria|ussuri)).*$
+ branches:
+ regex: ^stable/(yoga|xena|wallaby|victoria|ussuri)$
+ negate: true
- project-template:
name: manila-tempest-plugin-jobs-using-service-image
@@ -739,7 +844,7 @@
voting: false
- manila-tempest-plugin-cephfs-native-cephadm:
voting: false
- - manila-tempest-plugin-cephfs-nfs:
+ - manila-tempest-plugin-multinode-cephfs-nfs-cephadm:
voting: false
- manila-tempest-plugin-zfsonlinux:
voting: false
diff --git a/zuul.d/manila-tempest-stable-jobs.yaml b/zuul.d/manila-tempest-stable-jobs.yaml
index 28db229..a6b5e2b 100644
--- a/zuul.d/manila-tempest-stable-jobs.yaml
+++ b/zuul.d/manila-tempest-stable-jobs.yaml
@@ -1,5 +1,5 @@
-# Stable xena / yoga / zed branch jobs to test the trunk version of
-# manila-tempest-plugin against those released stable branches of manila
+# Stable branch jobs to test the trunk version of manila-tempest-plugin
+# against those released stable branches of manila
- job:
name: manila-tempest-plugin-generic-scenario-stable
@@ -7,7 +7,7 @@
Test the scenario test cases on the generic driver multibackend
(DHSS=True) with NFS and CIFS
parent: manila-tempest-plugin-generic-scenario-base
- branches: &manila_tempest_image_pinned_branches ^(stable/(zed|yoga|xena)).*$
+ branches: &manila_tempest_image_pinned_branches ^stable/(2023.1|zed|yoga|xena)$
vars: &manila_tempest_image_pinned_vars
devstack_localrc:
# NOTE(carloss): Pinning manila service image to a Focal version,
@@ -27,15 +27,12 @@
- job:
name: manila-tempest-plugin-lvm-stable
- # NOTE(carloss): we are aware that focal is the current default, but
- # in order to avoid breakages when devstack-minimal switches to a newer
- # branch, we are pinning focal here.
- nodeset: openstack-single-node-focal
description: |
Test LVM multibackend (DHSS=False) in a 4+6 (dual-stack) devstack
environment with IPv6 control plane endpoints.
branches: *manila_tempest_image_pinned_branches
parent: manila-tempest-plugin-lvm-base
+ nodeset: openstack-single-node-focal
vars: *manila_tempest_image_pinned_vars
- job:
@@ -68,21 +65,44 @@
- job:
name: manila-tempest-plugin-lvm-fips-stable
parent: manila-tempest-plugin-lvm-fips-base
- branches: ^(stable/(yoga|xena)).*$
+ branches: ^stable/(yoga|xena)$
vars: *manila_tempest_image_pinned_vars
- job:
- name: manila-tempest-plugin-lvm-yoga
+ name: manila-tempest-plugin-lvm-bobcat
parent: manila-tempest-plugin-lvm-base
- nodeset: openstack-single-node-focal
- override-checkout: stable/yoga
- vars: *manila_tempest_image_pinned_vars
+ override-checkout: stable/2023.2
+ vars:
+ # TODO(gouthamr): some tests are disabled due to bugs
+ # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
+ # drop these overrides once we address that bug.
+ tempest_exclude_regex: '(^manila_tempest_tests.tests.scenario.*IPv6.*)'
+ devstack_localrc:
+ MANILA_SETUP_IPV6: false
+ NEUTRON_CREATE_INITIAL_NETWORKS: true
- job:
- name: manila-tempest-plugin-lvm-xena
+ name: manila-tempest-plugin-lvm-antelope
parent: manila-tempest-plugin-lvm-base
- nodeset: openstack-single-node-focal
- override-checkout: stable/xena
+ override-checkout: stable/2023.1
+ vars:
+ # TODO(gouthamr): some tests are disabled due to bugs
+ # IPv6 Tests: https://bugs.launchpad.net/manila/+bug/1998489
+ # drop these overrides once we address that bug.
+ tempest_exclude_regex: '(^manila_tempest_tests.tests.scenario.*IPv6.*)'
+ devstack_localrc:
+ MANILA_SETUP_IPV6: false
+ NEUTRON_CREATE_INITIAL_NETWORKS: true
+ # NOTE(carloss): Pinning manila service image to a Focal version,
+ # since on Zed we moved to Ubuntu Jammy (22), and it requires more
+ # VM resources.
+ MANILA_SERVICE_IMAGE_URL: https://tarballs.opendev.org/openstack/manila-image-elements/images/manila-service-image-1.3.0-76-ga216835.qcow2
+ MANILA_SERVICE_IMAGE_NAME: manila-service-image-1.3.0-76-ga216835
+
+- job:
+ name: manila-tempest-plugin-lvm-zed
+ parent: manila-tempest-plugin-lvm-base
+ override-checkout: stable/zed
vars: *manila_tempest_image_pinned_vars
- project-template:
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 48d3d4c..06204d6 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -8,8 +8,9 @@
jobs:
- manila-tempest-plugin-dummy-no-dhss
- manila-tempest-plugin-dummy-dhss
- - manila-tempest-plugin-lvm-yoga
- - manila-tempest-plugin-lvm-xena
+ - manila-tempest-plugin-lvm-bobcat
+ - manila-tempest-plugin-lvm-antelope
+ - manila-tempest-plugin-lvm-zed
- manila-tempest-plugin-dummy-no-dhss-rbac
- manila-tempest-plugin-container:
voting: false