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