From faf72559ba48c19ea9908781ea2c1d88fc874a65 Mon Sep 17 00:00:00 2001 From: MiaAltieri Date: Tue, 26 Mar 2024 07:54:46 +0000 Subject: [PATCH 1/4] WIP tls sanity checks --- .../mongodb/v0/config_server_interface.py | 113 +++++++++++++++++- src/charm.py | 27 ++--- tests/integration/tls_tests/helpers.py | 8 +- tests/integration/tls_tests/test_tls.py | 85 ++++++++++--- 4 files changed, 197 insertions(+), 36 deletions(-) diff --git a/lib/charms/mongodb/v0/config_server_interface.py b/lib/charms/mongodb/v0/config_server_interface.py index 1d4cf7aa..8e5ddcf6 100644 --- a/lib/charms/mongodb/v0/config_server_interface.py +++ b/lib/charms/mongodb/v0/config_server_interface.py @@ -13,13 +13,17 @@ DatabaseProvides, DatabaseRequires, ) -from charms.mongodb.v1.helpers import add_args_to_env, get_mongos_args from charms.mongodb.v1.mongos import MongosConnection from ops.charm import CharmBase, EventBase, RelationBrokenEvent from ops.framework import Object -from ops.model import ActiveStatus, BlockedStatus, MaintenanceStatus, WaitingStatus +from ops.model import ( + ActiveStatus, + BlockedStatus, + MaintenanceStatus, + StatusBase, + WaitingStatus, +) -from typing import Optional from config import Config logger = logging.getLogger(__name__) @@ -38,7 +42,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 8 +LIBPATCH = 10 class ClusterProvider(Object): @@ -232,6 +236,10 @@ def _on_database_created(self, event) -> None: def _on_relation_changed(self, event) -> None: """Starts/restarts monogs with config server information.""" + if not self.pass_hook_checks(event): + logger.info("pre-hook checks did not pass, not executing event") + return + key_file_contents = self.database_requires.fetch_relation_field( event.relation.id, KEYFILE_KEY ) @@ -288,6 +296,34 @@ def _on_relation_broken(self, event: RelationBrokenEvent) -> None: self.charm.remove_connection_info() # BEGIN: helper functions + def pass_hook_checks(self, event): + """Runs the pre-hooks checks for ClusterRequirer, returns True if all pass.""" + if self.is_mongos_tls_needed(): + logger.info( + "Deferring %s. Config-server uses TLS, but mongos does not. Please synchronise encryption methods.", + str(type(event)), + ) + event.defer() + return False + + if self.is_config_server_tls_needed(): + logger.info( + "Deferring %s. mongos uses TLS, but config-server does not. Please synchronise encryption methods.", + str(type(event)), + ) + event.defer() + return False + + if not self.is_ca_compatible(): + logger.info( + "Deferring %s. mongos is integrated to a different CA than the config server. Please use the same CA for all cluster components.", + str(type(event)), + ) + + event.defer() + return False + + return True def is_mongos_running(self) -> bool: """Returns true if mongos service is running.""" @@ -328,6 +364,22 @@ def update_keyfile(self, key_file_contents: str) -> bool: return True + def get_tls_statuses(self) -> Optional[StatusBase]: + """Returns statuses relevant to TLS.""" + if self.is_mongos_tls_needed(): + return BlockedStatus("mongos requires TLS to be enabled.") + + if self.is_config_server_tls_needed(): + return BlockedStatus("mongos has TLS enabled, but config-server does not.") + + if not self.is_ca_compatible(): + logger.error( + "mongos is integrated to a different CA than the config server. Please use the same CA for all cluster components." + ) + return BlockedStatus("mongos CA and Config-Server CA don't match.") + + return + def get_config_server_name(self) -> Optional[str]: """Returns the name of the Juju Application that mongos is using as a config server.""" if not self.model.get_relation(self.relation_name): @@ -336,4 +388,57 @@ def get_config_server_name(self) -> Optional[str]: # metadata.yaml prevents having multiple config servers return self.model.get_relation(self.relation_name).app.name + def is_ca_compatible(self) -> bool: + """Returns true if both the mongos and the config server use the same CA.""" + config_server_relation = self.charm.model.get_relation(self.relation_name) + # base-case: nothing to compare + if not config_server_relation: + return True + + config_server_tls_ca = self.database_requires.fetch_relation_field( + config_server_relation.id, INT_TLS_CA_KEY + ) + + mongos_tls_ca = self.charm.tls.get_tls_secret( + internal=True, label_name=Config.TLS.SECRET_CA_LABEL + ) + + # base-case: missing one or more CA's to compare + if not config_server_tls_ca or not mongos_tls_ca: + return True + + return config_server_tls_ca == mongos_tls_ca + + def is_mongos_tls_needed(self) -> bool: + """Returns true if the config-server has TLS enabled but mongos does not.""" + config_server_relation = self.charm.model.get_relation(self.relation_name) + if not config_server_relation: + return False + + mongos_has_tls = self.charm.model.get_relation(Config.TLS.TLS_PEER_RELATION) is not None + config_server_has_tls = ( + self.database_requires.fetch_relation_field(config_server_relation.id, INT_TLS_CA_KEY) + is not None + ) + if config_server_has_tls and not mongos_has_tls: + return True + + return False + + def is_config_server_tls_needed(self) -> bool: + """Returns true if the mongos has TLS enabled but the config-server does not.""" + config_server_relation = self.charm.model.get_relation(self.relation_name) + if not config_server_relation: + return False + + mongos_has_tls = self.charm.model.get_relation(Config.TLS.TLS_PEER_RELATION) is not None + config_server_has_tls = ( + self.database_requires.fetch_relation_field(config_server_relation.id, INT_TLS_CA_KEY) + is not None + ) + if not config_server_has_tls and mongos_has_tls: + return True + + return False + # END: helper functions diff --git a/src/charm.py b/src/charm.py index 2f434798..0f663831 100755 --- a/src/charm.py +++ b/src/charm.py @@ -33,7 +33,7 @@ from config import Config import ops -from ops.model import BlockedStatus, MaintenanceStatus, WaitingStatus, Relation +from ops.model import BlockedStatus, MaintenanceStatus, WaitingStatus, Relation, ActiveStatus from ops.charm import InstallEvent, StartEvent, RelationDepartedEvent import logging @@ -105,12 +105,18 @@ def _on_update_status(self, _): self.unit.status = BlockedStatus("Missing relation to config-server.") return - # restart on high loaded databases can be very slow (e.g. up to 10-20 minutes). + if self.cluster.get_tls_statuses(): + self.unit.status = self.cluster.get_tls_statuses() + return + + # restart on high loaded databases can be very slow (e.g. up to 10-20 minutes). if not self.cluster.is_mongos_running(): logger.info("mongos has not started yet") self.unit.status = WaitingStatus("Waiting for mongos to start.") return + self.unit.status = ActiveStatus() + # END: hook functions # BEGIN: helper functions @@ -194,9 +200,7 @@ def remove_secret(self, scope, key) -> None: content = secret.get_content() if not content.get(key) or content[key] == Config.Secrets.SECRET_DELETED_LABEL: - logger.error( - f"Non-existing secret {scope}:{key} was attempted to be removed." - ) + logger.error(f"Non-existing secret {scope}:{key} was attempted to be removed.") return content[key] = Config.Secrets.SECRET_DELETED_LABEL @@ -267,7 +271,6 @@ def restart_charm_services(self) -> None: self.start_mongos_service() def update_mongos_args(self, config_server_db: Optional[str] = None): - """Updates the starting arguments for the mongos daemon.""" config_server_db = config_server_db or self.config_server_db if config_server_db is None: logger.error("cannot start mongos without a config_server_db") @@ -298,9 +301,7 @@ def set_user_roles(self, roles: List[str]) -> None: return # a mongos shard can only be related to one config server - config_server_rel = self.model.relations[ - Config.Relations.CLUSTER_RELATIONS_NAME - ][0] + config_server_rel = self.model.relations[Config.Relations.CLUSTER_RELATIONS_NAME][0] self.cluster.database_requires.update_relation_data( config_server_rel.id, {USER_ROLES_TAG: roles_str} ) @@ -313,18 +314,14 @@ def set_database(self, database: str) -> None: return # a mongos shard can only be related to one config server - config_server_rel = self.model.relations[ - Config.Relations.CLUSTER_RELATIONS_NAME - ][0] + config_server_rel = self.model.relations[Config.Relations.CLUSTER_RELATIONS_NAME][0] self.cluster.database_requires.update_relation_data( config_server_rel.id, {DATABASE_TAG: database} ) def set_external_connectivity(self, external_connectivity: bool) -> None: """Sets the connectivity type for mongos.""" - self.app_peer_data[EXTERNAL_CONNECTIVITY_TAG] = json.dumps( - external_connectivity - ) + self.app_peer_data[EXTERNAL_CONNECTIVITY_TAG] = json.dumps(external_connectivity) def check_relation_broken_or_scale_down(self, event: RelationDepartedEvent) -> None: """Checks relation departed event is the result of removed relation or scale down. diff --git a/tests/integration/tls_tests/helpers.py b/tests/integration/tls_tests/helpers.py index bcb42f2d..c9531f9f 100644 --- a/tests/integration/tls_tests/helpers.py +++ b/tests/integration/tls_tests/helpers.py @@ -29,17 +29,19 @@ async def check_mongos_tls_enabled(ops_test: OpsTest) -> None: await check_tls(ops_test, unit, enabled=True) -async def toggle_tls_mongos(ops_test: OpsTest, enable: bool) -> None: +async def toggle_tls_mongos( + ops_test: OpsTest, enable: bool, certs_app_name: str = CERTS_APP_NAME +) -> None: """Toggles TLS on mongos application to the specified enabled state.""" if enable: await ops_test.model.integrate( f"{MONGOS_APP_NAME}:{CERT_REL_NAME}", - f"{CERTS_APP_NAME}:{CERT_REL_NAME}", + f"{certs_app_name}:{CERT_REL_NAME}", ) else: await ops_test.model.applications[MONGOS_APP_NAME].remove_relation( f"{MONGOS_APP_NAME}:{CERT_REL_NAME}", - f"{CERTS_APP_NAME}:{CERT_REL_NAME}", + f"{certs_app_name}:{CERT_REL_NAME}", ) diff --git a/tests/integration/tls_tests/test_tls.py b/tests/integration/tls_tests/test_tls.py index 46d5301e..a7618abf 100644 --- a/tests/integration/tls_tests/test_tls.py +++ b/tests/integration/tls_tests/test_tls.py @@ -15,35 +15,45 @@ MONGODB_CHARM_NAME = "mongodb" CONFIG_SERVER_APP_NAME = "config-server" SHARD_APP_NAME = "shard" -CLUSTER_COMPONENTS = [MONGOS_APP_NAME, CONFIG_SERVER_APP_NAME, SHARD_APP_NAME] +CLUSTER_COMPONENTS = [CONFIG_SERVER_APP_NAME, SHARD_APP_NAME] CERT_REL_NAME = "certificates" SHARD_REL_NAME = "sharding" CLUSTER_REL_NAME = "cluster" CONFIG_SERVER_REL_NAME = "config-server" CERTS_APP_NAME = "self-signed-certificates" +DIFFERENT_CERTS_APP_NAME = "self-signed-certificates-separate" TIMEOUT = 15 * 60 -@pytest.mark.skip("Wait new MongoDB charm is published.") -@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.""" - await deploy_cluster(ops_test) - await build_cluster(ops_test) - await deploy_tls(ops_test) +# @pytest.mark.skip("Wait new MongoDB charm is published.") +# @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.""" +# await deploy_cluster(ops_test) +# await build_cluster(ops_test) +# await deploy_tls(ops_test) -@pytest.mark.skip("Wait new MongoDB charm is published.") +# @pytest.mark.skip("Wait new MongoDB charm is published.") @pytest.mark.group(1) @pytest.mark.abort_on_fail async def test_mongos_tls_enabled(ops_test: OpsTest) -> None: """Tests that mongos charm can enable TLS.""" - # await integrate_cluster_with_tls(ops_test) + await integrate_mongos_with_tls(ops_test) + + mongos_unit = ops_test.model.applications[MONGOS_APP_NAME].units[0] + assert ( + mongos_unit.workload_status_message + == "mongos has TLS enabled, but config-server does not." + ), "Shard fails to report TLS inconsistencies." + + await integrate_cluster_with_tls(ops_test) + await check_mongos_tls_enabled(ops_test) -@pytest.mark.skip("Wait until TLS sanity check functionality is implemented") +# @pytest.mark.skip("Wait new MongoDB charm is published.") @pytest.mark.group(1) @pytest.mark.abort_on_fail async def test_mongos_tls_disabled(ops_test: OpsTest) -> None: @@ -51,8 +61,13 @@ async def test_mongos_tls_disabled(ops_test: OpsTest) -> None: await toggle_tls_mongos(ops_test, enable=False) await check_mongos_tls_disabled(ops_test) + mongos_unit = ops_test.model.applications[MONGOS_APP_NAME].units[0] + assert ( + mongos_unit.workload_status_message == "mongos requires TLS to be enabled." + ), "Shard fails to report TLS inconsistencies." -@pytest.mark.skip("Wait until TLS sanity check functionality is implemented") + +# @pytest.mark.skip("Wait new MongoDB charm is published.") @pytest.mark.group(1) @pytest.mark.abort_on_fail async def test_tls_reenabled(ops_test: OpsTest) -> None: @@ -61,6 +76,32 @@ async def test_tls_reenabled(ops_test: OpsTest) -> None: await check_mongos_tls_enabled(ops_test) +# @pytest.mark.skip("Wait new MongoDB charm is published.") +@pytest.mark.group(1) +@pytest.mark.abort_on_fail +async def test_mongos_tls_ca_mismatch(ops_test: OpsTest) -> None: + """Tests that mongos charm can disable TLS.""" + + await toggle_tls_mongos(ops_test, enable=False) + await ops_test.model.deploy( + CERTS_APP_NAME, application_name=DIFFERENT_CERTS_APP_NAME, channel="stable" + ) + await ops_test.model.wait_for_idle( + apps=[DIFFERENT_CERTS_APP_NAME], + idle_period=10, + raise_on_blocked=False, + timeout=TIMEOUT, + ) + + await toggle_tls_mongos(ops_test, enable=False, certs_app_name=DIFFERENT_CERTS_APP_NAME) + + mongos_unit = ops_test.model.applications[MONGOS_APP_NAME].units[0] + assert ( + mongos_unit.workload_status_message + == "mongos has TLS enabled, but config-server does not." + ), "mongos CA and Config-Server CA don't match." + + async def deploy_cluster(ops_test: OpsTest) -> None: """Deploys the necessary cluster components""" application_charm = await ops_test.build_charm("tests/integration/application") @@ -153,6 +194,22 @@ async def deploy_tls(ops_test: OpsTest) -> None: ) +async def integrate_mongos_with_tls(ops_test: OpsTest) -> None: + """Integrate mongos to the TLS interface.""" + await ops_test.model.integrate( + f"{MONGOS_APP_NAME}:{CERT_REL_NAME}", + f"{CERTS_APP_NAME}:{CERT_REL_NAME}", + ) + + await ops_test.model.wait_for_idle( + apps=[MONGOS_APP_NAME], + idle_period=20, + timeout=TIMEOUT, + raise_on_blocked=False, + status="active", + ) + + async def integrate_cluster_with_tls(ops_test: OpsTest) -> None: """Integrate cluster components to the TLS interface.""" for cluster_component in CLUSTER_COMPONENTS: @@ -162,7 +219,7 @@ async def integrate_cluster_with_tls(ops_test: OpsTest) -> None: ) await ops_test.model.wait_for_idle( - apps=[CLUSTER_COMPONENTS], + apps=CLUSTER_COMPONENTS, idle_period=20, timeout=TIMEOUT, raise_on_blocked=False, From 102dd568ff69b6b77d1ba70ba2f5aab26c7e22c6 Mon Sep 17 00:00:00 2001 From: MiaAltieri Date: Tue, 26 Mar 2024 09:42:15 +0000 Subject: [PATCH 2/4] mongos correctly reports TLS statuses --- .../mongodb/v0/config_server_interface.py | 14 ++--- src/charm.py | 24 +++++-- tests/integration/tls_tests/test_tls.py | 63 +++++++++++-------- 3 files changed, 62 insertions(+), 39 deletions(-) diff --git a/lib/charms/mongodb/v0/config_server_interface.py b/lib/charms/mongodb/v0/config_server_interface.py index 8e5ddcf6..7d863d7e 100644 --- a/lib/charms/mongodb/v0/config_server_interface.py +++ b/lib/charms/mongodb/v0/config_server_interface.py @@ -298,7 +298,7 @@ def _on_relation_broken(self, event: RelationBrokenEvent) -> None: # BEGIN: helper functions def pass_hook_checks(self, event): """Runs the pre-hooks checks for ClusterRequirer, returns True if all pass.""" - if self.is_mongos_tls_needed(): + if self.is_mongos_tls_missing(): logger.info( "Deferring %s. Config-server uses TLS, but mongos does not. Please synchronise encryption methods.", str(type(event)), @@ -306,7 +306,7 @@ def pass_hook_checks(self, event): event.defer() return False - if self.is_config_server_tls_needed(): + if self.is_config_server_tls_missing(): logger.info( "Deferring %s. mongos uses TLS, but config-server does not. Please synchronise encryption methods.", str(type(event)), @@ -366,10 +366,10 @@ def update_keyfile(self, key_file_contents: str) -> bool: def get_tls_statuses(self) -> Optional[StatusBase]: """Returns statuses relevant to TLS.""" - if self.is_mongos_tls_needed(): + if self.is_mongos_tls_missing(): return BlockedStatus("mongos requires TLS to be enabled.") - if self.is_config_server_tls_needed(): + if self.is_config_server_tls_missing(): return BlockedStatus("mongos has TLS enabled, but config-server does not.") if not self.is_ca_compatible(): @@ -404,12 +404,12 @@ def is_ca_compatible(self) -> bool: ) # base-case: missing one or more CA's to compare - if not config_server_tls_ca or not mongos_tls_ca: + if not config_server_tls_ca and not mongos_tls_ca: return True return config_server_tls_ca == mongos_tls_ca - def is_mongos_tls_needed(self) -> bool: + def is_mongos_tls_missing(self) -> bool: """Returns true if the config-server has TLS enabled but mongos does not.""" config_server_relation = self.charm.model.get_relation(self.relation_name) if not config_server_relation: @@ -425,7 +425,7 @@ def is_mongos_tls_needed(self) -> bool: return False - def is_config_server_tls_needed(self) -> bool: + def is_config_server_tls_missing(self) -> bool: """Returns true if the mongos has TLS enabled but the config-server does not.""" config_server_relation = self.charm.model.get_relation(self.relation_name) if not config_server_relation: diff --git a/src/charm.py b/src/charm.py index 0f663831..44424e2a 100755 --- a/src/charm.py +++ b/src/charm.py @@ -33,7 +33,13 @@ from config import Config import ops -from ops.model import BlockedStatus, MaintenanceStatus, WaitingStatus, Relation, ActiveStatus +from ops.model import ( + BlockedStatus, + MaintenanceStatus, + WaitingStatus, + Relation, + ActiveStatus, +) from ops.charm import InstallEvent, StartEvent, RelationDepartedEvent import logging @@ -200,7 +206,9 @@ def remove_secret(self, scope, key) -> None: content = secret.get_content() if not content.get(key) or content[key] == Config.Secrets.SECRET_DELETED_LABEL: - logger.error(f"Non-existing secret {scope}:{key} was attempted to be removed.") + logger.error( + f"Non-existing secret {scope}:{key} was attempted to be removed." + ) return content[key] = Config.Secrets.SECRET_DELETED_LABEL @@ -301,7 +309,9 @@ def set_user_roles(self, roles: List[str]) -> None: return # a mongos shard can only be related to one config server - config_server_rel = self.model.relations[Config.Relations.CLUSTER_RELATIONS_NAME][0] + config_server_rel = self.model.relations[ + Config.Relations.CLUSTER_RELATIONS_NAME + ][0] self.cluster.database_requires.update_relation_data( config_server_rel.id, {USER_ROLES_TAG: roles_str} ) @@ -314,14 +324,18 @@ def set_database(self, database: str) -> None: return # a mongos shard can only be related to one config server - config_server_rel = self.model.relations[Config.Relations.CLUSTER_RELATIONS_NAME][0] + config_server_rel = self.model.relations[ + Config.Relations.CLUSTER_RELATIONS_NAME + ][0] self.cluster.database_requires.update_relation_data( config_server_rel.id, {DATABASE_TAG: database} ) def set_external_connectivity(self, external_connectivity: bool) -> None: """Sets the connectivity type for mongos.""" - self.app_peer_data[EXTERNAL_CONNECTIVITY_TAG] = json.dumps(external_connectivity) + self.app_peer_data[EXTERNAL_CONNECTIVITY_TAG] = json.dumps( + external_connectivity + ) def check_relation_broken_or_scale_down(self, event: RelationDepartedEvent) -> None: """Checks relation departed event is the result of removed relation or scale down. diff --git a/tests/integration/tls_tests/test_tls.py b/tests/integration/tls_tests/test_tls.py index a7618abf..0510cb1a 100644 --- a/tests/integration/tls_tests/test_tls.py +++ b/tests/integration/tls_tests/test_tls.py @@ -25,35 +25,43 @@ TIMEOUT = 15 * 60 -# @pytest.mark.skip("Wait new MongoDB charm is published.") -# @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.""" -# await deploy_cluster(ops_test) -# await build_cluster(ops_test) -# await deploy_tls(ops_test) +@pytest.mark.skip("Wait new MongoDB charm is published.") +@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.""" + await deploy_cluster(ops_test) + await build_cluster(ops_test) + await deploy_tls(ops_test) -# @pytest.mark.skip("Wait new MongoDB charm is published.") +@pytest.mark.skip("Wait new MongoDB charm is published.") @pytest.mark.group(1) @pytest.mark.abort_on_fail async def test_mongos_tls_enabled(ops_test: OpsTest) -> None: """Tests that mongos charm can enable TLS.""" - await integrate_mongos_with_tls(ops_test) + # await integrate_mongos_with_tls(ops_test) + + await ops_test.model.wait_for_idle( + apps=[MONGOS_APP_NAME], + idle_period=20, + timeout=TIMEOUT, + raise_on_blocked=False, + status="blocked", + ) mongos_unit = ops_test.model.applications[MONGOS_APP_NAME].units[0] assert ( mongos_unit.workload_status_message == "mongos has TLS enabled, but config-server does not." - ), "Shard fails to report TLS inconsistencies." + ), "mongos fails to report TLS inconsistencies." await integrate_cluster_with_tls(ops_test) await check_mongos_tls_enabled(ops_test) -# @pytest.mark.skip("Wait new MongoDB charm is published.") +@pytest.mark.skip("Wait new MongoDB charm is published.") @pytest.mark.group(1) @pytest.mark.abort_on_fail async def test_mongos_tls_disabled(ops_test: OpsTest) -> None: @@ -64,10 +72,10 @@ async def test_mongos_tls_disabled(ops_test: OpsTest) -> None: mongos_unit = ops_test.model.applications[MONGOS_APP_NAME].units[0] assert ( mongos_unit.workload_status_message == "mongos requires TLS to be enabled." - ), "Shard fails to report TLS inconsistencies." + ), "mongos fails to report TLS inconsistencies." -# @pytest.mark.skip("Wait new MongoDB charm is published.") +@pytest.mark.skip("Wait new MongoDB charm is published.") @pytest.mark.group(1) @pytest.mark.abort_on_fail async def test_tls_reenabled(ops_test: OpsTest) -> None: @@ -76,12 +84,11 @@ async def test_tls_reenabled(ops_test: OpsTest) -> None: await check_mongos_tls_enabled(ops_test) -# @pytest.mark.skip("Wait new MongoDB charm is published.") +@pytest.mark.skip("Wait new MongoDB charm is published.") @pytest.mark.group(1) @pytest.mark.abort_on_fail async def test_mongos_tls_ca_mismatch(ops_test: OpsTest) -> None: """Tests that mongos charm can disable TLS.""" - await toggle_tls_mongos(ops_test, enable=False) await ops_test.model.deploy( CERTS_APP_NAME, application_name=DIFFERENT_CERTS_APP_NAME, channel="stable" @@ -90,16 +97,26 @@ async def test_mongos_tls_ca_mismatch(ops_test: OpsTest) -> None: apps=[DIFFERENT_CERTS_APP_NAME], idle_period=10, raise_on_blocked=False, + status="active", timeout=TIMEOUT, ) - await toggle_tls_mongos(ops_test, enable=False, certs_app_name=DIFFERENT_CERTS_APP_NAME) + await toggle_tls_mongos( + ops_test, enable=True, certs_app_name=DIFFERENT_CERTS_APP_NAME + ) + + await ops_test.model.wait_for_idle( + apps=[MONGOS_APP_NAME], + idle_period=20, + raise_on_blocked=False, + timeout=TIMEOUT, + ) mongos_unit = ops_test.model.applications[MONGOS_APP_NAME].units[0] assert ( mongos_unit.workload_status_message - == "mongos has TLS enabled, but config-server does not." - ), "mongos CA and Config-Server CA don't match." + == "mongos CA and Config-Server CA don't match." + ), "mongos fails to report mismatch in CA." async def deploy_cluster(ops_test: OpsTest) -> None: @@ -201,14 +218,6 @@ async def integrate_mongos_with_tls(ops_test: OpsTest) -> None: f"{CERTS_APP_NAME}:{CERT_REL_NAME}", ) - await ops_test.model.wait_for_idle( - apps=[MONGOS_APP_NAME], - idle_period=20, - timeout=TIMEOUT, - raise_on_blocked=False, - status="active", - ) - async def integrate_cluster_with_tls(ops_test: OpsTest) -> None: """Integrate cluster components to the TLS interface.""" From 5311bab837c6642850bcddce9cab36986fbc6432 Mon Sep 17 00:00:00 2001 From: MiaAltieri Date: Tue, 26 Mar 2024 10:59:20 +0000 Subject: [PATCH 3/4] add icon --- icon.svg | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 icon.svg diff --git a/icon.svg b/icon.svg new file mode 100644 index 00000000..cf069ab2 --- /dev/null +++ b/icon.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + From 3c75d3de29a8ae17b4a61608a5f346a401f39dc0 Mon Sep 17 00:00:00 2001 From: MiaAltieri Date: Tue, 26 Mar 2024 11:27:27 +0000 Subject: [PATCH 4/4] fix unit tests --- tests/unit/test_charm.py | 1 + tests/unit/test_config_server_lib.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 04061e4b..5003acb9 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -138,6 +138,7 @@ def test_status_shows_mongos_waiting(self): """Tests when mongos accurately reports waiting status.""" cluster_mock = mock.Mock() cluster_mock.is_mongos_running.return_value = False + cluster_mock.get_tls_statuses.return_value = None self.harness.charm.cluster = cluster_mock # A running config server is a requirement to start for mongos diff --git a/tests/unit/test_config_server_lib.py b/tests/unit/test_config_server_lib.py index c568e799..495be12a 100644 --- a/tests/unit/test_config_server_lib.py +++ b/tests/unit/test_config_server_lib.py @@ -115,14 +115,14 @@ def test_non_leader_doesnt_set_keyfile_secret( @patch("charm.MongosOperatorCharm.set_secret") @patch("charm.ClusterRequirer.is_mongos_running") @patch("charm.MongosOperatorCharm.restart_charm_services") - @patch("charms.mongodb.v0.config_server_interface.add_args_to_env") + @patch("charm.MongosOperatorCharm.update_mongos_args") @patch("builtins.open", new_callable=mock_open, read_data=MONGOS_VAR) @patch("charm.Path") def test_same_config_db( self, path, open, - add_args_to_env, + update_mongos_args, restart_charm_services, is_mongos_running, set_secret, @@ -136,7 +136,7 @@ def test_same_config_db( self.harness.add_relation_unit(relation_id, "config-server/0") self.harness.update_relation_data(relation_id, "config-server", REL_DATA) - add_args_to_env.assert_not_called() + update_mongos_args.assert_not_called() @patch("charm.MongosOperatorCharm.push_file_to_unit") @patch("charm.MongosOperatorCharm.get_keyfile_contents")