Skip to content

Commit

Permalink
chore: update charm libraries (#196)
Browse files Browse the repository at this point in the history
Co-authored-by: Github Actions <github-actions@github.com>
  • Loading branch information
observability-noctua-bot and Github Actions authored Sep 29, 2023
1 parent 36dc399 commit 20bc185
Showing 1 changed file with 67 additions and 39 deletions.
106 changes: 67 additions & 39 deletions lib/charms/traefik_k8s/v2/ingress.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,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 = 5
LIBPATCH = 6

PYDEPS = ["pydantic<2.0"]

Expand Down Expand Up @@ -109,9 +109,10 @@ def load(cls, databag: MutableMapping):

try:
data = {k: json.loads(v) for k, v in databag.items() if k not in BUILTIN_JUJU_KEYS}
except json.JSONDecodeError:
log.error(f"invalid databag contents: expecting json. {databag}")
raise
except json.JSONDecodeError as e:
msg = f"invalid databag contents: expecting json. {databag}"
log.error(msg)
raise DataValidationError(msg) from e

try:
return cls.parse_raw(json.dumps(data)) # type: ignore
Expand All @@ -120,8 +121,15 @@ def load(cls, databag: MutableMapping):
log.error(msg, exc_info=True)
raise DataValidationError(msg) from e

def dump(self, databag: Optional[MutableMapping] = None):
"""Write the contents of this model to Juju databag."""
def dump(self, databag: Optional[MutableMapping] = None, clear: bool = True):
"""Write the contents of this model to Juju databag.
:param databag: the databag to write the data to.
:param clear: ensure the databag is cleared before writing it.
"""
if clear and databag:
databag.clear()

if databag is None:
databag = {}

Expand Down Expand Up @@ -421,7 +429,7 @@ def get_data(self, relation: Relation) -> IngressRequirerData:
return IngressRequirerData(
self._get_requirer_app_data(relation), self._get_requirer_units_data(relation)
)
except (pydantic.ValidationError, DataValidationError, json.JSONDecodeError) as e:
except (pydantic.ValidationError, DataValidationError) as e:
raise DataValidationError("failed to validate ingress requirer data") from e

def is_ready(self, relation: Optional[Relation] = None):
Expand Down Expand Up @@ -577,7 +585,7 @@ def __init__(

def _handle_relation(self, event):
# created, joined or changed: if we have auto data: publish it
self._publish_auto_data(event.relation)
self._publish_auto_data()

if self.is_ready():
# Avoid spurious events, emit only when there is a NEW URL available
Expand All @@ -596,8 +604,7 @@ def _handle_relation_broken(self, event):

def _handle_upgrade_or_leader(self, event):
"""On upgrade/leadership change: ensure we publish the data we have."""
for relation in self.relations:
self._publish_auto_data(relation)
self._publish_auto_data()

def is_ready(self):
"""The Requirer is ready if the Provider has sent valid data."""
Expand All @@ -607,13 +614,17 @@ def is_ready(self):
log.debug("Requirer not ready; validation error encountered: %s" % str(e))
return False

def _publish_auto_data(self, relation: Relation):
def _publish_auto_data(self):
if self._auto_data:
host, port = self._auto_data
self.provide_ingress_requirements(host=host, port=port)

def provide_ingress_requirements(
self, *, scheme: Optional[str] = None, host: Optional[str] = None, port: int
self,
*,
scheme: Optional[str] = None,
host: Optional[str] = None,
port: int,
):
"""Publishes the data that Traefik needs to provide ingress.
Expand All @@ -623,47 +634,64 @@ def provide_ingress_requirements(
requirer unit; if unspecified, FQDN will be used instead
port: the port of the service (required)
"""
# This public method may be used at various points of the charm lifecycle, possible when
# the ingress relation is not yet there.
# Abort if there is no relation (instead of requiring the caller to guard against it).
if not self.relation:
return
for relation in self.relations:
self._provide_ingress_requirements(scheme, host, port, relation)

# get only the leader to publish the data since we only
# require one unit to publish it -- it will not differ between units,
# unlike in ingress-per-unit.
def _provide_ingress_requirements(
self,
scheme: Optional[str],
host: Optional[str],
port: int,
relation: Relation,
):
if self.unit.is_leader():
app_databag = self.relation.data[self.app]
self._publish_app_data(scheme, port, relation)

if not scheme:
# If scheme was not provided, use the one given to the constructor.
scheme = self._get_scheme()

try:
IngressRequirerAppData( # type: ignore # pyright does not like aliases
model=self.model.name,
name=self.app.name,
scheme=scheme,
port=port,
strip_prefix=self._strip_prefix, # type: ignore # pyright does not like aliases
redirect_https=self._redirect_https, # type: ignore # pyright does not like aliases
).dump(app_databag)
except pydantic.ValidationError as e:
msg = "failed to validate app data"
log.info(msg, exc_info=True) # log to INFO because this might be expected
raise DataValidationError(msg) from e
self._publish_unit_data(host, relation)

def _publish_unit_data(
self,
host: Optional[str],
relation: Relation,
):
if not host:
host = socket.getfqdn()

unit_databag = self.relation.data[self.unit]
unit_databag = relation.data[self.unit]
try:
IngressRequirerUnitData(host=host).dump(unit_databag)
except pydantic.ValidationError as e:
msg = "failed to validate unit data"
log.info(msg, exc_info=True) # log to INFO because this might be expected
raise DataValidationError(msg) from e

def _publish_app_data(
self,
scheme: Optional[str],
port: int,
relation: Relation,
):
# assumes leadership!
app_databag = relation.data[self.app]

if not scheme:
# If scheme was not provided, use the one given to the constructor.
scheme = self._get_scheme()

try:
IngressRequirerAppData( # type: ignore # pyright does not like aliases
model=self.model.name,
name=self.app.name,
scheme=scheme,
port=port,
strip_prefix=self._strip_prefix, # type: ignore # pyright does not like aliases
redirect_https=self._redirect_https, # type: ignore # pyright does not like aliases
).dump(app_databag)
except pydantic.ValidationError as e:
msg = "failed to validate app data"
log.info(msg, exc_info=True) # log to INFO because this might be expected
raise DataValidationError(msg) from e

@property
def relation(self):
"""The established Relation instance, or None."""
Expand Down

0 comments on commit 20bc185

Please sign in to comment.