Make tcpsocket readiness and liveness configurable
[osm/devops.git] / installers / charm / kafka-exporter / src / charm.py
index 1316a4d..07a854f 100755 (executable)
@@ -28,10 +28,10 @@ from pathlib import Path
 from typing import NoReturn, Optional
 from urllib.parse import urlparse
 
+from charms.kafka_k8s.v0.kafka import KafkaEvents, KafkaRequires
 from ops.main import main
 from opslib.osm.charm import CharmedOsmBase, RelationsMissing
 from opslib.osm.interfaces.grafana import GrafanaDashboardTarget
-from opslib.osm.interfaces.kafka import KafkaClient
 from opslib.osm.interfaces.prometheus import PrometheusScrapeTarget
 from opslib.osm.pod import (
     ContainerV3Builder,
@@ -54,6 +54,7 @@ class ConfigModel(ModelValidator):
     tls_secret_name: Optional[str]
     image_pull_policy: str
     security_context: bool
+    kafka_endpoint: Optional[str]
 
     @validator("site_url")
     def validate_site_url(cls, v):
@@ -81,15 +82,29 @@ class ConfigModel(ModelValidator):
             raise ValueError("value must be always, ifnotpresent or never")
         return values[v]
 
+    @validator("kafka_endpoint")
+    def validate_kafka_endpoint(cls, v):
+        if v and len(v.split(":")) != 2:
+            raise ValueError("value must be in the format <host>:<port>")
+        return v
+
+
+class KafkaEndpoint:
+    def __init__(self, host: str, port: str) -> None:
+        self.host = host
+        self.port = port
+
 
 class KafkaExporterCharm(CharmedOsmBase):
+    on = KafkaEvents()
+
     def __init__(self, *args) -> NoReturn:
         super().__init__(*args, oci_image="image")
 
         # Provision Kafka relation to exchange information
-        self.kafka_client = KafkaClient(self, "kafka")
-        self.framework.observe(self.on["kafka"].relation_changed, self.configure_pod)
-        self.framework.observe(self.on["kafka"].relation_broken, self.configure_pod)
+        self.kafka = KafkaRequires(self)
+        self.framework.observe(self.on.kafka_available, self.configure_pod)
+        self.framework.observe(self.on.kafka_broken, self.configure_pod)
 
         # Register relation to provide a Scraping Target
         self.scrape_target = PrometheusScrapeTarget(self, "prometheus-scrape")
@@ -141,25 +156,23 @@ class KafkaExporterCharm(CharmedOsmBase):
                 dashboard=Path("templates/kafka_exporter_dashboard.json").read_text(),
             )
 
-    def _check_missing_dependencies(self, config: ConfigModel):
-        """Check if there is any relation missing.
+    def _is_kafka_endpoint_set(self, config: ConfigModel) -> bool:
+        """Check if Kafka endpoint is set."""
+        return config.kafka_endpoint or self._is_kafka_relation_set()
 
-        Args:
-            config (ConfigModel): object with configuration information.
-
-        Raises:
-            RelationsMissing: if kafka is missing.
-        """
-        missing_relations = []
+    def _is_kafka_relation_set(self) -> bool:
+        """Check if the Kafka relation is set or not."""
+        return self.kafka.host and self.kafka.port
 
-        if (
-            self.kafka_client.is_missing_data_in_unit()
-            and self.kafka_client.is_missing_data_in_app()
-        ):
-            missing_relations.append("kafka")
-
-        if missing_relations:
-            raise RelationsMissing(missing_relations)
+    @property
+    def kafka_endpoint(self) -> KafkaEndpoint:
+        config = ConfigModel(**dict(self.config))
+        if config.kafka_endpoint:
+            host, port = config.kafka_endpoint.split(":")
+        else:
+            host = self.kafka.host
+            port = self.kafka.port
+        return KafkaEndpoint(host, port)
 
     def build_pod_spec(self, image_info):
         """Build the PodSpec to be used.
@@ -174,7 +187,8 @@ class KafkaExporterCharm(CharmedOsmBase):
         config = ConfigModel(**dict(self.config))
 
         # Check relations
-        self._check_missing_dependencies(config)
+        if not self._is_kafka_endpoint_set(config):
+            raise RelationsMissing(["kafka"])
 
         # Create Builder for the PodSpec
         pod_spec_builder = PodSpecV3Builder(
@@ -188,7 +202,7 @@ class KafkaExporterCharm(CharmedOsmBase):
             config.image_pull_policy,
             run_as_non_root=config.security_context,
         )
-        container_builder.add_port(name=self.app.name, port=PORT)
+        container_builder.add_port(name="exporter", port=PORT)
         container_builder.add_http_readiness_probe(
             path="/api/health",
             port=PORT,
@@ -208,7 +222,7 @@ class KafkaExporterCharm(CharmedOsmBase):
         container_builder.add_command(
             [
                 "kafka_exporter",
-                f"--kafka.server={self.kafka_client.host}:{self.kafka_client.port}",
+                f"--kafka.server={self.kafka_endpoint.host}:{self.kafka_endpoint.port}",
             ]
         )
         container = container_builder.build()