Skip to content

Commit 000d842

Browse files
author
Ionut Balutoiu
committed
CephRGWTest: Add Ceph RGW Cloud Sync integration test
Add integration test for the Cloud Sync feature proposed to the upstream `ceph-radosgw` Juju charm. Signed-off-by: Ionut Balutoiu <ibalutoiu@cloudbasesolutions.com>
1 parent 6f9c9f7 commit 000d842

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed

zaza/openstack/charm_tests/ceph/tests.py

+153
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,12 @@ class CephRGWTest(test_utils.BaseCharmTest):
657657
primary_rgw_unit = 'ceph-radosgw/0'
658658
secondary_rgw_app = 'secondary-ceph-radosgw'
659659
secondary_rgw_unit = 'secondary-ceph-radosgw/0'
660+
cloud_sync_rgw_app = 'cloud-sync-ceph-radosgw'
661+
# These S3 Juju apps are used for the cloud sync tests. They are deployed
662+
# using the following Juju charm: https://charmhub.io/minio-test
663+
# Their purpose is to provide S3 destinations for the cloud sync tests.
664+
cloud_sync_default_s3_app = 's3-default'
665+
cloud_sync_dev_s3_app = 's3-dev'
660666

661667
@classmethod
662668
def setUpClass(cls):
@@ -685,6 +691,15 @@ def multisite(self):
685691
except KeyError:
686692
return False
687693

