summaryrefslogtreecommitdiffstats
path: root/src/test/rgw/test_multen.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/rgw/test_multen.py')
-rw-r--r--src/test/rgw/test_multen.py400
1 files changed, 400 insertions, 0 deletions
diff --git a/src/test/rgw/test_multen.py b/src/test/rgw/test_multen.py
new file mode 100644
index 00000000..91464d33
--- /dev/null
+++ b/src/test/rgw/test_multen.py
@@ -0,0 +1,400 @@
+# Test of mult-tenancy
+
+import json
+import sys
+
+from boto.s3.connection import S3Connection, OrdinaryCallingFormat
+
+# XXX once we're done, break out the common code into a library module
+# See https://github.com/ceph/ceph/pull/8646
+import test_multi as t
+
+class TestException(Exception):
+ pass
+
+#
+# Create a traditional user, S3-only, global (empty) tenant
+#
+def test2(cluster):
+ uid = "tester2"
+ display_name = "'Test User 2'"
+ access_key = "tester2KEY"
+ s3_secret = "test3pass"
+ cmd = t.build_cmd('--uid', uid,
+ '--display-name', display_name,
+ '--access-key', access_key,
+ '--secret', s3_secret,
+ "user create")
+ out, ret = cluster.rgw_admin(cmd, check_retcode=False)
+ if ret != 0:
+ raise TestException("failed command: user create --uid %s" % uid)
+
+ try:
+ outj = json.loads(out.decode('utf-8'))
+ except ValueError:
+ raise TestException("invalid json after: user create --uid %s" % uid)
+ if not isinstance(outj, dict):
+ raise TestException("bad json after: user create --uid %s" % uid)
+ if outj['user_id'] != uid:
+ raise TestException(
+ "command: user create --uid %s, returned user_id %s" %
+ (uid, outj['user_id']))
+
+#
+# Create a tenantized user with --tenant foo
+#
+def test3(cluster):
+ tid = "testx3"
+ uid = "tester3"
+ display_name = "Test_User_3"
+ access_key = "tester3KEY"
+ s3_secret = "test3pass"
+ cmd = t.build_cmd(
+ '--tenant', tid,
+ '--uid', uid,
+ '--display-name', display_name,
+ '--access-key', access_key,
+ '--secret', s3_secret,
+ "user create")
+ out, ret = cluster.rgw_admin(cmd, check_retcode=False)
+ if ret != 0:
+ raise TestException("failed command: user create --uid %s" % uid)
+
+ try:
+ outj = json.loads(out.decode('utf-8'))
+ except ValueError:
+ raise TestException("invalid json after: user create --uid %s" % uid)
+ if not isinstance(outj, dict):
+ raise TestException("bad json after: user create --uid %s" % uid)
+ tid_uid = "%s$%s" % (tid, uid)
+ if outj['user_id'] != tid_uid:
+ raise TestException(
+ "command: user create --uid %s, returned user_id %s" %
+ (tid_uid, outj['user_id']))
+
+#
+# Create a tenantized user with a subuser
+#
+# N.B. The aim of this test is not just to create a subuser, but to create
+# the key with a separate command, which does not use --tenant, but extracts
+# the tenant from the subuser. No idea why we allow this. There was some kind
+# of old script that did this.
+#
+def test4(cluster):
+ tid = "testx4"
+ uid = "tester4"
+ subid = "test4"
+
+ display_name = "Test_User_4"
+ cmd = t.build_cmd(
+ '--tenant', tid,
+ '--uid', uid,
+ '--display-name', display_name,
+ '--subuser', '%s:%s' % (uid, subid),
+ '--key-type', 'swift',
+ '--access', 'full',
+ "user create")
+ out, ret = cluster.rgw_admin(cmd, check_retcode=False)
+ if ret != 0:
+ raise TestException("failed command: user create --uid %s" % uid)
+
+ try:
+ outj = json.loads(out.decode('utf-8'))
+ except ValueError:
+ raise TestException("invalid json after: user create --uid %s" % uid)
+ if not isinstance(outj, dict):
+ raise TestException("bad json after: user create --uid %s" % uid)
+ tid_uid = "%s$%s" % (tid, uid)
+ if outj['user_id'] != tid_uid:
+ raise TestException(
+ "command: user create --uid %s, returned user_id %s" %
+ (tid_uid, outj['user_id']))
+
+ # Note that this tests a way to identify a fully-qualified subuser
+ # without --tenant and --uid. This is a historic use that we support.
+ swift_secret = "test3pass"
+ cmd = t.build_cmd(
+ '--subuser', "'%s$%s:%s'" % (tid, uid, subid),
+ '--key-type', 'swift',
+ '--secret', swift_secret,
+ "key create")
+ out, ret = cluster.rgw_admin(cmd, check_retcode=False)
+ if ret != 0:
+ raise TestException("failed command: key create --uid %s" % uid)
+
+ try:
+ outj = json.loads(out.decode('utf-8'))
+ except ValueError:
+ raise TestException("invalid json after: key create --uid %s" % uid)
+ if not isinstance(outj, dict):
+ raise TestException("bad json after: key create --uid %s" % uid)
+ tid_uid = "%s$%s" % (tid, uid)
+ if outj['user_id'] != tid_uid:
+ raise TestException(
+ "command: key create --uid %s, returned user_id %s" %
+ (tid_uid, outj['user_id']))
+ # These tests easily can throw KeyError, needs a try: XXX
+ skj = outj['swift_keys'][0]
+ if skj['secret_key'] != swift_secret:
+ raise TestException(
+ "command: key create --uid %s, returned swift key %s" %
+ (tid_uid, skj['secret_key']))
+
+#
+# Access the cluster, create containers in two tenants, verify it all works.
+#
+
+def test5_add_s3_key(cluster, tid, uid):
+ secret = "%spass" % uid
+ if tid:
+ tid_uid = "%s$%s" % (tid, uid)
+ else:
+ tid_uid = uid
+
+ cmd = t.build_cmd(
+ '--uid', "'%s'" % (tid_uid,),
+ '--access-key', uid,
+ '--secret', secret,
+ "key create")
+ out, ret = cluster.rgw_admin(cmd, check_retcode=False)
+ if ret != 0:
+ raise TestException("failed command: key create --uid %s" % uid)
+
+ try:
+ outj = json.loads(out.decode('utf-8'))
+ except ValueError:
+ raise TestException("invalid json after: key create --uid %s" % uid)
+ if not isinstance(outj, dict):
+ raise TestException("bad json after: key create --uid %s" % uid)
+ if outj['user_id'] != tid_uid:
+ raise TestException(
+ "command: key create --uid %s, returned user_id %s" %
+ (uid, outj['user_id']))
+ skj = outj['keys'][0]
+ if skj['secret_key'] != secret:
+ raise TestException(
+ "command: key create --uid %s, returned s3 key %s" %
+ (uid, skj['secret_key']))
+
+def test5_add_swift_key(cluster, tid, uid, subid):
+ secret = "%spass" % uid
+ if tid:
+ tid_uid = "%s$%s" % (tid, uid)
+ else:
+ tid_uid = uid
+
+ cmd = t.build_cmd(
+ '--subuser', "'%s:%s'" % (tid_uid, subid),
+ '--key-type', 'swift',
+ '--secret', secret,
+ "key create")
+ out, ret = cluster.rgw_admin(cmd, check_retcode=False)
+ if ret != 0:
+ raise TestException("failed command: key create --uid %s" % uid)
+
+ try:
+ outj = json.loads(out.decode('utf-8'))
+ except ValueError:
+ raise TestException("invalid json after: key create --uid %s" % uid)
+ if not isinstance(outj, dict):
+ raise TestException("bad json after: key create --uid %s" % uid)
+ if outj['user_id'] != tid_uid:
+ raise TestException(
+ "command: key create --uid %s, returned user_id %s" %
+ (uid, outj['user_id']))
+ # XXX checking wrong thing here (S3 key)
+ skj = outj['keys'][0]
+ if skj['secret_key'] != secret:
+ raise TestException(
+ "command: key create --uid %s, returned s3 key %s" %
+ (uid, skj['secret_key']))
+
+def test5_make_user(cluster, tid, uid, subid):
+ """
+ :param tid: Tenant ID string or None for the legacy tenant
+ :param uid: User ID string
+ :param subid: Subuser ID, may be None for S3-only users
+ """
+ display_name = "'Test User %s'" % uid
+
+ cmd = ""
+ if tid:
+ cmd = t.build_cmd(cmd,
+ '--tenant', tid)
+ cmd = t.build_cmd(cmd,
+ '--uid', uid,
+ '--display-name', display_name)
+ if subid:
+ cmd = t.build_cmd(cmd,
+ '--subuser', '%s:%s' % (uid, subid),
+ '--key-type', 'swift')
+ cmd = t.build_cmd(cmd,
+ '--access', 'full',
+ "user create")
+
+ out, ret = cluster.rgw_admin(cmd, check_retcode=False)
+ if ret != 0:
+ raise TestException("failed command: user create --uid %s" % uid)
+ try:
+ outj = json.loads(out.decode('utf-8'))
+ except ValueError:
+ raise TestException("invalid json after: user create --uid %s" % uid)
+ if not isinstance(outj, dict):
+ raise TestException("bad json after: user create --uid %s" % uid)
+ if tid:
+ tid_uid = "%s$%s" % (tid, uid)
+ else:
+ tid_uid = uid
+ if outj['user_id'] != tid_uid:
+ raise TestException(
+ "command: user create --uid %s, returned user_id %s" %
+ (tid_uid, outj['user_id']))
+
+ #
+ # For now, this uses hardcoded passwords based on uid.
+ # They are all different for ease of debugging in case something crosses.
+ #
+ test5_add_s3_key(cluster, tid, uid)
+ if subid:
+ test5_add_swift_key(cluster, tid, uid, subid)
+
+def test5_poke_s3(cluster):
+
+ bucketname = "test5cont1"
+ objname = "obj1"
+
+ # Not sure if we like useless information printed, but the rest of the
+ # test framework is insanely talkative when it executes commands.
+ # So, to keep it in line and have a marker when things go wrong, this.
+ print("PUT bucket %s object %s for tenant A (empty)" %
+ (bucketname, objname))
+ c = S3Connection(
+ aws_access_key_id="tester5a",
+ aws_secret_access_key="tester5apass",
+ is_secure=False,
+ host="localhost",
+ port = cluster.port,
+ calling_format = OrdinaryCallingFormat())
+
+ bucket = c.create_bucket(bucketname)
+
+ key = bucket.new_key(objname)
+ headers = { "Content-Type": "text/plain" }
+ key.set_contents_from_string(b"Test5A\n", headers)
+ key.set_acl('public-read')
+
+ #
+ # Now it's getting interesting. We're logging into a tenantized user.
+ #
+ print("PUT bucket %s object %s for tenant B" % (bucketname, objname))
+ c = S3Connection(
+ aws_access_key_id="tester5b1",
+ aws_secret_access_key="tester5b1pass",
+ is_secure=False,
+ host="localhost",
+ port = cluster.port,
+ calling_format = OrdinaryCallingFormat())
+
+ bucket = c.create_bucket(bucketname)
+ bucket.set_canned_acl('public-read')
+
+ key = bucket.new_key(objname)
+ headers = { "Content-Type": "text/plain" }
+ key.set_contents_from_string(b"Test5B\n", headers)
+ key.set_acl('public-read')
+
+ #
+ # Finally, let's fetch a couple of objects and verify that they
+ # are what they should be and we didn't get them overwritten.
+ # Note that we access one of objects across tenants using the colon.
+ #
+ print("GET bucket %s object %s for tenants A and B" %
+ (bucketname, objname))
+ c = S3Connection(
+ aws_access_key_id="tester5a",
+ aws_secret_access_key="tester5apass",
+ is_secure=False,
+ host="localhost",
+ port = cluster.port,
+ calling_format = OrdinaryCallingFormat())
+
+ bucket = c.get_bucket(bucketname)
+
+ key = bucket.get_key(objname)
+ body = key.get_contents_as_string()
+ if body != b"Test5A\n":
+ raise TestException("failed body check, bucket %s object %s" %
+ (bucketname, objname))
+
+ bucket = c.get_bucket("test5b:"+bucketname)
+ key = bucket.get_key(objname)
+ body = key.get_contents_as_string()
+ if body != b"Test5B\n":
+ raise TestException(
+ "failed body check, tenant %s bucket %s object %s" %
+ ("test5b", bucketname, objname))
+
+ print("Poke OK")
+
+
+def test5(cluster):
+ # Plan:
+ # 0. create users tester5a and test5b$tester5b1 test5b$tester5b2
+ # 1. create buckets "test5cont" under test5a and test5b
+ # 2. create objects in the buckets
+ # 3. access objects (across users in container test5b)
+
+ test5_make_user(cluster, None, "tester5a", "test5a")
+ test5_make_user(cluster, "test5b", "tester5b1", "test5b1")
+ test5_make_user(cluster, "test5b", "tester5b2", "test5b2")
+
+ test5_poke_s3(cluster)
+
+
+# XXX this parse_args boolean makes no sense. we should pass argv[] instead,
+# possibly empty. (copied from test_multi, correct it there too)
+def init(parse_args):
+
+ #argv = []
+ #if parse_args:
+ # argv = sys.argv[1:]
+ #args = parser.parse_args(argv)
+
+ #rgw_multi = RGWMulti(int(args.num_zones))
+ #rgw_multi.setup(not args.no_bootstrap)
+
+ # __init__():
+ port = 8001
+ clnum = 1 # number of clusters
+ clid = 1 # 1-based
+ cluster = t.RGWCluster(clid, port)
+
+ # setup():
+ cluster.start()
+ cluster.start_rgw()
+
+ # The cluster is always reset at this point, so we don't need to list
+ # users or delete pre-existing users.
+
+ try:
+ test2(cluster)
+ test3(cluster)
+ test4(cluster)
+ test5(cluster)
+ except TestException as e:
+ cluster.stop_rgw()
+ cluster.stop()
+ sys.stderr.write("FAIL\n")
+ sys.stderr.write("%s\n" % str(e))
+ return 1
+
+ # teardown():
+ cluster.stop_rgw()
+ cluster.stop()
+ return 0
+
+def setup_module():
+ return init(False)
+
+if __name__ == "__main__":
+ sys.exit(init(True))