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