Skip to content

Commit 06dfe06

Browse files
authored
Merge pull request #698 from viduship/vim-rgw-accounts
CEPH-83581974 : Test LC cloud transition with scale of 1M objects
2 parents bfaa5c7 + c94484d commit 06dfe06

File tree

4 files changed

+245
-33
lines changed

4 files changed

+245
-33
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#test_rgw_account_management.py
2+
#CEPH-83581974
3+
config:
4+
user_count: 1
5+
bucket_count: 0
6+
objects_count: 10
7+
parallel_lc: true
8+
test_lc_transition: True
9+
enable_resharding: false
10+
sharding_type: manual
11+
shards: 211
12+
pool_name: data.cold
13+
storage_class: cold
14+
ec_pool_transition: False
15+
multiple_transitions: True
16+
two_pool_transition: False
17+
second_pool_name: data.glacier
18+
second_storage_class: glacier
19+
remote_zone: secondary
20+
objects_size_range:
21+
min: 5
22+
max: 15
23+
test_ops:
24+
create_bucket: false
25+
create_object: false
26+
delete_marker: false
27+
test_via_rgw_accounts: true
28+
tenant_name: tenant1
29+
region: shared
30+
reuse_account_bucket: true
31+
test_cloud_transition: true
32+
test_pool_transition: false
33+
test_ibm_cloud_transition: false
34+
test_aws_cloud_transition: true
35+
test_retain_head: true
36+
test_cloud_transition_at_remote: false
37+
lifecycle_conf:
38+
- ID: LC_Rule_1
39+
Filter:
40+
Prefix: r
41+
Status: Enabled
42+
Transitions:
43+
- Days: 1
44+
StorageClass: CLOUDAWS
45+
NoncurrentVersionTransitions:
46+
- NoncurrentDays: 1
47+
StorageClass: CLOUDAWS

rgw/v2/tests/s3_swift/reusable.py

