Skip to content

Commit

Permalink
Update libraries (#106)
Browse files Browse the repository at this point in the history
* Update libraries

* Fetch `prometheus_scrape`, too
  • Loading branch information
rbarry82 authored Oct 20, 2022
1 parent 0ab4a3a commit e2ef70b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 25 deletions.
38 changes: 26 additions & 12 deletions lib/charms/prometheus_k8s/v0/prometheus_scrape.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Copyright 2021 Canonical Ltd.
# See LICENSE file for licensing details.
"""## Overview.
"""Source code can be found on GitHub at canonical/observability-libs/lib/charms/observability_libs.
## Overview
This document explains how to integrate with the Prometheus charm
for the purpose of providing a metrics endpoint to Prometheus. It
Expand All @@ -11,6 +13,13 @@
shared between Prometheus charms and any other charm that intends to
provide a scrape target for Prometheus.
## Dependencies
Using this library requires you to fetch the juju_topology library from
[observability-libs](https://charmhub.io/observability-libs/libraries/juju_topology).
`charmcraft fetch-lib charms.observability_libs.v0.juju_topology`
## Provider Library Usage
This Prometheus charm interacts with its scrape targets using its
Expand Down Expand Up @@ -341,7 +350,7 @@ def _on_scrape_targets_changed(self, event):

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 23
LIBPATCH = 24

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -1516,10 +1525,11 @@ def __init__(
self.external_url = external_url

events = self._charm.on[self._relation_name]
self.framework.observe(events.relation_joined, self._set_scrape_job_spec)
self.framework.observe(events.relation_changed, self._on_relation_changed)

if not refresh_event:
# FIXME remove once podspec charms are verified.
# `self._set_scrape_job_spec()` is called every re-init so this should not be needed.
if len(self._charm.meta.containers) == 1:
if "kubernetes" in self._charm.meta.series:
# This is a podspec charm
Expand All @@ -1544,10 +1554,16 @@ def __init__(
for ev in refresh_event:
self.framework.observe(ev, self._set_scrape_job_spec)

self.framework.observe(self._charm.on.upgrade_charm, self._set_scrape_job_spec)

# If there is no leader during relation_joined we will still need to set alert rules.
self.framework.observe(self._charm.on.leader_elected, self._set_scrape_job_spec)
# Update relation data every reinit. If instead we used event hooks then observing only
# relation-joined would not be sufficient:
# - Would need to observe leader-elected, in case there was no leader during
# relation-joined.
# - If later related to an ingress provider, then would need to register and wait for
# update-status interval to elapse before changes would apply.
# - The ingerss-ready custom event is currently emitted prematurely and cannot be relied
# upon: https://github.com/canonical/traefik-k8s-operator/issues/78
# NOTE We may still end up waiting for update-status before changes are applied.
self._set_scrape_job_spec()

def _on_relation_changed(self, event):
"""Check for alert rule messages in the relation data before moving on."""
Expand All @@ -1563,9 +1579,7 @@ def _on_relation_changed(self, event):
else:
self.on.alert_rule_status_changed.emit(valid=valid, errors=errors)

self._set_scrape_job_spec(event)

def _set_scrape_job_spec(self, event):
def _set_scrape_job_spec(self, _=None):
"""Ensure scrape target information is made available to prometheus.
When a metrics provider charm is related to a prometheus charm, the
Expand All @@ -1574,7 +1588,7 @@ def _set_scrape_job_spec(self, event):
data. In addition, each of the consumer units also sets its own
host address in Juju unit relation data.
"""
self._set_unit_ip(event)
self._set_unit_ip()

if not self._charm.unit.is_leader():
return
Expand All @@ -1594,7 +1608,7 @@ def _set_scrape_job_spec(self, event):
# that is written to the filesystem.
relation.data[self._charm.app]["alert_rules"] = json.dumps(alert_rules_as_dict)

def _set_unit_ip(self, _):
def _set_unit_ip(self, _=None):
"""Set unit host address.
Each time a metrics provider charm container is restarted it updates its own
Expand Down
38 changes: 25 additions & 13 deletions lib/charms/traefik_k8s/v1/ingress.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def _on_ingress_revoked(self, event: IngressPerAppRevokedEvent):
import logging
import socket
import typing
from typing import Any, Dict, Optional, Tuple
from typing import Any, Dict, Optional, Tuple, Union

import yaml
from ops.charm import CharmBase, RelationBrokenEvent, RelationEvent
Expand All @@ -69,7 +69,7 @@ def _on_ingress_revoked(self, event: IngressPerAppRevokedEvent):

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 3
LIBPATCH = 4

DEFAULT_RELATION_NAME = "ingress"
RELATION_INTERFACE = "ingress"
Expand Down Expand Up @@ -97,6 +97,7 @@ def _on_ingress_revoked(self, event: IngressPerAppRevokedEvent):
"name": {"type": "string"},
"host": {"type": "string"},
"port": {"type": "string"},
"strip-prefix": {"type": "string"},
},
"required": ["model", "name", "host", "port"],
}
Expand All @@ -115,7 +116,11 @@ def _on_ingress_revoked(self, event: IngressPerAppRevokedEvent):
from typing_extensions import TypedDict # py35 compat

# Model of the data a unit implementing the requirer will need to provide.
RequirerData = TypedDict("RequirerData", {"model": str, "name": str, "host": str, "port": int})
RequirerData = TypedDict(
"RequirerData",
{"model": str, "name": str, "host": str, "port": int, "strip-prefix": bool},
total=False,
)
# Provider ingress data model.
ProviderIngressData = TypedDict("ProviderIngressData", {"url": str})
# Provider application databag model.
Expand Down Expand Up @@ -221,12 +226,14 @@ def restore(self, snapshot: dict) -> None:
class IngressPerAppDataProvidedEvent(_IPAEvent):
"""Event representing that ingress data has been provided for an app."""

__args__ = ("name", "model", "port", "host")
__args__ = ("name", "model", "port", "host", "strip_prefix")

if typing.TYPE_CHECKING:
name = None # type: str
model = None # type: str
port = None # type: int
host = None # type: str
strip_prefix = False # type: bool


class IngressPerAppDataRemovedEvent(RelationEvent):
Expand Down Expand Up @@ -266,6 +273,7 @@ def _handle_relation(self, event):
data["model"],
data["port"],
data["host"],
data.get("strip-prefix", False),
)

def _handle_relation_broken(self, event):
Expand Down Expand Up @@ -297,17 +305,14 @@ def _get_requirer_data(self, relation: Relation) -> RequirerData:
return {}

databag = relation.data[relation.app]
try:
remote_data = {k: databag[k] for k in ("model", "name", "host", "port")}
except KeyError as e:
# incomplete data / invalid data
log.debug("error {}; ignoring...".format(e))
return {}
except TypeError as e:
raise DataValidationError("Error casting remote data: {}".format(e))
remote_data = {} # type: Dict[str, Union[int, str]]
for k in ("port", "host", "model", "name", "mode", "strip-prefix"):
v = databag.get(k)
if v is not None:
remote_data[k] = v
_validate_data(remote_data, INGRESS_REQUIRES_APP_SCHEMA)

remote_data["port"] = int(remote_data["port"])
remote_data["strip-prefix"] = bool(remote_data.get("strip-prefix", False))
return remote_data

def get_data(self, relation: Relation) -> RequirerData:
Expand Down Expand Up @@ -408,6 +413,7 @@ def __init__(
*,
host: str = None,
port: int = None,
strip_prefix: bool = False,
):
"""Constructor for IngressRequirer.
Expand All @@ -422,13 +428,15 @@ def __init__(
relation must be of interface type `ingress` and have "limit: 1")
host: Hostname to be used by the ingress provider to address the requiring
application; if unspecified, the default Kubernetes service name will be used.
strip_prefix: configure Traefik to strip the path prefix.
Request Args:
port: the port of the service
"""
super().__init__(charm, relation_name)
self.charm: CharmBase = charm
self.relation_name = relation_name
self._strip_prefix = strip_prefix

self._stored.set_default(current_url=None)

Expand Down Expand Up @@ -501,6 +509,10 @@ def provide_ingress_requirements(self, *, host: str = None, port: int):
"host": host,
"port": str(port),
}

if self._strip_prefix:
data["strip_prefix"] = "true"

_validate_data(data, INGRESS_REQUIRES_APP_SCHEMA)
self.relation.data[self.app].update(data)

Expand Down

0 comments on commit e2ef70b

Please sign in to comment.