diff --git a/lib/charms/mongodb/v0/mongos.py b/lib/charms/mongodb/v0/mongos.py index 06a007d31..f51ee4097 100644 --- a/lib/charms/mongodb/v0/mongos.py +++ b/lib/charms/mongodb/v0/mongos.py @@ -180,12 +180,12 @@ def remove_shard(self, shard_name: str) -> None: cannot_remove_shard = ( f"cannot remove shard {shard_name} from cluster, another shard is draining" ) - logger.info(cannot_remove_shard) + logger.error(cannot_remove_shard) raise NotReadyError(cannot_remove_shard) # TODO Follow up PR, there is no MongoDB command to retrieve primary shard, this is # possible with mongosh. - primary_shard = False + primary_shard = self.get_primary_shard() if primary_shard: # TODO Future PR, support removing Primary Shard if there are no unsharded collections # on it. All sharded collections should perform `MovePrimary` @@ -196,8 +196,24 @@ def remove_shard(self, shard_name: str) -> None: raise RemovePrimaryShardError(cannot_remove_primary_shard) logger.info("Attempting to remove shard %s", shard_name) - self.client.admin.command("removeShard", shard_name) - logger.info("Shard %s, now draining", shard_name) + removal_info = self.client.admin.command("removeShard", shard_name) + + # process removal status + remaining_chunks = ( + removal_info["remaining"]["chunks"] if "remaining" in removal_info else "None" + ) + dbs_to_move = ( + removal_info["dbsToMove"] + if "dbsToMove" in removal_info and removal_info["dbsToMove"] != [] + else ["None"] + ) + logger.info( + "Shard %s is draining status is: %s. Remaining chunks: %s. DBs to move: %s.", + shard_name, + removal_info["state"], + str(remaining_chunks), + ",".join(dbs_to_move), + ) def _is_shard_draining(self, shard_name: str) -> bool: """Reports if a given shard is currently in the draining state. @@ -219,6 +235,12 @@ def _is_shard_draining(self, shard_name: str) -> bool: f"Shard {shard_name} not in cluster, could not retrieve draining status" ) + def get_primary_shard(self) -> str: + """Processes sc_status and identifies the primary shard.""" + # TODO Follow up PR, implement this function there is no MongoDB command to retrieve + # primary shard, this is possible with mongosh. + return False + @staticmethod def _is_any_draining(sc_status: Dict, ignore_shard: str = "") -> bool: """Returns true if any shard members is draining. diff --git a/lib/charms/mongodb/v0/shards_interface.py b/lib/charms/mongodb/v0/shards_interface.py index 80bd22245..868c5b5de 100644 --- a/lib/charms/mongodb/v0/shards_interface.py +++ b/lib/charms/mongodb/v0/shards_interface.py @@ -46,6 +46,7 @@ KEYFILE_KEY = "key-file" HOSTS_KEY = "host" OPERATOR_PASSWORD_KEY = MongoDBUser.get_password_key_name_for_user(OperatorUser.get_username()) +FORBIDDEN_REMOVAL_ERR_CODE = 20 class RemoveLastShardError(Exception): @@ -83,6 +84,7 @@ def __init__( def _on_relation_joined(self, event): """Handles providing shards with secrets and adding shards to the config server.""" if not self.pass_hook_checks(event): + logger.info("Skipping relation joined event: hook checks did not pass") return # TODO Future PR, sync tls secrets and PBM password @@ -132,6 +134,13 @@ def _on_relation_event(self, event): Updating of shards is done automatically via MongoDB change-streams. """ if not self.pass_hook_checks(event): + logger.info("Skipping relation event: hook checks did not pass") + return + + # 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): + event.defer("Cannot add/remove shards while a backup/restore is in progress.") return departed_relation_id = None @@ -150,7 +159,7 @@ def _on_relation_event(self, event): event.defer() return except OperationFailure as e: - if e.code == 20: + if e.code == FORBIDDEN_REMOVAL_ERR_CODE: # TODO Future PR, allow removal of last shards that have no data. This will be # tricky since we are not allowed to update the mongos config in this way. logger.error( @@ -208,7 +217,7 @@ def remove_shards(self, departed_shard_id): self.charm.unit.status = MaintenanceStatus(f"Draining shard {shard}") logger.info("Attempting to removing shard: %s", shard) mongo.remove_shard(shard) - logger.info("Attempting to removing shard: %s", shard) + logger.info("Shard: %s, is now draining", shard) if shard in mongo.get_shard_members(): shard_draining_message = f"shard {shard} still exists in cluster after removal, it is still draining."