Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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()