Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update charms.traefik_route_k8s.v0.traefik_route library #103

Merged
merged 14 commits into from
Nov 29, 2022
46 changes: 40 additions & 6 deletions lib/charms/traefik_route_k8s/v0/traefik_route.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def __init__(self, *args):

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

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -148,7 +148,7 @@ def __init__(
super().__init__(charm, relation_name)
self._stored.set_default(external_host=None)

self.charm = charm
self._charm = charm
self._relation_name = relation_name

if self._stored.external_host != external_host:
Expand All @@ -157,9 +157,31 @@ def __init__(
self._update_requirers_with_external_host()

self.framework.observe(
self.charm.on[relation_name].relation_changed, self._on_relation_changed
self._charm.on[relation_name].relation_changed, self._on_relation_changed
)

@property
def external_host(self) -> str:
"""Return the external host set by Traefik, if any."""
self._update_stored_external_host()
return self._stored.external_host or ""

def _update_stored_external_host(self) -> None:
"""Ensure that the stored host is up to date.

This is split out into a separate method since, in the case of multi-unit deployments,
removal of a `TraefikRouteRequirer` will not cause a `RelationEvent`, but the guard on
app data ensures that only the previous leader will know what it is. Separating it
allows for re-use both when the property is called and if the relation changes, so a
leader change where the new leader checks the property will do the right thing."""
if self._charm.unit.is_leader():
for relation in self._charm.model.relations[self._relation_name]:
if not relation.app:
self._stored.external_host = ""
return
external_host = relation.data[relation.app].get("external_host", "")
self._stored.external_host = external_host or self._stored.external_host

def _on_relation_changed(self, event: RelationEvent):
if self.is_ready(event.relation):
# todo check data is valid here?
Expand All @@ -168,11 +190,11 @@ def _on_relation_changed(self, event: RelationEvent):

def _update_requirers_with_external_host(self):
"""Ensure that requirers know the external host for Traefik."""
if not self.charm.unit.is_leader():
if not self._charm.unit.is_leader():
return

for relation in self.charm.model.relations[self._relation_name]:
relation.data[self.charm.app]["external_host"] = self._stored.external_host
for relation in self._charm.model.relations[self._relation_name]:
relation.data[self._charm.app]["external_host"] = self.external_host

@staticmethod
def is_ready(relation: Relation) -> bool:
Expand Down Expand Up @@ -213,6 +235,9 @@ def __init__(self, charm: CharmBase, relation: Relation, relation_name: str = "t
self.framework.observe(
self._charm.on[relation_name].relation_changed, self._on_relation_changed
)
self.framework.observe(
self._charm.on[relation_name].relation_broken, self._on_relation_broken
)

@property
def external_host(self) -> str:
Expand All @@ -231,6 +256,9 @@ def _update_stored_external_host(self) -> None:
if self._charm.unit.is_leader():
if self._relation:
for relation in self._charm.model.relations[self._relation.name]:
if not relation.app:
self._stored.external_host = ""
return
external_host = relation.data[relation.app].get("external_host", "")
self._stored.external_host = external_host or self._stored.external_host

Expand All @@ -240,6 +268,12 @@ def _on_relation_changed(self, event: RelationEvent) -> None:
if self._charm.unit.is_leader():
self.on.ready.emit(event.relation)

def _on_relation_broken(self, event: RelationEvent) -> None:
"""On RelationBroken, clear the stored data if set and emit an event."""
self._stored.external_host = ""
if self._charm.unit.is_leader():
self.on.ready.emit(event.relation)

def is_ready(self) -> bool:
"""Is the TraefikRouteRequirer ready to submit data to Traefik?"""
return self._relation is not None
Expand Down