diff --git a/cinder_tempest_plugin/rbac/v3/test_volume_types.py b/cinder_tempest_plugin/rbac/v3/test_volume_types.py index cdbc341..dc29424 100644 --- a/cinder_tempest_plugin/rbac/v3/test_volume_types.py +++ b/cinder_tempest_plugin/rbac/v3/test_volume_types.py @@ -20,7 +20,24 @@ class RbacV3VolumeTypesTests(rbac_base.VolumeV3RbacBaseTests): min_microversion = '3.3' - extra_spec_key = 'key1' + extra_specs = { + 'key1': 'value1', + 'multiattach': ' False', + 'volume_backend_name': 'test-backend-name', + 'RESKEY:availability_zones': 'test-az', + 'replication_enabled': ' False' + } + extra_specs_keys = list(extra_specs.keys()) + expected_extra_specs = { + "reader": [ + 'multiattach', 'RESKEY:availability_zones', 'replication_enabled' + ], + "member": [ + 'multiattach', 'RESKEY:availability_zones', 'replication_enabled' + ], + "admin": extra_specs_keys + } + encryption_type_key_cipher = 'cipher' create_kwargs = { 'provider': 'LuksEncryptor', @@ -52,10 +69,9 @@ # create a volume type if not name: name = data_utils.rand_name("volume-type") - extra_specs = {cls.extra_spec_key: 'value1'} params = {'name': name, 'description': "description", - 'extra_specs': extra_specs, + 'extra_specs': cls.extra_specs, 'os-volume-type-access:is_public': True} volume_type = cls.admin_types_client.create_volume_type( **params @@ -74,6 +90,28 @@ return volume_type + def _extra_specs_content_validator(self, client, extra_specs): + """Validation of volume type's extra specs content + + Addition for feature: + https://specs.openstack.org/openstack/cinder-specs/specs/xena/ + expose-cinder-user-visible-extra-specs-spec.html + + This feature allows 'readers' and 'members' to "see" volume type's + extra specs: + 'multiattach', 'RESKEY:availability_zones' and 'replication_enabled' + + Args: + client: Client object to be used + extra_specs: extra_specs dict from response + + Returns: + Boolean: True if lists are equal, false otherwise + """ + role = client.user.split('-')[-1] + return (sorted(list(extra_specs.keys())) == + sorted(self.expected_extra_specs[role])) + def _update_volume_type(self, expected_status): """Update volume type""" self.do_request( @@ -112,30 +150,65 @@ expected_status=expected_status, volume_type_id=self.volume_type['id'] )['extra_specs'] - self.assertIn( - self.extra_spec_key, - list(extra_specs.keys()), - message=f"Key '{self.extra_spec_key}' not found in extra_specs." + self.assertTrue( + self._extra_specs_content_validator( + client=self.client, extra_specs=extra_specs + ) ) def _show_extra_spec_for_volume_type(self, expected_status): """Show extra_spec for a volume type""" - self.do_request( + + # Using 'multiattach' extra spec because all admin, member and readers + # should be able to "see". + spec = self.do_request( method='show_volume_type_extra_specs', expected_status=expected_status, volume_type_id=self.volume_type['id'], - extra_specs_name=self.extra_spec_key + extra_specs_name='multiattach' + ) + self.assertEqual(spec['multiattach'], self.extra_specs['multiattach']) + + # Using 'volume_backend_name' extra spec because only admin should + # "see" it. + role = self.client.user.split('-')[-1] + # 'reader' and 'member' will get 404 (NotFound) if they try to show + # the extra spec 'volume_backend_name' + try: + spec = self.do_request( + method='show_volume_type_extra_specs', + expected_status=expected_status, + volume_type_id=self.volume_type['id'], + extra_specs_name='volume_backend_name' + ) + except exceptions.NotFound: + # NotFound exception should be thrown for + # 'reader' and 'member' only + self.assertNotEqual( + role, 'admin', + "NotFound exception was thrown for admin" + ) + return + + # If no exception thrown, then check the content + # Only admin should reach to this point + self.assertNotIn( + role, ['reader', 'member'], + "NotFound should be thrown for non admin role" + ) + self.assertEqual( + spec['volume_backend_name'], + self.extra_specs['volume_backend_name'] ) def _update_extra_spec_for_volume_type(self, expected_status): """Update extra_spec for a volume type""" - spec_name = self.extra_spec_key - extra_spec = {spec_name: 'updated value'} + extra_spec = {'key1': 'key1 updated value'} self.do_request( method='update_volume_type_extra_specs', expected_status=expected_status, volume_type_id=self.volume_type['id'], - extra_spec_name=spec_name, + extra_spec_name='key1', extra_specs=extra_spec ) @@ -147,15 +220,20 @@ method='delete_volume_type_extra_specs', expected_status=expected_status, volume_type_id=volume_type['id'], - extra_spec_name=self.extra_spec_key + extra_spec_name='key1' ) def _show_volume_type_detail(self, expected_status): """Show volume type""" - self.do_request( + details = self.do_request( method='show_volume_type', expected_status=expected_status, volume_type_id=self.volume_type['id'] + )['volume_type'] + self.assertTrue( + self._extra_specs_content_validator( + client=self.client, extra_specs=details['extra_specs'] + ) ) def _show_default_volume_type(self, expected_status): @@ -181,10 +259,15 @@ def _list_volume_types(self, expected_status): """List all volume types""" - self.do_request( + volume_types = self.do_request( method='list_volume_types', expected_status=expected_status - ) + )['volume_types'] + for volume_type in volume_types: + if volume_type['id'] == self.volume_type['id']: + self._extra_specs_content_validator( + client=self.client, extra_specs=volume_type['extra_specs'] + ) def _create_volume_type(self, expected_status): """Create a volume type""" @@ -275,14 +358,12 @@ expected_status=exceptions.Forbidden ) - @decorators.skip_because(bug='2018467') @decorators.idempotent_id('9499752c-3b27-41a3-8f55-4bdba7297f92') def test_list_all_extra_specs_for_volume_type(self): self._list_all_extra_specs_for_volume_type( expected_status=200 ) - @decorators.skip_because(bug='2018467') @decorators.idempotent_id('a38f7248-3a5b-4e51-8e32-d2dcf9c771ea') def test_show_extra_spec_for_volume_type(self): self._show_extra_spec_for_volume_type(expected_status=200) @@ -364,14 +445,12 @@ expected_status=exceptions.Forbidden ) - @decorators.skip_because(bug='2018467') @decorators.idempotent_id('82fd0d34-17b3-4f45-bd2e-728c9a8bff8c') def test_list_all_extra_specs_for_volume_type(self): self._list_all_extra_specs_for_volume_type( expected_status=200 ) - @decorators.skip_because(bug='2018467') @decorators.idempotent_id('67aa0b40-7c0a-4ae7-8682-fb4f20abd390') def test_show_extra_spec_for_volume_type(self): self._show_extra_spec_for_volume_type(expected_status=200) @@ -457,7 +536,6 @@ expected_status=200 ) - @decorators.skip_because(bug='2018467') @decorators.idempotent_id('a2cca7b6-0af9-47e5-b8c1-4e0f01822d4e') def test_show_extra_spec_for_volume_type(self): self._show_extra_spec_for_volume_type(expected_status=200)