Merge "Add tests for share type availability_zones extra-spec"
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index b49fd32..9d891ec 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -30,7 +30,7 @@
help="The minimum api microversion is configured to be the "
"value of the minimum microversion supported by Manila."),
cfg.StrOpt("max_api_microversion",
- default="2.47",
+ default="2.48",
help="The maximum api microversion is configured to be the "
"value of the latest microversion supported by Manila."),
cfg.StrOpt("region",
diff --git a/manila_tempest_tests/tests/api/admin/test_migration_negative.py b/manila_tempest_tests/tests/api/admin/test_migration_negative.py
index c91148b..e8a22b6 100644
--- a/manila_tempest_tests/tests/api/admin/test_migration_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_migration_negative.py
@@ -264,6 +264,19 @@
new_share_type_id=new_type_opposite['share_type']['id'],
new_share_network_id=new_share_network_id)
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @base.skip_if_microversion_lt("2.48")
+ def test_share_type_azs_share_migrate_unsupported_az(self):
+ extra_specs = self.add_extra_specs_to_dict({
+ 'availability_zones': 'non-existent az'})
+ new_share_type = self.create_share_type(
+ name=data_utils.rand_name('share_type_specific_az'),
+ extra_specs=extra_specs, cleanup_in_class=False)
+ self.assertRaises(
+ lib_exc.BadRequest, self.shares_v2_client.migrate_share,
+ self.share['id'], self.dest_pool,
+ new_share_type_id=new_share_type['share_type']['id'])
+
@testtools.skipUnless(CONF.share.run_driver_assisted_migration_tests,
"Driver-assisted migration tests are disabled.")
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
diff --git a/manila_tempest_tests/tests/api/test_replication.py b/manila_tempest_tests/tests/api/test_replication.py
index 41ad287..d827c8d 100644
--- a/manila_tempest_tests/tests/api/test_replication.py
+++ b/manila_tempest_tests/tests/api/test_replication.py
@@ -248,6 +248,28 @@
self.assertEqual(access_to, rules_list[0]["access_to"])
self.assertEqual('ro', rules_list[0]["access_level"])
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @base.skip_if_microversion_not_supported("2.48")
+ def test_share_type_azs_share_replicas(self):
+ az_spec = ', '.join(self.zones)
+ self.admin_shares_v2_client.update_share_type_extra_spec(
+ self.share_type['id'], 'availability_zones', az_spec)
+ self.addCleanup(
+ self.admin_shares_v2_client.delete_share_type_extra_spec,
+ self.share_type['id'], 'availability_zones')
+
+ share = self.create_share(
+ share_type_id=self.share_type['id'], cleanup_in_class=False,
+ availability_zone=self.share_zone)
+ share = self.shares_v2_client.get_share(share['id'])
+ replica = self.create_share_replica(share['id'], self.replica_zone)
+ replica = self.shares_v2_client.get_share_replica(replica['id'])
+
+ self.assertEqual(self.share_zone, share['availability_zone'])
+ self.assertEqual(self.replica_zone, replica['availability_zone'])
+ self.assertIn(share['availability_zone'], self.zones)
+ self.assertIn(replica['availability_zone'], self.zones)
+
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_promote_and_promote_back(self):
# Test promote back and forth between 2 share replicas
diff --git a/manila_tempest_tests/tests/api/test_replication_negative.py b/manila_tempest_tests/tests/api/test_replication_negative.py
index 30feeb6..8e20483 100644
--- a/manila_tempest_tests/tests/api/test_replication_negative.py
+++ b/manila_tempest_tests/tests/api/test_replication_negative.py
@@ -194,6 +194,19 @@
lib_exc.Conflict, self.admin_client.migrate_share,
self.share1['id'], dest_host)
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @base.skip_if_microversion_lt("2.48")
+ def test_try_add_replica_share_type_azs_unsupported_az(self):
+ self.admin_shares_v2_client.update_share_type_extra_spec(
+ self.share_type['id'], 'availability_zones', 'non-existent az')
+ self.addCleanup(
+ self.admin_shares_v2_client.delete_share_type_extra_spec,
+ self.share_type['id'], 'availability_zones')
+ self.assertRaises(lib_exc.BadRequest,
+ self.create_share_replica,
+ self.share1['id'],
+ self.replica_zone)
+
@testtools.skipUnless(CONF.share.run_replication_tests,
'Replication tests are disabled.')
diff --git a/manila_tempest_tests/tests/api/test_share_type_availability_zones.py b/manila_tempest_tests/tests/api/test_share_type_availability_zones.py
new file mode 100644
index 0000000..79678ca
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_type_availability_zones.py
@@ -0,0 +1,143 @@
+# 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 ddt
+from tempest import config
+from tempest.lib.common.utils import data_utils
+import testtools
+
+from manila_tempest_tests.tests.api import base
+
+tc = testtools.testcase
+CONF = config.CONF
+
+
+@base.skip_if_microversion_not_supported("2.48")
+@ddt.ddt
+class ShareTypeAvailabilityZonesTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareTypeAvailabilityZonesTest, cls).resource_setup()
+ cls.share_type = cls._create_share_type()
+ cls.share_type_id = cls.share_type['id']
+ cls.share_group_type = cls._create_share_group_type()
+ cls.share_group_type_id = cls.share_group_type['id']
+ all_azs = cls.get_availability_zones()
+ cls.valid_azs = cls.get_availability_zones_matching_share_type(
+ cls.share_type)
+ cls.invalid_azs = ((set(all_azs) - set(cls.valid_azs))
+ or ['az_that_doesnt_exist'])
+ cls.az_spec = 'availability_zones'
+ cls.valid_azs_spec = ', '.join(cls.valid_azs)
+ cls.invalid_azs_spec = ', '.join(cls.invalid_azs)
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @ddt.data('az1, az2, az 3 ', 'az1,az2,az 3', 'az1 ,az2, az 3')
+ def test_share_type_azs_create_and_get_share_type(self, spec):
+ az_spec = {'availability_zones': spec}
+ extra_specs = self.add_extra_specs_to_dict(az_spec)
+ share_type = self.create_share_type(
+ data_utils.rand_name('az_share_type'),
+ cleanup_in_class=False,
+ extra_specs=extra_specs,
+ client=self.admin_shares_v2_client)['share_type']
+ self.assertEqual(
+ 'az1,az2,az 3', share_type['extra_specs']['availability_zones'])
+
+ share_type = self.admin_shares_v2_client.get_share_type(
+ share_type['id'])['share_type']
+ self.assertEqual(
+ 'az1,az2,az 3', share_type['extra_specs']['availability_zones'])
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @ddt.data('az1', 'az2', 'az 3', 'az1, az 3', 'az 3, az1',
+ 'az2, az 3, az1')
+ def test_share_type_azs_filter_by_availability_zones(self, filter):
+ az_spec = {'availability_zones': 'az1, az2, az 3'}
+ extra_specs = self.add_extra_specs_to_dict(az_spec)
+ share_type_in_specific_azs = self.create_share_type(
+ data_utils.rand_name('support_some_azs_share_type'),
+ cleanup_in_class=False,
+ extra_specs=extra_specs,
+ client=self.admin_shares_v2_client)['share_type']
+
+ extra_specs = self.add_extra_specs_to_dict()
+ share_type_no_az_spec = self.create_share_type(
+ data_utils.rand_name('support_any_az_share_type'),
+ cleanup_in_class=False,
+ extra_specs=extra_specs,
+ client=self.admin_shares_v2_client)['share_type']
+
+ share_types = self.admin_shares_v2_client.list_share_types(
+ params={'extra_specs': {'availability_zones': filter}}
+ )['share_types']
+ share_type_ids = [s['id'] for s in share_types]
+ self.assertIn(share_type_in_specific_azs['id'], share_type_ids)
+ self.assertIn(share_type_no_az_spec['id'], share_type_ids)
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ def test_share_type_azs_old_version_api_ignores_spec(self):
+ """< v2.48, configuring share type AZs shouldn't fail share creation"""
+ # Use valid AZs as share_type's availability_zones
+ self.admin_shares_v2_client.update_share_type_extra_spec(
+ self.share_type_id, self.az_spec, self.valid_azs_spec)
+ self.create_share(share_type_id=self.share_type_id,
+ cleanup_in_class=False, version='2.47')
+
+ # Use invalid AZs as share_type's availability_zones
+ self.admin_shares_v2_client.update_share_type_extra_spec(
+ self.share_type_id, self.az_spec, self.invalid_azs_spec)
+ share = self.create_share(share_type_id=self.share_type_id,
+ cleanup_in_class=False, version='2.47')
+ share = self.shares_v2_client.get_share(share['id'])
+ # Test default scheduler behavior: the share type capabilities should
+ # have ensured the share landed in an AZ that is supported
+ # regardless of the 'availability_zones' extra-spec
+ self.assertIn(share['availability_zone'], self.valid_azs)
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @ddt.data(True, False)
+ def test_share_type_azs_shares_az_in_create_req(self, specify_az):
+ self.admin_shares_v2_client.update_share_type_extra_spec(
+ self.share_type_id, self.az_spec, self.valid_azs_spec)
+ kwargs = {
+ 'share_type_id': self.share_type_id,
+ 'cleanup_in_class': False,
+ 'availability_zone': self.valid_azs[0] if specify_az else None,
+ }
+ share = self.create_share(**kwargs)
+ share = self.shares_v2_client.get_share(share['id'])
+ if specify_az:
+ self.assertEqual(self.valid_azs[0], share['availability_zone'])
+ else:
+ self.assertIn(share['availability_zone'], self.valid_azs)
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @ddt.data(True, False)
+ def test_share_type_azs_share_groups_az_in_create_req(self, specify_az):
+ self.admin_shares_v2_client.update_share_type_extra_spec(
+ self.share_type_id, self.az_spec, self.valid_azs_spec)
+ kwargs = {
+ 'share_group_type_id': self.share_group_type_id,
+ 'share_type_ids': [self.share_type_id],
+ 'cleanup_in_class': False,
+ 'availability_zone': self.valid_azs[0] if specify_az else None,
+ }
+ # Create share group
+ share_group = self.create_share_group(**kwargs)
+ share_group = self.shares_v2_client.get_share_group(share_group['id'])
+ if specify_az:
+ self.assertEqual(self.valid_azs[0],
+ share_group['availability_zone'])
+ else:
+ self.assertIn(share_group['availability_zone'], self.valid_azs)
diff --git a/manila_tempest_tests/tests/api/test_share_type_availability_zones_negative.py b/manila_tempest_tests/tests/api/test_share_type_availability_zones_negative.py
new file mode 100644
index 0000000..0e2d9c7
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_type_availability_zones_negative.py
@@ -0,0 +1,92 @@
+# 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 ddt
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.tests.api import base
+
+
+@base.skip_if_microversion_not_supported("2.48")
+@ddt.ddt
+class ShareTypeAvailabilityZonesNegativeTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareTypeAvailabilityZonesNegativeTest, cls).resource_setup()
+ cls.share_type = cls._create_share_type()
+ cls.share_type_id = cls.share_type['id']
+ cls.share_group_type = cls._create_share_group_type()
+ cls.share_group_type_id = cls.share_group_type['id']
+ all_azs = cls.get_availability_zones()
+ cls.valid_azs = cls.get_availability_zones_matching_share_type(
+ cls.share_type)
+ cls.invalid_azs = ((set(all_azs) - set(cls.valid_azs))
+ or ['az_that_doesnt_exist'])
+ cls.az_spec = 'availability_zones'
+ cls.valid_azs_spec = ', '.join(cls.valid_azs)
+ cls.invalid_azs_spec = ', '.join(cls.invalid_azs)
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @ddt.data('az1, az2, az 3, ', 'az1,,az 3', ',az2, az 3')
+ def test_share_type_azs_create_with_invalid_az_spec(self, spec):
+ az_spec = {'availability_zones': spec}
+ extra_specs = self.add_extra_specs_to_dict(az_spec)
+
+ self.assertRaises(
+ lib_exc.BadRequest,
+ self.create_share_type,
+ data_utils.rand_name('share_type_invalid_az_spec'),
+ cleanup_in_class=False,
+ extra_specs=extra_specs,
+ client=self.admin_shares_v2_client)
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ @base.skip_if_microversion_not_supported("2.48")
+ def test_share_type_azs_filter_by_invalid_azs_extra_spec(self):
+ self.admin_shares_v2_client.update_share_type_extra_spec(
+ self.share_type_id, self.az_spec, self.valid_azs_spec)
+ share_type_no_az_spec = self.create_share_type(
+ data_utils.rand_name('support_any_az_share_type'),
+ cleanup_in_class=False,
+ extra_specs=self.add_extra_specs_to_dict(),
+ client=self.admin_shares_v2_client)['share_type']
+
+ share_types = self.admin_shares_v2_client.list_share_types(params={
+ 'extra_specs': {'availability_zones': self.invalid_azs_spec}}
+ )['share_types']
+ share_type_ids = [s['id'] for s in share_types]
+ self.assertNotIn(self.share_type_id, share_type_ids)
+ self.assertIn(share_type_no_az_spec['id'], share_type_ids)
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_share_type_azs_shares_unsupported_az(self):
+ """Test using an AZ not supported by the share type."""
+ self.admin_shares_v2_client.update_share_type_extra_spec(
+ self.share_type_id, self.az_spec, self.invalid_azs_spec)
+ self.assertRaises(
+ lib_exc.BadRequest, self.create_share,
+ share_type_id=self.share_type_id,
+ availability_zone=self.valid_azs[0],
+ cleanup_in_class=False)
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_share_type_azs_share_groups_unsupported(self):
+ self.admin_shares_v2_client.update_share_type_extra_spec(
+ self.share_type_id, self.az_spec, self.invalid_azs_spec)
+ self.assertRaises(
+ lib_exc.BadRequest, self.create_share_group,
+ share_group_type_id=self.share_group_type_id,
+ share_type_ids=[self.share_type_id],
+ availability_zone=self.valid_azs[0],
+ cleanup_in_class=False)