]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | # -*- coding: utf-8 -*- |
2 | from __future__ import absolute_import | |
3 | ||
9f95a23c | 4 | import base64 |
11fdf7f2 | 5 | import logging |
9f95a23c | 6 | import time |
f67539c2 | 7 | from urllib import parse |
9f95a23c TL |
8 | |
9 | from cryptography.hazmat.backends import default_backend | |
9f95a23c | 10 | from cryptography.hazmat.primitives.hashes import SHA1 |
f67539c2 | 11 | from cryptography.hazmat.primitives.twofactor.totp import TOTP |
11fdf7f2 | 12 | |
f67539c2 | 13 | from .helper import DashboardTestCase, JLeaf, JList, JObj |
11fdf7f2 TL |
14 | |
15 | logger = logging.getLogger(__name__) | |
16 | ||
17 | ||
18 | class RgwTestCase(DashboardTestCase): | |
19 | ||
20 | maxDiff = None | |
21 | create_test_user = False | |
22 | ||
23 | AUTH_ROLES = ['rgw-manager'] | |
24 | ||
25 | @classmethod | |
26 | def setUpClass(cls): | |
27 | super(RgwTestCase, cls).setUpClass() | |
28 | # Create the administrator account. | |
29 | cls._radosgw_admin_cmd([ | |
30 | 'user', 'create', '--uid', 'admin', '--display-name', 'admin', | |
31 | '--system', '--access-key', 'admin', '--secret', 'admin' | |
32 | ]) | |
33 | # Update the dashboard configuration. | |
cd265ab1 TL |
34 | cls._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-secret-key'], 'admin') |
35 | cls._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-access-key'], 'admin') | |
11fdf7f2 TL |
36 | # Create a test user? |
37 | if cls.create_test_user: | |
38 | cls._radosgw_admin_cmd([ | |
39 | 'user', 'create', '--uid', 'teuth-test-user', '--display-name', | |
40 | 'teuth-test-user' | |
41 | ]) | |
42 | cls._radosgw_admin_cmd([ | |
43 | 'caps', 'add', '--uid', 'teuth-test-user', '--caps', | |
44 | 'metadata=write' | |
45 | ]) | |
46 | cls._radosgw_admin_cmd([ | |
47 | 'subuser', 'create', '--uid', 'teuth-test-user', '--subuser', | |
48 | 'teuth-test-subuser', '--access', 'full', '--key-type', 's3', | |
49 | '--access-key', 'xyz123' | |
50 | ]) | |
51 | cls._radosgw_admin_cmd([ | |
52 | 'subuser', 'create', '--uid', 'teuth-test-user', '--subuser', | |
53 | 'teuth-test-subuser2', '--access', 'full', '--key-type', | |
54 | 'swift' | |
55 | ]) | |
56 | ||
57 | @classmethod | |
58 | def tearDownClass(cls): | |
9f95a23c TL |
59 | # Delete administrator account. |
60 | cls._radosgw_admin_cmd(['user', 'rm', '--uid', 'admin']) | |
11fdf7f2 | 61 | if cls.create_test_user: |
9f95a23c | 62 | cls._radosgw_admin_cmd(['user', 'rm', '--uid=teuth-test-user', '--purge-data']) |
11fdf7f2 TL |
63 | super(RgwTestCase, cls).tearDownClass() |
64 | ||
f67539c2 TL |
65 | def get_rgw_user(self, uid, stats=True): |
66 | return self._get('/api/rgw/user/{}?stats={}'.format(uid, stats)) | |
11fdf7f2 TL |
67 | |
68 | ||
69 | class RgwApiCredentialsTest(RgwTestCase): | |
70 | ||
71 | AUTH_ROLES = ['rgw-manager'] | |
72 | ||
522d829b TL |
73 | def test_invalid_credentials(self): |
74 | self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-secret-key'], 'invalid') | |
75 | self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-access-key'], 'invalid') | |
11fdf7f2 | 76 | resp = self._get('/api/rgw/user') |
522d829b | 77 | self.assertStatus(404) |
11fdf7f2 TL |
78 | self.assertIn('detail', resp) |
79 | self.assertIn('component', resp) | |
522d829b | 80 | self.assertIn('Error connecting to Object Gateway', resp['detail']) |
11fdf7f2 TL |
81 | self.assertEqual(resp['component'], 'rgw') |
82 | ||
83 | def test_success(self): | |
522d829b TL |
84 | # Set the default credentials. |
85 | self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-secret-key'], 'admin') | |
86 | self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-access-key'], 'admin') | |
2a845540 | 87 | data = self._get('/ui-api/rgw/status') |
11fdf7f2 TL |
88 | self.assertStatus(200) |
89 | self.assertIn('available', data) | |
90 | self.assertIn('message', data) | |
91 | self.assertTrue(data['available']) | |
92 | ||
11fdf7f2 | 93 | |
e306af50 TL |
94 | class RgwSiteTest(RgwTestCase): |
95 | ||
96 | AUTH_ROLES = ['rgw-manager'] | |
97 | ||
98 | def test_get_placement_targets(self): | |
99 | data = self._get('/api/rgw/site?query=placement-targets') | |
100 | self.assertStatus(200) | |
101 | self.assertSchema(data, JObj({ | |
102 | 'zonegroup': str, | |
103 | 'placement_targets': JList(JObj({ | |
104 | 'name': str, | |
105 | 'data_pool': str | |
106 | })) | |
107 | })) | |
108 | ||
109 | def test_get_realms(self): | |
110 | data = self._get('/api/rgw/site?query=realms') | |
111 | self.assertStatus(200) | |
112 | self.assertSchema(data, JList(str)) | |
113 | ||
114 | ||
11fdf7f2 TL |
115 | class RgwBucketTest(RgwTestCase): |
116 | ||
9f95a23c TL |
117 | _mfa_token_serial = '1' |
118 | _mfa_token_seed = '23456723' | |
1911f103 | 119 | _mfa_token_time_step = 2 |
9f95a23c | 120 | |
11fdf7f2 TL |
121 | AUTH_ROLES = ['rgw-manager'] |
122 | ||
123 | @classmethod | |
124 | def setUpClass(cls): | |
125 | cls.create_test_user = True | |
126 | super(RgwBucketTest, cls).setUpClass() | |
9f95a23c TL |
127 | # Create MFA TOTP token for test user. |
128 | cls._radosgw_admin_cmd([ | |
129 | 'mfa', 'create', '--uid', 'teuth-test-user', '--totp-serial', cls._mfa_token_serial, | |
130 | '--totp-seed', cls._mfa_token_seed, '--totp-seed-type', 'base32', | |
131 | '--totp-seconds', str(cls._mfa_token_time_step), '--totp-window', '1' | |
132 | ]) | |
eafe8130 | 133 | # Create tenanted users. |
11fdf7f2 TL |
134 | cls._radosgw_admin_cmd([ |
135 | 'user', 'create', '--tenant', 'testx', '--uid', 'teuth-test-user', | |
136 | '--display-name', 'tenanted teuth-test-user' | |
137 | ]) | |
eafe8130 | 138 | cls._radosgw_admin_cmd([ |
9f95a23c | 139 | 'user', 'create', '--tenant', 'testx2', '--uid', 'teuth-test-user2', |
eafe8130 TL |
140 | '--display-name', 'tenanted teuth-test-user 2' |
141 | ]) | |
11fdf7f2 TL |
142 | |
143 | @classmethod | |
144 | def tearDownClass(cls): | |
145 | cls._radosgw_admin_cmd( | |
9f95a23c | 146 | ['user', 'rm', '--tenant', 'testx', '--uid=teuth-test-user', '--purge-data']) |
eafe8130 | 147 | cls._radosgw_admin_cmd( |
9f95a23c | 148 | ['user', 'rm', '--tenant', 'testx2', '--uid=teuth-test-user2', '--purge-data']) |
11fdf7f2 TL |
149 | super(RgwBucketTest, cls).tearDownClass() |
150 | ||
9f95a23c TL |
151 | def _get_mfa_token_pin(self): |
152 | totp_key = base64.b32decode(self._mfa_token_seed) | |
153 | totp = TOTP(totp_key, 6, SHA1(), self._mfa_token_time_step, backend=default_backend(), | |
154 | enforce_key_length=False) | |
1911f103 | 155 | time_value = int(time.time()) |
9f95a23c TL |
156 | return totp.generate(time_value) |
157 | ||
11fdf7f2 TL |
158 | def test_all(self): |
159 | # Create a new bucket. | |
160 | self._post( | |
161 | '/api/rgw/bucket', | |
162 | params={ | |
163 | 'bucket': 'teuth-test-bucket', | |
9f95a23c TL |
164 | 'uid': 'admin', |
165 | 'zonegroup': 'default', | |
166 | 'placement_target': 'default-placement' | |
11fdf7f2 TL |
167 | }) |
168 | self.assertStatus(201) | |
169 | data = self.jsonBody() | |
170 | self.assertSchema(data, JObj(sub_elems={ | |
171 | 'bucket_info': JObj(sub_elems={ | |
172 | 'bucket': JObj(allow_unknown=True, sub_elems={ | |
173 | 'name': JLeaf(str), | |
174 | 'bucket_id': JLeaf(str), | |
175 | 'tenant': JLeaf(str) | |
176 | }), | |
177 | 'quota': JObj(sub_elems={}, allow_unknown=True), | |
178 | 'creation_time': JLeaf(str) | |
179 | }, allow_unknown=True) | |
180 | }, allow_unknown=True)) | |
181 | data = data['bucket_info']['bucket'] | |
182 | self.assertEqual(data['name'], 'teuth-test-bucket') | |
183 | self.assertEqual(data['tenant'], '') | |
184 | ||
185 | # List all buckets. | |
a4b75251 | 186 | data = self._get('/api/rgw/bucket', version='1.1') |
11fdf7f2 TL |
187 | self.assertStatus(200) |
188 | self.assertEqual(len(data), 1) | |
189 | self.assertIn('teuth-test-bucket', data) | |
190 | ||
f91f0fd5 | 191 | # List all buckets with stats. |
a4b75251 | 192 | data = self._get('/api/rgw/bucket?stats=true', version='1.1') |
f91f0fd5 TL |
193 | self.assertStatus(200) |
194 | self.assertEqual(len(data), 1) | |
195 | self.assertSchema(data[0], JObj(sub_elems={ | |
196 | 'bid': JLeaf(str), | |
197 | 'bucket': JLeaf(str), | |
198 | 'bucket_quota': JObj(sub_elems={}, allow_unknown=True), | |
199 | 'id': JLeaf(str), | |
200 | 'owner': JLeaf(str), | |
201 | 'usage': JObj(sub_elems={}, allow_unknown=True), | |
202 | 'tenant': JLeaf(str), | |
203 | }, allow_unknown=True)) | |
204 | ||
522d829b | 205 | # List all buckets names without stats. |
a4b75251 | 206 | data = self._get('/api/rgw/bucket?stats=false', version='1.1') |
522d829b TL |
207 | self.assertStatus(200) |
208 | self.assertEqual(data, ['teuth-test-bucket']) | |
209 | ||
11fdf7f2 TL |
210 | # Get the bucket. |
211 | data = self._get('/api/rgw/bucket/teuth-test-bucket') | |
212 | self.assertStatus(200) | |
213 | self.assertSchema(data, JObj(sub_elems={ | |
214 | 'id': JLeaf(str), | |
215 | 'bid': JLeaf(str), | |
216 | 'tenant': JLeaf(str), | |
217 | 'bucket': JLeaf(str), | |
218 | 'bucket_quota': JObj(sub_elems={}, allow_unknown=True), | |
f91f0fd5 TL |
219 | 'owner': JLeaf(str), |
220 | 'mfa_delete': JLeaf(str), | |
221 | 'usage': JObj(sub_elems={}, allow_unknown=True), | |
222 | 'versioning': JLeaf(str) | |
11fdf7f2 TL |
223 | }, allow_unknown=True)) |
224 | self.assertEqual(data['bucket'], 'teuth-test-bucket') | |
225 | self.assertEqual(data['owner'], 'admin') | |
9f95a23c TL |
226 | self.assertEqual(data['placement_rule'], 'default-placement') |
227 | self.assertEqual(data['versioning'], 'Suspended') | |
11fdf7f2 | 228 | |
9f95a23c | 229 | # Update bucket: change owner, enable versioning. |
11fdf7f2 TL |
230 | self._put( |
231 | '/api/rgw/bucket/teuth-test-bucket', | |
232 | params={ | |
233 | 'bucket_id': data['id'], | |
9f95a23c TL |
234 | 'uid': 'teuth-test-user', |
235 | 'versioning_state': 'Enabled' | |
11fdf7f2 TL |
236 | }) |
237 | self.assertStatus(200) | |
238 | data = self._get('/api/rgw/bucket/teuth-test-bucket') | |
239 | self.assertStatus(200) | |
240 | self.assertSchema(data, JObj(sub_elems={ | |
241 | 'owner': JLeaf(str), | |
242 | 'bid': JLeaf(str), | |
243 | 'tenant': JLeaf(str) | |
244 | }, allow_unknown=True)) | |
245 | self.assertEqual(data['owner'], 'teuth-test-user') | |
9f95a23c TL |
246 | self.assertEqual(data['versioning'], 'Enabled') |
247 | ||
248 | # Update bucket: enable MFA Delete. | |
249 | self._put( | |
250 | '/api/rgw/bucket/teuth-test-bucket', | |
251 | params={ | |
252 | 'bucket_id': data['id'], | |
253 | 'uid': 'teuth-test-user', | |
254 | 'versioning_state': 'Enabled', | |
255 | 'mfa_delete': 'Enabled', | |
256 | 'mfa_token_serial': self._mfa_token_serial, | |
257 | 'mfa_token_pin': self._get_mfa_token_pin() | |
258 | }) | |
259 | self.assertStatus(200) | |
260 | data = self._get('/api/rgw/bucket/teuth-test-bucket') | |
261 | self.assertStatus(200) | |
262 | self.assertEqual(data['versioning'], 'Enabled') | |
263 | self.assertEqual(data['mfa_delete'], 'Enabled') | |
264 | ||
265 | # Update bucket: disable versioning & MFA Delete. | |
1911f103 | 266 | time.sleep(self._mfa_token_time_step * 3) # Required to get new TOTP pin. |
9f95a23c TL |
267 | self._put( |
268 | '/api/rgw/bucket/teuth-test-bucket', | |
269 | params={ | |
270 | 'bucket_id': data['id'], | |
271 | 'uid': 'teuth-test-user', | |
272 | 'versioning_state': 'Suspended', | |
273 | 'mfa_delete': 'Disabled', | |
274 | 'mfa_token_serial': self._mfa_token_serial, | |
275 | 'mfa_token_pin': self._get_mfa_token_pin() | |
276 | }) | |
277 | self.assertStatus(200) | |
278 | data = self._get('/api/rgw/bucket/teuth-test-bucket') | |
279 | self.assertStatus(200) | |
280 | self.assertEqual(data['versioning'], 'Suspended') | |
281 | self.assertEqual(data['mfa_delete'], 'Disabled') | |
11fdf7f2 TL |
282 | |
283 | # Delete the bucket. | |
284 | self._delete('/api/rgw/bucket/teuth-test-bucket') | |
285 | self.assertStatus(204) | |
a4b75251 | 286 | data = self._get('/api/rgw/bucket', version='1.1') |
11fdf7f2 TL |
287 | self.assertStatus(200) |
288 | self.assertEqual(len(data), 0) | |
289 | ||
9f95a23c | 290 | def test_crud_w_tenant(self): |
11fdf7f2 TL |
291 | # Create a new bucket. The tenant of the user is used when |
292 | # the bucket is created. | |
293 | self._post( | |
294 | '/api/rgw/bucket', | |
295 | params={ | |
296 | 'bucket': 'teuth-test-bucket', | |
9f95a23c TL |
297 | 'uid': 'testx$teuth-test-user', |
298 | 'zonegroup': 'default', | |
299 | 'placement_target': 'default-placement' | |
11fdf7f2 TL |
300 | }) |
301 | self.assertStatus(201) | |
302 | # It's not possible to validate the result because there | |
303 | # IS NO result object returned by the RGW Admin OPS API | |
304 | # when a tenanted bucket is created. | |
305 | data = self.jsonBody() | |
306 | self.assertIsNone(data) | |
307 | ||
308 | # List all buckets. | |
a4b75251 | 309 | data = self._get('/api/rgw/bucket', version='1.1') |
11fdf7f2 TL |
310 | self.assertStatus(200) |
311 | self.assertEqual(len(data), 1) | |
312 | self.assertIn('testx/teuth-test-bucket', data) | |
313 | ||
9f95a23c TL |
314 | def _verify_tenant_bucket(bucket, tenant, uid): |
315 | full_bucket_name = '{}/{}'.format(tenant, bucket) | |
316 | _data = self._get('/api/rgw/bucket/{}'.format( | |
e306af50 | 317 | parse.quote_plus(full_bucket_name))) |
9f95a23c TL |
318 | self.assertStatus(200) |
319 | self.assertSchema(_data, JObj(sub_elems={ | |
320 | 'owner': JLeaf(str), | |
321 | 'bucket': JLeaf(str), | |
322 | 'tenant': JLeaf(str), | |
323 | 'bid': JLeaf(str) | |
324 | }, allow_unknown=True)) | |
325 | self.assertEqual(_data['owner'], '{}${}'.format(tenant, uid)) | |
326 | self.assertEqual(_data['bucket'], bucket) | |
327 | self.assertEqual(_data['tenant'], tenant) | |
328 | self.assertEqual(_data['bid'], full_bucket_name) | |
329 | return _data | |
330 | ||
11fdf7f2 | 331 | # Get the bucket. |
9f95a23c TL |
332 | data = _verify_tenant_bucket('teuth-test-bucket', 'testx', 'teuth-test-user') |
333 | self.assertEqual(data['placement_rule'], 'default-placement') | |
334 | self.assertEqual(data['versioning'], 'Suspended') | |
11fdf7f2 | 335 | |
9f95a23c | 336 | # Update bucket: different user with different tenant, enable versioning. |
eafe8130 TL |
337 | self._put( |
338 | '/api/rgw/bucket/{}'.format( | |
e306af50 | 339 | parse.quote_plus('testx/teuth-test-bucket')), |
eafe8130 TL |
340 | params={ |
341 | 'bucket_id': data['id'], | |
9f95a23c TL |
342 | 'uid': 'testx2$teuth-test-user2', |
343 | 'versioning_state': 'Enabled' | |
eafe8130 | 344 | }) |
9f95a23c TL |
345 | data = _verify_tenant_bucket('teuth-test-bucket', 'testx2', 'teuth-test-user2') |
346 | self.assertEqual(data['versioning'], 'Enabled') | |
eafe8130 | 347 | |
9f95a23c | 348 | # Change owner to a non-tenanted user |
11fdf7f2 TL |
349 | self._put( |
350 | '/api/rgw/bucket/{}'.format( | |
e306af50 | 351 | parse.quote_plus('testx2/teuth-test-bucket')), |
11fdf7f2 TL |
352 | params={ |
353 | 'bucket_id': data['id'], | |
354 | 'uid': 'admin' | |
355 | }) | |
356 | self.assertStatus(200) | |
9f95a23c | 357 | data = self._get('/api/rgw/bucket/teuth-test-bucket') |
11fdf7f2 TL |
358 | self.assertStatus(200) |
359 | self.assertIn('owner', data) | |
360 | self.assertEqual(data['owner'], 'admin') | |
9f95a23c TL |
361 | self.assertEqual(data['tenant'], '') |
362 | self.assertEqual(data['bucket'], 'teuth-test-bucket') | |
363 | self.assertEqual(data['bid'], 'teuth-test-bucket') | |
364 | self.assertEqual(data['versioning'], 'Enabled') | |
365 | ||
366 | # Change owner back to tenanted user, suspend versioning. | |
367 | self._put( | |
368 | '/api/rgw/bucket/teuth-test-bucket', | |
369 | params={ | |
370 | 'bucket_id': data['id'], | |
371 | 'uid': 'testx$teuth-test-user', | |
372 | 'versioning_state': 'Suspended' | |
373 | }) | |
374 | self.assertStatus(200) | |
375 | data = _verify_tenant_bucket('teuth-test-bucket', 'testx', 'teuth-test-user') | |
376 | self.assertEqual(data['versioning'], 'Suspended') | |
11fdf7f2 TL |
377 | |
378 | # Delete the bucket. | |
379 | self._delete('/api/rgw/bucket/{}'.format( | |
e306af50 | 380 | parse.quote_plus('testx/teuth-test-bucket'))) |
11fdf7f2 | 381 | self.assertStatus(204) |
a4b75251 | 382 | data = self._get('/api/rgw/bucket', version='1.1') |
11fdf7f2 TL |
383 | self.assertStatus(200) |
384 | self.assertEqual(len(data), 0) | |
385 | ||
9f95a23c TL |
386 | def test_crud_w_locking(self): |
387 | # Create | |
388 | self._post('/api/rgw/bucket', | |
389 | params={ | |
390 | 'bucket': 'teuth-test-bucket', | |
391 | 'uid': 'teuth-test-user', | |
392 | 'zonegroup': 'default', | |
393 | 'placement_target': 'default-placement', | |
394 | 'lock_enabled': 'true', | |
395 | 'lock_mode': 'GOVERNANCE', | |
396 | 'lock_retention_period_days': '0', | |
397 | 'lock_retention_period_years': '1' | |
398 | }) | |
399 | self.assertStatus(201) | |
400 | # Read | |
401 | data = self._get('/api/rgw/bucket/teuth-test-bucket') | |
402 | self.assertStatus(200) | |
403 | self.assertSchema( | |
404 | data, | |
405 | JObj(sub_elems={ | |
406 | 'lock_enabled': JLeaf(bool), | |
407 | 'lock_mode': JLeaf(str), | |
408 | 'lock_retention_period_days': JLeaf(int), | |
409 | 'lock_retention_period_years': JLeaf(int) | |
410 | }, | |
f67539c2 | 411 | allow_unknown=True)) |
9f95a23c TL |
412 | self.assertTrue(data['lock_enabled']) |
413 | self.assertEqual(data['lock_mode'], 'GOVERNANCE') | |
414 | self.assertEqual(data['lock_retention_period_days'], 0) | |
415 | self.assertEqual(data['lock_retention_period_years'], 1) | |
416 | # Update | |
417 | self._put('/api/rgw/bucket/teuth-test-bucket', | |
418 | params={ | |
419 | 'bucket_id': data['id'], | |
420 | 'uid': 'teuth-test-user', | |
421 | 'lock_mode': 'COMPLIANCE', | |
422 | 'lock_retention_period_days': '15', | |
423 | 'lock_retention_period_years': '0' | |
424 | }) | |
425 | self.assertStatus(200) | |
426 | data = self._get('/api/rgw/bucket/teuth-test-bucket') | |
427 | self.assertTrue(data['lock_enabled']) | |
428 | self.assertEqual(data['lock_mode'], 'COMPLIANCE') | |
429 | self.assertEqual(data['lock_retention_period_days'], 15) | |
430 | self.assertEqual(data['lock_retention_period_years'], 0) | |
431 | self.assertStatus(200) | |
b3b6e05e TL |
432 | |
433 | # Update: Disabling bucket versioning should fail if object locking enabled | |
434 | self._put('/api/rgw/bucket/teuth-test-bucket', | |
435 | params={ | |
436 | 'bucket_id': data['id'], | |
437 | 'uid': 'teuth-test-user', | |
438 | 'versioning_state': 'Suspended' | |
439 | }) | |
440 | self.assertStatus(409) | |
441 | ||
9f95a23c TL |
442 | # Delete |
443 | self._delete('/api/rgw/bucket/teuth-test-bucket') | |
444 | self.assertStatus(204) | |
445 | ||
11fdf7f2 | 446 | |
9f95a23c | 447 | class RgwDaemonTest(RgwTestCase): |
11fdf7f2 TL |
448 | |
449 | AUTH_ROLES = ['rgw-manager'] | |
450 | ||
451 | @DashboardTestCase.RunAs('test', 'test', [{ | |
452 | 'rgw': ['create', 'update', 'delete'] | |
453 | }]) | |
454 | def test_read_access_permissions(self): | |
455 | self._get('/api/rgw/daemon') | |
456 | self.assertStatus(403) | |
457 | self._get('/api/rgw/daemon/id') | |
458 | self.assertStatus(403) | |
459 | ||
460 | def test_list(self): | |
461 | data = self._get('/api/rgw/daemon') | |
462 | self.assertStatus(200) | |
463 | self.assertEqual(len(data), 1) | |
464 | data = data[0] | |
465 | self.assertIn('id', data) | |
466 | self.assertIn('version', data) | |
467 | self.assertIn('server_hostname', data) | |
f67539c2 TL |
468 | self.assertIn('zonegroup_name', data) |
469 | self.assertIn('zone_name', data) | |
1e59de90 | 470 | self.assertIn('port', data) |
11fdf7f2 TL |
471 | |
472 | def test_get(self): | |
473 | data = self._get('/api/rgw/daemon') | |
474 | self.assertStatus(200) | |
475 | ||
476 | data = self._get('/api/rgw/daemon/{}'.format(data[0]['id'])) | |
477 | self.assertStatus(200) | |
478 | self.assertIn('rgw_metadata', data) | |
479 | self.assertIn('rgw_id', data) | |
480 | self.assertIn('rgw_status', data) | |
481 | self.assertTrue(data['rgw_metadata']) | |
482 | ||
483 | def test_status(self): | |
2a845540 | 484 | data = self._get('/ui-api/rgw/status') |
11fdf7f2 TL |
485 | self.assertStatus(200) |
486 | self.assertIn('available', data) | |
487 | self.assertIn('message', data) | |
488 | self.assertTrue(data['available']) | |
489 | ||
490 | ||
491 | class RgwUserTest(RgwTestCase): | |
492 | ||
493 | AUTH_ROLES = ['rgw-manager'] | |
494 | ||
495 | @classmethod | |
496 | def setUpClass(cls): | |
497 | super(RgwUserTest, cls).setUpClass() | |
498 | ||
499 | def _assert_user_data(self, data): | |
500 | self.assertSchema(data, JObj(sub_elems={ | |
501 | 'caps': JList(JObj(sub_elems={}, allow_unknown=True)), | |
502 | 'display_name': JLeaf(str), | |
503 | 'email': JLeaf(str), | |
504 | 'keys': JList(JObj(sub_elems={}, allow_unknown=True)), | |
505 | 'max_buckets': JLeaf(int), | |
506 | 'subusers': JList(JLeaf(str)), | |
507 | 'suspended': JLeaf(int), | |
508 | 'swift_keys': JList(JObj(sub_elems={}, allow_unknown=True)), | |
509 | 'tenant': JLeaf(str), | |
510 | 'user_id': JLeaf(str), | |
511 | 'uid': JLeaf(str) | |
512 | }, allow_unknown=True)) | |
513 | self.assertGreaterEqual(len(data['keys']), 1) | |
514 | ||
515 | def test_get(self): | |
516 | data = self.get_rgw_user('admin') | |
517 | self.assertStatus(200) | |
518 | self._assert_user_data(data) | |
519 | self.assertEqual(data['user_id'], 'admin') | |
f67539c2 TL |
520 | self.assertTrue(data['stats']) |
521 | self.assertIsInstance(data['stats'], dict) | |
522 | # Test without stats. | |
523 | data = self.get_rgw_user('admin', False) | |
524 | self.assertStatus(200) | |
525 | self._assert_user_data(data) | |
526 | self.assertEqual(data['user_id'], 'admin') | |
11fdf7f2 TL |
527 | |
528 | def test_list(self): | |
529 | data = self._get('/api/rgw/user') | |
530 | self.assertStatus(200) | |
531 | self.assertGreaterEqual(len(data), 1) | |
532 | self.assertIn('admin', data) | |
533 | ||
f6b5b4d7 TL |
534 | def test_get_emails(self): |
535 | data = self._get('/api/rgw/user/get_emails') | |
536 | self.assertStatus(200) | |
537 | self.assertSchema(data, JList(str)) | |
538 | ||
11fdf7f2 TL |
539 | def test_create_get_update_delete(self): |
540 | # Create a new user. | |
541 | self._post('/api/rgw/user', params={ | |
542 | 'uid': 'teuth-test-user', | |
543 | 'display_name': 'display name' | |
544 | }) | |
545 | self.assertStatus(201) | |
546 | data = self.jsonBody() | |
547 | self._assert_user_data(data) | |
548 | self.assertEqual(data['user_id'], 'teuth-test-user') | |
549 | self.assertEqual(data['display_name'], 'display name') | |
550 | ||
551 | # Get the user. | |
552 | data = self.get_rgw_user('teuth-test-user') | |
553 | self.assertStatus(200) | |
554 | self._assert_user_data(data) | |
555 | self.assertEqual(data['tenant'], '') | |
556 | self.assertEqual(data['user_id'], 'teuth-test-user') | |
557 | self.assertEqual(data['uid'], 'teuth-test-user') | |
558 | ||
559 | # Update the user. | |
560 | self._put( | |
561 | '/api/rgw/user/teuth-test-user', | |
562 | params={'display_name': 'new name'}) | |
563 | self.assertStatus(200) | |
564 | data = self.jsonBody() | |
565 | self._assert_user_data(data) | |
566 | self.assertEqual(data['display_name'], 'new name') | |
567 | ||
568 | # Delete the user. | |
569 | self._delete('/api/rgw/user/teuth-test-user') | |
570 | self.assertStatus(204) | |
571 | self.get_rgw_user('teuth-test-user') | |
572 | self.assertStatus(500) | |
573 | resp = self.jsonBody() | |
574 | self.assertIn('detail', resp) | |
575 | self.assertIn('failed request with status code 404', resp['detail']) | |
576 | self.assertIn('"Code":"NoSuchUser"', resp['detail']) | |
577 | self.assertIn('"HostId"', resp['detail']) | |
578 | self.assertIn('"RequestId"', resp['detail']) | |
579 | ||
580 | def test_create_get_update_delete_w_tenant(self): | |
581 | # Create a new user. | |
582 | self._post( | |
583 | '/api/rgw/user', | |
584 | params={ | |
585 | 'uid': 'test01$teuth-test-user', | |
586 | 'display_name': 'display name' | |
587 | }) | |
588 | self.assertStatus(201) | |
589 | data = self.jsonBody() | |
590 | self._assert_user_data(data) | |
591 | self.assertEqual(data['user_id'], 'teuth-test-user') | |
592 | self.assertEqual(data['display_name'], 'display name') | |
593 | ||
594 | # Get the user. | |
595 | data = self.get_rgw_user('test01$teuth-test-user') | |
596 | self.assertStatus(200) | |
597 | self._assert_user_data(data) | |
598 | self.assertEqual(data['tenant'], 'test01') | |
599 | self.assertEqual(data['user_id'], 'teuth-test-user') | |
600 | self.assertEqual(data['uid'], 'test01$teuth-test-user') | |
601 | ||
602 | # Update the user. | |
603 | self._put( | |
604 | '/api/rgw/user/test01$teuth-test-user', | |
605 | params={'display_name': 'new name'}) | |
606 | self.assertStatus(200) | |
607 | data = self.jsonBody() | |
608 | self._assert_user_data(data) | |
609 | self.assertEqual(data['display_name'], 'new name') | |
610 | ||
611 | # Delete the user. | |
612 | self._delete('/api/rgw/user/test01$teuth-test-user') | |
613 | self.assertStatus(204) | |
614 | self.get_rgw_user('test01$teuth-test-user') | |
615 | self.assertStatus(500) | |
616 | resp = self.jsonBody() | |
617 | self.assertIn('detail', resp) | |
618 | self.assertIn('failed request with status code 404', resp['detail']) | |
619 | self.assertIn('"Code":"NoSuchUser"', resp['detail']) | |
620 | self.assertIn('"HostId"', resp['detail']) | |
621 | self.assertIn('"RequestId"', resp['detail']) | |
622 | ||
623 | ||
624 | class RgwUserCapabilityTest(RgwTestCase): | |
625 | ||
626 | AUTH_ROLES = ['rgw-manager'] | |
627 | ||
628 | @classmethod | |
629 | def setUpClass(cls): | |
630 | cls.create_test_user = True | |
631 | super(RgwUserCapabilityTest, cls).setUpClass() | |
632 | ||
633 | def test_set(self): | |
634 | self._post( | |
635 | '/api/rgw/user/teuth-test-user/capability', | |
636 | params={ | |
637 | 'type': 'usage', | |
638 | 'perm': 'read' | |
639 | }) | |
640 | self.assertStatus(201) | |
641 | data = self.jsonBody() | |
642 | self.assertEqual(len(data), 1) | |
643 | data = data[0] | |
644 | self.assertEqual(data['type'], 'usage') | |
645 | self.assertEqual(data['perm'], 'read') | |
646 | ||
647 | # Get the user data to validate the capabilities. | |
648 | data = self.get_rgw_user('teuth-test-user') | |
649 | self.assertStatus(200) | |
650 | self.assertGreaterEqual(len(data['caps']), 1) | |
651 | self.assertEqual(data['caps'][0]['type'], 'usage') | |
652 | self.assertEqual(data['caps'][0]['perm'], 'read') | |
653 | ||
654 | def test_delete(self): | |
655 | self._delete( | |
656 | '/api/rgw/user/teuth-test-user/capability', | |
657 | params={ | |
658 | 'type': 'metadata', | |
659 | 'perm': 'write' | |
660 | }) | |
661 | self.assertStatus(204) | |
662 | ||
663 | # Get the user data to validate the capabilities. | |
664 | data = self.get_rgw_user('teuth-test-user') | |
665 | self.assertStatus(200) | |
666 | self.assertEqual(len(data['caps']), 0) | |
667 | ||
668 | ||
669 | class RgwUserKeyTest(RgwTestCase): | |
670 | ||
671 | AUTH_ROLES = ['rgw-manager'] | |
672 | ||
673 | @classmethod | |
674 | def setUpClass(cls): | |
675 | cls.create_test_user = True | |
676 | super(RgwUserKeyTest, cls).setUpClass() | |
677 | ||
678 | def test_create_s3(self): | |
679 | self._post( | |
680 | '/api/rgw/user/teuth-test-user/key', | |
681 | params={ | |
682 | 'key_type': 's3', | |
683 | 'generate_key': 'false', | |
684 | 'access_key': 'abc987', | |
685 | 'secret_key': 'aaabbbccc' | |
686 | }) | |
687 | data = self.jsonBody() | |
688 | self.assertStatus(201) | |
689 | self.assertGreaterEqual(len(data), 3) | |
690 | key = self.find_object_in_list('access_key', 'abc987', data) | |
691 | self.assertIsInstance(key, object) | |
692 | self.assertEqual(key['secret_key'], 'aaabbbccc') | |
693 | ||
694 | def test_create_swift(self): | |
695 | self._post( | |
696 | '/api/rgw/user/teuth-test-user/key', | |
697 | params={ | |
698 | 'key_type': 'swift', | |
699 | 'subuser': 'teuth-test-subuser', | |
700 | 'generate_key': 'false', | |
701 | 'secret_key': 'xxxyyyzzz' | |
702 | }) | |
703 | data = self.jsonBody() | |
704 | self.assertStatus(201) | |
705 | self.assertGreaterEqual(len(data), 2) | |
706 | key = self.find_object_in_list('secret_key', 'xxxyyyzzz', data) | |
707 | self.assertIsInstance(key, object) | |
708 | ||
709 | def test_delete_s3(self): | |
710 | self._delete( | |
711 | '/api/rgw/user/teuth-test-user/key', | |
712 | params={ | |
713 | 'key_type': 's3', | |
714 | 'access_key': 'xyz123' | |
715 | }) | |
716 | self.assertStatus(204) | |
717 | ||
718 | def test_delete_swift(self): | |
719 | self._delete( | |
720 | '/api/rgw/user/teuth-test-user/key', | |
721 | params={ | |
722 | 'key_type': 'swift', | |
723 | 'subuser': 'teuth-test-user:teuth-test-subuser2' | |
724 | }) | |
725 | self.assertStatus(204) | |
726 | ||
727 | ||
728 | class RgwUserQuotaTest(RgwTestCase): | |
729 | ||
730 | AUTH_ROLES = ['rgw-manager'] | |
731 | ||
732 | @classmethod | |
733 | def setUpClass(cls): | |
734 | cls.create_test_user = True | |
735 | super(RgwUserQuotaTest, cls).setUpClass() | |
736 | ||
737 | def _assert_quota(self, data): | |
738 | self.assertIn('user_quota', data) | |
739 | self.assertIn('max_objects', data['user_quota']) | |
740 | self.assertIn('enabled', data['user_quota']) | |
741 | self.assertIn('max_size_kb', data['user_quota']) | |
742 | self.assertIn('max_size', data['user_quota']) | |
743 | self.assertIn('bucket_quota', data) | |
744 | self.assertIn('max_objects', data['bucket_quota']) | |
745 | self.assertIn('enabled', data['bucket_quota']) | |
746 | self.assertIn('max_size_kb', data['bucket_quota']) | |
747 | self.assertIn('max_size', data['bucket_quota']) | |
748 | ||
749 | def test_get_quota(self): | |
750 | data = self._get('/api/rgw/user/teuth-test-user/quota') | |
751 | self.assertStatus(200) | |
752 | self._assert_quota(data) | |
753 | ||
754 | def test_set_user_quota(self): | |
755 | self._put( | |
756 | '/api/rgw/user/teuth-test-user/quota', | |
757 | params={ | |
758 | 'quota_type': 'user', | |
759 | 'enabled': 'true', | |
760 | 'max_size_kb': 2048, | |
761 | 'max_objects': 101 | |
762 | }) | |
763 | self.assertStatus(200) | |
764 | ||
765 | data = self._get('/api/rgw/user/teuth-test-user/quota') | |
766 | self.assertStatus(200) | |
767 | self._assert_quota(data) | |
768 | self.assertEqual(data['user_quota']['max_objects'], 101) | |
769 | self.assertTrue(data['user_quota']['enabled']) | |
770 | self.assertEqual(data['user_quota']['max_size_kb'], 2048) | |
771 | ||
772 | def test_set_bucket_quota(self): | |
773 | self._put( | |
774 | '/api/rgw/user/teuth-test-user/quota', | |
775 | params={ | |
776 | 'quota_type': 'bucket', | |
777 | 'enabled': 'false', | |
778 | 'max_size_kb': 4096, | |
779 | 'max_objects': 2000 | |
780 | }) | |
781 | self.assertStatus(200) | |
782 | ||
783 | data = self._get('/api/rgw/user/teuth-test-user/quota') | |
784 | self.assertStatus(200) | |
785 | self._assert_quota(data) | |
786 | self.assertEqual(data['bucket_quota']['max_objects'], 2000) | |
787 | self.assertFalse(data['bucket_quota']['enabled']) | |
788 | self.assertEqual(data['bucket_quota']['max_size_kb'], 4096) | |
789 | ||
790 | ||
791 | class RgwUserSubuserTest(RgwTestCase): | |
792 | ||
793 | AUTH_ROLES = ['rgw-manager'] | |
794 | ||
795 | @classmethod | |
796 | def setUpClass(cls): | |
797 | cls.create_test_user = True | |
798 | super(RgwUserSubuserTest, cls).setUpClass() | |
799 | ||
800 | def test_create_swift(self): | |
801 | self._post( | |
802 | '/api/rgw/user/teuth-test-user/subuser', | |
803 | params={ | |
804 | 'subuser': 'tux', | |
805 | 'access': 'readwrite', | |
806 | 'key_type': 'swift' | |
807 | }) | |
39ae355f | 808 | self.assertStatus(200) |
11fdf7f2 TL |
809 | data = self.jsonBody() |
810 | subuser = self.find_object_in_list('id', 'teuth-test-user:tux', data) | |
811 | self.assertIsInstance(subuser, object) | |
812 | self.assertEqual(subuser['permissions'], 'read-write') | |
813 | ||
814 | # Get the user data to validate the keys. | |
815 | data = self.get_rgw_user('teuth-test-user') | |
816 | self.assertStatus(200) | |
817 | key = self.find_object_in_list('user', 'teuth-test-user:tux', | |
818 | data['swift_keys']) | |
819 | self.assertIsInstance(key, object) | |
820 | ||
821 | def test_create_s3(self): | |
822 | self._post( | |
823 | '/api/rgw/user/teuth-test-user/subuser', | |
824 | params={ | |
825 | 'subuser': 'hugo', | |
826 | 'access': 'write', | |
827 | 'generate_secret': 'false', | |
828 | 'access_key': 'yyy', | |
829 | 'secret_key': 'xxx' | |
830 | }) | |
39ae355f | 831 | self.assertStatus(200) |
11fdf7f2 TL |
832 | data = self.jsonBody() |
833 | subuser = self.find_object_in_list('id', 'teuth-test-user:hugo', data) | |
834 | self.assertIsInstance(subuser, object) | |
835 | self.assertEqual(subuser['permissions'], 'write') | |
836 | ||
837 | # Get the user data to validate the keys. | |
838 | data = self.get_rgw_user('teuth-test-user') | |
839 | self.assertStatus(200) | |
840 | key = self.find_object_in_list('user', 'teuth-test-user:hugo', | |
841 | data['keys']) | |
842 | self.assertIsInstance(key, object) | |
843 | self.assertEqual(key['secret_key'], 'xxx') | |
844 | ||
845 | def test_delete_w_purge(self): | |
846 | self._delete( | |
847 | '/api/rgw/user/teuth-test-user/subuser/teuth-test-subuser2') | |
848 | self.assertStatus(204) | |
849 | ||
850 | # Get the user data to check that the keys don't exist anymore. | |
851 | data = self.get_rgw_user('teuth-test-user') | |
852 | self.assertStatus(200) | |
853 | key = self.find_object_in_list( | |
854 | 'user', 'teuth-test-user:teuth-test-subuser2', data['swift_keys']) | |
855 | self.assertIsNone(key) | |
856 | ||
857 | def test_delete_wo_purge(self): | |
858 | self._delete( | |
859 | '/api/rgw/user/teuth-test-user/subuser/teuth-test-subuser', | |
860 | params={'purge_keys': 'false'}) | |
861 | self.assertStatus(204) | |
862 | ||
863 | # Get the user data to check whether they keys still exist. | |
864 | data = self.get_rgw_user('teuth-test-user') | |
865 | self.assertStatus(200) | |
866 | key = self.find_object_in_list( | |
867 | 'user', 'teuth-test-user:teuth-test-subuser', data['keys']) | |
868 | self.assertIsInstance(key, object) |