]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rgw/test_multen.py
add subtree-ish sources for 12.0.3
[ceph.git] / 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))