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,
ingress_class: Optional[str]
ingress_whitelist_source_range: Optional[str]
tls_secret_name: Optional[str]
- image_pull_policy: Optional[str]
+ image_pull_policy: str
+ security_context: bool
+ kafka_endpoint: Optional[str]
@validator("site_url")
def validate_site_url(cls, v):
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")
dashboard=Path("templates/kafka_exporter_dashboard.json").read_text(),
)
- def _check_missing_dependencies(self, config: ConfigModel):
- """Check if there is any relation missing.
-
- Args:
- config (ConfigModel): object with configuration information.
-
- Raises:
- RelationsMissing: if kafka is missing.
- """
- missing_relations = []
+ 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()
- if self.kafka_client.is_missing_data_in_unit():
- missing_relations.append("kafka")
+ 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 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.
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()
+ pod_spec_builder = PodSpecV3Builder(
+ enable_security_context=config.security_context
+ )
# Build container
container_builder = ContainerV3Builder(
- self.app.name, image_info, config.image_pull_policy
+ self.app.name,
+ image_info,
+ 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,
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()
ingress_resource = ingress_resource_builder.build()
pod_spec_builder.add_ingress_resource(ingress_resource)
- logger.debug(pod_spec_builder.build())
-
return pod_spec_builder.build()