From 6dcdf010d501c32c86a335dcad02f7f0c9a405d9 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Mon, 24 Jul 2023 15:07:08 +0300 Subject: [PATCH 01/14] Create the delete_all_noobaa_buckets util function Signed-off-by: Sagi Hirshfeld --- ocs_ci/ocs/bucket_utils.py | 29 ++++ .../object/mcg/test_bucket_deletion.py | 28 +--- .../mcg/test_default_backingstore_override.py | 131 ++++++++++++++++++ 3 files changed, 163 insertions(+), 25 deletions(-) create mode 100644 tests/functional/object/mcg/test_default_backingstore_override.py diff --git a/ocs_ci/ocs/bucket_utils.py b/ocs_ci/ocs/bucket_utils.py index 989fdc57163..7ba07755f33 100644 --- a/ocs_ci/ocs/bucket_utils.py +++ b/ocs_ci/ocs/bucket_utils.py @@ -2029,3 +2029,32 @@ def sample_if_objects_expired(mcg_obj, bucket_name, prefix="", timeout=600, slee assert sampler.wait_for_func_status(result=True), f"{message} are not expired" logger.info(f"{message} are expired") + + +def delete_all_noobaa_buckets(mcg_obj, request): + """ + Deletes all the buckets in noobaa and restores the first.bucket after the current test + + Args: + mcg_obj: MCG object + request: pytest request object + """ + + logger.info("Listing all buckets in the cluster") + buckets = mcg_obj.s3_client.list_buckets() + + logger.info("Deleting all buckets and its objects") + for bucket in buckets["Buckets"]: + logger.info(f"Deleting {bucket} and its objects") + s3_bucket = mcg_obj.s3_resource.Bucket(bucket["Name"]) + s3_bucket.objects.all().delete() + s3_bucket.delete() + + def finalizer(): + if "first.bucket" not in mcg_obj.s3_client.list_buckets()["Buckets"]: + logger.info("Creating the default bucket: first.bucket") + mcg_obj.s3_client.create_bucket(Bucket="first.bucket") + else: + logger.info("Skipping creation of first.bucket as it already exists") + + request.addfinalizer(finalizer) diff --git a/tests/functional/object/mcg/test_bucket_deletion.py b/tests/functional/object/mcg/test_bucket_deletion.py index 2ee6925dc4a..ef3b769e533 100644 --- a/tests/functional/object/mcg/test_bucket_deletion.py +++ b/tests/functional/object/mcg/test_bucket_deletion.py @@ -17,6 +17,7 @@ from ocs_ci.framework.testlib import MCGTest from ocs_ci.helpers.helpers import create_unique_resource_name from ocs_ci.ocs.bucket_utils import ( + delete_all_noobaa_buckets, sync_object_directory, rm_object_recursive, ) @@ -202,40 +203,17 @@ def test_s3_bucket_delete_1t_objects(self, mcg_obj, awscli_pod_session): rm_object_recursive(awscli_pod_session, bucketname, mcg_obj) mcg_obj.s3_resource.Bucket(bucketname).delete() - @pytest.fixture(scope="function") - def default_bucket_teardown(self, request, mcg_obj): - """ - Recreates first.bucket - """ - - def finalizer(): - if "first.bucket" not in mcg_obj.s3_client.list_buckets()["Buckets"]: - logger.info("Creating the default bucket: first.bucket") - mcg_obj.s3_client.create_bucket(Bucket="first.bucket") - else: - logger.info("Skipping creation of first.bucket as it already exists") - - request.addfinalizer(finalizer) - @tier3 @skipif_managed_service @bugzilla("1980299") @pytest.mark.polarion_id("OCS-2704") @skipif_ocs_version("<4.9") - def test_delete_all_buckets(self, mcg_obj, bucket_factory, default_bucket_teardown): + def test_delete_all_buckets(self, request, mcg_obj, bucket_factory): """ Test with deletion of all buckets including the default first.bucket. """ - logger.info("Listing all buckets in the cluster") - buckets = mcg_obj.s3_client.list_buckets() - - logger.info("Deleting all buckets and its objects") - for bucket in buckets["Buckets"]: - logger.info(f"Deleting {bucket} and its objects") - s3_bucket = mcg_obj.s3_resource.Bucket(bucket["Name"]) - s3_bucket.objects.all().delete() - s3_bucket.delete() + delete_all_noobaa_buckets(mcg_obj, request) logger.info("Verifying no bucket exists") assert not mcg_obj.s3_get_all_bucket_names(), "Failed: Buckets exists" diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py new file mode 100644 index 00000000000..19267b7914c --- /dev/null +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -0,0 +1,131 @@ +import json +import logging +import pytest + +from ocs_ci.framework import config +from ocs_ci.framework.testlib import MCGTest +from ocs_ci.ocs import constants +from ocs_ci.ocs.bucket_utils import delete_all_noobaa_buckets +from ocs_ci.ocs.ocp import OCP + +logger = logging.getLogger(__name__) + + +class TestDefaultBackingstoreOverride(MCGTest): + """ + Test overriding the default noobaa backingstore + """ + + @pytest.fixture(scope="function") + def override_nb_default_backingstore_fixture( + self, request, mcg_obj_session, backingstore_factory + ): + """ """ + + nb_ocp_obj = OCP( + kind="noobaa", + namespace=config.ENV_DATA["cluster_namespace"], + resource_name="noobaa", + ) + + bucketclass_ocp_obj = OCP( + kind=constants.BUCKETCLASS, + namespace=config.ENV_DATA["cluster_namespace"], + resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + ) + + # Add manualDefaultBackingStore: true to the noobaa CR + add_op = [ + {"op": "add", "path": "/spec/manualDefaultBackingStore", "value": True} + ] + nb_ocp_obj.patch( + resource_name=constants.NOOBAA_RESOURCE_NAME, + params=json.dumps(add_op), + format_type="json", + ) + + def override_nb_default_backingstore_implementation( + mcg_obj, alternative_backingstore_name + ): + """ """ + + # Delete all the noobaa buckets + delete_all_noobaa_buckets(mcg_obj, request) + + # Update the new default resource of the admin account + + mcg_obj.exec_mcg_cmd( + "".join( + ( + f"account update {mcg_obj.noobaa_user} ", + f"--new_default_resource={alternative_backingstore_name}", + ) + ) + ) + + # Patch the default bucketclass to use the new default backingstore + update_op = [ + { + "op": "replace", + "path": "/spec/placementPolicy/tiers/0/backingStores/0", + "value": alternative_backingstore_name, + } + ] + bucketclass_ocp_obj.patch( + resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + params=json.dumps(update_op), + format_type="json", + ) + + def finalizer(): + override_nb_default_backingstore_implementation( + mcg_obj_session, constants.DEFAULT_NOOBAA_BACKINGSTORE + ) + + # Remove manualDefaultBackingStore: true to the noobaa CR + remove_op = [ + { + "op": "remove", + "path": "/spec/manualDefaultBackingStore", + } + ] + nb_ocp_obj.patch( + resource_name=constants.NOOBAA_RESOURCE_NAME, + params=json.dumps(remove_op), + format_type="json", + ) + + request.addfinalizer(finalizer) + return override_nb_default_backingstore_implementation + + def test_default_mcg_cli_buckets_use_new_backingstore( + self, + mcg_obj_session, + backingstore_factory, + bucket_factory, + override_nb_default_backingstore_fixture, + ): + alternative_backingstore = backingstore_factory( + *("oc", {"aws": [(1, "eu-central-1")]}) + )[0] + override_nb_default_backingstore_fixture( + mcg_obj_session, alternative_backingstore.name + ) + + default_cli_bucket = bucket_factory(amount=1, interface="cli")[0] + # TODO assert that default_cli_bucket is using the new backingstore + + assert default_cli_bucket + + def test_default_obcs_use_new_backingstore( + self, override_nb_default_backingstore_fixture + ): + pass + + def test_default_backingstore_override_post_upgrade(self): + pass + + def test_bucketclass_replication_after_default_backingstore_override( + self, override_nb_default_backingstore_fixture + ): + pass From f4d078db21f6db5c0718aba6ca7544f5731c53eb Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Sun, 6 Aug 2023 14:52:12 +0300 Subject: [PATCH 02/14] Combine test 1 and 2, verify new bstore Signed-off-by: Sagi Hirshfeld --- ocs_ci/ocs/bucket_utils.py | 34 +++++ .../mcg/test_default_backingstore_override.py | 139 ++++++++++++------ 2 files changed, 124 insertions(+), 49 deletions(-) diff --git a/ocs_ci/ocs/bucket_utils.py b/ocs_ci/ocs/bucket_utils.py index 7ba07755f33..9f452b83a1f 100644 --- a/ocs_ci/ocs/bucket_utils.py +++ b/ocs_ci/ocs/bucket_utils.py @@ -2058,3 +2058,37 @@ def finalizer(): logger.info("Skipping creation of first.bucket as it already exists") request.addfinalizer(finalizer) + + +def get_nb_bucket_stores(mcg_obj, bucket_name): + """ + Query the noobaa-db for the backingstores/namespacestores + that a given bucket is using for its data placement + + Args: + mcg_obj: MCG object + bucket_name: name of the bucket + + Returns: + list: list of backingstores/namespacestores names + + """ + stores = set() + bucket_data = bucket_read_api(mcg_obj, bucket_name) + + # Namespacestore bucket + if "namespace" in bucket_data: + read_srcs_list = [ + d["resource"] for d in bucket_data["namespace"]["read_resources"] + ] + write_src = bucket_data["namespace"]["write_resource"]["resource"] + stores.update(read_srcs_list + [write_src]) + + # Data bucket + else: + tiers = [d["tier"] for d in bucket_data["tiering"]["tiers"]] + for tier in tiers: + tier_data = mcg_obj.send_rpc_query("tier_api", "read_tier", {"name": tier}) + stores.update(tier_data["reply"]["attached_pools"]) + + return list(stores) diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py index 19267b7914c..66c597eb603 100644 --- a/tests/functional/object/mcg/test_default_backingstore_override.py +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -5,36 +5,30 @@ from ocs_ci.framework import config from ocs_ci.framework.testlib import MCGTest from ocs_ci.ocs import constants -from ocs_ci.ocs.bucket_utils import delete_all_noobaa_buckets +from ocs_ci.ocs.bucket_utils import get_nb_bucket_stores from ocs_ci.ocs.ocp import OCP logger = logging.getLogger(__name__) -class TestDefaultBackingstoreOverride(MCGTest): +@pytest.fixture(scope="class") +def allow_default_backingstore_override(request): """ - Test overriding the default noobaa backingstore + Modify the noobaa CR to allow overriding the default backingstore + """ - @pytest.fixture(scope="function") - def override_nb_default_backingstore_fixture( - self, request, mcg_obj_session, backingstore_factory - ): - """ """ + nb_ocp_obj = OCP( + kind="noobaa", + namespace=config.ENV_DATA["cluster_namespace"], + resource_name="noobaa", + ) - nb_ocp_obj = OCP( - kind="noobaa", - namespace=config.ENV_DATA["cluster_namespace"], - resource_name="noobaa", - ) - - bucketclass_ocp_obj = OCP( - kind=constants.BUCKETCLASS, - namespace=config.ENV_DATA["cluster_namespace"], - resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, - ) + def patch_allow_manual_default_backingstore(): + """ + Patch "manualDefaultBackingStore: true" to the noobaa CR - # Add manualDefaultBackingStore: true to the noobaa CR + """ add_op = [ {"op": "add", "path": "/spec/manualDefaultBackingStore", "value": True} ] @@ -44,16 +38,59 @@ def override_nb_default_backingstore_fixture( format_type="json", ) + def finalizer(): + """ + Remove "manualDefaultBackingStore: true" from the noobaa CR + + """ + remove_op = [ + { + "op": "remove", + "path": "/spec/manualDefaultBackingStore", + } + ] + nb_ocp_obj.patch( + resource_name=constants.NOOBAA_RESOURCE_NAME, + params=json.dumps(remove_op), + format_type="json", + ) + + request.addfinalizer(finalizer) + patch_allow_manual_default_backingstore() + + +@pytest.mark.usefixtures(allow_default_backingstore_override.__name__) +class TestDefaultBackingstoreOverride(MCGTest): + """ + Test overriding the default noobaa backingstore + """ + + @pytest.fixture(scope="function") + def override_nb_default_backingstore(self, request, mcg_obj_session): + """ + Override the default noobaa backingstore to the given alternative backingstore + + """ + + bucketclass_ocp_obj = OCP( + kind=constants.BUCKETCLASS, + namespace=config.ENV_DATA["cluster_namespace"], + resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + ) + def override_nb_default_backingstore_implementation( mcg_obj, alternative_backingstore_name ): - """ """ + """ + 1. Update the new default resource of the admin account + 2. Patch the default bucketclass to use the new default backingstore - # Delete all the noobaa buckets - delete_all_noobaa_buckets(mcg_obj, request) + Args: + mcg_obj (MCG): An MCG object + alternative_backingstore_name (str): The name of the alternative backingstore + """ # Update the new default resource of the admin account - mcg_obj.exec_mcg_cmd( "".join( ( @@ -78,54 +115,58 @@ def override_nb_default_backingstore_implementation( ) def finalizer(): + """ + Change the default backingstore back to the original + + """ override_nb_default_backingstore_implementation( mcg_obj_session, constants.DEFAULT_NOOBAA_BACKINGSTORE ) - # Remove manualDefaultBackingStore: true to the noobaa CR - remove_op = [ - { - "op": "remove", - "path": "/spec/manualDefaultBackingStore", - } - ] - nb_ocp_obj.patch( - resource_name=constants.NOOBAA_RESOURCE_NAME, - params=json.dumps(remove_op), - format_type="json", - ) - request.addfinalizer(finalizer) return override_nb_default_backingstore_implementation - def test_default_mcg_cli_buckets_use_new_backingstore( + def test_default_buckets_backingstore( self, mcg_obj_session, backingstore_factory, bucket_factory, - override_nb_default_backingstore_fixture, + override_nb_default_backingstore, ): + """ + 1. Override the default noobaa backingstore + 2. Create a new bucket using the mcg-cli with the default config + 3. Create a new OBC using oc and yamls without specifying the bucketclass + 4. Verify the buckets' backingstore is the new default backingstore + + """ + + # Override the default noobaa backingstore alternative_backingstore = backingstore_factory( *("oc", {"aws": [(1, "eu-central-1")]}) )[0] - override_nb_default_backingstore_fixture( - mcg_obj_session, alternative_backingstore.name - ) + override_nb_default_backingstore(mcg_obj_session, alternative_backingstore.name) + # Create a new bucket using the mcg-cli with the default backingstore default_cli_bucket = bucket_factory(amount=1, interface="cli")[0] - # TODO assert that default_cli_bucket is using the new backingstore - assert default_cli_bucket + # Create a new OBC using oc and yamls without specifying the bucketclass + default_obc_bucket = bucket_factory(amount=1, interface="oc")[0] - def test_default_obcs_use_new_backingstore( - self, override_nb_default_backingstore_fixture - ): - pass + # Verify the bucket's backingstore is the new default backingstore + assert ( + get_nb_bucket_stores(mcg_obj_session, default_cli_bucket.name)[0] + == alternative_backingstore.name + ), "The default mcg-cli bucket does not use the new default backingstore!" + assert ( + get_nb_bucket_stores(mcg_obj_session, default_obc_bucket.name)[0] + == alternative_backingstore.name + ), "The default OC bucket does not use the new default backingstore!" def test_default_backingstore_override_post_upgrade(self): pass def test_bucketclass_replication_after_default_backingstore_override( - self, override_nb_default_backingstore_fixture + self, override_nb_default_backingstore ): pass From 666f3f404b6708ca1a5bb86481af89cd04982dbe Mon Sep 17 00:00:00 2001 From: Vijay Bhaskar Reddy Avuthu Date: Mon, 31 Jul 2023 12:13:39 +0530 Subject: [PATCH 03/14] Merge pull request #8127 from DanielOsypenko/fix--flak8-isinstance-failure Fix for the common tox issue: 'isinstance instead of type(obj) == type' Signed-off-by: Sagi Hirshfeld --- .../mcg/test_default_backingstore_override.py | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py index 66c597eb603..173c47395f3 100644 --- a/tests/functional/object/mcg/test_default_backingstore_override.py +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -1,8 +1,10 @@ import json import logging + import pytest from ocs_ci.framework import config +from ocs_ci.framework.pytest_customization.marks import tier1 from ocs_ci.framework.testlib import MCGTest from ocs_ci.ocs import constants from ocs_ci.ocs.bucket_utils import get_nb_bucket_stores @@ -126,6 +128,7 @@ def finalizer(): request.addfinalizer(finalizer) return override_nb_default_backingstore_implementation + @tier1 def test_default_buckets_backingstore( self, mcg_obj_session, @@ -141,19 +144,22 @@ def test_default_buckets_backingstore( """ - # Override the default noobaa backingstore - alternative_backingstore = backingstore_factory( - *("oc", {"aws": [(1, "eu-central-1")]}) - )[0] + # 1. Override the default noobaa backingstore + if config.ENV_DATA["mcg_only_deployment"]: + uls_dict = {"aws": [(1, "eu-central-1")]} + else: + # Supported in all deployment types except mcg-only + uls_dict = {"pv": [(1, 20, constants.DEFAULT_STORAGECLASS_RBD)]} + alternative_backingstore = backingstore_factory("oc", uls_dict)[0] override_nb_default_backingstore(mcg_obj_session, alternative_backingstore.name) - # Create a new bucket using the mcg-cli with the default backingstore + # 2. Create a new bucket using the mcg-cli with the default backingstore default_cli_bucket = bucket_factory(amount=1, interface="cli")[0] - # Create a new OBC using oc and yamls without specifying the bucketclass + # 3. Create a new OBC using oc and yamls without specifying the bucketclass default_obc_bucket = bucket_factory(amount=1, interface="oc")[0] - # Verify the bucket's backingstore is the new default backingstore + # 4. Verify the bucket's backingstore is the new default backingstore assert ( get_nb_bucket_stores(mcg_obj_session, default_cli_bucket.name)[0] == alternative_backingstore.name @@ -163,6 +169,8 @@ def test_default_buckets_backingstore( == alternative_backingstore.name ), "The default OC bucket does not use the new default backingstore!" + self.a + def test_default_backingstore_override_post_upgrade(self): pass From aa333f4340b10b1726c79689ee5e1ffee8d72f53 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Sun, 3 Sep 2023 19:50:30 +0300 Subject: [PATCH 04/14] bucket_utils.py changes: - Remove the obsolete version checking in patch_replication_policy_to_bucket - Add the patch_replication_policy_to_bucketclass Signed-off-by: Sagi Hirshfeld --- ocs_ci/ocs/bucket_utils.py | 40 +++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/ocs_ci/ocs/bucket_utils.py b/ocs_ci/ocs/bucket_utils.py index 9f452b83a1f..9dc2e8a0638 100644 --- a/ocs_ci/ocs/bucket_utils.py +++ b/ocs_ci/ocs/bucket_utils.py @@ -15,7 +15,7 @@ from ocs_ci.ocs import constants from ocs_ci.ocs.exceptions import TimeoutExpiredError, UnexpectedBehaviour from ocs_ci.ocs.ocp import OCP -from ocs_ci.utility import templating, version +from ocs_ci.utility import templating from ocs_ci.utility.ssl_certs import get_root_ca_cert from ocs_ci.utility.utils import TimeoutSampler, run_cmd from ocs_ci.helpers.helpers import create_resource @@ -1757,16 +1757,9 @@ def patch_replication_policy_to_bucket(bucket_name, rule_id, destination_bucket_ rule_id (str): The ID of the replication rule destination_bucket_name (str): The name of the replication destination bucket """ - if version.get_semantic_ocs_version_from_config() >= version.VERSION_4_12: - replication_policy = { - "rules": [ - {"rule_id": rule_id, "destination_bucket": destination_bucket_name} - ] - } - else: - replication_policy = [ - {"rule_id": rule_id, "destination_bucket": destination_bucket_name} - ] + replication_policy = { + "rules": [{"rule_id": rule_id, "destination_bucket": destination_bucket_name}] + } replication_policy_patch_dict = { "spec": { "additionalConfig": {"replicationPolicy": json.dumps(replication_policy)} @@ -1802,6 +1795,31 @@ def update_replication_policy(bucket_name, replication_policy_dict): ).patch(params=json.dumps(replication_policy_patch_dict), format_type="merge") +def patch_replication_policy_to_bucketclass( + bucketclass_name, rule_id, destination_bucket_name +): + """ + Patches replication policy to a bucket + + Args: + bucketclass_name (str): The name of the bucketclass to patch + rule_id (str): The ID of the replication rule + destination_bucket_name (str): The name of the replication destination bucket + """ + + replication_policy = { + "rules": [{"rule_id": rule_id, "destination_bucket": destination_bucket_name}] + } + replication_policy_patch_dict = { + "spec": {"replicationPolicy": json.dumps(replication_policy)} + } + OCP( + kind="bucketclass", + namespace=config.ENV_DATA["cluster_namespace"], + resource_name=bucketclass_name, + ).patch(params=json.dumps(replication_policy_patch_dict), format_type="merge") + + def random_object_round_trip_verification( io_pod, bucket_name, From 2b92878518e5c0e12b6e06297865f3b519fd0729 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Tue, 26 Sep 2023 18:21:18 +0300 Subject: [PATCH 05/14] Add the red_squad decoator Signed-off-by: Sagi Hirshfeld --- .../object/mcg/test_default_backingstore_override.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py index 173c47395f3..77728da59c4 100644 --- a/tests/functional/object/mcg/test_default_backingstore_override.py +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -4,7 +4,7 @@ import pytest from ocs_ci.framework import config -from ocs_ci.framework.pytest_customization.marks import tier1 +from ocs_ci.framework.pytest_customization.marks import tier1, red_squad from ocs_ci.framework.testlib import MCGTest from ocs_ci.ocs import constants from ocs_ci.ocs.bucket_utils import get_nb_bucket_stores @@ -61,6 +61,7 @@ def finalizer(): patch_allow_manual_default_backingstore() +@red_squad @pytest.mark.usefixtures(allow_default_backingstore_override.__name__) class TestDefaultBackingstoreOverride(MCGTest): """ From ab2b6fcf52b11c133e07ef1960c0f20c21e8e0e1 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Mon, 20 Nov 2023 17:59:10 +0200 Subject: [PATCH 06/14] Implement the pre-post-upgrade TC Signed-off-by: Sagi Hirshfeld --- ocs_ci/ocs/constants.py | 2 + .../mcg/test_default_backingstore_override.py | 147 +++++++++++++++++- 2 files changed, 143 insertions(+), 6 deletions(-) diff --git a/ocs_ci/ocs/constants.py b/ocs_ci/ocs/constants.py index c80df013df0..28f71d195d5 100644 --- a/ocs_ci/ocs/constants.py +++ b/ocs_ci/ocs/constants.py @@ -1886,6 +1886,8 @@ BACKINGSTORE_TYPE_AZURE = "azure-blob" BACKINGSTORE_TYPE_S3_COMP = "s3-compatible" BACKINGSTORE_TYPE_GOOGLE = "google-cloud-storage" +BACKINGSTORE_TYPE_PV_POOL = "pv-pool" + # Squads assignment # Tests are assigned to Squads based on patterns matching test path. diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py index 77728da59c4..e0654fb8b88 100644 --- a/tests/functional/object/mcg/test_default_backingstore_override.py +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -4,7 +4,13 @@ import pytest from ocs_ci.framework import config -from ocs_ci.framework.pytest_customization.marks import tier1, red_squad +from ocs_ci.framework.pytest_customization.marks import ( + red_squad, + tier1, + pre_upgrade, + post_upgrade, + skipif_mcg_only, +) from ocs_ci.framework.testlib import MCGTest from ocs_ci.ocs import constants from ocs_ci.ocs.bucket_utils import get_nb_bucket_stores @@ -61,14 +67,69 @@ def finalizer(): patch_allow_manual_default_backingstore() +def get_admin_default_resource_name(mcg_obj): + """ + Get the default resource name of the admin account + + Args: + mcg_obj (MCG): An MCG object + + Returns: + str: The default resource name + + """ + + read_account_output = mcg_obj.send_rpc_query( + "account_api", + "read_account", + params={ + "email": mcg_obj.noobaa_user, + }, + ) + return read_account_output.json()["reply"]["default_resource"] + + +def get_default_bc_backingstore_name(mcg_obj): + """ + Get the default backingstore name of the default bucketclass + + Args: + mcg_obj (MCG): An MCG object + + Returns: + str: The default backingstore name + + """ + bucketclass_ocp_obj = OCP( + kind=constants.BUCKETCLASS, + namespace=config.ENV_DATA["cluster_namespace"], + resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + ) + return ( + bucketclass_ocp_obj.get() + .get("spec") + .get("placementPolicy") + .get("tiers")[0] + .get("backingStores")[0] + ) + + @red_squad @pytest.mark.usefixtures(allow_default_backingstore_override.__name__) class TestDefaultBackingstoreOverride(MCGTest): """ Test overriding the default noobaa backingstore + """ + @pytest.fixture(scope="session") + def override_nb_default_backingstore_session(self, request, mcg_obj_session): + return self.override_nb_default_backingstore(request, mcg_obj_session) + @pytest.fixture(scope="function") + def override_nb_default_backingstore_function(self, request, mcg_obj_session): + return self.override_nb_default_backingstore(request, mcg_obj_session) + def override_nb_default_backingstore(self, request, mcg_obj_session): """ Override the default noobaa backingstore to the given alternative backingstore @@ -91,6 +152,7 @@ def override_nb_default_backingstore_implementation( Args: mcg_obj (MCG): An MCG object alternative_backingstore_name (str): The name of the alternative backingstore + """ # Update the new default resource of the admin account @@ -135,7 +197,7 @@ def test_default_buckets_backingstore( mcg_obj_session, backingstore_factory, bucket_factory, - override_nb_default_backingstore, + override_nb_default_backingstore_function, ): """ 1. Override the default noobaa backingstore @@ -152,7 +214,9 @@ def test_default_buckets_backingstore( # Supported in all deployment types except mcg-only uls_dict = {"pv": [(1, 20, constants.DEFAULT_STORAGECLASS_RBD)]} alternative_backingstore = backingstore_factory("oc", uls_dict)[0] - override_nb_default_backingstore(mcg_obj_session, alternative_backingstore.name) + override_nb_default_backingstore_function( + mcg_obj_session, alternative_backingstore.name + ) # 2. Create a new bucket using the mcg-cli with the default backingstore default_cli_bucket = bucket_factory(amount=1, interface="cli")[0] @@ -170,10 +234,81 @@ def test_default_buckets_backingstore( == alternative_backingstore.name ), "The default OC bucket does not use the new default backingstore!" - self.a + @pytest.fixture(scope="session") + def alt_bs_for_upgrade_tc(self, mcg_obj_session, backingstore_factory_session): + """ + Create a new backingstore with the same type of the current default. - def test_default_backingstore_override_post_upgrade(self): - pass + Returns: + str: The name of the alternative backingstore + + """ + # Create the alternative backingstore that will be used as the new default. + original_bs_type = OCP( + kind="backingstore", + namespace=config.ENV_DATA["cluster_namespace"], + resource_name=constants.DEFAULT_NOOBAA_BACKINGSTORE, + ).data["spec"]["type"] + bs_type_to_platform_mapping = { + constants.BACKINGSTORE_TYPE_AWS: "aws", + constants.BACKINGSTORE_TYPE_AZURE: "azure", + constants.BACKINGSTORE_TYPE_GOOGLE: "gcp", + constants.BACKINGSTORE_TYPE_PV_POOL: "pv", + constants.BACKINGSTORE_TYPE_S3_COMP: "rgw", + } + original_bs_platform_name = bs_type_to_platform_mapping[original_bs_type] + alternative_backingstore = backingstore_factory_session( + "oc", + {original_bs_platform_name: [(1, None)]} + if original_bs_platform_name != "pv" + else {"pv": [(1, 20, constants.DEFAULT_STORAGECLASS_RBD)]}, + )[0] + return alternative_backingstore.name + + @pre_upgrade + @skipif_mcg_only # We can't create a bs with the same type of the current default in mcg-only + def test_default_backingstore_override_pre_upgrade( + self, + mcg_obj_session, + alt_bs_for_upgrade_tc, + override_nb_default_backingstore_session, + ): + """ + 1. Create a new backingstore with the same type of the current default + - We're using the same type of the current default to avoid affecting subsequent tests + - This step is done in the alt_bs_for_upgrade_tc fixture above to avoid leftover erors + 2. Override the current default using the new backingstore + 3. Verify the new default is set before the upgrade + + """ + # Create a new backingstore with the same type of the current default (implemented in fixture) + alt_bs = alt_bs_for_upgrade_tc + + # Override the default noobaa backingstore + override_nb_default_backingstore_session(mcg_obj_session, alt_bs) + + # Verify the new default is set before the upgrade + default_admin_resource = get_admin_default_resource_name(mcg_obj_session) + default_bc_backingstore = get_default_bc_backingstore_name(mcg_obj_session) + assert ( + default_admin_resource == default_bc_backingstore == alt_bs + ), "The new default backingstore was not overriden before the upgrade!" + + @post_upgrade + def test_default_backingstore_override_post_upgrade( + self, + mcg_obj_session, + alt_bs_for_upgrade_tc, + ): + """ + Verify the new default is still set post-upgrade + + """ + default_admin_resource = get_admin_default_resource_name(mcg_obj_session) + default_bc_backingstore = get_default_bc_backingstore_name(mcg_obj_session) + assert ( + default_admin_resource == default_bc_backingstore == alt_bs_for_upgrade_tc + ), "The new default backingstore was not preserved after the upgrade!" def test_bucketclass_replication_after_default_backingstore_override( self, override_nb_default_backingstore From 1969d4840c91d0b8fc5de000911e6c4305edfe63 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Tue, 21 Nov 2023 13:48:55 +0200 Subject: [PATCH 07/14] Add polarion ids & mark the tier for the last test Signed-off-by: Sagi Hirshfeld --- .../object/mcg/test_default_backingstore_override.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py index e0654fb8b88..d6b2b5c0d2d 100644 --- a/tests/functional/object/mcg/test_default_backingstore_override.py +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -7,9 +7,11 @@ from ocs_ci.framework.pytest_customization.marks import ( red_squad, tier1, + tier2, pre_upgrade, post_upgrade, skipif_mcg_only, + polarion_id, ) from ocs_ci.framework.testlib import MCGTest from ocs_ci.ocs import constants @@ -192,6 +194,7 @@ def finalizer(): return override_nb_default_backingstore_implementation @tier1 + @polarion_id("OCS-5193") def test_default_buckets_backingstore( self, mcg_obj_session, @@ -295,6 +298,7 @@ def test_default_backingstore_override_pre_upgrade( ), "The new default backingstore was not overriden before the upgrade!" @post_upgrade + @polarion_id("OCS-5194") def test_default_backingstore_override_post_upgrade( self, mcg_obj_session, @@ -310,6 +314,8 @@ def test_default_backingstore_override_post_upgrade( default_admin_resource == default_bc_backingstore == alt_bs_for_upgrade_tc ), "The new default backingstore was not preserved after the upgrade!" + @tier2 + @polarion_id("OCS-5195") def test_bucketclass_replication_after_default_backingstore_override( self, override_nb_default_backingstore ): From 74418328dbd0b5274f199a91cb0146325cf40322 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Sun, 26 Nov 2023 17:40:37 +0200 Subject: [PATCH 08/14] Add support for rgw backingstore creatoin Signed-off-by: Sagi Hirshfeld --- ocs_ci/ocs/bucket_utils.py | 50 +++++++++++++++++++++++++--- ocs_ci/ocs/resources/backingstore.py | 4 +++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/ocs_ci/ocs/bucket_utils.py b/ocs_ci/ocs/bucket_utils.py index 9dc2e8a0638..a5c478c227b 100644 --- a/ocs_ci/ocs/bucket_utils.py +++ b/ocs_ci/ocs/bucket_utils.py @@ -724,12 +724,54 @@ def cli_create_ibmcos_backingstore( ) -def oc_create_s3comp_backingstore(cld_mgr, backingstore_name, uls_name, region): - pass +def oc_create_rgw_backingstore(cld_mgr, backingstore_name, uls_name, region): + """ + Create a new backingstore with RGW underlying storage using oc create command + Args: + cld_mgr (CloudManager): holds secret for backingstore creation + backingstore_name (str): backingstore name + uls_name (str): underlying storage name + region (str): which region to create backingstore (should be the same as uls) -def cli_create_s3comp_backingstore(cld_mgr, backingstore_name, uls_name, region): - pass + """ + bs_data = templating.load_yaml(constants.MCG_BACKINGSTORE_YAML) + bs_data["metadata"]["name"] = backingstore_name + bs_data["metadata"]["namespace"] = config.ENV_DATA["cluster_namespace"] + bs_data["spec"] = { + "type": "s3-compatible", + "s3Compatible": { + "targetBucket": uls_name, + "endpoint": cld_mgr.rgw_client.endpoint, + "signatureVersion": "v2", + "secret": { + "name": cld_mgr.rgw_client.secret.name, + "namespace": bs_data["metadata"]["namespace"], + }, + }, + } + create_resource(**bs_data) + + +def cli_create_rgw_backingstore(mcg_obj, cld_mgr, backingstore_name, uls_name, region): + """ + Create a new backingstore with IBM COS underlying storage using a NooBaa CLI command + + Args: + cld_mgr (CloudManager): holds secret for backingstore creation + backingstore_name (str): backingstore name + uls_name (str): underlying storage name + region (str): which region to create backingstore (should be the same as uls) + + """ + mcg_obj.exec_mcg_cmd( + f"backingstore create s3-compatible {backingstore_name} " + f"--endpoint {cld_mgr.rgw_client.endpoint} " + f"--access-key {cld_mgr.rgw_client.access_key} " + f"--secret-key {cld_mgr.rgw_client.secret_key} " + f"--target-bucket {uls_name}", + use_yes=True, + ) def oc_create_pv_backingstore(backingstore_name, vol_num, size, storage_class): diff --git a/ocs_ci/ocs/resources/backingstore.py b/ocs_ci/ocs/resources/backingstore.py index 81d2e813f0a..74e691775e4 100644 --- a/ocs_ci/ocs/resources/backingstore.py +++ b/ocs_ci/ocs/resources/backingstore.py @@ -8,11 +8,13 @@ oc_create_azure_backingstore, oc_create_pv_backingstore, oc_create_ibmcos_backingstore, + oc_create_rgw_backingstore, cli_create_google_backingstore, cli_create_azure_backingstore, cli_create_pv_backingstore, cli_create_ibmcos_backingstore, cli_create_aws_backingstore, + cli_create_rgw_backingstore, ) from ocs_ci.ocs.exceptions import ( TimeoutExpiredError, @@ -265,6 +267,7 @@ def backingstore_factory(request, cld_mgr, mcg_obj, cloud_uls_factory): "gcp": oc_create_google_backingstore, "azure": oc_create_azure_backingstore, "ibmcos": oc_create_ibmcos_backingstore, + "rgw": oc_create_rgw_backingstore, "pv": oc_create_pv_backingstore, }, "cli": { @@ -272,6 +275,7 @@ def backingstore_factory(request, cld_mgr, mcg_obj, cloud_uls_factory): "gcp": cli_create_google_backingstore, "azure": cli_create_azure_backingstore, "ibmcos": cli_create_ibmcos_backingstore, + "rgw": cli_create_rgw_backingstore, "pv": cli_create_pv_backingstore, }, } From 96d89b531e6998dcf20b9f997781e92ec37a28e2 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Sun, 26 Nov 2023 21:06:53 +0200 Subject: [PATCH 09/14] Add basic rgw backingstore test cases Signed-off-by: Sagi Hirshfeld --- .../object/mcg/test_write_to_bucket.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/functional/object/mcg/test_write_to_bucket.py b/tests/functional/object/mcg/test_write_to_bucket.py index 1222dfc766f..8ab316ce654 100644 --- a/tests/functional/object/mcg/test_write_to_bucket.py +++ b/tests/functional/object/mcg/test_write_to_bucket.py @@ -31,6 +31,7 @@ skipif_managed_service, bugzilla, skipif_ocs_version, + on_prem_platform_required, ) from ocs_ci.ocs.constants import AWSCLI_TEST_OBJ_DIR from uuid import uuid4 @@ -132,6 +133,20 @@ class TestBucketIO(MCGTest): ], marks=[tier1], ), + pytest.param( + *[ + "OC", + {"interface": "OC", "backingstore_dict": {"rgw": [(1, None)]}}, + ], + marks=[tier1, on_prem_platform_required], + ), + pytest.param( + *[ + "CLI", + {"interface": "CLI", "backingstore_dict": {"rgw": [(1, None)]}}, + ], + marks=[tier1, on_prem_platform_required], + ), ], ids=[ "DEFAULT-BACKINGSTORE", @@ -140,6 +155,8 @@ class TestBucketIO(MCGTest): "GCP-OC-1", "IBMCOS-OC-1", "IBMCOS-CLI-1", + "RGW-OC-1", + "RGW-CLI-1", ], ) @flaky From 05fd779cdef6e4c8b8e79a02ca52e4e813574e0b Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Mon, 27 Nov 2023 17:56:03 +0200 Subject: [PATCH 10/14] Refactor + Add repli TC Signed-off-by: Sagi Hirshfeld --- ocs_ci/ocs/constants.py | 10 + ocs_ci/ocs/resources/mcg.py | 39 +++ tests/conftest.py | 154 ++++++++ .../mcg/test_default_backingstore_override.py | 330 +++++------------- 4 files changed, 295 insertions(+), 238 deletions(-) diff --git a/ocs_ci/ocs/constants.py b/ocs_ci/ocs/constants.py index 28f71d195d5..22be4da0749 100644 --- a/ocs_ci/ocs/constants.py +++ b/ocs_ci/ocs/constants.py @@ -295,6 +295,8 @@ DEFAULT_STORAGECLASS_RBD_THICK = f"{DEFAULT_CLUSTERNAME}-ceph-rbd-thick" DEFAULT_OCS_STORAGECLASS = "default-ocs-storage-class" +THIN_CSI_STORAGECLASS = "thin-csi" + # Independent mode default StorageClasses DEFAULT_EXTERNAL_MODE_STORAGECLASS_RGW = f"{DEFAULT_CLUSTERNAME_EXTERNAL_MODE}-ceph-rgw" @@ -1888,6 +1890,14 @@ BACKINGSTORE_TYPE_GOOGLE = "google-cloud-storage" BACKINGSTORE_TYPE_PV_POOL = "pv-pool" +BS_TYPE_TO_PLATFORM_NAME_MAPPING = { + BACKINGSTORE_TYPE_AWS: "aws", + BACKINGSTORE_TYPE_AZURE: "azure", + BACKINGSTORE_TYPE_GOOGLE: "gcp", + BACKINGSTORE_TYPE_PV_POOL: "pv", + BACKINGSTORE_TYPE_S3_COMP: "rgw", +} + # Squads assignment # Tests are assigned to Squads based on patterns matching test path. diff --git a/ocs_ci/ocs/resources/mcg.py b/ocs_ci/ocs/resources/mcg.py index ce57c42e8ce..a9f16fff2ba 100644 --- a/ocs_ci/ocs/resources/mcg.py +++ b/ocs_ci/ocs/resources/mcg.py @@ -1108,3 +1108,42 @@ def reset_admin_pw(self, new_password): logger.info("Waiting a bit for the change to propogate through the system...") sleep(15) + + def get_admin_default_resource_name(self): + """ + Get the default resource name of the admin account + + Returns: + str: The default resource name + + """ + + read_account_output = self.send_rpc_query( + "account_api", + "read_account", + params={ + "email": self.noobaa_user, + }, + ) + return read_account_output.json()["reply"]["default_resource"] + + def get_default_bc_backingstore_name(self): + """ + Get the default backingstore name of the default bucketclass + + Returns: + str: The default backingstore name + + """ + bucketclass_ocp_obj = OCP( + kind=constants.BUCKETCLASS, + namespace=config.ENV_DATA["cluster_namespace"], + resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + ) + return ( + bucketclass_ocp_obj.get() + .get("spec") + .get("placementPolicy") + .get("tiers")[0] + .get("backingStores")[0] + ) diff --git a/tests/conftest.py b/tests/conftest.py index e2a7ef812bd..b638da41847 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7054,3 +7054,157 @@ def reset_conn_score(): from ocs_ci.ocs.resources.stretchcluster import StretchCluster return StretchCluster().reset_conn_score() + + +@pytest.fixture(scope="session") +def allow_default_backingstore_override(request): + """ + Modify the noobaa CR to allow overriding the default backingstore + + """ + + nb_ocp_obj = OCP( + kind="noobaa", + namespace=ocsci_config.ENV_DATA["cluster_namespace"], + resource_name="noobaa", + ) + + def patch_allow_manual_default_backingstore(): + """ + Patch "manualDefaultBackingStore: true" to the noobaa CR + + """ + add_op = [ + {"op": "add", "path": "/spec/manualDefaultBackingStore", "value": True} + ] + nb_ocp_obj.patch( + resource_name=constants.NOOBAA_RESOURCE_NAME, + params=json.dumps(add_op), + format_type="json", + ) + + def finalizer(): + """ + Remove "manualDefaultBackingStore: true" from the noobaa CR + + """ + remove_op = [ + { + "op": "remove", + "path": "/spec/manualDefaultBackingStore", + } + ] + nb_ocp_obj.patch( + resource_name=constants.NOOBAA_RESOURCE_NAME, + params=json.dumps(remove_op), + format_type="json", + ) + + request.addfinalizer(finalizer) + patch_allow_manual_default_backingstore() + + +@pytest.fixture(scope="session") +def override_default_backingstore_session( + request, + mcg_obj_session, + backingstore_factory_session, + allow_default_backingstore_override, +): + return override_default_backingstore_fixture( + request, mcg_obj_session, backingstore_factory_session + ) + + +@pytest.fixture(scope="function") +def override_default_backingstore( + request, mcg_obj_session, backingstore_factory, allow_default_backingstore_override +): + return override_default_backingstore_fixture( + request, mcg_obj_session, backingstore_factory + ) + + +def override_default_backingstore_fixture( + request, mcg_obj_session, backingstore_factory +): + """ + Returns a function that overrides the default backingstore with an alternative + of the same type. + + """ + + bucketclass_ocp_obj = OCP( + kind=constants.BUCKETCLASS, + namespace=ocsci_config.ENV_DATA["cluster_namespace"], + resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + ) + + def _override_nb_default_backingstore_implementation(alt_backingstore_name=None): + """ + 1. If the name of an alternative backingstore is not provided, + Create a new backingstore of the same type as the current default + 2. Update the new default resource of the admin account + 3. Patch the default bucketclass to use the new default backingstore + + Args: + alternative_backingstore_name (str, optional): The name of an alternative backingstore + + """ + + # 1. if the name of an alternative backingstore is not provided, + # Create a new backingstore of the same type as the current default + if alt_backingstore_name is None: + original_bs_type = OCP( + kind="backingstore", + namespace=ocsci_config.ENV_DATA["cluster_namespace"], + resource_name=constants.DEFAULT_NOOBAA_BACKINGSTORE, + ).data["spec"]["type"] + original_bs_platform_name = constants.BS_TYPE_TO_PLATFORM_NAME_MAPPING[ + original_bs_type + ] + if original_bs_platform_name != "pv": + alt_bs_dict = {original_bs_platform_name: [(1, None)]} + elif ocsci_config.ENV_DATA["mcg_only_deployment"]: + alt_bs_dict = {"pv": [1, 20, constants.THIN_CSI_STORAGECLASS]} + else: + alt_bs_dict = {"pv": [(1, 20, constants.DEFAULT_STORAGECLASS_RBD)]} + alt_backingstore_name = backingstore_factory("oc", alt_bs_dict)[0].name + + # 2. Update the new default resource of the admin account + mcg_obj_session.exec_mcg_cmd( + "".join( + ( + f"account update {mcg_obj_session.noobaa_user} ", + f"--new_default_resource={alt_backingstore_name}", + ) + ) + ) + + # 3. Patch the default bucketclass to use the new default backingstore + update_op = [ + { + "op": "replace", + "path": "/spec/placementPolicy/tiers/0/backingStores/0", + "value": alt_backingstore_name, + } + ] + bucketclass_ocp_obj.patch( + resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + params=json.dumps(update_op), + format_type="json", + ) + + return alt_backingstore_name + + def finalizer(): + """ + Change the default backingstore back to the original + + """ + _override_nb_default_backingstore_implementation( + constants.DEFAULT_NOOBAA_BACKINGSTORE + ) + + request.addfinalizer(finalizer) + return _override_nb_default_backingstore_implementation diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py index d6b2b5c0d2d..9bf3f2b3b8e 100644 --- a/tests/functional/object/mcg/test_default_backingstore_override.py +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -1,206 +1,46 @@ import json import logging - -import pytest +from uuid import uuid4 from ocs_ci.framework import config from ocs_ci.framework.pytest_customization.marks import ( red_squad, + polarion_id, + bugzilla, tier1, tier2, pre_upgrade, post_upgrade, - skipif_mcg_only, - polarion_id, + skipif_aws_creds_are_missing, + ignore_leftovers, ) from ocs_ci.framework.testlib import MCGTest from ocs_ci.ocs import constants -from ocs_ci.ocs.bucket_utils import get_nb_bucket_stores +from ocs_ci.ocs.bucket_utils import ( + get_nb_bucket_stores, + write_random_test_objects_to_bucket, + compare_bucket_object_list, +) from ocs_ci.ocs.ocp import OCP logger = logging.getLogger(__name__) -@pytest.fixture(scope="class") -def allow_default_backingstore_override(request): - """ - Modify the noobaa CR to allow overriding the default backingstore - - """ - - nb_ocp_obj = OCP( - kind="noobaa", - namespace=config.ENV_DATA["cluster_namespace"], - resource_name="noobaa", - ) - - def patch_allow_manual_default_backingstore(): - """ - Patch "manualDefaultBackingStore: true" to the noobaa CR - - """ - add_op = [ - {"op": "add", "path": "/spec/manualDefaultBackingStore", "value": True} - ] - nb_ocp_obj.patch( - resource_name=constants.NOOBAA_RESOURCE_NAME, - params=json.dumps(add_op), - format_type="json", - ) - - def finalizer(): - """ - Remove "manualDefaultBackingStore: true" from the noobaa CR - - """ - remove_op = [ - { - "op": "remove", - "path": "/spec/manualDefaultBackingStore", - } - ] - nb_ocp_obj.patch( - resource_name=constants.NOOBAA_RESOURCE_NAME, - params=json.dumps(remove_op), - format_type="json", - ) - - request.addfinalizer(finalizer) - patch_allow_manual_default_backingstore() - - -def get_admin_default_resource_name(mcg_obj): - """ - Get the default resource name of the admin account - - Args: - mcg_obj (MCG): An MCG object - - Returns: - str: The default resource name - - """ - - read_account_output = mcg_obj.send_rpc_query( - "account_api", - "read_account", - params={ - "email": mcg_obj.noobaa_user, - }, - ) - return read_account_output.json()["reply"]["default_resource"] - - -def get_default_bc_backingstore_name(mcg_obj): - """ - Get the default backingstore name of the default bucketclass - - Args: - mcg_obj (MCG): An MCG object - - Returns: - str: The default backingstore name - - """ - bucketclass_ocp_obj = OCP( - kind=constants.BUCKETCLASS, - namespace=config.ENV_DATA["cluster_namespace"], - resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, - ) - return ( - bucketclass_ocp_obj.get() - .get("spec") - .get("placementPolicy") - .get("tiers")[0] - .get("backingStores")[0] - ) - - @red_squad -@pytest.mark.usefixtures(allow_default_backingstore_override.__name__) +@ignore_leftovers # needed for the upgrade TCs class TestDefaultBackingstoreOverride(MCGTest): """ Test overriding the default noobaa backingstore """ - @pytest.fixture(scope="session") - def override_nb_default_backingstore_session(self, request, mcg_obj_session): - return self.override_nb_default_backingstore(request, mcg_obj_session) - - @pytest.fixture(scope="function") - def override_nb_default_backingstore_function(self, request, mcg_obj_session): - return self.override_nb_default_backingstore(request, mcg_obj_session) - - def override_nb_default_backingstore(self, request, mcg_obj_session): - """ - Override the default noobaa backingstore to the given alternative backingstore - - """ - - bucketclass_ocp_obj = OCP( - kind=constants.BUCKETCLASS, - namespace=config.ENV_DATA["cluster_namespace"], - resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, - ) - - def override_nb_default_backingstore_implementation( - mcg_obj, alternative_backingstore_name - ): - """ - 1. Update the new default resource of the admin account - 2. Patch the default bucketclass to use the new default backingstore - - Args: - mcg_obj (MCG): An MCG object - alternative_backingstore_name (str): The name of the alternative backingstore - - """ - - # Update the new default resource of the admin account - mcg_obj.exec_mcg_cmd( - "".join( - ( - f"account update {mcg_obj.noobaa_user} ", - f"--new_default_resource={alternative_backingstore_name}", - ) - ) - ) - - # Patch the default bucketclass to use the new default backingstore - update_op = [ - { - "op": "replace", - "path": "/spec/placementPolicy/tiers/0/backingStores/0", - "value": alternative_backingstore_name, - } - ] - bucketclass_ocp_obj.patch( - resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, - params=json.dumps(update_op), - format_type="json", - ) - - def finalizer(): - """ - Change the default backingstore back to the original - - """ - override_nb_default_backingstore_implementation( - mcg_obj_session, constants.DEFAULT_NOOBAA_BACKINGSTORE - ) - - request.addfinalizer(finalizer) - return override_nb_default_backingstore_implementation - @tier1 @polarion_id("OCS-5193") def test_default_buckets_backingstore( self, mcg_obj_session, - backingstore_factory, + override_default_backingstore, bucket_factory, - override_nb_default_backingstore_function, ): """ 1. Override the default noobaa backingstore @@ -211,15 +51,7 @@ def test_default_buckets_backingstore( """ # 1. Override the default noobaa backingstore - if config.ENV_DATA["mcg_only_deployment"]: - uls_dict = {"aws": [(1, "eu-central-1")]} - else: - # Supported in all deployment types except mcg-only - uls_dict = {"pv": [(1, 20, constants.DEFAULT_STORAGECLASS_RBD)]} - alternative_backingstore = backingstore_factory("oc", uls_dict)[0] - override_nb_default_backingstore_function( - mcg_obj_session, alternative_backingstore.name - ) + alt_default_bs_name = override_default_backingstore() # 2. Create a new bucket using the mcg-cli with the default backingstore default_cli_bucket = bucket_factory(amount=1, interface="cli")[0] @@ -230,93 +62,115 @@ def test_default_buckets_backingstore( # 4. Verify the bucket's backingstore is the new default backingstore assert ( get_nb_bucket_stores(mcg_obj_session, default_cli_bucket.name)[0] - == alternative_backingstore.name + == alt_default_bs_name ), "The default mcg-cli bucket does not use the new default backingstore!" assert ( get_nb_bucket_stores(mcg_obj_session, default_obc_bucket.name)[0] - == alternative_backingstore.name + == alt_default_bs_name ), "The default OC bucket does not use the new default backingstore!" - @pytest.fixture(scope="session") - def alt_bs_for_upgrade_tc(self, mcg_obj_session, backingstore_factory_session): - """ - Create a new backingstore with the same type of the current default. - - Returns: - str: The name of the alternative backingstore - - """ - # Create the alternative backingstore that will be used as the new default. - original_bs_type = OCP( - kind="backingstore", - namespace=config.ENV_DATA["cluster_namespace"], - resource_name=constants.DEFAULT_NOOBAA_BACKINGSTORE, - ).data["spec"]["type"] - bs_type_to_platform_mapping = { - constants.BACKINGSTORE_TYPE_AWS: "aws", - constants.BACKINGSTORE_TYPE_AZURE: "azure", - constants.BACKINGSTORE_TYPE_GOOGLE: "gcp", - constants.BACKINGSTORE_TYPE_PV_POOL: "pv", - constants.BACKINGSTORE_TYPE_S3_COMP: "rgw", - } - original_bs_platform_name = bs_type_to_platform_mapping[original_bs_type] - alternative_backingstore = backingstore_factory_session( - "oc", - {original_bs_platform_name: [(1, None)]} - if original_bs_platform_name != "pv" - else {"pv": [(1, 20, constants.DEFAULT_STORAGECLASS_RBD)]}, - )[0] - return alternative_backingstore.name - @pre_upgrade - @skipif_mcg_only # We can't create a bs with the same type of the current default in mcg-only def test_default_backingstore_override_pre_upgrade( self, + request, mcg_obj_session, - alt_bs_for_upgrade_tc, - override_nb_default_backingstore_session, + override_default_backingstore_session, ): """ - 1. Create a new backingstore with the same type of the current default - - We're using the same type of the current default to avoid affecting subsequent tests - - This step is done in the alt_bs_for_upgrade_tc fixture above to avoid leftover erors - 2. Override the current default using the new backingstore - 3. Verify the new default is set before the upgrade + 1. Override the current default using the new backingstore of the same type + 2. Verify the new default is set before the upgrade """ - # Create a new backingstore with the same type of the current default (implemented in fixture) - alt_bs = alt_bs_for_upgrade_tc - - # Override the default noobaa backingstore - override_nb_default_backingstore_session(mcg_obj_session, alt_bs) - - # Verify the new default is set before the upgrade - default_admin_resource = get_admin_default_resource_name(mcg_obj_session) - default_bc_backingstore = get_default_bc_backingstore_name(mcg_obj_session) + # 1. Override the current default using the new backingstore of the same type + alt_default_bs_name = override_default_backingstore_session() + # Cache the new default backingstore name to pass to the post-upgrade test + request.config.cache.set("pre_upgrade_alt_bs_name", alt_default_bs_name) + + # 2. Verify the new default is set before the upgrade + default_admin_resource = mcg_obj_session.get_admin_default_resource_name() + default_bc_bs = mcg_obj_session.get_default_bc_backingstore_name() assert ( - default_admin_resource == default_bc_backingstore == alt_bs + default_admin_resource == default_bc_bs == alt_default_bs_name ), "The new default backingstore was not overriden before the upgrade!" @post_upgrade @polarion_id("OCS-5194") def test_default_backingstore_override_post_upgrade( self, + request, mcg_obj_session, - alt_bs_for_upgrade_tc, ): """ Verify the new default is still set post-upgrade """ - default_admin_resource = get_admin_default_resource_name(mcg_obj_session) - default_bc_backingstore = get_default_bc_backingstore_name(mcg_obj_session) + # Retrieve the new default backingstore name from the pre-upgrade test + alt_default_bs_name = request.config.cache.get("pre_upgrade_alt_bs_name", None) + + # Verify the new default is still set post-upgrade + default_admin_resource = mcg_obj_session.get_admin_default_resource_name() + default_bc_backingstore = mcg_obj_session.get_default_bc_backingstore_name() assert ( - default_admin_resource == default_bc_backingstore == alt_bs_for_upgrade_tc + default_admin_resource == default_bc_backingstore == alt_default_bs_name ), "The new default backingstore was not preserved after the upgrade!" @tier2 + @skipif_aws_creds_are_missing @polarion_id("OCS-5195") + @bugzilla("2237427") def test_bucketclass_replication_after_default_backingstore_override( - self, override_nb_default_backingstore + self, + mcg_obj_session, + bucket_factory, + override_default_backingstore, + awscli_pod_session, + test_directory_setup, ): - pass + # 1. Create a target bucket + target_bucketclass_dict = ( + { + "interface": "OC", + "backingstore_dict": {"aws": [(1, "eu-central-1")]}, + }, + ) + target_bucket = bucket_factory(bucketclass=target_bucketclass_dict)[0] + + # 2. Set a bucketclass replication policy to the target bucket on the default bucket class + replication_policy = { + "rules": [ + {"rule_id": uuid4.hex(), "destination_bucket": target_bucket.name} + ] + } + replication_policy_patch_dict = { + "spec": { + "additionalConfig": { + "replicationPolicy": json.dumps(replication_policy) + } + } + } + OCP( + kind="obc", + namespace=config.ENV_DATA["cluster_namespace"], + resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + ).patch(params=json.dumps(replication_policy_patch_dict), format_type="merge") + + # 3. Override the default noobaa backingstore + override_default_backingstore() + + # 4. Create the source bucket using the new default backingstore + source_bucket = bucket_factory()[0] + + # 5. Upload objects to the source bucket and verify they are replicated to the target bucket + write_random_test_objects_to_bucket( + awscli_pod_session, + source_bucket.name, + test_directory_setup.origin_dir, + amount=5, + mcg_obj=mcg_obj_session, + ) + assert compare_bucket_object_list( + mcg_obj_session, + source_bucket.name, + target_bucket.name, + timeout=self.TIMEOUT, + ), f"Objects in {source_bucket.name} and {target_bucket.name} dont match" From 074c93ddf8e93b503900d156d163ef5da56068d5 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Sun, 17 Dec 2023 20:20:06 +0200 Subject: [PATCH 11/14] Documentation and fixes to TC number 3 Signed-off-by: Sagi Hirshfeld --- .../mcg/test_default_backingstore_override.py | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py index 9bf3f2b3b8e..4e762ca4c2b 100644 --- a/tests/functional/object/mcg/test_default_backingstore_override.py +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -126,30 +126,32 @@ def test_bucketclass_replication_after_default_backingstore_override( awscli_pod_session, test_directory_setup, ): + """ + 1. Create a target bucket + 2. Set a bucketclass replication policy to the target bucket on the default bucket class + 3. Override the default noobaa backingstore + 4. Create a source OBC under the default bucketclass + 5. Upload objects to the source bucket and verify they are replicated to the target bucket + + """ # 1. Create a target bucket - target_bucketclass_dict = ( - { - "interface": "OC", - "backingstore_dict": {"aws": [(1, "eu-central-1")]}, - }, - ) + target_bucketclass_dict = { + "interface": "OC", + "backingstore_dict": {"aws": [(1, "eu-central-1")]}, + } target_bucket = bucket_factory(bucketclass=target_bucketclass_dict)[0] # 2. Set a bucketclass replication policy to the target bucket on the default bucket class replication_policy = { "rules": [ - {"rule_id": uuid4.hex(), "destination_bucket": target_bucket.name} + {"rule_id": uuid4().hex, "destination_bucket": target_bucket.name} ] } replication_policy_patch_dict = { - "spec": { - "additionalConfig": { - "replicationPolicy": json.dumps(replication_policy) - } - } + "spec": {"replicationPolicy": json.dumps(replication_policy)} } OCP( - kind="obc", + kind=constants.BUCKETCLASS, namespace=config.ENV_DATA["cluster_namespace"], resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, ).patch(params=json.dumps(replication_policy_patch_dict), format_type="merge") @@ -157,8 +159,8 @@ def test_bucketclass_replication_after_default_backingstore_override( # 3. Override the default noobaa backingstore override_default_backingstore() - # 4. Create the source bucket using the new default backingstore - source_bucket = bucket_factory()[0] + # 4. Create a source OBC using the new default backingstore + source_bucket = bucket_factory(interface="OC")[0] # 5. Upload objects to the source bucket and verify they are replicated to the target bucket write_random_test_objects_to_bucket( @@ -172,5 +174,4 @@ def test_bucketclass_replication_after_default_backingstore_override( mcg_obj_session, source_bucket.name, target_bucket.name, - timeout=self.TIMEOUT, ), f"Objects in {source_bucket.name} and {target_bucket.name} dont match" From 64169bee6600172eb41330538c01ccf3ef758b96 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Tue, 9 Jan 2024 16:12:31 +0200 Subject: [PATCH 12/14] Add the @mcg decorator Signed-off-by: Sagi Hirshfeld --- .../functional/object/mcg/test_default_backingstore_override.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py index 4e762ca4c2b..23b1ad03a3d 100644 --- a/tests/functional/object/mcg/test_default_backingstore_override.py +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -13,6 +13,7 @@ post_upgrade, skipif_aws_creds_are_missing, ignore_leftovers, + mcg, ) from ocs_ci.framework.testlib import MCGTest from ocs_ci.ocs import constants @@ -26,6 +27,7 @@ logger = logging.getLogger(__name__) +@mcg @red_squad @ignore_leftovers # needed for the upgrade TCs class TestDefaultBackingstoreOverride(MCGTest): From 7318575a45590b4a04c42020f3b2d91bda2ec7f9 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Sun, 21 Jan 2024 15:39:42 +0200 Subject: [PATCH 13/14] Review fix + clear nb default bc cleanup on teardown Signed-off-by: Sagi Hirshfeld --- .../mcg/test_default_backingstore_override.py | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/tests/functional/object/mcg/test_default_backingstore_override.py b/tests/functional/object/mcg/test_default_backingstore_override.py index 23b1ad03a3d..dae3bfbaad9 100644 --- a/tests/functional/object/mcg/test_default_backingstore_override.py +++ b/tests/functional/object/mcg/test_default_backingstore_override.py @@ -2,6 +2,8 @@ import logging from uuid import uuid4 +import pytest + from ocs_ci.framework import config from ocs_ci.framework.pytest_customization.marks import ( red_squad, @@ -21,6 +23,7 @@ get_nb_bucket_stores, write_random_test_objects_to_bucket, compare_bucket_object_list, + patch_replication_policy_to_bucketclass, ) from ocs_ci.ocs.ocp import OCP @@ -116,6 +119,26 @@ def test_default_backingstore_override_post_upgrade( default_admin_resource == default_bc_backingstore == alt_default_bs_name ), "The new default backingstore was not preserved after the upgrade!" + @pytest.fixture() + def nb_default_bc_cleanup_fixture(self, request): + """ + Clear all replication policies from the default noobaa bucketclass + + """ + + def clear_replication_policies_from_nb_default_bucketclass(): + replication_policy_patch_dict = {"spec": {"replicationPolicy": None}} + + OCP( + kind="bucketclass", + namespace=config.ENV_DATA["cluster_namespace"], + resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + ).patch( + params=json.dumps(replication_policy_patch_dict), format_type="merge" + ) + + request.addfinalizer(clear_replication_policies_from_nb_default_bucketclass) + @tier2 @skipif_aws_creds_are_missing @polarion_id("OCS-5195") @@ -127,6 +150,7 @@ def test_bucketclass_replication_after_default_backingstore_override( override_default_backingstore, awscli_pod_session, test_directory_setup, + nb_default_bc_cleanup_fixture, ): """ 1. Create a target bucket @@ -139,24 +163,16 @@ def test_bucketclass_replication_after_default_backingstore_override( # 1. Create a target bucket target_bucketclass_dict = { "interface": "OC", - "backingstore_dict": {"aws": [(1, "eu-central-1")]}, + "backingstore_dict": {"aws": [(1, None)]}, } target_bucket = bucket_factory(bucketclass=target_bucketclass_dict)[0] # 2. Set a bucketclass replication policy to the target bucket on the default bucket class - replication_policy = { - "rules": [ - {"rule_id": uuid4().hex, "destination_bucket": target_bucket.name} - ] - } - replication_policy_patch_dict = { - "spec": {"replicationPolicy": json.dumps(replication_policy)} - } - OCP( - kind=constants.BUCKETCLASS, - namespace=config.ENV_DATA["cluster_namespace"], - resource_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, - ).patch(params=json.dumps(replication_policy_patch_dict), format_type="merge") + patch_replication_policy_to_bucketclass( + bucketclass_name=constants.DEFAULT_NOOBAA_BUCKETCLASS, + rule_id=uuid4().hex, + destination_bucket_name=target_bucket.name, + ) # 3. Override the default noobaa backingstore override_default_backingstore() From ea913e5ad70757c686c14a6296a613b3356d89a4 Mon Sep 17 00:00:00 2001 From: Sagi Hirshfeld Date: Wed, 7 Feb 2024 14:43:14 +0200 Subject: [PATCH 14/14] Handle IBMCOS default backingtore case Signed-off-by: Sagi Hirshfeld --- ocs_ci/ocs/constants.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ocs_ci/ocs/constants.py b/ocs_ci/ocs/constants.py index 22be4da0749..03807568dfe 100644 --- a/ocs_ci/ocs/constants.py +++ b/ocs_ci/ocs/constants.py @@ -1889,6 +1889,7 @@ BACKINGSTORE_TYPE_S3_COMP = "s3-compatible" BACKINGSTORE_TYPE_GOOGLE = "google-cloud-storage" BACKINGSTORE_TYPE_PV_POOL = "pv-pool" +BACKINGSTORE_TYPE_IBMCOS = "ibm-cos" BS_TYPE_TO_PLATFORM_NAME_MAPPING = { BACKINGSTORE_TYPE_AWS: "aws", @@ -1896,6 +1897,7 @@ BACKINGSTORE_TYPE_GOOGLE: "gcp", BACKINGSTORE_TYPE_PV_POOL: "pv", BACKINGSTORE_TYPE_S3_COMP: "rgw", + BACKINGSTORE_TYPE_IBMCOS: "ibmcos", }