]> git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/radosgw_admin.py
import quincy beta 17.1.0
[ceph.git] / ceph / qa / tasks / radosgw_admin.py
1 """
2 Rgw admin testing against a running instance
3 """
4 # The test cases in this file have been annotated for inventory.
5 # To extract the inventory (in csv format) use the command:
6 #
7 # grep '^ *# TESTCASE' | sed 's/^ *# TESTCASE //'
8 #
9 # to run this standalone:
10 # python qa/tasks/radosgw_admin.py [--user=uid] --host=host --port=port
11 #
12
13 import json
14 import logging
15 import time
16 import datetime
17 import sys
18
19 from io import StringIO
20 from queue import Queue
21
22 import boto.exception
23 import boto.s3.connection
24 import boto.s3.acl
25
26 import httplib2
27
28 #import pdb
29
30 import tasks.vstart_runner
31 from tasks.rgw import RGWEndpoint
32 from tasks.util.rgw import rgwadmin as tasks_util_rgw_rgwadmin
33 from tasks.util.rgw import get_user_summary, get_user_successful_ops
34
35 log = logging.getLogger(__name__)
36
37 def rgwadmin(*args, **kwargs):
38 ctx = args[0]
39 # Is this a local runner?
40 omit_sudo = hasattr(ctx.rgw, 'omit_sudo') and ctx.rgw.omit_sudo == True
41 omit_tdir = hasattr(ctx.rgw, 'omit_tdir') and ctx.rgw.omit_tdir == True
42 return tasks_util_rgw_rgwadmin(*args, **kwargs, omit_sudo=omit_sudo, omit_tdir=omit_tdir)
43
44 def usage_acc_findentry2(entries, user, add=True):
45 for e in entries:
46 if e['user'] == user:
47 return e
48 if not add:
49 return None
50 e = {'user': user, 'buckets': []}
51 entries.append(e)
52 return e
53 def usage_acc_findsum2(summaries, user, add=True):
54 for e in summaries:
55 if e['user'] == user:
56 return e
57 if not add:
58 return None
59 e = {'user': user, 'categories': [],
60 'total': {'bytes_received': 0,
61 'bytes_sent': 0, 'ops': 0, 'successful_ops': 0 }}
62 summaries.append(e)
63 return e
64 def usage_acc_update2(x, out, b_in, err):
65 x['bytes_sent'] += b_in
66 x['bytes_received'] += out
67 x['ops'] += 1
68 if not err:
69 x['successful_ops'] += 1
70 def usage_acc_validate_fields(r, x, x2, what):
71 q=[]
72 for field in ['bytes_sent', 'bytes_received', 'ops', 'successful_ops']:
73 try:
74 if x2[field] < x[field]:
75 q.append("field %s: %d < %d" % (field, x2[field], x[field]))
76 except Exception as ex:
77 r.append( "missing/bad field " + field + " in " + what + " " + str(ex))
78 return
79 if len(q) > 0:
80 r.append("incomplete counts in " + what + ": " + ", ".join(q))
81 class usage_acc:
82 def __init__(self):
83 self.results = {'entries': [], 'summary': []}
84 def findentry(self, user):
85 return usage_acc_findentry2(self.results['entries'], user)
86 def findsum(self, user):
87 return usage_acc_findsum2(self.results['summary'], user)
88 def e2b(self, e, bucket, add=True):
89 for b in e['buckets']:
90 if b['bucket'] == bucket:
91 return b
92 if not add:
93 return None
94 b = {'bucket': bucket, 'categories': []}
95 e['buckets'].append(b)
96 return b
97 def c2x(self, c, cat, add=True):
98 for x in c:
99 if x['category'] == cat:
100 return x
101 if not add:
102 return None
103 x = {'bytes_received': 0, 'category': cat,
104 'bytes_sent': 0, 'ops': 0, 'successful_ops': 0 }
105 c.append(x)
106 return x
107 def update(self, c, cat, user, out, b_in, err):
108 x = self.c2x(c, cat)
109 usage_acc_update2(x, out, b_in, err)
110 if not err and cat == 'create_bucket' and 'owner' not in x:
111 x['owner'] = user
112 def make_entry(self, cat, bucket, user, out, b_in, err):
113 if cat == 'create_bucket' and err:
114 return
115 e = self.findentry(user)
116 b = self.e2b(e, bucket)
117 self.update(b['categories'], cat, user, out, b_in, err)
118 s = self.findsum(user)
119 x = self.c2x(s['categories'], cat)
120 usage_acc_update2(x, out, b_in, err)
121 x = s['total']
122 usage_acc_update2(x, out, b_in, err)
123 def generate_make_entry(self):
124 return lambda cat,bucket,user,out,b_in,err: self.make_entry(cat, bucket, user, out, b_in, err)
125 def get_usage(self):
126 return self.results
127 def compare_results(self, results):
128 if 'entries' not in results or 'summary' not in results:
129 return ['Missing entries or summary']
130 r = []
131 for e in self.results['entries']:
132 try:
133 e2 = usage_acc_findentry2(results['entries'], e['user'], False)
134 except Exception as ex:
135 r.append("malformed entry looking for user "
136 + e['user'] + " " + str(ex))
137 break
138 if e2 == None:
139 r.append("missing entry for user " + e['user'])
140 continue
141 for b in e['buckets']:
142 c = b['categories']
143 if b['bucket'] == 'nosuchbucket':
144 print("got here")
145 try:
146 b2 = self.e2b(e2, b['bucket'], False)
147 if b2 != None:
148 c2 = b2['categories']
149 except Exception as ex:
150 r.append("malformed entry looking for bucket "
151 + b['bucket'] + " in user " + e['user'] + " " + str(ex))
152 break
153 if b2 == None:
154 r.append("can't find bucket " + b['bucket']
155 + " in user " + e['user'])
156 continue
157 for x in c:
158 try:
159 x2 = self.c2x(c2, x['category'], False)
160 except Exception as ex:
161 r.append("malformed entry looking for "
162 + x['category'] + " in bucket " + b['bucket']
163 + " user " + e['user'] + " " + str(ex))
164 break
165 usage_acc_validate_fields(r, x, x2, "entry: category "
166 + x['category'] + " bucket " + b['bucket']
167 + " in user " + e['user'])
168 for s in self.results['summary']:
169 c = s['categories']
170 try:
171 s2 = usage_acc_findsum2(results['summary'], s['user'], False)
172 except Exception as ex:
173 r.append("malformed summary looking for user " + e['user']
174 + " " + str(ex))
175 break
176 if s2 == None:
177 r.append("missing summary for user " + e['user'] + " " + str(ex))
178 continue
179 try:
180 c2 = s2['categories']
181 except Exception as ex:
182 r.append("malformed summary missing categories for user "
183 + e['user'] + " " + str(ex))
184 break
185 for x in c:
186 try:
187 x2 = self.c2x(c2, x['category'], False)
188 except Exception as ex:
189 r.append("malformed summary looking for "
190 + x['category'] + " user " + e['user'] + " " + str(ex))
191 break
192 usage_acc_validate_fields(r, x, x2, "summary: category "
193 + x['category'] + " in user " + e['user'])
194 x = s['total']
195 try:
196 x2 = s2['total']
197 except Exception as ex:
198 r.append("malformed summary looking for totals for user "
199 + e['user'] + " " + str(ex))
200 break
201 usage_acc_validate_fields(r, x, x2, "summary: totals for user" + e['user'])
202 return r
203
204 def ignore_this_entry(cat, bucket, user, out, b_in, err):
205 pass
206 class requestlog_queue():
207 def __init__(self, add):
208 self.q = Queue(1000)
209 self.adder = add
210 def handle_request_data(self, request, response, error=False):
211 now = datetime.datetime.now()
212 if error:
213 pass
214 elif response.status < 200 or response.status >= 400:
215 error = True
216 self.q.put({'t': now, 'o': request, 'i': response, 'e': error})
217 def clear(self):
218 with self.q.mutex:
219 self.q.queue.clear()
220 def log_and_clear(self, cat, bucket, user, add_entry = None):
221 while not self.q.empty():
222 j = self.q.get()
223 bytes_out = 0
224 if 'Content-Length' in j['o'].headers:
225 bytes_out = int(j['o'].headers['Content-Length'])
226 bytes_in = 0
227 msg = j['i'].msg
228 if 'content-length'in msg:
229 bytes_in = int(msg['content-length'])
230 log.info('RL: %s %s %s bytes_out=%d bytes_in=%d failed=%r'
231 % (cat, bucket, user, bytes_out, bytes_in, j['e']))
232 if add_entry == None:
233 add_entry = self.adder
234 add_entry(cat, bucket, user, bytes_out, bytes_in, j['e'])
235
236 def create_presigned_url(conn, method, bucket_name, key_name, expiration):
237 return conn.generate_url(expires_in=expiration,
238 method=method,
239 bucket=bucket_name,
240 key=key_name,
241 query_auth=True,
242 )
243
244 def send_raw_http_request(conn, method, bucket_name, key_name, follow_redirects = False):
245 url = create_presigned_url(conn, method, bucket_name, key_name, 3600)
246 print(url)
247 h = httplib2.Http()
248 h.follow_redirects = follow_redirects
249 return h.request(url, method)
250
251
252 def get_acl(key):
253 """
254 Helper function to get the xml acl from a key, ensuring that the xml
255 version tag is removed from the acl response
256 """
257 raw_acl = key.get_xml_acl().decode()
258
259 def remove_version(string):
260 return string.split(
261 '<?xml version="1.0" encoding="UTF-8"?>'
262 )[-1]
263
264 def remove_newlines(string):
265 return string.strip('\n')
266
267 return remove_version(
268 remove_newlines(raw_acl)
269 )
270
271 def cleanup(ctx, client):
272 # remove objects and buckets
273 (err, out) = rgwadmin(ctx, client, ['bucket', 'list'], check_status=True)
274 try:
275 for bucket in out:
276 (err, out) = rgwadmin(ctx, client, [
277 'bucket', 'rm', '--bucket', bucket, '--purge-objects'],
278 check_status=True)
279 except:
280 pass
281
282 # remove test user(s)
283 users = ['foo', 'fud', 'bar', 'bud']
284 users.reverse()
285 for user in users:
286 try:
287 (err, out) = rgwadmin(ctx, client, [
288 'user', 'rm', '--uid', user],
289 check_status=True)
290 except:
291 pass
292
293 # remove custom placement
294 try:
295 zonecmd = ['zone', 'placement', 'rm', '--rgw-zone', 'default',
296 '--placement-id', 'new-placement']
297 (err, out) = rgwadmin(ctx, client, zonecmd, check_status=True)
298 except:
299 pass
300
301 def task(ctx, config):
302 """
303 Test radosgw-admin functionality against a running rgw instance.
304 """
305 global log
306
307 assert ctx.rgw.config, \
308 "radosgw_admin task needs a config passed from the rgw task"
309 config = ctx.rgw.config
310 log.debug('config is: %r', config)
311
312 clients_from_config = config.keys()
313
314 # choose first client as default
315 client = next(iter(clients_from_config))
316
317 # once the client is chosen, pull the host name and assigned port out of
318 # the role_endpoints that were assigned by the rgw task
319 endpoint = ctx.rgw.role_endpoints[client]
320
321 cleanup(ctx, client)
322
323 ##
324 user1='foo'
325 user2='fud'
326 user3='bar'
327 user4='bud'
328 subuser1='foo:foo1'
329 subuser2='foo:foo2'
330 display_name1='Foo'
331 display_name2='Fud'
332 display_name3='Bar'
333 email='foo@foo.com'
334 access_key='9te6NH5mcdcq0Tc5i8i1'
335 secret_key='Ny4IOauQoL18Gp2zM7lC1vLmoawgqcYP/YGcWfXu'
336 access_key2='p5YnriCv1nAtykxBrupQ'
337 secret_key2='Q8Tk6Q/27hfbFSYdSkPtUqhqx1GgzvpXa4WARozh'
338 access_key3='NX5QOQKC6BH2IDN8HC7A'
339 secret_key3='LnEsqNNqZIpkzauboDcLXLcYaWwLQ3Kop0zAnKIn'
340 swift_secret1='gpS2G9RREMrnbqlp29PP2D36kgPR1tm72n5fPYfL'
341 swift_secret2='ri2VJQcKSYATOY6uaDUX7pxgkW+W1YmC6OCxPHwy'
342
343 bucket_name='myfoo'
344 bucket_name2='mybar'
345
346 # connect to rgw
347 connection = boto.s3.connection.S3Connection(
348 aws_access_key_id=access_key,
349 aws_secret_access_key=secret_key,
350 is_secure=False,
351 port=endpoint.port,
352 host=endpoint.hostname,
353 calling_format=boto.s3.connection.OrdinaryCallingFormat(),
354 )
355 connection.auth_region_name='us-east-1'
356
357 connection2 = boto.s3.connection.S3Connection(
358 aws_access_key_id=access_key2,
359 aws_secret_access_key=secret_key2,
360 is_secure=False,
361 port=endpoint.port,
362 host=endpoint.hostname,
363 calling_format=boto.s3.connection.OrdinaryCallingFormat(),
364 )
365 connection2.auth_region_name='us-east-1'
366
367 connection3 = boto.s3.connection.S3Connection(
368 aws_access_key_id=access_key3,
369 aws_secret_access_key=secret_key3,
370 is_secure=False,
371 port=endpoint.port,
372 host=endpoint.hostname,
373 calling_format=boto.s3.connection.OrdinaryCallingFormat(),
374 )
375 connection3.auth_region_name='us-east-1'
376
377 acc = usage_acc()
378 rl = requestlog_queue(acc.generate_make_entry())
379 connection.set_request_hook(rl)
380 connection2.set_request_hook(rl)
381 connection3.set_request_hook(rl)
382
383 # legend (test cases can be easily grep-ed out)
384 # TESTCASE 'testname','object','method','operation','assertion'
385
386 # TESTCASE 'usage-show0' 'usage' 'show' 'all usage' 'succeeds'
387 (err, summary0) = rgwadmin(ctx, client, ['usage', 'show'], check_status=True)
388
389 # TESTCASE 'info-nosuch','user','info','non-existent user','fails'
390 (err, out) = rgwadmin(ctx, client, ['user', 'info', '--uid', user1])
391 assert err
392
393 # TESTCASE 'create-ok','user','create','w/all valid info','succeeds'
394 (err, out) = rgwadmin(ctx, client, [
395 'user', 'create',
396 '--uid', user1,
397 '--display-name', display_name1,
398 '--email', email,
399 '--access-key', access_key,
400 '--secret', secret_key,
401 '--max-buckets', '4'
402 ],
403 check_status=True)
404
405 # TESTCASE 'duplicate email','user','create','existing user email','fails'
406 (err, out) = rgwadmin(ctx, client, [
407 'user', 'create',
408 '--uid', user2,
409 '--display-name', display_name2,
410 '--email', email,
411 ])
412 assert err
413
414 # TESTCASE 'info-existing','user','info','existing user','returns correct info'
415 (err, out) = rgwadmin(ctx, client, ['user', 'info', '--uid', user1], check_status=True)
416 assert out['user_id'] == user1
417 assert out['email'] == email
418 assert out['display_name'] == display_name1
419 assert len(out['keys']) == 1
420 assert out['keys'][0]['access_key'] == access_key
421 assert out['keys'][0]['secret_key'] == secret_key
422 assert not out['suspended']
423
424 # TESTCASE 'suspend-ok','user','suspend','active user','succeeds'
425 (err, out) = rgwadmin(ctx, client, ['user', 'suspend', '--uid', user1],
426 check_status=True)
427
428 # TESTCASE 'suspend-suspended','user','suspend','suspended user','succeeds w/advisory'
429 (err, out) = rgwadmin(ctx, client, ['user', 'info', '--uid', user1], check_status=True)
430 assert out['suspended']
431
432 # TESTCASE 're-enable','user','enable','suspended user','succeeds'
433 (err, out) = rgwadmin(ctx, client, ['user', 'enable', '--uid', user1], check_status=True)
434
435 # TESTCASE 'info-re-enabled','user','info','re-enabled user','no longer suspended'
436 (err, out) = rgwadmin(ctx, client, ['user', 'info', '--uid', user1], check_status=True)
437 assert not out['suspended']
438
439 # TESTCASE 'add-keys','key','create','w/valid info','succeeds'
440 (err, out) = rgwadmin(ctx, client, [
441 'key', 'create', '--uid', user1,
442 '--access-key', access_key2, '--secret', secret_key2,
443 ], check_status=True)
444
445 # TESTCASE 'info-new-key','user','info','after key addition','returns all keys'
446 (err, out) = rgwadmin(ctx, client, ['user', 'info', '--uid', user1],
447 check_status=True)
448 assert len(out['keys']) == 2
449 assert out['keys'][0]['access_key'] == access_key2 or out['keys'][1]['access_key'] == access_key2
450 assert out['keys'][0]['secret_key'] == secret_key2 or out['keys'][1]['secret_key'] == secret_key2
451
452 # TESTCASE 'rm-key','key','rm','newly added key','succeeds, key is removed'
453 (err, out) = rgwadmin(ctx, client, [
454 'key', 'rm', '--uid', user1,
455 '--access-key', access_key2,
456 ], check_status=True)
457 assert len(out['keys']) == 1
458 assert out['keys'][0]['access_key'] == access_key
459 assert out['keys'][0]['secret_key'] == secret_key
460
461 # TESTCASE 'add-swift-key','key','create','swift key','succeeds'
462 subuser_access = 'full'
463 subuser_perm = 'full-control'
464
465 (err, out) = rgwadmin(ctx, client, [
466 'subuser', 'create', '--subuser', subuser1,
467 '--access', subuser_access
468 ], check_status=True)
469
470 # TESTCASE 'add-swift-key','key','create','swift key','succeeds'
471 (err, out) = rgwadmin(ctx, client, [
472 'subuser', 'modify', '--subuser', subuser1,
473 '--secret', swift_secret1,
474 '--key-type', 'swift',
475 ], check_status=True)
476
477 # TESTCASE 'subuser-perm-mask', 'subuser', 'info', 'test subuser perm mask durability', 'succeeds'
478 (err, out) = rgwadmin(ctx, client, ['user', 'info', '--uid', user1])
479
480 assert out['subusers'][0]['permissions'] == subuser_perm
481
482 # TESTCASE 'info-swift-key','user','info','after key addition','returns all keys'
483 (err, out) = rgwadmin(ctx, client, ['user', 'info', '--uid', user1], check_status=True)
484 assert len(out['swift_keys']) == 1
485 assert out['swift_keys'][0]['user'] == subuser1
486 assert out['swift_keys'][0]['secret_key'] == swift_secret1
487
488 # TESTCASE 'add-swift-subuser','key','create','swift sub-user key','succeeds'
489 (err, out) = rgwadmin(ctx, client, [
490 'subuser', 'create', '--subuser', subuser2,
491 '--secret', swift_secret2,
492 '--key-type', 'swift',
493 ], check_status=True)
494
495 # TESTCASE 'info-swift-subuser','user','info','after key addition','returns all sub-users/keys'
496 (err, out) = rgwadmin(ctx, client, ['user', 'info', '--uid', user1], check_status=True)
497 assert len(out['swift_keys']) == 2
498 assert out['swift_keys'][0]['user'] == subuser2 or out['swift_keys'][1]['user'] == subuser2
499 assert out['swift_keys'][0]['secret_key'] == swift_secret2 or out['swift_keys'][1]['secret_key'] == swift_secret2
500
501 # TESTCASE 'rm-swift-key1','key','rm','subuser','succeeds, one key is removed'
502 (err, out) = rgwadmin(ctx, client, [
503 'key', 'rm', '--subuser', subuser1,
504 '--key-type', 'swift',
505 ], check_status=True)
506 assert len(out['swift_keys']) == 1
507
508 # TESTCASE 'rm-subuser','subuser','rm','subuser','success, subuser is removed'
509 (err, out) = rgwadmin(ctx, client, [
510 'subuser', 'rm', '--subuser', subuser1,
511 ], check_status=True)
512 assert len(out['subusers']) == 1
513
514 # TESTCASE 'rm-subuser-with-keys','subuser','rm','subuser','succeeds, second subser and key is removed'
515 (err, out) = rgwadmin(ctx, client, [
516 'subuser', 'rm', '--subuser', subuser2,
517 '--key-type', 'swift', '--purge-keys',
518 ], check_status=True)
519 assert len(out['swift_keys']) == 0
520 assert len(out['subusers']) == 0
521
522 # TESTCASE 'bucket-stats','bucket','stats','no session/buckets','succeeds, empty list'
523 (err, out) = rgwadmin(ctx, client, ['bucket', 'stats', '--uid', user1],
524 check_status=True)
525 assert len(out) == 0
526
527 # TESTCASE 'bucket-stats2','bucket','stats','no buckets','succeeds, empty list'
528 (err, out) = rgwadmin(ctx, client, ['bucket', 'list', '--uid', user1], check_status=True)
529 assert len(out) == 0
530
531 # create a first bucket
532 bucket = connection.create_bucket(bucket_name)
533
534 rl.log_and_clear("create_bucket", bucket_name, user1)
535
536 # TESTCASE 'bucket-list','bucket','list','one bucket','succeeds, expected list'
537 (err, out) = rgwadmin(ctx, client, ['bucket', 'list', '--uid', user1], check_status=True)
538 assert len(out) == 1
539 assert out[0] == bucket_name
540
541 bucket_list = connection.get_all_buckets()
542 assert len(bucket_list) == 1
543 assert bucket_list[0].name == bucket_name
544
545 rl.log_and_clear("list_buckets", '', user1)
546
547 # TESTCASE 'bucket-list-all','bucket','list','all buckets','succeeds, expected list'
548 (err, out) = rgwadmin(ctx, client, ['bucket', 'list'], check_status=True)
549 assert len(out) >= 1
550 assert bucket_name in out;
551
552 # TESTCASE 'max-bucket-limit,'bucket','create','4 buckets','5th bucket fails due to max buckets == 4'
553 bucket2 = connection.create_bucket(bucket_name + '2')
554 rl.log_and_clear("create_bucket", bucket_name + '2', user1)
555 bucket3 = connection.create_bucket(bucket_name + '3')
556 rl.log_and_clear("create_bucket", bucket_name + '3', user1)
557 bucket4 = connection.create_bucket(bucket_name + '4')
558 rl.log_and_clear("create_bucket", bucket_name + '4', user1)
559 # the 5th should fail.
560 failed = False
561 try:
562 connection.create_bucket(bucket_name + '5')
563 except Exception:
564 failed = True
565 assert failed
566 rl.log_and_clear("create_bucket", bucket_name + '5', user1)
567
568 # delete the buckets
569 bucket2.delete()
570 rl.log_and_clear("delete_bucket", bucket_name + '2', user1)
571 bucket3.delete()
572 rl.log_and_clear("delete_bucket", bucket_name + '3', user1)
573 bucket4.delete()
574 rl.log_and_clear("delete_bucket", bucket_name + '4', user1)
575
576 # TESTCASE 'bucket-stats3','bucket','stats','new empty bucket','succeeds, empty list'
577 (err, out) = rgwadmin(ctx, client, [
578 'bucket', 'stats', '--bucket', bucket_name], check_status=True)
579 assert out['owner'] == user1
580 bucket_id = out['id']
581
582 # TESTCASE 'bucket-stats4','bucket','stats','new empty bucket','succeeds, expected bucket ID'
583 (err, out) = rgwadmin(ctx, client, ['bucket', 'stats', '--uid', user1], check_status=True)
584 assert len(out) == 1
585 assert out[0]['id'] == bucket_id # does it return the same ID twice in a row?
586
587 # use some space
588 key = boto.s3.key.Key(bucket)
589 key.set_contents_from_string('one')
590 rl.log_and_clear("put_obj", bucket_name, user1)
591
592 # TESTCASE 'bucket-stats5','bucket','stats','after creating key','succeeds, lists one non-empty object'
593 (err, out) = rgwadmin(ctx, client, [
594 'bucket', 'stats', '--bucket', bucket_name], check_status=True)
595 assert out['id'] == bucket_id
596 assert out['usage']['rgw.main']['num_objects'] == 1
597 assert out['usage']['rgw.main']['size_kb'] > 0
598
599 #validate we have a positive user stats now
600 (err, out) = rgwadmin(ctx, client,
601 ['user', 'stats','--uid', user1, '--sync-stats'],
602 check_status=True)
603 assert out['stats']['size'] > 0
604
605 # reclaim it
606 key.delete()
607 rl.log_and_clear("delete_obj", bucket_name, user1)
608
609 # TESTCASE 'bucket unlink', 'bucket', 'unlink', 'unlink bucket from user', 'fails', 'access denied error'
610 (err, out) = rgwadmin(ctx, client,
611 ['bucket', 'unlink', '--uid', user1, '--bucket', bucket_name],
612 check_status=True)
613
614 # create a second user to link the bucket to
615 (err, out) = rgwadmin(ctx, client, [
616 'user', 'create',
617 '--uid', user2,
618 '--display-name', display_name2,
619 '--access-key', access_key2,
620 '--secret', secret_key2,
621 '--max-buckets', '1',
622 ],
623 check_status=True)
624
625 # try creating an object with the first user before the bucket is relinked
626 denied = False
627 key = boto.s3.key.Key(bucket)
628
629 try:
630 key.set_contents_from_string('two')
631 except boto.exception.S3ResponseError:
632 denied = True
633
634 assert not denied
635 rl.log_and_clear("put_obj", bucket_name, user1)
636
637 # delete the object
638 key.delete()
639 rl.log_and_clear("delete_obj", bucket_name, user1)
640
641 # link the bucket to another user
642 (err, out) = rgwadmin(ctx, client, ['metadata', 'get', 'bucket:{n}'.format(n=bucket_name)],
643 check_status=True)
644
645 bucket_data = out['data']
646 assert bucket_data['bucket']['name'] == bucket_name
647
648 bucket_id = bucket_data['bucket']['bucket_id']
649
650 # link the bucket to another user
651 (err, out) = rgwadmin(ctx, client, ['bucket', 'link', '--uid', user2, '--bucket', bucket_name, '--bucket-id', bucket_id],
652 check_status=True)
653
654 # try to remove user, should fail (has a linked bucket)
655 (err, out) = rgwadmin(ctx, client, ['user', 'rm', '--uid', user2])
656 assert err
657
658 # TESTCASE 'bucket unlink', 'bucket', 'unlink', 'unlink bucket from user', 'succeeds, bucket unlinked'
659 (err, out) = rgwadmin(ctx, client, ['bucket', 'unlink', '--uid', user2, '--bucket', bucket_name],
660 check_status=True)
661
662 # relink the bucket to the first user and delete the second user
663 (err, out) = rgwadmin(ctx, client,
664 ['bucket', 'link', '--uid', user1, '--bucket', bucket_name, '--bucket-id', bucket_id],
665 check_status=True)
666
667 (err, out) = rgwadmin(ctx, client, ['user', 'rm', '--uid', user2],
668 check_status=True)
669
670 #TESTCASE 'bucket link', 'bucket', 'tenanted user', 'succeeds'
671 tenant_name = "testx"
672 # create a tenanted user to link the bucket to
673 (err, out) = rgwadmin(ctx, client, [
674 'user', 'create',
675 '--tenant', tenant_name,
676 '--uid', 'tenanteduser',
677 '--display-name', 'tenanted-user',
678 '--access-key', access_key2,
679 '--secret', secret_key2,
680 '--max-buckets', '1',
681 ],
682 check_status=True)
683
684 # link the bucket to a tenanted user
685 (err, out) = rgwadmin(ctx, client, ['bucket', 'link', '--bucket', '/' + bucket_name, '--tenant', tenant_name, '--uid', 'tenanteduser'],
686 check_status=True)
687
688 # check if the bucket name has tenant/ prefix
689 (err, out) = rgwadmin(ctx, client, ['metadata', 'get', 'bucket:{n}'.format(n= tenant_name + '/' + bucket_name)],
690 check_status=True)
691
692 bucket_data = out['data']
693 assert bucket_data['bucket']['name'] == bucket_name
694 assert bucket_data['bucket']['tenant'] == tenant_name
695
696 # relink the bucket to the first user and delete the tenanted user
697 (err, out) = rgwadmin(ctx, client,
698 ['bucket', 'link', '--bucket', tenant_name + '/' + bucket_name, '--uid', user1],
699 check_status=True)
700
701 (err, out) = rgwadmin(ctx, client, ['user', 'rm', '--tenant', tenant_name, '--uid', 'tenanteduser'],
702 check_status=True)
703
704 # TESTCASE 'object-rm', 'object', 'rm', 'remove object', 'succeeds, object is removed'
705
706 # upload an object
707 object_name = 'four'
708 key = boto.s3.key.Key(bucket, object_name)
709 key.set_contents_from_string(object_name)
710 rl.log_and_clear("put_obj", bucket_name, user1)
711
712 # fetch it too (for usage stats presently)
713 s = key.get_contents_as_string(encoding='ascii')
714 rl.log_and_clear("get_obj", bucket_name, user1)
715 assert s == object_name
716 # list bucket too (for usage stats presently)
717 keys = list(bucket.list())
718 rl.log_and_clear("list_bucket", bucket_name, user1)
719 assert len(keys) == 1
720 assert keys[0].name == object_name
721
722 # now delete it
723 (err, out) = rgwadmin(ctx, client,
724 ['object', 'rm', '--bucket', bucket_name, '--object', object_name],
725 check_status=True)
726
727 # TESTCASE 'bucket-stats6','bucket','stats','after deleting key','succeeds, lists one no objects'
728 (err, out) = rgwadmin(ctx, client, [
729 'bucket', 'stats', '--bucket', bucket_name],
730 check_status=True)
731 assert out['id'] == bucket_id
732 assert out['usage']['rgw.main']['num_objects'] == 0
733
734 # list log objects
735 # TESTCASE 'log-list','log','list','after activity','succeeds, lists one no objects'
736 (err, out) = rgwadmin(ctx, client, ['log', 'list'], check_status=True)
737 assert len(out) > 0
738
739 for obj in out:
740 # TESTCASE 'log-show','log','show','after activity','returns expected info'
741 if obj[:4] == 'meta' or obj[:4] == 'data' or obj[:18] == 'obj_delete_at_hint':
742 continue
743
744 (err, rgwlog) = rgwadmin(ctx, client, ['log', 'show', '--object', obj],
745 check_status=True)
746 assert len(rgwlog) > 0
747
748 # skip any entry for which there is no bucket name--e.g., list_buckets,
749 # since that is valid but cannot pass the following checks
750 entry_bucket_name = rgwlog['bucket']
751 if entry_bucket_name.strip() != "":
752 # exempt bucket_name2 from checking as it was only used for multi-region tests
753 assert rgwlog['bucket'].find(bucket_name) == 0 or rgwlog['bucket'].find(bucket_name2) == 0
754 assert rgwlog['bucket'] != bucket_name or rgwlog['bucket_id'] == bucket_id
755 assert rgwlog['bucket_owner'] == user1 or rgwlog['bucket'] == bucket_name + '5' or rgwlog['bucket'] == bucket_name2
756 for entry in rgwlog['log_entries']:
757 log.debug('checking log entry: ', entry)
758 assert entry['bucket'] == rgwlog['bucket']
759 possible_buckets = [bucket_name + '5', bucket_name2]
760 user = entry['user']
761 assert user == user1 or user.endswith('system-user') or \
762 rgwlog['bucket'] in possible_buckets
763
764 # TESTCASE 'log-rm','log','rm','delete log objects','succeeds'
765 (err, out) = rgwadmin(ctx, client, ['log', 'rm', '--object', obj],
766 check_status=True)
767
768 # TODO: show log by bucket+date
769
770 # TESTCASE 'user-suspend2','user','suspend','existing user','succeeds'
771 (err, out) = rgwadmin(ctx, client, ['user', 'suspend', '--uid', user1],
772 check_status=True)
773
774 # TESTCASE 'user-suspend3','user','suspend','suspended user','cannot write objects'
775 denied = False
776 try:
777 key = boto.s3.key.Key(bucket)
778 key.set_contents_from_string('five')
779 except boto.exception.S3ResponseError as e:
780 denied = True
781 assert e.status == 403
782
783 assert denied
784 rl.log_and_clear("put_obj", bucket_name, user1)
785
786 # TESTCASE 'user-renable2','user','enable','suspended user','succeeds'
787 (err, out) = rgwadmin(ctx, client, ['user', 'enable', '--uid', user1],
788 check_status=True)
789
790 # TESTCASE 'user-renable3','user','enable','reenabled user','can write objects'
791 key = boto.s3.key.Key(bucket)
792 key.set_contents_from_string('six')
793 rl.log_and_clear("put_obj", bucket_name, user1)
794
795 # TESTCASE 'gc-list', 'gc', 'list', 'get list of objects ready for garbage collection'
796
797 # create an object large enough to be split into multiple parts
798 test_string = 'foo'*10000000
799
800 big_key = boto.s3.key.Key(bucket)
801 big_key.set_contents_from_string(test_string)
802 rl.log_and_clear("put_obj", bucket_name, user1)
803
804 # now delete the head
805 big_key.delete()
806 rl.log_and_clear("delete_obj", bucket_name, user1)
807
808 # wait a bit to give the garbage collector time to cycle
809 time.sleep(15)
810
811 (err, out) = rgwadmin(ctx, client, ['gc', 'list', '--include-all'])
812 assert len(out) > 0
813
814 # TESTCASE 'gc-process', 'gc', 'process', 'manually collect garbage'
815 (err, out) = rgwadmin(ctx, client, ['gc', 'process'], check_status=True)
816
817 #confirm
818 (err, out) = rgwadmin(ctx, client, ['gc', 'list', '--include-all'])
819
820 # don't assume rgw_gc_obj_min_wait has been overridden
821 omit_tdir = hasattr(ctx.rgw, 'omit_tdir') and ctx.rgw.omit_tdir == True
822 if omit_tdir==False:
823 assert len(out) == 0
824
825 # TESTCASE 'rm-user-buckets','user','rm','existing user','fails, still has buckets'
826 (err, out) = rgwadmin(ctx, client, ['user', 'rm', '--uid', user1])
827 assert err
828
829 # delete should fail because ``key`` still exists
830 try:
831 bucket.delete()
832 except boto.exception.S3ResponseError as e:
833 assert e.status == 409
834 rl.log_and_clear("delete_bucket", bucket_name, user1)
835
836 key.delete()
837 rl.log_and_clear("delete_obj", bucket_name, user1)
838 bucket.delete()
839 rl.log_and_clear("delete_bucket", bucket_name, user1)
840
841 # TESTCASE 'policy', 'bucket', 'policy', 'get bucket policy', 'returns S3 policy'
842 bucket = connection.create_bucket(bucket_name)
843 rl.log_and_clear("create_bucket", bucket_name, user1)
844
845 # create an object
846 key = boto.s3.key.Key(bucket)
847 key.set_contents_from_string('seven')
848 rl.log_and_clear("put_obj", bucket_name, user1)
849
850 # should be private already but guarantee it
851 key.set_acl('private')
852 rl.log_and_clear("put_acls", bucket_name, user1)
853
854 (err, out) = rgwadmin(ctx, client,
855 ['policy', '--bucket', bucket.name, '--object', key.key.decode()],
856 check_status=True, format='xml')
857
858 acl = get_acl(key)
859 rl.log_and_clear("get_acls", bucket_name, user1)
860
861 assert acl == out.strip('\n')
862
863 # add another grantee by making the object public read
864 key.set_acl('public-read')
865 rl.log_and_clear("put_acls", bucket_name, user1)
866
867 (err, out) = rgwadmin(ctx, client,
868 ['policy', '--bucket', bucket.name, '--object', key.key.decode()],
869 check_status=True, format='xml')
870
871 acl = get_acl(key)
872 rl.log_and_clear("get_acls", bucket_name, user1)
873
874 assert acl == out.strip('\n')
875
876 # TESTCASE 'rm-bucket', 'bucket', 'rm', 'bucket with objects', 'succeeds'
877 bucket = connection.create_bucket(bucket_name)
878 rl.log_and_clear("create_bucket", bucket_name, user1)
879 key_name = ['eight', 'nine', 'ten', 'eleven']
880 for i in range(4):
881 key = boto.s3.key.Key(bucket)
882 key.set_contents_from_string(key_name[i])
883 rl.log_and_clear("put_obj", bucket_name, user1)
884
885 (err, out) = rgwadmin(ctx, client,
886 ['bucket', 'rm', '--bucket', bucket_name, '--purge-objects'],
887 check_status=True)
888
889 # TESTCASE 'caps-add', 'caps', 'add', 'add user cap', 'succeeds'
890 caps='user=read'
891 (err, out) = rgwadmin(ctx, client, ['caps', 'add', '--uid', user1, '--caps', caps])
892
893 assert out['caps'][0]['perm'] == 'read'
894
895 # TESTCASE 'caps-rm', 'caps', 'rm', 'remove existing cap from user', 'succeeds'
896 (err, out) = rgwadmin(ctx, client, ['caps', 'rm', '--uid', user1, '--caps', caps])
897
898 assert not out['caps']
899
900 # TESTCASE 'rm-user','user','rm','existing user','fails, still has buckets'
901 bucket = connection.create_bucket(bucket_name)
902 rl.log_and_clear("create_bucket", bucket_name, user1)
903 key = boto.s3.key.Key(bucket)
904
905 (err, out) = rgwadmin(ctx, client, ['user', 'rm', '--uid', user1])
906 assert err
907
908 # TESTCASE 'rm-user2', 'user', 'rm', 'user with data', 'succeeds'
909 bucket = connection.create_bucket(bucket_name)
910 rl.log_and_clear("create_bucket", bucket_name, user1)
911 key = boto.s3.key.Key(bucket)
912 key.set_contents_from_string('twelve')
913 rl.log_and_clear("put_obj", bucket_name, user1)
914
915 time.sleep(35)
916
917 # need to wait for all usage data to get flushed, should take up to 30 seconds
918 timestamp = time.time()
919 while time.time() - timestamp <= (2 * 60): # wait up to 20 minutes
920 (err, out) = rgwadmin(ctx, client, ['usage', 'show', '--categories', 'delete_obj']) # one of the operations we did is delete_obj, should be present.
921 if get_user_successful_ops(out, user1) > 0:
922 break
923 time.sleep(1)
924
925 assert time.time() - timestamp <= (20 * 60)
926
927 # TESTCASE 'usage-show' 'usage' 'show' 'all usage' 'succeeds'
928 (err, out) = rgwadmin(ctx, client, ['usage', 'show'], check_status=True)
929 assert len(out['entries']) > 0
930 assert len(out['summary']) > 0
931
932 r = acc.compare_results(out)
933 if len(r) != 0:
934 sys.stderr.write(("\n".join(r))+"\n")
935 assert(len(r) == 0)
936
937 user_summary = get_user_summary(out, user1)
938
939 total = user_summary['total']
940 assert total['successful_ops'] > 0
941
942 # TESTCASE 'usage-show2' 'usage' 'show' 'user usage' 'succeeds'
943 (err, out) = rgwadmin(ctx, client, ['usage', 'show', '--uid', user1],
944 check_status=True)
945 assert len(out['entries']) > 0
946 assert len(out['summary']) > 0
947 user_summary = out['summary'][0]
948 for entry in user_summary['categories']:
949 assert entry['successful_ops'] > 0
950 assert user_summary['user'] == user1
951
952 # TESTCASE 'usage-show3' 'usage' 'show' 'user usage categories' 'succeeds'
953 test_categories = ['create_bucket', 'put_obj', 'delete_obj', 'delete_bucket']
954 for cat in test_categories:
955 (err, out) = rgwadmin(ctx, client, ['usage', 'show', '--uid', user1, '--categories', cat],
956 check_status=True)
957 assert len(out['summary']) > 0
958 user_summary = out['summary'][0]
959 assert user_summary['user'] == user1
960 assert len(user_summary['categories']) == 1
961 entry = user_summary['categories'][0]
962 assert entry['category'] == cat
963 assert entry['successful_ops'] > 0
964
965 # TESTCASE 'user-rename', 'user', 'rename', 'existing user', 'new user', 'succeeds'
966 # create a new user user3
967 (err, out) = rgwadmin(ctx, client, [
968 'user', 'create',
969 '--uid', user3,
970 '--display-name', display_name3,
971 '--access-key', access_key3,
972 '--secret', secret_key3,
973 '--max-buckets', '4'
974 ],
975 check_status=True)
976
977 # create a bucket
978 bucket = connection3.create_bucket(bucket_name + '6')
979
980 rl.log_and_clear("create_bucket", bucket_name + '6', user3)
981
982 # create object
983 object_name1 = 'thirteen'
984 key1 = boto.s3.key.Key(bucket, object_name1)
985 key1.set_contents_from_string(object_name1)
986 rl.log_and_clear("put_obj", bucket_name + '6', user3)
987
988 # rename user3
989 (err, out) = rgwadmin(ctx, client, ['user', 'rename', '--uid', user3, '--new-uid', user4], check_status=True)
990 assert out['user_id'] == user4
991 assert out['keys'][0]['access_key'] == access_key3
992 assert out['keys'][0]['secret_key'] == secret_key3
993
994 time.sleep(5)
995
996 # get bucket and object to test if user keys are preserved
997 bucket = connection3.get_bucket(bucket_name + '6')
998 s = key1.get_contents_as_string(encoding='ascii')
999 rl.log_and_clear("get_obj", bucket_name + '6', user4)
1000 assert s == object_name1
1001
1002 # TESTCASE 'user-rename', 'user', 'rename', 'existing user', 'another existing user', 'fails'
1003 # create a new user user2
1004 (err, out) = rgwadmin(ctx, client, [
1005 'user', 'create',
1006 '--uid', user2,
1007 '--display-name', display_name2,
1008 '--access-key', access_key2,
1009 '--secret', secret_key2,
1010 '--max-buckets', '4'
1011 ],
1012 check_status=True)
1013
1014 # create a bucket
1015 bucket = connection2.create_bucket(bucket_name + '7')
1016
1017 rl.log_and_clear("create_bucket", bucket_name + '7', user2)
1018
1019 # create object
1020 object_name2 = 'fourteen'
1021 key2 = boto.s3.key.Key(bucket, object_name2)
1022 key2.set_contents_from_string(object_name2)
1023 rl.log_and_clear("put_obj", bucket_name + '7', user2)
1024
1025 (err, out) = rgwadmin(ctx, client, ['user', 'rename', '--uid', user4, '--new-uid', user2])
1026 assert err
1027
1028 # test if user 2 and user4 can still access their bucket and objects after rename fails
1029 bucket = connection3.get_bucket(bucket_name + '6')
1030 s = key1.get_contents_as_string(encoding='ascii')
1031 rl.log_and_clear("get_obj", bucket_name + '6', user4)
1032 assert s == object_name1
1033
1034 bucket = connection2.get_bucket(bucket_name + '7')
1035 s = key2.get_contents_as_string(encoding='ascii')
1036 rl.log_and_clear("get_obj", bucket_name + '7', user2)
1037 assert s == object_name2
1038
1039 (err, out) = rgwadmin(ctx, client,
1040 ['user', 'rm', '--uid', user4, '--purge-data' ],
1041 check_status=True)
1042
1043 (err, out) = rgwadmin(ctx, client,
1044 ['user', 'rm', '--uid', user2, '--purge-data' ],
1045 check_status=True)
1046
1047 time.sleep(5)
1048
1049 # should be all through with connection. (anything using connection
1050 # should be BEFORE the usage stuff above.)
1051 rl.log_and_clear("(before-close)", '-', '-', ignore_this_entry)
1052 connection.close()
1053 connection = None
1054
1055 # the usage flush interval is 30 seconds, wait that much an then some
1056 # to make sure everything has been flushed
1057 time.sleep(35)
1058
1059 # TESTCASE 'usage-trim' 'usage' 'trim' 'user usage' 'succeeds, usage removed'
1060 (err, out) = rgwadmin(ctx, client, ['usage', 'trim', '--uid', user1],
1061 check_status=True)
1062 (err, out) = rgwadmin(ctx, client, ['usage', 'show', '--uid', user1],
1063 check_status=True)
1064 assert len(out['entries']) == 0
1065 assert len(out['summary']) == 0
1066
1067 (err, out) = rgwadmin(ctx, client,
1068 ['user', 'rm', '--uid', user1, '--purge-data' ],
1069 check_status=True)
1070
1071 # TESTCASE 'rm-user3','user','rm','deleted user','fails'
1072 (err, out) = rgwadmin(ctx, client, ['user', 'info', '--uid', user1])
1073 assert err
1074
1075 # TESTCASE 'zone-info', 'zone', 'get', 'get zone info', 'succeeds, has default placement rule'
1076 (err, out) = rgwadmin(ctx, client, ['zone', 'get','--rgw-zone','default'])
1077 orig_placement_pools = len(out['placement_pools'])
1078
1079 # removed this test, it is not correct to assume that zone has default placement, it really
1080 # depends on how we set it up before
1081 #
1082 # assert len(out) > 0
1083 # assert len(out['placement_pools']) == 1
1084
1085 # default_rule = out['placement_pools'][0]
1086 # assert default_rule['key'] == 'default-placement'
1087
1088 rule={'key': 'new-placement', 'val': {'data_pool': '.rgw.buckets.2', 'index_pool': '.rgw.buckets.index.2'}}
1089
1090 out['placement_pools'].append(rule)
1091
1092 (err, out) = rgwadmin(ctx, client, ['zone', 'set'],
1093 stdin=StringIO(json.dumps(out)),
1094 check_status=True)
1095
1096 (err, out) = rgwadmin(ctx, client, ['zone', 'get'])
1097 assert len(out) > 0
1098 assert len(out['placement_pools']) == orig_placement_pools + 1
1099
1100 zonecmd = ['zone', 'placement', 'rm',
1101 '--rgw-zone', 'default',
1102 '--placement-id', 'new-placement']
1103
1104 (err, out) = rgwadmin(ctx, client, zonecmd, check_status=True)
1105
1106 # TESTCASE 'zonegroup-info', 'zonegroup', 'get', 'get zonegroup info', 'succeeds'
1107 (err, out) = rgwadmin(ctx, client, ['zonegroup', 'get'], check_status=True)
1108
1109 from teuthology.config import config
1110 from teuthology.orchestra import cluster
1111
1112 import argparse;
1113
1114 def main():
1115 parser = argparse.ArgumentParser()
1116 parser.add_argument('--uid')
1117 parser.add_argument('--host', required=True)
1118 parser.add_argument('--port', type=int)
1119
1120 args = parser.parse_args()
1121 host = args.host
1122 if args.port:
1123 port = args.port
1124 else:
1125 port = 80
1126
1127 client0 = tasks.vstart_runner.LocalRemote()
1128 ctx = config
1129 ctx.cluster=cluster.Cluster(remotes=[(client0,
1130 [ 'ceph.client.rgw.%s' % (port), ]),])
1131 ctx.rgw = argparse.Namespace()
1132 endpoints = {}
1133 endpoints['ceph.client.rgw.%s' % port] = RGWEndpoint(
1134 hostname=host,
1135 port=port)
1136 ctx.rgw.role_endpoints = endpoints
1137 ctx.rgw.realm = None
1138 ctx.rgw.regions = {'region0': { 'api name': 'api1',
1139 'is master': True, 'master zone': 'r0z0',
1140 'zones': ['r0z0', 'r0z1'] }}
1141 ctx.rgw.omit_sudo = True
1142 ctx.rgw.omit_tdir = True
1143 ctx.rgw.config = {'ceph.client.rgw.%s' % port: {'system user': {'name': '%s-system-user' % port}}}
1144 task(config, None)
1145 exit()
1146
1147 if __name__ == '__main__':
1148 main()