Merge "Test user visible extra spec"
Zuul authored 1 year, 5 months ago
Gerrit Code Review committed 1 year, 5 months ago
| 19 | 19 | class RbacV3VolumeTypesTests(rbac_base.VolumeV3RbacBaseTests): |
| 20 | 20 | |
| 21 | 21 | min_microversion = '3.3' |
| 22 | extra_spec_key = 'key1' | |
| 22 | extra_specs = { | |
| 23 | 'key1': 'value1', | |
| 24 | 'multiattach': '<is> False', | |
| 25 | 'volume_backend_name': 'test-backend-name', | |
| 26 | 'RESKEY:availability_zones': 'test-az', | |
| 27 | 'replication_enabled': '<is> False' | |
| 28 | } | |
| 29 | extra_specs_keys = list(extra_specs.keys()) | |
| 30 | expected_extra_specs = { | |
| 31 | "reader": [ | |
| 32 | 'multiattach', 'RESKEY:availability_zones', 'replication_enabled' | |
| 33 | ], | |
| 34 | "member": [ | |
| 35 | 'multiattach', 'RESKEY:availability_zones', 'replication_enabled' | |
| 36 | ], | |
| 37 | "admin": extra_specs_keys | |
| 38 | } | |
| 39 | ||
| 23 | 40 | encryption_type_key_cipher = 'cipher' |
| 24 | 41 | create_kwargs = { |
| 25 | 42 | 'provider': 'LuksEncryptor', |
| 51 | 68 | # create a volume type |
| 52 | 69 | if not name: |
| 53 | 70 | name = data_utils.rand_name("volume-type") |
| 54 | extra_specs = {cls.extra_spec_key: 'value1'} | |
| 55 | 71 | params = {'name': name, |
| 56 | 72 | 'description': "description", |
| 57 | 'extra_specs': extra_specs, | |
| 73 | 'extra_specs': cls.extra_specs, | |
| 58 | 74 | 'os-volume-type-access:is_public': True} |
| 59 | 75 | volume_type = cls.admin_types_client.create_volume_type( |
| 60 | 76 | **params |
| 73 | 89 | |
| 74 | 90 | return volume_type |
| 75 | 91 | |
| 92 | def _extra_specs_content_validator(self, client, extra_specs): | |
| 93 | """Validation of volume type's extra specs content | |
| 94 | ||
| 95 | Addition for feature: | |
| 96 | https://specs.openstack.org/openstack/cinder-specs/specs/xena/ | |
| 97 | expose-cinder-user-visible-extra-specs-spec.html | |
| 98 | ||
| 99 | This feature allows 'readers' and 'members' to "see" volume type's | |
| 100 | extra specs: | |
| 101 | 'multiattach', 'RESKEY:availability_zones' and 'replication_enabled' | |
| 102 | ||
| 103 | Args: | |
| 104 | client: Client object to be used | |
| 105 | extra_specs: extra_specs dict from response | |
| 106 | ||
| 107 | Returns: | |
| 108 | Boolean: True if lists are equal, false otherwise | |
| 109 | """ | |
| 110 | role = client.user.split('-')[-1] | |
| 111 | return (sorted(list(extra_specs.keys())) == | |
| 112 | sorted(self.expected_extra_specs[role])) | |
| 113 | ||
| 76 | 114 | def _update_volume_type(self, expected_status): |
| 77 | 115 | """Update volume type""" |
| 78 | 116 | self.do_request( |
| 111 | 149 | expected_status=expected_status, |
| 112 | 150 | volume_type_id=self.volume_type['id'] |
| 113 | 151 | )['extra_specs'] |
| 114 | self.assertIn( | |
| 115 | self.extra_spec_key, | |
| 116 | list(extra_specs.keys()), | |
| 117 | message=f"Key '{self.extra_spec_key}' not found in extra_specs." | |
| 152 | self.assertTrue( | |
| 153 | self._extra_specs_content_validator( | |
| 154 | client=self.client, extra_specs=extra_specs | |
| 155 | ) | |
| 118 | 156 | ) |
| 119 | 157 | |
| 120 | 158 | def _show_extra_spec_for_volume_type(self, expected_status): |
| 121 | 159 | """Show extra_spec for a volume type""" |
| 122 | self.do_request( | |
| 160 | ||
| 161 | # Using 'multiattach' extra spec because all admin, member and readers | |
| 162 | # should be able to "see". | |
| 163 | spec = self.do_request( | |
| 123 | 164 | method='show_volume_type_extra_specs', |
| 124 | 165 | expected_status=expected_status, |
| 125 | 166 | volume_type_id=self.volume_type['id'], |
| 126 | extra_specs_name=self.extra_spec_key | |
| 167 | extra_specs_name='multiattach' | |
| 168 | ) | |
| 169 | self.assertEqual(spec['multiattach'], self.extra_specs['multiattach']) | |
| 170 | ||
| 171 | # Using 'volume_backend_name' extra spec because only admin should | |
| 172 | # "see" it. | |
| 173 | role = self.client.user.split('-')[-1] | |
| 174 | # 'reader' and 'member' will get 404 (NotFound) if they try to show | |
| 175 | # the extra spec 'volume_backend_name' | |
| 176 | try: | |
| 177 | spec = self.do_request( | |
| 178 | method='show_volume_type_extra_specs', | |
| 179 | expected_status=expected_status, | |
| 180 | volume_type_id=self.volume_type['id'], | |
| 181 | extra_specs_name='volume_backend_name' | |
| 182 | ) | |
| 183 | except exceptions.NotFound: | |
| 184 | # NotFound exception should be thrown for | |
| 185 | # 'reader' and 'member' only | |
| 186 | self.assertNotEqual( | |
| 187 | role, 'admin', | |
| 188 | "NotFound exception was thrown for admin" | |
| 189 | ) | |
| 190 | return | |
| 191 | ||
| 192 | # If no exception thrown, then check the content | |
| 193 | # Only admin should reach to this point | |
| 194 | self.assertNotIn( | |
| 195 | role, ['reader', 'member'], | |
| 196 | "NotFound should be thrown for non admin role" | |
| 197 | ) | |
| 198 | self.assertEqual( | |
| 199 | spec['volume_backend_name'], | |
| 200 | self.extra_specs['volume_backend_name'] | |
| 127 | 201 | ) |
| 128 | 202 | |
| 129 | 203 | def _update_extra_spec_for_volume_type(self, expected_status): |
| 130 | 204 | """Update extra_spec for a volume type""" |
| 131 | spec_name = self.extra_spec_key | |
| 132 | extra_spec = {spec_name: 'updated value'} | |
| 205 | extra_spec = {'key1': 'key1 updated value'} | |
| 133 | 206 | self.do_request( |
| 134 | 207 | method='update_volume_type_extra_specs', |
| 135 | 208 | expected_status=expected_status, |
| 136 | 209 | volume_type_id=self.volume_type['id'], |
| 137 | extra_spec_name=spec_name, | |
| 210 | extra_spec_name='key1', | |
| 138 | 211 | extra_specs=extra_spec |
| 139 | 212 | ) |
| 140 | 213 | |
| 146 | 219 | method='delete_volume_type_extra_specs', |
| 147 | 220 | expected_status=expected_status, |
| 148 | 221 | volume_type_id=volume_type['id'], |
| 149 | extra_spec_name=self.extra_spec_key | |
| 222 | extra_spec_name='key1' | |
| 150 | 223 | ) |
| 151 | 224 | |
| 152 | 225 | def _show_volume_type_detail(self, expected_status): |
| 153 | 226 | """Show volume type""" |
| 154 | self.do_request( | |
| 227 | details = self.do_request( | |
| 155 | 228 | method='show_volume_type', |
| 156 | 229 | expected_status=expected_status, |
| 157 | 230 | volume_type_id=self.volume_type['id'] |
| 231 | )['volume_type'] | |
| 232 | self.assertTrue( | |
| 233 | self._extra_specs_content_validator( | |
| 234 | client=self.client, extra_specs=details['extra_specs'] | |
| 235 | ) | |
| 158 | 236 | ) |
| 159 | 237 | |
| 160 | 238 | def _show_default_volume_type(self, expected_status): |
| 180 | 258 | |
| 181 | 259 | def _list_volume_types(self, expected_status): |
| 182 | 260 | """List all volume types""" |
| 183 | self.do_request( | |
| 261 | volume_types = self.do_request( | |
| 184 | 262 | method='list_volume_types', |
| 185 | 263 | expected_status=expected_status |
| 186 | ) | |
| 264 | )['volume_types'] | |
| 265 | for volume_type in volume_types: | |
| 266 | if volume_type['id'] == self.volume_type['id']: | |
| 267 | self._extra_specs_content_validator( | |
| 268 | client=self.client, extra_specs=volume_type['extra_specs'] | |
| 269 | ) | |
| 187 | 270 | |
| 188 | 271 | def _create_volume_type(self, expected_status): |
| 189 | 272 | """Create a volume type""" |
| 274 | 357 | expected_status=exceptions.Forbidden |
| 275 | 358 | ) |
| 276 | 359 | |
| 277 | @decorators.skip_because(bug='2018467') | |
| 278 | 360 | @decorators.idempotent_id('9499752c-3b27-41a3-8f55-4bdba7297f92') |
| 279 | 361 | def test_list_all_extra_specs_for_volume_type(self): |
| 280 | 362 | self._list_all_extra_specs_for_volume_type( |
| 281 | 363 | expected_status=200 |
| 282 | 364 | ) |
| 283 | 365 | |
| 284 | @decorators.skip_because(bug='2018467') | |
| 285 | 366 | @decorators.idempotent_id('a38f7248-3a5b-4e51-8e32-d2dcf9c771ea') |
| 286 | 367 | def test_show_extra_spec_for_volume_type(self): |
| 287 | 368 | self._show_extra_spec_for_volume_type(expected_status=200) |
| 363 | 444 | expected_status=exceptions.Forbidden |
| 364 | 445 | ) |
| 365 | 446 | |
| 366 | @decorators.skip_because(bug='2018467') | |
| 367 | 447 | @decorators.idempotent_id('82fd0d34-17b3-4f45-bd2e-728c9a8bff8c') |
| 368 | 448 | def test_list_all_extra_specs_for_volume_type(self): |
| 369 | 449 | self._list_all_extra_specs_for_volume_type( |
| 370 | 450 | expected_status=200 |
| 371 | 451 | ) |
| 372 | 452 | |
| 373 | @decorators.skip_because(bug='2018467') | |
| 374 | 453 | @decorators.idempotent_id('67aa0b40-7c0a-4ae7-8682-fb4f20abd390') |
| 375 | 454 | def test_show_extra_spec_for_volume_type(self): |
| 376 | 455 | self._show_extra_spec_for_volume_type(expected_status=200) |
| 456 | 535 | expected_status=200 |
| 457 | 536 | ) |
| 458 | 537 | |
| 459 | @decorators.skip_because(bug='2018467') | |
| 460 | 538 | @decorators.idempotent_id('a2cca7b6-0af9-47e5-b8c1-4e0f01822d4e') |
| 461 | 539 | def test_show_extra_spec_for_volume_type(self): |
| 462 | 540 | self._show_extra_spec_for_volume_type(expected_status=200) |