Skip to content

Commit 053e704

Browse files
committed
test/rgw/notifications: integration test for migrating a topic to an account
Tests https://tracker.ceph.com/issues/67656 Signed-off-by: Oguzhan Ozmen <[email protected]>
1 parent 1fd58c7 commit 053e704

File tree

1 file changed

+206
-1
lines changed

1 file changed

+206
-1
lines changed

src/test/rgw/bucket_notification/test_bn.py

Lines changed: 206 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
admin
4242

4343
from nose import SkipTest
44-
from nose.tools import assert_not_equal, assert_equal, assert_in, assert_true
44+
from nose.tools import assert_not_equal, assert_equal, assert_in, assert_not_in, assert_true
4545
import boto.s3.tagging
4646

4747
# configure logging for the tests module
@@ -5429,3 +5429,208 @@ def test_connection_caching():
54295429
conn.delete_bucket(bucket_name)
54305430
receiver_1.close(task_1)
54315431
receiver_2.close(task_2)
5432+
5433+
5434+
@attr("http_test")
5435+
def test_topic_migration_to_an_account():
5436+
"""test the topic migration procedure described at
5437+
https://docs.ceph.com/en/latest/radosgw/account/#migrate-an-existing-user-into-an-account
5438+
"""
5439+
try:
5440+
# create an http server for notification delivery
5441+
host = get_ip()
5442+
port = random.randint(10000, 20000)
5443+
http_server = HTTPServerWithEvents((host, port))
5444+
5445+
# start with two non-account users
5446+
# create a new user for "user1" which is going to be migrated to an account
5447+
user1_conn, user1_arn = another_user()
5448+
user1_id = user1_arn.split("/")[1]
5449+
user2_conn = connection()
5450+
log.info(
5451+
f"two non-account users with acckeys user1 {user1_conn.access_key} and user2 {user2_conn.access_key}"
5452+
)
5453+
5454+
# create a bucket per user
5455+
user1_bucket_name = gen_bucket_name()
5456+
user2_bucket_name = gen_bucket_name()
5457+
user1_bucket = user1_conn.create_bucket(user1_bucket_name)
5458+
user2_bucket = user2_conn.create_bucket(user2_bucket_name)
5459+
log.info(
5460+
f"one bucket per user {user1_conn.access_key}: {user1_bucket_name} and {user2_conn.access_key}: {user2_bucket_name}"
5461+
)
5462+
5463+
# create an S3 topic owned by the first user
5464+
topic_name = user1_bucket_name + TOPIC_SUFFIX
5465+
zonegroup = get_config_zonegroup()
5466+
endpoint_address = "http://" + host + ":" + str(port)
5467+
endpoint_args = "push-endpoint=" + endpoint_address + "&persistent=true"
5468+
expected_topic_arn = "arn:aws:sns:" + zonegroup + "::" + topic_name
5469+
topic_conf = PSTopicS3(
5470+
user1_conn, topic_name, zonegroup, endpoint_args=endpoint_args
5471+
)
5472+
topic_arn = topic_conf.set_config()
5473+
assert_equal(topic_arn, expected_topic_arn)
5474+
log.info(
5475+
f"{user1_conn.access_key} created the topic {topic_arn} with args {endpoint_args}"
5476+
)
5477+
5478+
# both buckets subscribe to the same and only topic using the same notification id
5479+
notification_name = user1_bucket_name + NOTIFICATION_SUFFIX
5480+
topic_conf_list = [
5481+
{
5482+
"Id": notification_name,
5483+
"TopicArn": topic_arn,
5484+
"Events": ["s3:ObjectCreated:*"],
5485+
}
5486+
]
5487+
s3_notification_conf1 = PSNotificationS3(
5488+
user1_conn, user1_bucket_name, topic_conf_list
5489+
)
5490+
s3_notification_conf2 = PSNotificationS3(
5491+
user2_conn, user2_bucket_name, topic_conf_list
5492+
)
5493+
_, status = s3_notification_conf1.set_config()
5494+
assert_equal(status / 100, 2)
5495+
_, status = s3_notification_conf2.set_config()
5496+
assert_equal(status / 100, 2)
5497+
# verify both buckets are subscribed to the topic
5498+
rgw_topic_entry = [
5499+
t for t in list_topics()["topics"] if t["name"] == topic_name
5500+
]
5501+
assert_equal(len(rgw_topic_entry), 1)
5502+
subscribed_buckets = rgw_topic_entry[0]["subscribed_buckets"]
5503+
assert_equal(len(subscribed_buckets), 2)
5504+
assert_in(user1_bucket_name, subscribed_buckets)
5505+
assert_in(user2_bucket_name, subscribed_buckets)
5506+
log.info(
5507+
"buckets {user1_bucket_name} and {user2_bucket_name} are subscribed to {topic_arn}"
5508+
)
5509+
5510+
# move user1 to an account
5511+
account_id = "RGW98765432101234567"
5512+
cmd = ["account", "create", "--account-id", account_id]
5513+
_, rc = admin(cmd, get_config_cluster())
5514+
assert rc == 0, f"failed to create {account_id}: {rc}"
5515+
cmd = [
5516+
"user",
5517+
"modify",
5518+
"--uid",
5519+
user1_id,
5520+
"--account-id",
5521+
account_id,
5522+
"--account-root",
5523+
]
5524+
_, rc = admin(cmd, get_config_cluster())
5525+
assert rc == 0, f"failed to modify {user1_id}: {rc}"
5526+
log.info(
5527+
f"{user1_conn.access_key}/{user1_id} is migrated to account {account_id} as root user"
5528+
)
5529+
5530+
# verify the topic is functional
5531+
user1_bucket.new_key("user1obj1").set_contents_from_string("object content")
5532+
user2_bucket.new_key("user2obj1").set_contents_from_string("object content")
5533+
wait_for_queue_to_drain(topic_name, http_port=port)
5534+
http_server.verify_s3_events(
5535+
list(user1_bucket.list()) + list(user2_bucket.list()), exact_match=True
5536+
)
5537+
5538+
# create a new account topic with the same name as the existing topic
5539+
# note that the expected arn now contains the account ID
5540+
expected_topic_arn = (
5541+
"arn:aws:sns:" + zonegroup + ":" + account_id + ":" + topic_name
5542+
)
5543+
topic_conf = PSTopicS3(
5544+
user1_conn, topic_name, zonegroup, endpoint_args=endpoint_args
5545+
)
5546+
account_topic_arn = topic_conf.set_config()
5547+
assert_equal(account_topic_arn, expected_topic_arn)
5548+
log.info(
5549+
f"{user1_conn.access_key} created the account topic {account_topic_arn} with args {endpoint_args}"
5550+
)
5551+
5552+
# verify that the old topic is still functional
5553+
user1_bucket.new_key("user1obj1").set_contents_from_string("object content")
5554+
user2_bucket.new_key("user2obj1").set_contents_from_string("object content")
5555+
wait_for_queue_to_drain(topic_name, http_port=port)
5556+
# wait_for_queue_to_drain(topic_name, tenant=account_id, http_port=port)
5557+
http_server.verify_s3_events(
5558+
list(user1_bucket.list()) + list(user2_bucket.list()), exact_match=True
5559+
)
5560+
5561+
# change user1 bucket's subscription to the account topic - using the same notification ID but with the new account_topic_arn
5562+
topic_conf_list = [
5563+
{
5564+
"Id": notification_name,
5565+
"TopicArn": account_topic_arn,
5566+
"Events": ["s3:ObjectCreated:*"],
5567+
}
5568+
]
5569+
s3_notification_conf1 = PSNotificationS3(
5570+
user1_conn, user1_bucket_name, topic_conf_list
5571+
)
5572+
_, status = s3_notification_conf1.set_config()
5573+
assert_equal(status / 100, 2)
5574+
rgw_topic_entry = [
5575+
t
5576+
for t in list_topics(tenant=account_id)["topics"]
5577+
if t["name"] == topic_name
5578+
]
5579+
assert_equal(len(rgw_topic_entry), 1)
5580+
subscribed_buckets = rgw_topic_entry[0]["subscribed_buckets"]
5581+
assert_equal(len(subscribed_buckets), 1)
5582+
assert_in(user1_bucket_name, subscribed_buckets)
5583+
assert_not_in(user2_bucket_name, subscribed_buckets)
5584+
5585+
# verify both topics are functional at the same time with no duplicate notifications
5586+
user1_bucket.new_key("user1obj1").set_contents_from_string("object content")
5587+
user2_bucket.new_key("user2obj1").set_contents_from_string("object content")
5588+
wait_for_queue_to_drain(topic_name, http_port=port)
5589+
wait_for_queue_to_drain(topic_name, tenant=account_id, http_port=port)
5590+
http_server.verify_s3_events(
5591+
list(user1_bucket.list()) + list(user2_bucket.list()), exact_match=True
5592+
)
5593+
5594+
# also change user2 bucket's subscription to the account topic
5595+
s3_notification_conf2 = PSNotificationS3(
5596+
user2_conn, user2_bucket_name, topic_conf_list
5597+
)
5598+
_, status = s3_notification_conf2.set_config()
5599+
assert_equal(status / 100, 2)
5600+
# remove old topic
5601+
# note that, although account topic has the same name, it has to be scoped by account/tenant id to be removed
5602+
# so below command will only remove the old topic
5603+
_, rc = admin(["topic", "rm", "--topic", topic_name], get_config_cluster())
5604+
assert_equal(rc, 0)
5605+
5606+
# now verify account topic serves both buckets
5607+
rgw_topic_entry = [
5608+
t
5609+
for t in list_topics(tenant=account_id)["topics"]
5610+
if t["name"] == topic_name
5611+
]
5612+
assert_equal(len(rgw_topic_entry), 1)
5613+
subscribed_buckets = rgw_topic_entry[0]["subscribed_buckets"]
5614+
assert_equal(len(subscribed_buckets), 2)
5615+
assert_in(user1_bucket_name, subscribed_buckets)
5616+
assert_in(user2_bucket_name, subscribed_buckets)
5617+
5618+
# finally, make sure that notifications are going thru via the new account topic
5619+
user1_bucket.new_key("user1obj1").set_contents_from_string("object content")
5620+
user2_bucket.new_key("user2obj1").set_contents_from_string("object content")
5621+
wait_for_queue_to_drain(topic_name, tenant=account_id, http_port=port)
5622+
http_server.verify_s3_events(
5623+
list(user1_bucket.list()) + list(user2_bucket.list()), exact_match=True
5624+
)
5625+
log.info("topic migration test has completed successfully")
5626+
finally:
5627+
admin(["user", "rm", "--uid", user1_id, "--purge-data"], get_config_cluster())
5628+
admin(
5629+
["bucket", "rm", "--bucket", user1_bucket_name, "--purge-data"],
5630+
get_config_cluster(),
5631+
)
5632+
admin(
5633+
["bucket", "rm", "--bucket", user2_bucket_name, "--purge-data"],
5634+
get_config_cluster(),
5635+
)
5636+
admin(["account", "rm", "--account-id", account_id], get_config_cluster())

0 commit comments

Comments
 (0)