Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / rgw / test_multen.py
1 # Test of mult-tenancy
2
3 import json
4 import sys
5
6 from boto.s3.connection import S3Connection, OrdinaryCallingFormat
7
8 # XXX once we're done, break out the common code into a library module
9 #     See  https://github.com/ceph/ceph/pull/8646
10 import test_multi as t
11
12 class TestException(Exception):
13     pass
14
15 #
16 # Create a traditional user, S3-only, global (empty) tenant
17 #
18 def test2(cluster):
19     uid = "tester2"
20     display_name = "'Test User 2'"
21     access_key = "tester2KEY"
22     s3_secret = "test3pass"
23     cmd = t.build_cmd('--uid', uid,
24                     '--display-name', display_name,
25                     '--access-key', access_key,
26                     '--secret', s3_secret,
27                     "user create")
28     out, ret = cluster.rgw_admin(cmd, check_retcode=False)
29     if ret != 0:
30         raise TestException("failed command: user create --uid %s" % uid)
31
32     try:
33         outj = json.loads(out.decode('utf-8'))
34     except ValueError:
35         raise TestException("invalid json after: user create --uid %s" % uid)
36     if not isinstance(outj, dict):
37         raise TestException("bad json after: user create --uid %s" % uid)
38     if outj['user_id'] != uid:
39         raise TestException(
40             "command: user create --uid %s, returned user_id %s" %
41             (uid, outj['user_id']))
42
43 #
44 # Create a tenantized user with --tenant foo
45 #
46 def test3(cluster):
47     tid = "testx3"
48     uid = "tester3"
49     display_name = "Test_User_3"
50     access_key = "tester3KEY"
51     s3_secret = "test3pass"
52     cmd = t.build_cmd(
53         '--tenant', tid,
54         '--uid', uid,
55         '--display-name', display_name,
56         '--access-key', access_key,
57         '--secret', s3_secret,
58         "user create")
59     out, ret = cluster.rgw_admin(cmd, check_retcode=False)
60     if ret != 0:
61         raise TestException("failed command: user create --uid %s" % uid)
62
63     try:
64         outj = json.loads(out.decode('utf-8'))
65     except ValueError:
66         raise TestException("invalid json after: user create --uid %s" % uid)
67     if not isinstance(outj, dict):
68         raise TestException("bad json after: user create --uid %s" % uid)
69     tid_uid = "%s$%s" % (tid, uid)
70     if outj['user_id'] != tid_uid:
71         raise TestException(
72             "command: user create --uid %s, returned user_id %s" %
73             (tid_uid, outj['user_id']))
74
75 #
76 # Create a tenantized user with a subuser
77 #
78 # N.B. The aim of this test is not just to create a subuser, but to create
79 # the key with a separate command, which does not use --tenant, but extracts
80 # the tenant from the subuser. No idea why we allow this. There was some kind
81 # of old script that did this.
82 #
83 def test4(cluster):
84     tid = "testx4"
85     uid = "tester4"
86     subid = "test4"
87
88     display_name = "Test_User_4"
89     cmd = t.build_cmd(
90         '--tenant', tid,
91         '--uid', uid,
92         '--display-name', display_name,
93         '--subuser', '%s:%s' % (uid, subid),
94         '--key-type', 'swift',
95         '--access', 'full',
96         "user create")
97     out, ret = cluster.rgw_admin(cmd, check_retcode=False)
98     if ret != 0:
99         raise TestException("failed command: user create --uid %s" % uid)
100
101     try:
102         outj = json.loads(out.decode('utf-8'))
103     except ValueError:
104         raise TestException("invalid json after: user create --uid %s" % uid)
105     if not isinstance(outj, dict):
106         raise TestException("bad json after: user create --uid %s" % uid)
107     tid_uid = "%s$%s" % (tid, uid)
108     if outj['user_id'] != tid_uid:
109         raise TestException(
110             "command: user create --uid %s, returned user_id %s" %
111             (tid_uid, outj['user_id']))
112
113     # Note that this tests a way to identify a fully-qualified subuser
114     # without --tenant and --uid. This is a historic use that we support.
115     swift_secret = "test3pass"
116     cmd = t.build_cmd(
117         '--subuser', "'%s$%s:%s'" % (tid, uid, subid),
118         '--key-type', 'swift',
119         '--secret', swift_secret,
120         "key create")
121     out, ret = cluster.rgw_admin(cmd, check_retcode=False)
122     if ret != 0:
123         raise TestException("failed command: key create --uid %s" % uid)
124
125     try:
126         outj = json.loads(out.decode('utf-8'))
127     except ValueError:
128         raise TestException("invalid json after: key create --uid %s" % uid)
129     if not isinstance(outj, dict):
130         raise TestException("bad json after: key create --uid %s" % uid)
131     tid_uid = "%s$%s" % (tid, uid)
132     if outj['user_id'] != tid_uid:
133         raise TestException(
134             "command: key create --uid %s, returned user_id %s" %
135             (tid_uid, outj['user_id']))
136     # These tests easily can throw KeyError, needs a try: XXX
137     skj = outj['swift_keys'][0]
138     if skj['secret_key'] != swift_secret:
139         raise TestException(
140             "command: key create --uid %s, returned swift key %s" %
141             (tid_uid, skj['secret_key']))
142
143 #
144 # Access the cluster, create containers in two tenants, verify it all works.
145 #
146
147 def test5_add_s3_key(cluster, tid, uid):
148     secret = "%spass" % uid
149     if tid:
150         tid_uid = "%s$%s" % (tid, uid)
151     else:
152         tid_uid = uid
153
154     cmd = t.build_cmd(
155         '--uid', "'%s'" % (tid_uid,),
156         '--access-key', uid,
157         '--secret', secret,
158         "key create")
159     out, ret = cluster.rgw_admin(cmd, check_retcode=False)
160     if ret != 0:
161         raise TestException("failed command: key create --uid %s" % uid)
162
163     try:
164         outj = json.loads(out.decode('utf-8'))
165     except ValueError:
166         raise TestException("invalid json after: key create --uid %s" % uid)
167     if not isinstance(outj, dict):
168         raise TestException("bad json after: key create --uid %s" % uid)
169     if outj['user_id'] != tid_uid:
170         raise TestException(
171             "command: key create --uid %s, returned user_id %s" %
172             (uid, outj['user_id']))
173     skj = outj['keys'][0]
174     if skj['secret_key'] != secret:
175         raise TestException(
176             "command: key create --uid %s, returned s3 key %s" %
177             (uid, skj['secret_key']))
178
179 def test5_add_swift_key(cluster, tid, uid, subid):
180     secret = "%spass" % uid
181     if tid:
182         tid_uid = "%s$%s" % (tid, uid)
183     else:
184         tid_uid = uid
185
186     cmd = t.build_cmd(
187         '--subuser', "'%s:%s'" % (tid_uid, subid),
188         '--key-type', 'swift',
189         '--secret', secret,
190         "key create")
191     out, ret = cluster.rgw_admin(cmd, check_retcode=False)
192     if ret != 0:
193         raise TestException("failed command: key create --uid %s" % uid)
194
195     try:
196         outj = json.loads(out.decode('utf-8'))
197     except ValueError:
198         raise TestException("invalid json after: key create --uid %s" % uid)
199     if not isinstance(outj, dict):
200         raise TestException("bad json after: key create --uid %s" % uid)
201     if outj['user_id'] != tid_uid:
202         raise TestException(
203             "command: key create --uid %s, returned user_id %s" %
204             (uid, outj['user_id']))
205     # XXX checking wrong thing here (S3 key)
206     skj = outj['keys'][0]
207     if skj['secret_key'] != secret:
208         raise TestException(
209             "command: key create --uid %s, returned s3 key %s" %
210             (uid, skj['secret_key']))
211
212 def test5_make_user(cluster, tid, uid, subid):
213     """
214     :param tid: Tenant ID string or None for the legacy tenant
215     :param uid: User ID string
216     :param subid: Subuser ID, may be None for S3-only users
217     """
218     display_name = "'Test User %s'" % uid
219
220     cmd = ""
221     if tid:
222         cmd = t.build_cmd(cmd,
223             '--tenant', tid)
224     cmd = t.build_cmd(cmd,
225         '--uid', uid,
226         '--display-name', display_name)
227     if subid:
228         cmd = t.build_cmd(cmd,
229             '--subuser', '%s:%s' % (uid, subid),
230             '--key-type', 'swift')
231     cmd = t.build_cmd(cmd,
232         '--access', 'full',
233         "user create")
234
235     out, ret = cluster.rgw_admin(cmd, check_retcode=False)
236     if ret != 0:
237         raise TestException("failed command: user create --uid %s" % uid)
238     try:
239         outj = json.loads(out.decode('utf-8'))
240     except ValueError:
241         raise TestException("invalid json after: user create --uid %s" % uid)
242     if not isinstance(outj, dict):
243         raise TestException("bad json after: user create --uid %s" % uid)
244     if tid:
245         tid_uid = "%s$%s" % (tid, uid)
246     else:
247         tid_uid = uid
248     if outj['user_id'] != tid_uid:
249         raise TestException(
250             "command: user create --uid %s, returned user_id %s" %
251             (tid_uid, outj['user_id']))
252
253     #
254     # For now, this uses hardcoded passwords based on uid.
255     # They are all different for ease of debugging in case something crosses.
256     #
257     test5_add_s3_key(cluster, tid, uid)
258     if subid:
259         test5_add_swift_key(cluster, tid, uid, subid)
260
261 def test5_poke_s3(cluster):
262
263     bucketname = "test5cont1"
264     objname = "obj1"
265
266     # Not sure if we like useless information printed, but the rest of the
267     # test framework is insanely talkative when it executes commands.
268     # So, to keep it in line and have a marker when things go wrong, this.
269     print("PUT bucket %s object %s for tenant A (empty)" %
270           (bucketname, objname))
271     c = S3Connection(
272         aws_access_key_id="tester5a",
273         aws_secret_access_key="tester5apass",
274         is_secure=False,
275         host="localhost",
276         port = cluster.port,
277         calling_format = OrdinaryCallingFormat())
278
279     bucket = c.create_bucket(bucketname)
280
281     key = bucket.new_key(objname)
282     headers = { "Content-Type": "text/plain" }
283     key.set_contents_from_string(b"Test5A\n", headers)
284     key.set_acl('public-read')
285
286     #
287     # Now it's getting interesting. We're logging into a tenantized user.
288     #
289     print("PUT bucket %s object %s for tenant B" % (bucketname, objname))
290     c = S3Connection(
291         aws_access_key_id="tester5b1",
292         aws_secret_access_key="tester5b1pass",
293         is_secure=False,
294         host="localhost",
295         port = cluster.port,
296         calling_format = OrdinaryCallingFormat())
297
298     bucket = c.create_bucket(bucketname)
299     bucket.set_canned_acl('public-read')
300
301     key = bucket.new_key(objname)
302     headers = { "Content-Type": "text/plain" }
303     key.set_contents_from_string(b"Test5B\n", headers)
304     key.set_acl('public-read')
305
306     #
307     # Finally, let's fetch a couple of objects and verify that they
308     # are what they should be and we didn't get them overwritten.
309     # Note that we access one of objects across tenants using the colon.
310     #
311     print("GET bucket %s object %s for tenants A and B" %
312           (bucketname, objname))
313     c = S3Connection(
314         aws_access_key_id="tester5a",
315         aws_secret_access_key="tester5apass",
316         is_secure=False,
317         host="localhost",
318         port = cluster.port,
319         calling_format = OrdinaryCallingFormat())
320
321     bucket = c.get_bucket(bucketname)
322
323     key = bucket.get_key(objname)
324     body = key.get_contents_as_string()
325     if body != b"Test5A\n":
326         raise TestException("failed body check, bucket %s object %s" %
327                             (bucketname, objname))
328
329     bucket = c.get_bucket("test5b:"+bucketname)
330     key = bucket.get_key(objname)
331     body = key.get_contents_as_string()
332     if body != b"Test5B\n":
333         raise TestException(
334             "failed body check, tenant %s bucket %s object %s" %
335             ("test5b", bucketname, objname))
336
337     print("Poke OK")
338
339
340 def test5(cluster):
341     # Plan:
342     # 0. create users tester5a and test5b$tester5b1 test5b$tester5b2
343     # 1. create buckets "test5cont" under test5a and test5b
344     # 2. create objects in the buckets
345     # 3. access objects (across users in container test5b)
346
347     test5_make_user(cluster, None, "tester5a", "test5a")
348     test5_make_user(cluster, "test5b", "tester5b1", "test5b1")
349     test5_make_user(cluster, "test5b", "tester5b2", "test5b2")
350
351     test5_poke_s3(cluster)
352
353
354 # XXX this parse_args boolean makes no sense. we should pass argv[] instead,
355 #     possibly empty. (copied from test_multi, correct it there too)
356 def init(parse_args):
357
358     #argv = []
359     #if parse_args:
360     #    argv = sys.argv[1:]
361     #args = parser.parse_args(argv)
362
363     #rgw_multi = RGWMulti(int(args.num_zones))
364     #rgw_multi.setup(not args.no_bootstrap)
365
366     # __init__():
367     port = 8001
368     clnum = 1  # number of clusters
369     clid = 1   # 1-based
370     cluster = t.RGWCluster(clid, port)
371
372     # setup():
373     cluster.start()
374     cluster.start_rgw()
375
376     # The cluster is always reset at this point, so we don't need to list
377     # users or delete pre-existing users.
378
379     try:
380         test2(cluster)
381         test3(cluster)
382         test4(cluster)
383         test5(cluster)
384     except TestException as e:
385         cluster.stop_rgw()
386         cluster.stop()
387         sys.stderr.write("FAIL\n")
388         sys.stderr.write("%s\n" % str(e))
389         return 1
390
391     # teardown():
392     cluster.stop_rgw()
393     cluster.stop()
394     return 0
395
396 def setup_module():
397     return init(False)
398
399 if __name__ == "__main__":
400     sys.exit(init(True))