From d4067587420f5e71f51b521b38927a935c28780c Mon Sep 17 00:00:00 2001 From: Andrew Scribner Date: Fri, 22 Mar 2024 12:03:53 -0400 Subject: [PATCH] Add warning if ingress is not established --- src/charm.py | 12 ++++++++++++ src/components/ingress.py | 39 +++++++++++++++++++++++++++++++++++++++ tests/unit/test_charm.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 src/components/ingress.py diff --git a/src/charm.py b/src/charm.py index 00893d6..b53aeb9 100755 --- a/src/charm.py +++ b/src/charm.py @@ -17,6 +17,7 @@ from ops.main import main from components.config_generation import GenerateEnvoyConfig, GenerateEnvoyConfigInputs +from components.ingress import IngressRelationWarnIfMissing, IngressRelationWarnIfMissingInputs from components.pebble import EnvoyPebbleService, EnvoyPebbleServiceInputs ENVOY_CONFIG_FILE_PATH = "/envoy/envoy.json" @@ -68,6 +69,17 @@ def __init__(self, *args): depends_on=[self.leadership_gate], ) + self.ingress_relation_warn_if_missing = self.charm_reconciler.add( + component=IngressRelationWarnIfMissing( + charm=self, + name="ingress-relation-warn-if-missing", + inputs_getter=lambda: IngressRelationWarnIfMissingInputs( + interface=self.ingress_relation.component.get_interface() + ), + ), + depends_on=[self.ingress_relation], + ) + self.envoy_config_generator = self.charm_reconciler.add( GenerateEnvoyConfig( charm=self, diff --git a/src/components/ingress.py b/src/components/ingress.py new file mode 100644 index 0000000..878e21f --- /dev/null +++ b/src/components/ingress.py @@ -0,0 +1,39 @@ +import dataclasses +import logging +from typing import Optional + +from charmed_kubeflow_chisme.components import Component +from ops import ActiveStatus, BlockedStatus, StatusBase + + +@dataclasses.dataclass +class IngressRelationWarnIfMissingInputs: + """Defines the required inputs for IngressRelationWarnIfMissing.""" + + interface: Optional[dict] + + +class IngressRelationWarnIfMissing(Component): + """Component that logs a warning if we have no Ingress relation established.""" + + def __init__(self, *args, **kwargs): + """Component that logs a warning if we have no Ingress relation established.""" + super().__init__(*args, **kwargs) + # Attach a logger. Use this instead of the global one to make mocking easier + self.logger = logging.getLogger(__name__) + + def get_status(self) -> StatusBase: + """Always Active unless it cannot get inputs.""" + try: + inputs = self._inputs_getter() + if not inputs.interface: + self.logger.warning( + "No ingress relation established. To be used by KFP in Charmed Kubeflow, this" + " charm requires an Ingress relation." + ) + return ActiveStatus("Active but no ingress relation established") + + return ActiveStatus() + except Exception as e: + self.logger.error(f"Error getting inputs for IngressRelationWarnIfMissing: {e}") + return BlockedStatus("Error getting inputs. See logs") diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 169b658..7196472 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -81,6 +81,41 @@ def test_with_ingress_relation(self, harness): assert harness.charm.ingress_relation.status == ActiveStatus() + def test_warning_if_ingress_missing(self, harness, mocker): + """Test that we emit a warning if we do not have an ingress established.""" + harness.set_leader(True) + setup_grpc_relation(harness, "grpc-one", "8080") + + harness.begin() + + # Mock the ingress warning logger so we can check if it was called + mock_logger = mocker.MagicMock() + harness.charm.ingress_relation_warn_if_missing.component.logger = mock_logger + + # Do something that will reconcile the charm + harness.charm.on.config_changed.emit() + + # Assert that we've logged the missing ingress relation + assert "No ingress relation established" in mock_logger.warning.call_args[0][0] + + def test_no_warning_if_ingress_is_established(self, harness, mocker): + """Test that we emit a warning if we do not have an ingress established.""" + harness.set_leader(True) + setup_grpc_relation(harness, "grpc-one", "8080") + setup_ingress_relation(harness) + + harness.begin() + + # Mock the ingress warning logger so we can check if it was called + mock_logger = mocker.MagicMock() + harness.charm.ingress_relation_warn_if_missing.component.logger = mock_logger + + # Do something that will reconcile the charm + harness.charm.on.config_changed.emit() + + # Assert that we haven't logged anything + assert mock_logger.warning.call_args is None + def test_envoy_config_generator(self, harness): """Test the envoy_config_generator Component is active when prerequisites are ready.""" harness.set_leader(True)