694+
@property
695+
def cloud_sync(self):
696+
"""Determine whether Ceph cloud sync application is present."""
697+
try:
698+
zaza_model.get_application(self.cloud_sync_rgw_app)
699+
return True
700+
except KeyError:
701+
return False
702+
688703
def get_rgwadmin_cmd_skeleton(self, unit_name):
689704
"""
690705
Get radosgw-admin cmd skeleton with rgw.hostname populated key.
@@ -855,6 +870,35 @@ def get_rgw_endpoint(self, unit_name: str):
855870
except KeyError:
856871
return "http://{}:80".format(unit_address)
857872

873+
def get_minio_boto3_client(self, app_name: str):
874+
"""Get boto3 client for MinIO application.
875+
876+
:param app_name: MinIO Juju app name.
877+
:type app_name: str
878+
"""
879+
leader_unit = zaza_model.get_lead_unit(app_name)
880+
unit_address = zaza_model.get_unit_public_address(
881+
leader_unit,
882+
self.model_name
883+
)
884+
885+
logging.debug("Minio Leader Unit: {}, Endpoint: {}".format(
886+
leader_unit.entity_id, unit_address))
887+
if unit_address is None:
888+
return None
889+
890+
app_config = zaza_model.get_application_config(app_name)
891+
port = app_config['port'].get('value')
892+
access_key = app_config['root-user'].get('value')
893+
access_secret = app_config['root-password'].get('value')
894+
895+
return boto3.resource(
896+
"s3",
897+
verify=False,
898+
endpoint_url="http://{}:{}".format(unit_address, port),
899+
aws_access_key_id=access_key,
900+
aws_secret_access_key=access_secret)
901+
858902
def configure_rgw_apps_for_multisite(self):
859903
"""Configure Multisite values on primary and secondary apps."""
860904
realm = 'zaza_realm'
@@ -876,6 +920,15 @@ def configure_rgw_apps_for_multisite(self):
876920
'zone': 'zaza_secondary'
877921
}
878922
)
923+
if self.cloud_sync:
924+
zaza_model.set_application_config(
925+
self.cloud_sync_rgw_app,
926+
{
927+
'realm': realm,
928+
'zonegroup': zonegroup,
929+
'zone': 'zaza_cloud_sync'
930+
}
931+
)
879932

880933
def configure_rgw_multisite_relation(self):
881934
"""Configure multi-site relation between primary and secondary apps."""
@@ -1074,6 +1127,13 @@ def test_003_object_storage_and_secondary_block(self):
10741127
"Non-Pristine RGW site can't be used as secondary"
10751128
}
10761129
}
1130+
if self.cloud_sync:
1131+
assert_state[self.cloud_sync_rgw_app] = {
1132+
"workload-status": "blocked",
1133+
"workload-status-message-prefix":
1134+
"multi-site configuration but primary/secondary "
1135+
"relation missing",
1136+
}
10771137
zaza_model.wait_for_application_states(states=assert_state,
10781138
timeout=900)
10791139

@@ -1294,6 +1354,99 @@ def test_004_multisite_directional_sync_policy(self):
12941354
)
12951355
zaza_model.wait_for_unit_idle(self.primary_rgw_unit)
12961356

1357+
def test_005_object_storage_cloud_sync(self):
1358+
"""Verify Ceph RGW Cloud Sync functionality."""
1359+
# Skip cloud sync tests if not compatible with bundle.
1360+
if not self.cloud_sync:
1361+
raise unittest.SkipTest('Skipping Cloud Sync Test')
1362+
1363+
obj_name = 'testfile'
1364+
# Syncs to default S3 target.
1365+
default_container_name = 'zaza-cloud-sync-container'
1366+
default_obj_data = 'Test data from Zaza'
1367+
# Syncs to dev S3 target.
1368+
dev_container_name = 'dev-zaza-cloud-sync-container'
1369+
dev_obj_data = 'Test dev data from Zaza'
1370+
1371+
# Configure cloud-sync multi-site relation.
1372+
logging.info('Configuring Cloud Sync Multisite')
1373+
self.configure_rgw_apps_for_multisite()
1374+
zaza_model.add_relation(
1375+
self.primary_rgw_app,
1376+
self.primary_rgw_app + ":primary",
1377+
self.cloud_sync_rgw_app + ":cloud-sync"
1378+
)
1379+
assert_state = {
1380+
self.secondary_rgw_app: {
1381+
"workload-status": "blocked",
1382+
"workload-status-message-prefix":
1383+
"multi-site configuration but primary/secondary "
1384+
"relation missing",
1385+
}
1386+
}
1387+
zaza_model.wait_for_application_states(states=assert_state,
1388+
timeout=900)
1389+
1390+
logging.info('Verifying Ceph RGW Cloud Sync functionality')
1391+
1392+
# Fetch Primary Endpoint Details.
1393+
primary_endpoint = self.get_rgw_endpoint(self.primary_rgw_unit)
1394+
self.assertNotEqual(primary_endpoint, None)
1395+
1396+
# Create RGW client and perform IO to be synced to both S3 targets.
1397+
access_key, secret_key = self.get_client_keys()
1398+
primary_client = boto3.resource("s3",
1399+
verify=False,
1400+
endpoint_url=primary_endpoint,
1401+
aws_access_key_id=access_key,
1402+
aws_secret_access_key=secret_key)
1403+
default_container = primary_client.Bucket(default_container_name)
1404+
default_container.create()
1405+
default_obj = primary_client.Object(default_container_name, obj_name)
1406+
default_obj.put(Body=default_obj_data)
1407+
dev_container = primary_client.Bucket(dev_container_name)
1408+
dev_container.create()
1409+
dev_obj = primary_client.Object(dev_container_name, obj_name)
1410+
dev_obj.put(Body=dev_obj_data)
1411+
1412+
# Wait for sync to complete.
1413+
logging.info('Waiting for Cloud Sync Data and Metadata to Synchronize')
1414+
self.wait_for_status(self.cloud_sync_rgw_app, is_primary=False)
1415+
1416+
# Create clients for the cloud-sync S3 targets.
1417+
default_s3_client = self.get_minio_boto3_client(
1418+
self.cloud_sync_default_s3_app
1419+
)
1420+
self.assertNotEqual(default_s3_client, None)
1421+
dev_s3_client = self.get_minio_boto3_client(self.cloud_sync_dev_s3_app)
1422+
self.assertNotEqual(dev_s3_client, None)
1423+
1424+
# Verify that data was properly synced.
1425+
logging.info('Verifying Synced Data on S3 Targets')
1426+
test_data = self.fetch_rgw_object(default_s3_client,
1427+
default_container_name,
1428+
obj_name)
1429+
self.assertEqual(test_data, default_obj_data)
1430+
test_data = self.fetch_rgw_object(dev_s3_client,
1431+
dev_container_name,
1432+
obj_name)
1433+
self.assertEqual(test_data, dev_obj_data)
1434+
1435+
# Perform cleanup.
1436+
logging.info('Performing Cleanup')
1437+
self.purge_bucket(self.primary_rgw_app, default_container_name)
1438+
self.purge_bucket(self.primary_rgw_app, dev_container_name)
1439+
1440+
# Wait for sync to complete.
1441+
self.wait_for_status(self.cloud_sync_rgw_app, is_primary=False)
1442+
1443+
# Validate that synced data was removed from the S3 targets.
1444+
logging.info('Verifying that data was deleted on the S3 targets')
1445+
with self.assertRaises(botocore.exceptions.ClientError):
1446+
default_s3_client.Object(default_container_name, obj_name).get()
1447+
with self.assertRaises(botocore.exceptions.ClientError):
1448+
dev_s3_client.Object(dev_container_name, obj_name).get()
1449+
12971450
def test_100_migration_and_multisite_failover(self):
12981451
"""Perform multisite migration and verify failover."""
12991452
container_name = 'zaza-container'

0 commit comments

Comments
 (0)