+122-32
Original file line numberDiff line numberDiff line change
@@ -1046,36 +1046,78 @@ def put_get_bucket_lifecycle_test(
10461046
raise TestExecError("bucket lifecycle config retrieval failed")
10471047
else:
10481048
raise TestExecError("bucket life cycle retrieved")
1049-
objs_total = (config.test_ops["version_count"]) * (config.objects_count)
1050-
if not upload_start_time:
1051-
upload_start_time = time.time()
1052-
if not upload_end_time:
1053-
upload_end_time = time.time()
1054-
time_diff = math.ceil(upload_end_time - upload_start_time)
1055-
time_limit = upload_start_time + (
1056-
config.rgw_lc_debug_interval * config.test_ops.get("actual_lc_days", 20)
1057-
)
1058-
for rule in config.lifecycle_conf:
1059-
if rule.get("Expiration", {}).get("Date", False):
1060-
# todo: need to get the interval value from yaml file
1061-
log.info(f"wait for 60 seconds")
1062-
time.sleep(60)
1063-
else:
1064-
while time.time() < time_limit:
1065-
bucket_stats_op = utils.exec_shell_cmd(
1066-
"radosgw-admin bucket stats --bucket=%s" % bucket.name
1049+
if config.test_ops.get("reuse_account_bucket", False) is True:
1050+
max_retries = 1500
1051+
sleep_interval = 30
1052+
bucket_stats_output = utils.exec_shell_cmd(
1053+
f"radosgw-admin bucket stats --bucket tenant1/{bucket.name}"
1054+
)
1055+
bucket_stats_json = json.loads(bucket_stats_output)
1056+
objects_before_transition = bucket_stats_json["usage"]["rgw.main"][
1057+
"num_objects"
1058+
]
1059+
lc_transition_start_time = time.time()
1060+
for retry in range(max_retries + 2):
1061+
if retry == 0:
1062+
time.sleep(
1063+
max_retries
1064+
) # since value of max_retries is same as rgw_lc_debug_interval
1065+
1066+
bucket_stats_output = utils.exec_shell_cmd(
1067+
f"radosgw-admin bucket stats --bucket tenant1/{bucket.name}"
1068+
)
1069+
log.info(f"bucket stats output for {bucket.name}: {bucket_stats_output}")
1070+
bucket_stats_json = json.loads(bucket_stats_output)
1071+
1072+
if (
1073+
bucket_stats_json["usage"]["rgw.cloudtiered"]["num_objects"]
1074+
>= objects_before_transition
1075+
and bucket_stats_json["usage"]["rgw.usage"]["num_objects"] == 0
1076+
):
1077+
log.info(
1078+
f" all the objects for bucket successfully cloud transitioned to IBM"
10671079
)
1068-
json_doc1 = json.loads(bucket_stats_op)
1069-
obj_pre_lc = json_doc1["usage"]["rgw.main"]["num_objects"]
1070-
if obj_pre_lc == objs_total or config.test_lc_transition:
1071-
time.sleep(config.rgw_lc_debug_interval)
1072-
else:
1073-
raise TestExecError("Objects expired before the expected days")
1074-
lc_grace_time = config.test_ops.get("lc_grace_time", 90)
1075-
log.info(
1076-
f"sleeping for {time_diff + lc_grace_time} seconds so that all objects gets expired/transitioned"
1077-
)
1078-
time.sleep(time_diff + lc_grace_time)
1080+
break
1081+
else:
1082+
log.info(
1083+
f"Cloud transition still in progress after {retry} retry, sleep for {sleep_interval} and retry"
1084+
)
1085+
time.sleep(sleep_interval)
1086+
if retry > max_retries:
1087+
raise AssertionError(
1088+
f"LC transition to cloud for {objects_before_transition} failed"
1089+
)
1090+
else:
1091+
1092+
objs_total = (config.test_ops["version_count"]) * (config.objects_count)
1093+
if not upload_start_time:
1094+
upload_start_time = time.time()
1095+
if not upload_end_time:
1096+
upload_end_time = time.time()
1097+
time_diff = math.ceil(upload_end_time - upload_start_time)
1098+
time_limit = upload_start_time + (
1099+
config.rgw_lc_debug_interval * config.test_ops.get("actual_lc_days", 20)
1100+
)
1101+
for rule in config.lifecycle_conf:
1102+
if rule.get("Expiration", {}).get("Date", False):
1103+
# todo: need to get the interval value from yaml file
1104+
log.info("wait for 60 seconds")
1105+
time.sleep(60)
1106+
else:
1107+
while time.time() < time_limit:
1108+
bucket_stats_op = utils.exec_shell_cmd(
1109+
"radosgw-admin bucket stats --bucket=%s" % bucket.name
1110+
)
1111+
json_doc1 = json.loads(bucket_stats_op)
1112+
obj_pre_lc = json_doc1["usage"]["rgw.main"]["num_objects"]
1113+
if obj_pre_lc == objs_total or config.test_lc_transition:
1114+
time.sleep(config.rgw_lc_debug_interval)
1115+
else:
1116+
raise TestExecError("Objects expired before the expected days")
1117+
log.info(
1118+
f"sleeping for {time_diff + 90} seconds so that all objects gets expired/transitioned"
1119+
)
1120+
time.sleep(time_diff + 90)
10791121

10801122
if config.test_ops.get("conflict_exp_days"):
10811123
bucket_stats_op = utils.exec_shell_cmd(
@@ -2029,17 +2071,23 @@ def prepare_for_bucket_lc_transition(config):
20292071
f"radosgw-admin zonegroup placement add --rgw-zonegroup {zonegroup} --placement-id default-placement --storage-class CLOUDIBM --tier-type=cloud-s3 --tier-config=endpoint={endpoint},access_key={access},secret={secret},target_path={target_path},multipart_sync_threshold=44432,multipart_min_part_size=44432,retain_head_object=false,region=au-syd"
20302072
)
20312073
else:
2032-
target_path = "aws-bucket-01"
2074+
wget_cmd = "curl -o aws_cloud.env http://magna002.ceph.redhat.com/cephci-jenkins/aws_cloud_file"
2075+
utils.exec_shell_cmd(cmd=f"{wget_cmd}")
2076+
aws_config = configobj.ConfigObj("aws_cloud.env")
2077+
target_path = aws_config["TARGET"]
2078+
access = aws_config["ACCESS"]
2079+
secret = aws_config["SECRET"]
2080+
endpoint = aws_config["ENDPOINT"]
20332081
utils.exec_shell_cmd(
20342082
f"radosgw-admin zonegroup placement add --rgw-zonegroup {zonegroup} --placement-id default-placement --storage-class=CLOUDAWS --tier-type=cloud-s3"
20352083
)
20362084
if config.test_ops.get("test_retain_head", False):
20372085
utils.exec_shell_cmd(
2038-
f"radosgw-admin zonegroup placement add --rgw-zonegroup {zonegroup} --placement-id default-placement --storage-class CLOUDAWS --tier-type=cloud-s3 --tier-config=endpoint=http://s3region.amazonaws.com,access_key=awsaccesskey,secret=awssecretkey,target_path={target_path},multipart_sync_threshold=44432,multipart_min_part_size=44432,retain_head_object=true,region=aws-region"
2086+
f"radosgw-admin zonegroup placement add --rgw-zonegroup {zonegroup} --placement-id default-placement --storage-class CLOUDAWS --tier-type=cloud-s3 --tier-config=endpoint={endpoint},access_key={access},secret={secret},target_path={target_path},multipart_sync_threshold=44432,multipart_min_part_size=44432,retain_head_object=true,region=us-east-1"
20392087
)
20402088
else:
20412089
utils.exec_shell_cmd(
2042-
f"radosgw-admin zonegroup placement add --rgw-zonegroup {zonegroup} --placement-id default-placement --storage-class CLOUDAWS --tier-type=cloud-s3 --tier-config=endpoint=http://s3.aws-region.amazonaws.com,access_key=awsaccesskey,secret=awssecretkey,target_path={target_path},multipart_sync_threshold=44432,multipart_min_part_size=44432,retain_head_object=false,region=us-east-1"
2090+
f"radosgw-admin zonegroup placement add --rgw-zonegroup {zonegroup} --placement-id default-placement --storage-class CLOUDAWS --tier-type=cloud-s3 --tier-config=endpoint={endpoint},access_key={access},secret={secret},target_path={target_path},multipart_sync_threshold=44432,multipart_min_part_size=44432,retain_head_object=false,region=us-east-1"
20432091
)
20442092
if is_multisite:
20452093
utils.exec_shell_cmd("radosgw-admin period update --commit")
@@ -3172,3 +3220,45 @@ def bring_up_all_rgws_in_the_site(rgw_service_name, retry=10, delay=10):
31723220
break
31733221
if retry_count + 1 == retry:
31743222
raise AssertionError("Node is not in expected state!!")
3223+
3224+
3225+
def configure_rgw_lc_settings():
3226+
"""
3227+
Retrieves RGW services using 'ceph orch ls | grep rgw' and sets LC debug configs.
3228+
"""
3229+
log.info("Retrieving RGW service names...")
3230+
3231+
# Fetch RGW services
3232+
rgw_services_output = utils.exec_shell_cmd("ceph orch ls | grep rgw")
3233+
3234+
if not rgw_services_output:
3235+
log.error("No RGW services found or failed to retrieve.")
3236+
return
3237+
3238+
# Extract service names from output
3239+
rgw_services = []
3240+
for line in rgw_services_output.split("\n"):
3241+
line = line.strip()
3242+
if line: # Ignore empty lines
3243+
columns = line.split()
3244+
if columns: # Ensure there are columns before accessing
3245+
rgw_services.append(columns[0])
3246+
3247+
if not rgw_services:
3248+
log.warning("No valid RGW services extracted.")
3249+
return
3250+
3251+
log.info(f"Found RGW services: {rgw_services}")
3252+
3253+
# Set LC debug interval for each RGW service
3254+
for service in rgw_services:
3255+
lc_config_cmd1 = f"ceph config set client.{service} rgw_lc_debug_interval 600"
3256+
log.info(f"Setting LC config for {service}: {lc_config_cmd1}")
3257+
utils.exec_shell_cmd(lc_config_cmd1)
3258+
lc_config_cmd2 = "ceph config set client.{service} rgw_lc_max_worker 10"
3259+
log.info(f"Setting LC config for {service}: {lc_config_cmd2}")
3260+
utils.exec_shell_cmd(lc_config_cmd2)
3261+
ceph_restart_cmd = f"ceph orch restart {service}"
3262+
utils.exec_shell_cmd(ceph_restart_cmd)
3263+
3264+
log.info("RGW LC debug interval settings updated successfully.")

rgw/v2/tests/s3_swift/reusables/rgw_accounts.py

+66
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import boto
88
import boto3
9+
import v2.lib.resource_op as s3lib
910
import v2.utils.utils as utils
1011
from v2.lib.exceptions import TestExecError
1112
from v2.lib.rgw_config_opts import CephConfOp, ConfigOpts
@@ -255,6 +256,71 @@ def create_rgw_account_with_iam_user(config, tenant_name, region="shared"):
255256
return iam_user_details
256257

257258

259+
def reuse_account_bucket(config, rgw, user_info, location=None):
260+
"""
261+
Reuse an existing bucket for an RGW account if it meets predefined conditions.
262+
If the bucket has more than 1M objects, it is selected for reuse.
263+
:param rgw: RGW resource connection
264+
:param user_info: Dictionary containing user credentials
265+
:return: Bucket resource object if criteria met, else None
266+
"""
267+
rgw_account_id = get_rgw_account()
268+
log.info(f"Fetching bucket list for RGW account: {rgw_account_id}")
269+
270+
# Get the list of buckets
271+
cmd = f"radosgw-admin bucket list --account-id {rgw_account_id}"
272+
bucket_list_json = utils.exec_shell_cmd(cmd)
273+
274+
if not bucket_list_json:
275+
log.error("Failed to retrieve bucket list or received empty response.")
276+
return None
277+
278+
bucket_list = json.loads(bucket_list_json)
279+
280+
if not bucket_list:
281+
log.warning("No buckets found for the given account.")
282+
return None
283+
284+
log.info(f"Found {len(bucket_list)} buckets. Checking stats...")
285+
286+
for bucket_name in bucket_list:
287+
original_bucket_name = bucket_name # Keep original for logging
288+
if "tenant" in bucket_name:
289+
tenant_name, bucket_short_name = bucket_name.split(".", 1)
290+
bucket_name = f"{tenant_name}/{bucket_name}"
291+
292+
log.info(f"Checking stats for bucket: {original_bucket_name}")
293+
294+
# Fetch bucket statistics
295+
stats_cmd = f"radosgw-admin bucket stats --bucket {bucket_name}"
296+
bucket_stats_json = utils.exec_shell_cmd(stats_cmd)
297+
298+
if not bucket_stats_json:
299+
log.warning(f"Skipping {original_bucket_name}: Failed to retrieve stats.")
300+
continue
301+
302+
bucket_stats = json.loads(bucket_stats_json)
303+
num_objects = (
304+
bucket_stats.get("usage", {}).get("rgw.main", {}).get("num_objects", 0)
305+
)
306+
307+
log.info(f"Bucket {original_bucket_name} has {num_objects} objects.")
308+
309+
if num_objects >= 1100000:
310+
log.info(
311+
f"Bucket {original_bucket_name} meets criteria. Returning for reuse."
312+
)
313+
314+
# Return bucket in the expected format
315+
bucket = s3lib.resource_op(
316+
{"obj": rgw, "resource": "Bucket", "args": [original_bucket_name]}
317+
)
318+
return bucket # Return the first valid bucket
319+
320+
log.warning("No buckets met the 1M objects criteria.")
321+
return None # No valid bucket found
322+
323+
258324
def perform_user_adoption(config, user_info, bucket):
259325
"""
260326
Perform user adoption by migrating an RGW user to an RGW account.

rgw/v2/tests/s3_swift/test_rgw_account_management.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
The Input yamls are
88
# configs/test_account_ownership_change_user_adoption.yaml
99
# multisite_configs/test_rgw_accounts_at_scale.yaml
10+
# multisite_configs/test_scale_aws_transition_retain_true.yaml
1011
1112
Usage is test_rgw_account_management.py -c <path_to_config_file>
1213
@@ -64,9 +65,17 @@ def test_exec(config, ssh_con):
6465
for each_user in all_users_info:
6566
auth = Auth(each_user, ssh_con, ssl=config.ssl)
6667
rgw_conn = auth.do_auth()
68+
rgw_conn2 = auth.do_auth_using_client()
6769
log.info(f"Creating {config.bucket_count} buckets for {each_user['user_id']}")
6870
user_buckets = [] # Store buckets for this user
69-
71+
if config.test_ops.get("reuse_account_bucket", False) is True:
72+
life_cycle_rule = {"Rules": config.lifecycle_conf}
73+
reusable.prepare_for_bucket_lc_transition(config)
74+
bucket = accounts.reuse_account_bucket(config, rgw_conn, each_user)
75+
reusable.configure_rgw_lc_settings()
76+
reusable.put_get_bucket_lifecycle_test(
77+
bucket, rgw_conn, rgw_conn2, life_cycle_rule, config
78+
)
7079
for bc in range(config.bucket_count):
7180
bucket_name = utils.gen_bucket_name_from_userid(
7281
each_user["user_id"], rand_no=bc

0 commit comments

Comments
 (0)