From 12b35dabe4f89a987c9e65eaea2f596daa65898e Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Wed, 31 Jan 2024 13:20:52 +0000 Subject: [PATCH 01/14] add messages for incorrect rels to mongos --- .../mongodb/v0/config_server_interface.py | 7 +- lib/charms/mongodb/v1/shards_interface.py | 5 +- src/charm.py | 23 +++-- .../sharding_tests/test_sharding_relations.py | 88 ++++++++++++++++++- 4 files changed, 114 insertions(+), 9 deletions(-) diff --git a/lib/charms/mongodb/v0/config_server_interface.py b/lib/charms/mongodb/v0/config_server_interface.py index 70df7aa37..847c91267 100644 --- a/lib/charms/mongodb/v0/config_server_interface.py +++ b/lib/charms/mongodb/v0/config_server_interface.py @@ -16,7 +16,7 @@ from charms.mongodb.v1.mongos import MongosConnection from ops.charm import CharmBase, EventBase, RelationBrokenEvent from ops.framework import Object -from ops.model import ActiveStatus, MaintenanceStatus, WaitingStatus +from ops.model import ActiveStatus, BlockedStatus, MaintenanceStatus, WaitingStatus from config import Config @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 5 +LIBPATCH = 6 class ClusterProvider(Object): @@ -73,6 +73,9 @@ def pass_hook_checks(self, event: EventBase) -> bool: logger.info( "Skipping %s. ShardingProvider is only be executed by config-server", type(event) ) + self.charm.unit.status = BlockedStatus( + "Relation to mongos not supported, config role must be config-server" + ) return False if not self.charm.unit.is_leader(): diff --git a/lib/charms/mongodb/v1/shards_interface.py b/lib/charms/mongodb/v1/shards_interface.py index b9a876aec..57a5451b0 100644 --- a/lib/charms/mongodb/v1/shards_interface.py +++ b/lib/charms/mongodb/v1/shards_interface.py @@ -51,7 +51,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 5 +LIBPATCH = 6 KEYFILE_KEY = "key-file" HOSTS_KEY = "host" OPERATOR_PASSWORD_KEY = MongoDBUser.get_password_key_name_for_user(OperatorUser.get_username()) @@ -520,6 +520,9 @@ def pass_hook_checks(self, event): logger.info("skipping %s is only be executed by shards", type(event)) return False + if not event.relation.app: + return False + mongos_hosts = event.relation.data[event.relation.app].get(HOSTS_KEY, None) if isinstance(event, RelationBrokenEvent) and not mongos_hosts: logger.info("Config-server relation never set up, no need to process broken event.") diff --git a/src/charm.py b/src/charm.py index 6c0477577..1095cecaf 100755 --- a/src/charm.py +++ b/src/charm.py @@ -529,11 +529,11 @@ def _on_storage_detaching(self, event: StorageDetachingEvent) -> None: logger.error("Failed to remove %s from replica set, error=%r", self.unit.name, e) def _on_update_status(self, event: UpdateStatusEvent): - # cannot have both legacy and new relations since they have different auth requirements - if self.client_relations._get_users_from_relations( - None, rel="obsolete" - ) and self.client_relations._get_users_from_relations(None): - self.unit.status = BlockedStatus("cannot have both legacy and new relations") + # user-made mistakes might result in other incorrect statues. Prioritise informing users of + # their mistake. + invalid_integration_status = self.get_invalid_integration_status() + if invalid_integration_status: + self.unit.status = invalid_integration_status return # no need to report on replica set status until initialised @@ -1353,6 +1353,19 @@ def _is_removing_last_replica(self) -> bool: """Returns True if the last replica (juju unit) is getting removed.""" return self.app.planned_units() == 0 and len(self._peers.units) == 0 + def get_invalid_integration_status(self) -> Optional[StatusBase]: + """Returns a status if an invalid integration is present.""" + if self.client_relations._get_users_from_relations( + None, rel="obsolete" + ) and self.client_relations._get_users_from_relations(None): + return BlockedStatus("cannot have both legacy and new relations") + + integrated_to_mongos = self.model.relations[Config.Relations.CLUSTER_RELATIONS_NAME] + if not self.is_role(Config.Role.CONFIG_SERVER) and integrated_to_mongos: + return BlockedStatus( + "Relation to mongos not supported, config role must be config-server" + ) + def get_status(self) -> StatusBase: """Returns the status with the highest priority from backups, sharding, and mongod. diff --git a/tests/integration/sharding_tests/test_sharding_relations.py b/tests/integration/sharding_tests/test_sharding_relations.py index bcfa3d2a8..9e1a0e123 100644 --- a/tests/integration/sharding_tests/test_sharding_relations.py +++ b/tests/integration/sharding_tests/test_sharding_relations.py @@ -11,6 +11,8 @@ REPLICATION_APP_NAME = "replication" APP_CHARM_NAME = "application" LEGACY_APP_CHARM_NAME = "legacy-application" +MONGOS_APP_NAME = "mongos" +MONGOS_HOST_APP_NAME = "application-host" SHARDING_COMPONENTS = [SHARD_ONE_APP_NAME, CONFIG_SERVER_ONE_APP_NAME] @@ -28,7 +30,11 @@ @pytest.mark.abort_on_fail async def test_build_and_deploy( - ops_test: OpsTest, application_charm, legacy_charm, database_charm + ops_test: OpsTest, + application_charm, + legacy_charm, + database_charm, + mongos_host_application_charm, ) -> None: """Build and deploy a sharded cluster.""" await ops_test.model.deploy( @@ -44,6 +50,17 @@ async def test_build_and_deploy( await ops_test.model.deploy( database_charm, config={"role": "shard"}, application_name=SHARD_ONE_APP_NAME ) + await ops_test.model.deploy( + MONGOS_APP_NAME, + channel="6/edge", + revision=3, + ) + # TODO: Future PR, once data integrator works with mongos charm deploy that charm instead of + # packing and deploying the charm in the application dir. + await ops_test.model.deploy( + mongos_host_application_charm, application_name=MONGOS_HOST_APP_NAME + ) + await ops_test.model.deploy(database_charm, application_name=REPLICATION_APP_NAME) await ops_test.model.deploy(application_charm, application_name=APP_CHARM_NAME) await ops_test.model.deploy(legacy_charm, application_name=LEGACY_APP_CHARM_NAME) @@ -59,6 +76,19 @@ async def test_build_and_deploy( timeout=TIMEOUT, ) + await ops_test.model.integrate( + f"{MONGOS_APP_NAME}", + f"{MONGOS_HOST_APP_NAME}", + ) + + await ops_test.model.wait_for_idle( + apps=[MONGOS_HOST_APP_NAME, MONGOS_APP_NAME], + idle_period=20, + raise_on_blocked=False, + timeout=TIMEOUT, + raise_on_error=False, + ) + async def test_only_one_config_server_relation(ops_test: OpsTest) -> None: """Verify that a shard can only be related to one config server.""" @@ -218,3 +248,59 @@ async def test_replication_shard_relation(ops_test: OpsTest): raise_on_blocked=False, timeout=TIMEOUT, ) + + +async def test_replication_mongos_relation(ops_test: OpsTest) -> None: + """Verifies connecting a replica to a mongos router fails.""" + # attempt to add a replication deployment as a shard to the config server. + await ops_test.model.integrate( + f"{REPLICATION_APP_NAME}", + f"{MONGOS_APP_NAME}", + ) + + await ops_test.model.wait_for_idle( + apps=[REPLICATION_APP_NAME], + idle_period=20, + raise_on_blocked=False, + timeout=TIMEOUT, + ) + + replication_unit = ops_test.model.applications[REPLICATION_APP_NAME].units[0] + assert ( + replication_unit.workload_status_message + == "Relation to mongos not supported, config role must be config-server" + ), "replica cannot be related to mongos." + + # clean up relations + await ops_test.model.applications[REPLICATION_APP_NAME].remove_relation( + f"{REPLICATION_APP_NAME}:cluster", + f"{SHARD_ONE_APP_NAME}:cluster", + ) + + +async def test_shard_mongos_relation(ops_test: OpsTest) -> None: + """Verifies connecting a shard to a mongos router fails.""" + # attempt to add a replication deployment as a shard to the config server. + await ops_test.model.integrate( + f"{SHARD_ONE_APP_NAME}", + f"{MONGOS_APP_NAME}", + ) + + await ops_test.model.wait_for_idle( + apps=[SHARD_ONE_APP_NAME], + idle_period=20, + raise_on_blocked=False, + timeout=TIMEOUT, + ) + + shard_unit = ops_test.model.applications[SHARD_ONE_APP_NAME].units[0] + assert ( + shard_unit.workload_status_message + == "Relation to mongos not supported, config role must be config-server" + ), "replica cannot be related to mongos." + + # clean up relations + await ops_test.model.applications[SHARD_ONE_APP_NAME].remove_relation( + f"{MONGOS_APP_NAME}:cluster", + f"{SHARD_ONE_APP_NAME}:cluster", + ) From 0bc5cf0e663a76cd5b290661f63815f67151e462 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Wed, 31 Jan 2024 14:24:08 +0000 Subject: [PATCH 02/14] fix to prevent mongos from forever waiting for creds --- lib/charms/mongodb/v0/config_server_interface.py | 1 - tests/integration/sharding_tests/test_sharding_relations.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/charms/mongodb/v0/config_server_interface.py b/lib/charms/mongodb/v0/config_server_interface.py index 847c91267..c67eb7c1f 100644 --- a/lib/charms/mongodb/v0/config_server_interface.py +++ b/lib/charms/mongodb/v0/config_server_interface.py @@ -211,7 +211,6 @@ def _on_relation_changed(self, event) -> None: event.relation.id, CONFIG_SERVER_DB_KEY ) if not key_file_contents or not config_server_db: - event.defer() self.charm.unit.status = WaitingStatus("Waiting for secrets from config-server") return diff --git a/tests/integration/sharding_tests/test_sharding_relations.py b/tests/integration/sharding_tests/test_sharding_relations.py index 9e1a0e123..b57664ae5 100644 --- a/tests/integration/sharding_tests/test_sharding_relations.py +++ b/tests/integration/sharding_tests/test_sharding_relations.py @@ -55,6 +55,7 @@ async def test_build_and_deploy( channel="6/edge", revision=3, ) + # TODO: Future PR, once data integrator works with mongos charm deploy that charm instead of # packing and deploying the charm in the application dir. await ops_test.model.deploy( @@ -274,7 +275,7 @@ async def test_replication_mongos_relation(ops_test: OpsTest) -> None: # clean up relations await ops_test.model.applications[REPLICATION_APP_NAME].remove_relation( f"{REPLICATION_APP_NAME}:cluster", - f"{SHARD_ONE_APP_NAME}:cluster", + f"{MONGOS_APP_NAME}:cluster", ) From 93af195bb026682b79884661313c0a4bd35a7e30 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Wed, 31 Jan 2024 14:41:54 +0000 Subject: [PATCH 03/14] small fix in status check --- .../mongodb/v0/config_server_interface.py | 21 ++++++++++++++----- src/charm.py | 6 ++++-- .../sharding_tests/test_sharding_relations.py | 8 +++++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/charms/mongodb/v0/config_server_interface.py b/lib/charms/mongodb/v0/config_server_interface.py index c67eb7c1f..73cf62b86 100644 --- a/lib/charms/mongodb/v0/config_server_interface.py +++ b/lib/charms/mongodb/v0/config_server_interface.py @@ -69,12 +69,12 @@ def pass_hook_checks(self, event: EventBase) -> bool: event.defer() return False - if not self.charm.is_role(Config.Role.CONFIG_SERVER): + is_integrated_to_mongos = len( + self.charm.model.relations[Config.Relations.CLUSTER_RELATIONS_NAME] + ) + if not self.charm.is_role(Config.Role.CONFIG_SERVER) and is_integrated_to_mongos: logger.info( - "Skipping %s. ShardingProvider is only be executed by config-server", type(event) - ) - self.charm.unit.status = BlockedStatus( - "Relation to mongos not supported, config role must be config-server" + "Skipping %s. ClusterProvider is only be executed by config-server", type(event) ) return False @@ -83,9 +83,20 @@ def pass_hook_checks(self, event: EventBase) -> bool: return True + def set_blocked_status_impossible_integration(self) -> None: + """Sets the status of the charm in the case that the integration is not possible.""" + is_integrated_to_mongos = len( + self.charm.model.relations[Config.Relations.CLUSTER_RELATIONS_NAME] + ) + if not self.charm.is_role(Config.Role.CONFIG_SERVER) and is_integrated_to_mongos: + self.charm.unit.status = BlockedStatus( + "Relation to mongos not supported, config role must be config-server" + ) + def _on_relation_changed(self, event) -> None: """Handles providing mongos with KeyFile and hosts.""" if not self.pass_hook_checks(event): + self.set_blocked_status_impossible_integration() logger.info("Skipping relation joined event: hook checks did not pass") return diff --git a/src/charm.py b/src/charm.py index 1095cecaf..2ccebc515 100755 --- a/src/charm.py +++ b/src/charm.py @@ -1360,8 +1360,10 @@ def get_invalid_integration_status(self) -> Optional[StatusBase]: ) and self.client_relations._get_users_from_relations(None): return BlockedStatus("cannot have both legacy and new relations") - integrated_to_mongos = self.model.relations[Config.Relations.CLUSTER_RELATIONS_NAME] - if not self.is_role(Config.Role.CONFIG_SERVER) and integrated_to_mongos: + is_integrated_to_mongos = len( + self.model.relations[Config.Relations.CLUSTER_RELATIONS_NAME] + ) + if not self.is_role(Config.Role.CONFIG_SERVER) and is_integrated_to_mongos: return BlockedStatus( "Relation to mongos not supported, config role must be config-server" ) diff --git a/tests/integration/sharding_tests/test_sharding_relations.py b/tests/integration/sharding_tests/test_sharding_relations.py index b57664ae5..1f87a4b64 100644 --- a/tests/integration/sharding_tests/test_sharding_relations.py +++ b/tests/integration/sharding_tests/test_sharding_relations.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 # Copyright 2023 Canonical Ltd. # See LICENSE file for licensing details. +import time + import pytest from juju.errors import JujuAPIError from pytest_operator.plugin import OpsTest @@ -278,6 +280,12 @@ async def test_replication_mongos_relation(ops_test: OpsTest) -> None: f"{MONGOS_APP_NAME}:cluster", ) + # TODO remove this and wait for mongos to be active + # right now we cannot wait for `mongos` to be active after removing the relation due to a bug + # in the mongos charm. To fix the bug it is first necessary to publish the updated library + # lib/charms/mongodb/v0/config_server.py + time.sleep(60) + async def test_shard_mongos_relation(ops_test: OpsTest) -> None: """Verifies connecting a shard to a mongos router fails.""" From 68d6b46170e669bd9c2708eb19a9810143ea85b0 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Thu, 1 Feb 2024 08:46:55 +0000 Subject: [PATCH 04/14] update units tests --- tests/unit/test_config_server_lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/test_config_server_lib.py b/tests/unit/test_config_server_lib.py index 3a7f27fb2..05e791e1e 100644 --- a/tests/unit/test_config_server_lib.py +++ b/tests/unit/test_config_server_lib.py @@ -62,6 +62,7 @@ def is_not_config_mock_call(*args): return False self.harness.charm.app_peer_data["db_initialised"] = "True" + self.harness.add_relation("cluster", "mongos") # fails due to being run on non-config-server self.harness.charm.is_role = is_not_config_mock_call From 8372fa69e1c36d5187240691b08e4b443505ffc3 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Fri, 2 Feb 2024 15:43:58 +0000 Subject: [PATCH 05/14] small changes for backups --- lib/charms/mongodb/v1/mongodb_backups.py | 4 +- lib/charms/mongodb/v1/shards_interface.py | 50 +++++++++++++++-------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/lib/charms/mongodb/v1/mongodb_backups.py b/lib/charms/mongodb/v1/mongodb_backups.py index 9dc6b274a..6d91a6b86 100644 --- a/lib/charms/mongodb/v1/mongodb_backups.py +++ b/lib/charms/mongodb/v1/mongodb_backups.py @@ -57,7 +57,7 @@ REMAPPING_PATTERN = r"\ABackup doesn't match current cluster topology - it has different replica set names. Extra shards in the backup will cause this, for a simple example. The extra/unknown replica set names found in the backup are: ([^,\s]+)([.] Backup has no data for the config server or sole replicaset)?\Z" PBM_STATUS_CMD = ["status", "-o", "json"] MONGODB_SNAP_DATA_DIR = "/var/snap/charmed-mongodb/current" -BACKUP_RESTORE_MAX_ATTEMPTS = 5 +BACKUP_RESTORE_MAX_ATTEMPTS = 10 BACKUP_RESTORE_ATTEMPT_COOLDOWN = 15 @@ -292,6 +292,8 @@ def _on_restore_action(self, event) -> None: def _configure_pbm_options(self, event) -> None: action = "configure-pbm" + # if not self._need_configure(): + # return try: self._set_config_options() self._resync_config_options() diff --git a/lib/charms/mongodb/v1/shards_interface.py b/lib/charms/mongodb/v1/shards_interface.py index 57a5451b0..d24e82553 100644 --- a/lib/charms/mongodb/v1/shards_interface.py +++ b/lib/charms/mongodb/v1/shards_interface.py @@ -26,7 +26,7 @@ ShardNotInClusterError, ShardNotPlannedForRemovalError, ) -from charms.mongodb.v1.users import MongoDBUser, OperatorUser +from charms.mongodb.v1.users import MongoDBUser, OperatorUser, BackupUser from ops.charm import CharmBase, EventBase, RelationBrokenEvent from ops.framework import Object from ops.model import ( @@ -55,6 +55,7 @@ KEYFILE_KEY = "key-file" HOSTS_KEY = "host" OPERATOR_PASSWORD_KEY = MongoDBUser.get_password_key_name_for_user(OperatorUser.get_username()) +BACKUP_PASSWORD_KEY = MongoDBUser.get_password_key_name_for_user(BackupUser.get_username()) FORBIDDEN_REMOVAL_ERR_CODE = 20 AUTH_FAILED_CODE = 18 @@ -112,6 +113,10 @@ def _on_relation_joined(self, event): Config.Relations.APP_SCOPE, OPERATOR_PASSWORD_KEY, ), + BACKUP_PASSWORD_KEY: self.charm.get_secret( + Config.Relations.APP_SCOPE, + BACKUP_PASSWORD_KEY, + ), KEYFILE_KEY: self.charm.get_secret( Config.Relations.APP_SCOPE, Config.Secrets.SECRET_KEYFILE_NAME ), @@ -139,12 +144,12 @@ def pass_hook_checks(self, event: EventBase) -> bool: if not self.charm.unit.is_leader(): return False - # adding/removing shards while a backup/restore is in progress can be disastrous - pbm_status = self.charm.backups.get_pbm_status() - if isinstance(pbm_status, MaintenanceStatus): - logger.info("Cannot add/remove shards while a backup/restore is in progress.") - event.defer() - return False + # # adding/removing shards while a backup/restore is in progress can be disastrous + # pbm_status = self.charm.backups.get_pbm_status() + # if isinstance(pbm_status, MaintenanceStatus): + # logger.info("Cannot add/remove shards while a backup/restore is in progress.") + # event.defer() + # return False if isinstance(event, RelationBrokenEvent): if not self.charm.has_departed_run(event.relation.id): @@ -176,6 +181,10 @@ def _on_relation_event(self, event): logger.info("Adding/Removing shards not present in cluster.") self.add_shards(departed_relation_id) self.remove_shards(departed_relation_id) + # pbm has bug where when shard configuration is updated the config for pbm is removed + # pbm agent should be restarted when the cluster config is changed. + + # self.charm._connect_pbm_agent() except NotDrainedError: # it is necessary to removeShard multiple times for the shard to be removed. logger.info( @@ -464,7 +473,6 @@ def _on_relation_changed(self, event): # if re-using an old shard, re-set drained flag. self.charm.unit_peer_data["drained"] = json.dumps(False) - self.charm.unit.status = MaintenanceStatus("Adding shard to config-server") # shards rely on the config server for secrets @@ -488,13 +496,22 @@ def _on_relation_changed(self, event): return # TODO Future work, see if needed to check for all units restarted / primary elected - if not relation_data.get(OPERATOR_PASSWORD_KEY): + if not relation_data.get(OPERATOR_PASSWORD_KEY) or not relation_data.get( + BACKUP_PASSWORD_KEY + ): event.defer() self.charm.unit.status = WaitingStatus("Waiting for secrets from config-server") return try: - self.update_operator_password(new_password=relation_data.get(OPERATOR_PASSWORD_KEY)) + self.update_password( + username=OperatorUser.get_username(), + new_password=relation_data.get(OPERATOR_PASSWORD_KEY), + ) + self.update_password( + username=BackupUser.get_username(), + new_password=relation_data.get(BACKUP_PASSWORD_KEY), + ) except RetryError: self.charm.unit.status = BlockedStatus("Shard not added to config-server") logger.error( @@ -503,6 +520,8 @@ def _on_relation_changed(self, event): event.defer() return + # after updating the password of the backup user, restart pbm with correct password + self.charm._connect_pbm_agent() self.charm.app_peer_data["mongos_hosts"] = json.dumps(self.get_mongos_hosts()) def pass_hook_checks(self, event): @@ -664,8 +683,8 @@ def drained(self, mongos_hosts: Set[str], shard_name: str) -> bool: self.charm.unit_peer_data["drained"] = json.dumps(drained) return drained - def update_operator_password(self, new_password: str) -> None: - """Updates the password for the operator user. + def update_password(self, username: str, new_password: str) -> None: + """Updates the password for the given user. Raises: RetryError @@ -675,8 +694,7 @@ def update_operator_password(self, new_password: str) -> None: current_password = ( self.charm.get_secret( - Config.Relations.APP_SCOPE, - OPERATOR_PASSWORD_KEY, + Config.Relations.APP_SCOPE, MongoDBUser.get_password_key_name_for_user(username) ), ) @@ -691,7 +709,7 @@ def update_operator_password(self, new_password: str) -> None: # a library, for exceptions used in both charm code and lib code. with MongoDBConnection(self.charm.mongodb_config) as mongo: try: - mongo.set_user_password(OperatorUser.get_username(), new_password) + mongo.set_user_password(username, new_password) except NotReadyError: logger.error( "Failed changing the password: Not all members healthy or finished initial sync." @@ -703,7 +721,7 @@ def update_operator_password(self, new_password: str) -> None: self.charm.set_secret( Config.Relations.APP_SCOPE, - OPERATOR_PASSWORD_KEY, + MongoDBUser.get_password_key_name_for_user(username), new_password, ) From b2962ed96d4e72694bcac4ab2ac6b6c86cd4fa2e Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Wed, 7 Feb 2024 16:47:22 +0000 Subject: [PATCH 06/14] basic backups work --- lib/charms/mongodb/v0/mongodb.py | 9 +++++++++ lib/charms/mongodb/v1/shards_interface.py | 4 ---- percona-release_latest.generic_all.deb | Bin 0 -> 11804 bytes src/charm.py | 7 +++++-- src/config.py | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 percona-release_latest.generic_all.deb diff --git a/lib/charms/mongodb/v0/mongodb.py b/lib/charms/mongodb/v0/mongodb.py index 2bc5c6657..bc9851c6c 100644 --- a/lib/charms/mongodb/v0/mongodb.py +++ b/lib/charms/mongodb/v0/mongodb.py @@ -57,6 +57,7 @@ class MongoDBConfiguration: roles: Set[str] tls_external: bool tls_internal: bool + standalone: bool = False @property def uri(self): @@ -66,6 +67,14 @@ def uri(self): auth_source = "" if self.database != "admin": auth_source = "&authSource=admin" + + if self.standalone: + return ( + f"mongodb://{quote_plus(self.username)}:" + f"{quote_plus(self.password)}@" + f"localhost:27017/?authSource=admin" + ) + return ( f"mongodb://{quote_plus(self.username)}:" f"{quote_plus(self.password)}@" diff --git a/lib/charms/mongodb/v1/shards_interface.py b/lib/charms/mongodb/v1/shards_interface.py index d24e82553..7b1ba4b8f 100644 --- a/lib/charms/mongodb/v1/shards_interface.py +++ b/lib/charms/mongodb/v1/shards_interface.py @@ -181,10 +181,6 @@ def _on_relation_event(self, event): logger.info("Adding/Removing shards not present in cluster.") self.add_shards(departed_relation_id) self.remove_shards(departed_relation_id) - # pbm has bug where when shard configuration is updated the config for pbm is removed - # pbm agent should be restarted when the cluster config is changed. - - # self.charm._connect_pbm_agent() except NotDrainedError: # it is necessary to removeShard multiple times for the shard to be removed. logger.info( diff --git a/percona-release_latest.generic_all.deb b/percona-release_latest.generic_all.deb new file mode 100644 index 0000000000000000000000000000000000000000..a5e0b5cc1b9d7d7594503468f52a8849f0293207 GIT binary patch literal 11804 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 literal 0 HcmV?d00001 diff --git a/src/charm.py b/src/charm.py index 2ccebc515..13a9f8516 100755 --- a/src/charm.py +++ b/src/charm.py @@ -225,7 +225,9 @@ def monitor_config(self) -> MongoDBConfiguration: def backup_config(self) -> MongoDBConfiguration: """Generates a MongoDBConfiguration object for backup.""" self._check_or_set_user_password(BackupUser) - return self._get_mongodb_config_for_user(BackupUser, BackupUser.get_hosts()) + return self._get_mongodb_config_for_user( + BackupUser, BackupUser.get_hosts(), standalone=True + ) @property def unit_peer_data(self) -> Dict: @@ -773,7 +775,7 @@ def _get_mongos_config_for_user( ) def _get_mongodb_config_for_user( - self, user: MongoDBUser, hosts: Set[str] + self, user: MongoDBUser, hosts: Set[str], standalone: bool = False ) -> MongoDBConfiguration: external_ca, _ = self.tls.get_tls_files(UNIT_SCOPE) internal_ca, _ = self.tls.get_tls_files(APP_SCOPE) @@ -787,6 +789,7 @@ def _get_mongodb_config_for_user( roles=user.get_roles(), tls_external=external_ca is not None, tls_internal=internal_ca is not None, + standalone=standalone, ) def _get_user_or_fail_event(self, event: ActionEvent, default_username: str) -> Optional[str]: diff --git a/src/config.py b/src/config.py index 2e9feae4b..62b71001d 100644 --- a/src/config.py +++ b/src/config.py @@ -17,7 +17,7 @@ class Config: MONGODB_SNAP_DATA_DIR = "/var/snap/charmed-mongodb/current" MONGOD_CONF_DIR = f"{MONGODB_SNAP_DATA_DIR}/etc/mongod" MONGOD_CONF_FILE_PATH = f"{MONGOD_CONF_DIR}/mongod.conf" - SNAP_PACKAGES = [("charmed-mongodb", "6/edge", 93)] + SNAP_PACKAGES = [("charmed-mongodb", "6/edge/new-pbm-test-0", 107)] # Keep these alphabetically sorted class Actions: From ba3b739e953f3b08489bb74a0b3d4bd1e632ef26 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Fri, 9 Feb 2024 08:07:47 +0000 Subject: [PATCH 07/14] nits + tests --- lib/charms/mongodb/v1/mongodb_backups.py | 4 +--- lib/charms/mongodb/v1/shards_interface.py | 12 ++++++------ .../sharding_tests/test_sharding_backups.py | 15 ++++----------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/lib/charms/mongodb/v1/mongodb_backups.py b/lib/charms/mongodb/v1/mongodb_backups.py index 6d91a6b86..5f7d07427 100644 --- a/lib/charms/mongodb/v1/mongodb_backups.py +++ b/lib/charms/mongodb/v1/mongodb_backups.py @@ -40,7 +40,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 2 +LIBPATCH = 3 logger = logging.getLogger(__name__) @@ -292,8 +292,6 @@ def _on_restore_action(self, event) -> None: def _configure_pbm_options(self, event) -> None: action = "configure-pbm" - # if not self._need_configure(): - # return try: self._set_config_options() self._resync_config_options() diff --git a/lib/charms/mongodb/v1/shards_interface.py b/lib/charms/mongodb/v1/shards_interface.py index 8a3c30b1f..1bcfafc8c 100644 --- a/lib/charms/mongodb/v1/shards_interface.py +++ b/lib/charms/mongodb/v1/shards_interface.py @@ -150,12 +150,12 @@ def pass_hook_checks(self, event: EventBase) -> bool: if not self.charm.unit.is_leader(): return False - # # adding/removing shards while a backup/restore is in progress can be disastrous - # pbm_status = self.charm.backups.get_pbm_status() - # if isinstance(pbm_status, MaintenanceStatus): - # logger.info("Cannot add/remove shards while a backup/restore is in progress.") - # event.defer() - # return False + # adding/removing shards while a backup/restore is in progress can be disastrous + pbm_status = self.charm.backups.get_pbm_status() + if isinstance(pbm_status, MaintenanceStatus): + logger.info("Cannot add/remove shards while a backup/restore is in progress.") + event.defer() + return False if isinstance(event, RelationBrokenEvent): if not self.charm.has_departed_run(event.relation.id): diff --git a/tests/integration/sharding_tests/test_sharding_backups.py b/tests/integration/sharding_tests/test_sharding_backups.py index 771d90758..cb9965033 100644 --- a/tests/integration/sharding_tests/test_sharding_backups.py +++ b/tests/integration/sharding_tests/test_sharding_backups.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 -# Copyright 2023 Canonical Ltd. +# Copyright 2024 Canonical Ltd. # See LICENSE file for licensing details. -import asyncio import pytest from pytest_operator.plugin import OpsTest @@ -9,13 +8,7 @@ import string import secrets -from .helpers import ( - generate_mongodb_client, - has_correct_shards, - shard_has_databases, - verify_data_mongodb, - write_data_to_mongodb, -) + from ..backup_tests import helpers as backup_helpers S3_APP_NAME = "s3-integrator" @@ -59,7 +52,7 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: async def test_set_credentials_in_cluster(ops_test: OpsTest) -> None: - # set correct AWS credentials for s3 storage but incorrect configs + """Tests that sharded cluster can be configured for s3 configurations.""" await backup_helpers.set_credentials(ops_test, cloud="AWS") choices = string.ascii_letters + string.digits unique_path = "".join([secrets.choice(choices) for _ in range(4)]) @@ -101,7 +94,7 @@ async def test_set_credentials_in_cluster(ops_test: OpsTest) -> None: async def test_create_and_list_backups_in_cluster(ops_test: OpsTest) -> None: - """Pass""" + """Tests that sharded cluster can successfully create and list backups.""" leader_unit = await backup_helpers.get_leader_unit( ops_test, db_app_name=CONFIG_SERVER_APP_NAME ) From 55506a75a5acf25f3e6b24f55b49032c360c7079 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Fri, 9 Feb 2024 08:19:00 +0000 Subject: [PATCH 08/14] personal nits --- lib/charms/mongodb/v0/mongodb.py | 6 ++++-- lib/charms/mongodb/v1/shards_interface.py | 4 ++-- src/config.py | 2 +- .../sharding_tests/test_sharding_backups.py | 12 ++++++------ 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/charms/mongodb/v0/mongodb.py b/lib/charms/mongodb/v0/mongodb.py index bc9851c6c..9528fa8f1 100644 --- a/lib/charms/mongodb/v0/mongodb.py +++ b/lib/charms/mongodb/v0/mongodb.py @@ -30,11 +30,13 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 7 +LIBPATCH = 8 # path to store mongodb ketFile logger = logging.getLogger(__name__) +MONGODB_PORT = 27017 + @dataclass class MongoDBConfiguration: @@ -72,7 +74,7 @@ def uri(self): return ( f"mongodb://{quote_plus(self.username)}:" f"{quote_plus(self.password)}@" - f"localhost:27017/?authSource=admin" + f"localhost:{MONGODB_PORT}/?authSource=admin" ) return ( diff --git a/lib/charms/mongodb/v1/shards_interface.py b/lib/charms/mongodb/v1/shards_interface.py index 15d0052f3..4669974ff 100644 --- a/lib/charms/mongodb/v1/shards_interface.py +++ b/lib/charms/mongodb/v1/shards_interface.py @@ -30,7 +30,7 @@ ShardNotInClusterError, ShardNotPlannedForRemovalError, ) -from charms.mongodb.v1.users import MongoDBUser, OperatorUser, BackupUser +from charms.mongodb.v1.users import BackupUser, MongoDBUser, OperatorUser from ops.charm import CharmBase, EventBase, RelationBrokenEvent from ops.framework import Object from ops.model import ( @@ -55,7 +55,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 6 +LIBPATCH = 7 KEYFILE_KEY = "key-file" HOSTS_KEY = "host" OPERATOR_PASSWORD_KEY = MongoDBUser.get_password_key_name_for_user(OperatorUser.get_username()) diff --git a/src/config.py b/src/config.py index 62b71001d..e6161ba8a 100644 --- a/src/config.py +++ b/src/config.py @@ -17,7 +17,7 @@ class Config: MONGODB_SNAP_DATA_DIR = "/var/snap/charmed-mongodb/current" MONGOD_CONF_DIR = f"{MONGODB_SNAP_DATA_DIR}/etc/mongod" MONGOD_CONF_FILE_PATH = f"{MONGOD_CONF_DIR}/mongod.conf" - SNAP_PACKAGES = [("charmed-mongodb", "6/edge/new-pbm-test-0", 107)] + SNAP_PACKAGES = [("charmed-mongodb", "6/edge", 111)] # Keep these alphabetically sorted class Actions: diff --git a/tests/integration/sharding_tests/test_sharding_backups.py b/tests/integration/sharding_tests/test_sharding_backups.py index cb9965033..84f937dee 100644 --- a/tests/integration/sharding_tests/test_sharding_backups.py +++ b/tests/integration/sharding_tests/test_sharding_backups.py @@ -2,12 +2,12 @@ # Copyright 2024 Canonical Ltd. # See LICENSE file for licensing details. +import secrets +import string + import pytest from pytest_operator.plugin import OpsTest from tenacity import RetryError, Retrying, stop_after_delay, wait_fixed -import string -import secrets - from ..backup_tests import helpers as backup_helpers @@ -43,7 +43,7 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: await ops_test.model.deploy(S3_APP_NAME, channel="edge") await ops_test.model.wait_for_idle( - apps=[S3_APP_NAME, CONFIG_SERVER_APP_NAME, SHARD_ONE_APP_NAME], + apps=[S3_APP_NAME, CONFIG_SERVER_APP_NAME, SHARD_ONE_APP_NAME, SHARD_TWO_APP_NAME], idle_period=20, raise_on_blocked=False, timeout=TIMEOUT, @@ -66,8 +66,8 @@ async def test_set_credentials_in_cluster(ops_test: OpsTest) -> None: # apply new configuration options await ops_test.model.applications[S3_APP_NAME].set_config(configuration_parameters) - # provide config-server to entire cluster - integrations made in succession to test race - # conditions. + # provide config-server to entire cluster and s3-integrator to config-server - integrations + # made in succession to test race conditions. await ops_test.model.integrate( f"{S3_APP_NAME}:{S3_REL_NAME}", f"{CONFIG_SERVER_APP_NAME}:{S3_REL_NAME}", From d7af712d6fc42b6a37e6b919e5182247ac3eb8e1 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Fri, 9 Feb 2024 08:47:09 +0000 Subject: [PATCH 09/14] give access keys to tests --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index d468f8fd4..8dbe381fb 100644 --- a/tox.ini +++ b/tox.ini @@ -254,6 +254,8 @@ description = Run sharding backups tests pass_env = {[testenv]pass_env} CI + AWS_ACCESS_KEY + AWS_SECRET_KEY deps = pytest juju==3.2.0.1 From 20d9018be99d33eb2c5b11dde7116c3383767b97 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Fri, 9 Feb 2024 09:50:34 +0000 Subject: [PATCH 10/14] fix race-cond in test --- tests/integration/sharding_tests/test_sharding_backups.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/sharding_tests/test_sharding_backups.py b/tests/integration/sharding_tests/test_sharding_backups.py index 84f937dee..189918626 100644 --- a/tests/integration/sharding_tests/test_sharding_backups.py +++ b/tests/integration/sharding_tests/test_sharding_backups.py @@ -65,6 +65,7 @@ async def test_set_credentials_in_cluster(ops_test: OpsTest) -> None: # apply new configuration options await ops_test.model.applications[S3_APP_NAME].set_config(configuration_parameters) + await ops_test.model.wait_for_idle(apps=[S3_APP_NAME], status="active", timeout=TIMEOUT) # provide config-server to entire cluster and s3-integrator to config-server - integrations # made in succession to test race conditions. From 3e2d7d5b3c5b3101a2cf6a2d4e22491cab00c011 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Fri, 9 Feb 2024 10:19:05 +0000 Subject: [PATCH 11/14] have CI send secrets --- .github/workflows/ci.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index af3eee6da..9c8ea8b5e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -133,7 +133,7 @@ jobs: run: tox run -e ${{ matrix.tox-environments }} -- -m '${{ steps.select-tests.outputs.mark_expression }}' env: CI_PACKED_CHARMS: ${{ needs.build.outputs.charms }} - AWS_ACCESS_KEY: ${{ matrix.tox-environments != 'backup-integration' || secrets.AWS_ACCESS_KEY }} - AWS_SECRET_KEY: ${{ matrix.tox-environments != 'backup-integration' || secrets.AWS_SECRET_KEY }} - GCP_ACCESS_KEY: ${{ matrix.tox-environments != 'backup-integration' || secrets.GCP_ACCESS_KEY }} + AWS_ACCESS_KEY: ${{ (matrix.tox-environments != 'backup-integration' || matrix.tox-environments != 'sharding-backups-integration')|| secrets.AWS_ACCESS_KEY }} + AWS_SECRET_KEY: ${{ (matrix.tox-environments != 'backup-integration' || matrix.tox-environments != 'sharding-backups-integration') || secrets.AWS_SECRET_KEY }} + GCP_ACCESS_KEY: ${{ matrix.tox-environments != 'backup-integration' || secrets.GCP_ACCESS_KEY }} GCP_SECRET_KEY: ${{ matrix.tox-environments != 'backup-integration' || secrets.GCP_SECRET_KEY }} From e3c8390816808cd58f35e15ef595c671b43e06e0 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Mon, 19 Feb 2024 10:22:14 +0000 Subject: [PATCH 12/14] sharding backup tests use github secrets --- .../sharding_tests/test_sharding_backups.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/integration/sharding_tests/test_sharding_backups.py b/tests/integration/sharding_tests/test_sharding_backups.py index 189918626..3a807837f 100644 --- a/tests/integration/sharding_tests/test_sharding_backups.py +++ b/tests/integration/sharding_tests/test_sharding_backups.py @@ -22,6 +22,7 @@ TIMEOUT = 10 * 60 +@pytest.mark.group(1) @pytest.mark.abort_on_fail async def test_build_and_deploy(ops_test: OpsTest) -> None: """Build and deploy a sharded cluster.""" @@ -51,9 +52,10 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: ) -async def test_set_credentials_in_cluster(ops_test: OpsTest) -> None: +@pytest.mark.group(1) +async def test_set_credentials_in_cluster(ops_test: OpsTest, github_secrets) -> None: """Tests that sharded cluster can be configured for s3 configurations.""" - await backup_helpers.set_credentials(ops_test, cloud="AWS") + await backup_helpers.set_credentials(ops_test, github_secrets, cloud="AWS") choices = string.ascii_letters + string.digits unique_path = "".join([secrets.choice(choices) for _ in range(4)]) configuration_parameters = { @@ -94,12 +96,13 @@ async def test_set_credentials_in_cluster(ops_test: OpsTest) -> None: ) -async def test_create_and_list_backups_in_cluster(ops_test: OpsTest) -> None: +@pytest.mark.group(1) +async def test_create_and_list_backups_in_cluster(ops_test: OpsTest, github_secrets) -> None: """Tests that sharded cluster can successfully create and list backups.""" leader_unit = await backup_helpers.get_leader_unit( ops_test, db_app_name=CONFIG_SERVER_APP_NAME ) - await backup_helpers.set_credentials(ops_test, cloud="AWS") + await backup_helpers.set_credentials(ops_test, github_secrets, cloud="AWS") # verify backup list works action = await leader_unit.run_action(action_name="list-backups") list_result = await action.wait() From f5b7ce6dd77d2ee21291b13ee7447c7a0f721303 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Mon, 19 Feb 2024 15:23:14 +0000 Subject: [PATCH 13/14] PR feedback --- lib/charms/mongodb/v0/mongodb.py | 6 +++--- percona-release_latest.generic_all.deb | Bin 11804 -> 0 bytes 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 percona-release_latest.generic_all.deb diff --git a/lib/charms/mongodb/v0/mongodb.py b/lib/charms/mongodb/v0/mongodb.py index 9528fa8f1..e2b1582e5 100644 --- a/lib/charms/mongodb/v0/mongodb.py +++ b/lib/charms/mongodb/v0/mongodb.py @@ -9,6 +9,8 @@ from typing import Dict, List, Optional, Set from urllib.parse import quote_plus +from config import Config + from bson.json_util import dumps from pymongo import MongoClient from pymongo.errors import OperationFailure, PyMongoError @@ -35,8 +37,6 @@ # path to store mongodb ketFile logger = logging.getLogger(__name__) -MONGODB_PORT = 27017 - @dataclass class MongoDBConfiguration: @@ -74,7 +74,7 @@ def uri(self): return ( f"mongodb://{quote_plus(self.username)}:" f"{quote_plus(self.password)}@" - f"localhost:{MONGODB_PORT}/?authSource=admin" + f"localhost:{Config.MONGODB_PORT}/?authSource=admin" ) return ( diff --git a/percona-release_latest.generic_all.deb b/percona-release_latest.generic_all.deb deleted file mode 100644 index a5e0b5cc1b9d7d7594503468f52a8849f0293207..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11804 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 From 90e186f2cb78a1b76213eaa2a46ada0af8c32e76 Mon Sep 17 00:00:00 2001 From: Mia Altieri Date: Mon, 19 Feb 2024 15:47:45 +0000 Subject: [PATCH 14/14] fmt + lint --- lib/charms/mongodb/v0/mongodb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/charms/mongodb/v0/mongodb.py b/lib/charms/mongodb/v0/mongodb.py index e2b1582e5..f482f7eec 100644 --- a/lib/charms/mongodb/v0/mongodb.py +++ b/lib/charms/mongodb/v0/mongodb.py @@ -9,8 +9,6 @@ from typing import Dict, List, Optional, Set from urllib.parse import quote_plus -from config import Config - from bson.json_util import dumps from pymongo import MongoClient from pymongo.errors import OperationFailure, PyMongoError @@ -24,6 +22,8 @@ wait_fixed, ) +from config import Config + # The unique Charmhub library identifier, never change it LIBID = "49c69d9977574dd7942eb7b54f43355b"