Skip to content

Commit 78c7bb3

Browse files
authored
[MISC] Update libs and remove warning (#1014)
* Update libs * Workflow tweaks * Remove from_environ warning
1 parent bd38bc3 commit 78c7bb3

File tree

13 files changed

+175
-60
lines changed

13 files changed

+175
-60
lines changed

.github/workflows/cla-check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CLA check
22

33
on:
44
pull_request:
5-
branches: [main]
5+
branches: [main, 16/edge]
66

77
jobs:
88
cla-check:

.github/workflows/lib-check.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,6 @@ jobs:
3232
with:
3333
credentials: "${{ secrets.CHARMHUB_TOKEN }}"
3434
github-token: "${{ secrets.GITHUB_TOKEN }}"
35-
35+
permissions:
36+
# Add label to prs
37+
pull-requests: write

lib/charms/data_platform_libs/v0/data_interfaces.py

Lines changed: 92 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent):
331331

332332
# Increment this PATCH version before using `charmcraft publish-lib` or reset
333333
# to 0 if you are raising the major API version
334-
LIBPATCH = 45
334+
LIBPATCH = 47
335335

336336
PYDEPS = ["ops>=2.0.0"]
337337

@@ -989,11 +989,7 @@ def __init__(
989989
@property
990990
def relations(self) -> List[Relation]:
991991
"""The list of Relation instances associated with this relation_name."""
992-
return [
993-
relation
994-
for relation in self._model.relations[self.relation_name]
995-
if self._is_relation_active(relation)
996-
]
992+
return self._model.relations[self.relation_name]
997993

998994
@property
999995
def secrets_enabled(self):
@@ -1271,15 +1267,6 @@ def _legacy_apply_on_delete(self, fields: List[str]) -> None:
12711267

12721268
# Internal helper methods
12731269

1274-
@staticmethod
1275-
def _is_relation_active(relation: Relation):
1276-
"""Whether the relation is active based on contained data."""
1277-
try:
1278-
_ = repr(relation.data)
1279-
return True
1280-
except (RuntimeError, ModelError):
1281-
return False
1282-
12831270
@staticmethod
12841271
def _is_secret_field(field: str) -> bool:
12851272
"""Is the field in question a secret reference (URI) field or not?"""
@@ -2582,7 +2569,7 @@ def __init__(
25822569

25832570

25842571
################################################################################
2585-
# Cross-charm Relatoins Data Handling and Evenets
2572+
# Cross-charm Relations Data Handling and Events
25862573
################################################################################
25872574

25882575
# Generic events
@@ -3281,7 +3268,7 @@ def __init__(
32813268
# Kafka Events
32823269

32833270

3284-
class KafkaProvidesEvent(RelationEvent):
3271+
class KafkaProvidesEvent(RelationEventWithSecret):
32853272
"""Base class for Kafka events."""
32863273

32873274
@property
@@ -3300,6 +3287,40 @@ def consumer_group_prefix(self) -> Optional[str]:
33003287

33013288
return self.relation.data[self.relation.app].get("consumer-group-prefix")
33023289

3290+
@property
3291+
def mtls_cert(self) -> Optional[str]:
3292+
"""Returns TLS cert of the client."""
3293+
if not self.relation.app:
3294+
return None
3295+
3296+
if not self.secrets_enabled:
3297+
raise SecretsUnavailableError("Secrets unavailable on current Juju version")
3298+
3299+
secret_field = f"{PROV_SECRET_PREFIX}{SECRET_GROUPS.MTLS}"
3300+
if secret_uri := self.relation.data[self.app].get(secret_field):
3301+
secret = self.framework.model.get_secret(id=secret_uri)
3302+
content = secret.get_content(refresh=True)
3303+
if content:
3304+
return content.get("mtls-cert")
3305+
3306+
3307+
class KafkaClientMtlsCertUpdatedEvent(KafkaProvidesEvent):
3308+
"""Event emitted when the mtls relation is updated."""
3309+
3310+
def __init__(self, handle, relation, old_mtls_cert: Optional[str] = None, app=None, unit=None):
3311+
super().__init__(handle, relation, app, unit)
3312+
3313+
self.old_mtls_cert = old_mtls_cert
3314+
3315+
def snapshot(self):
3316+
"""Return a snapshot of the event."""
3317+
return super().snapshot() | {"old_mtls_cert": self.old_mtls_cert}
3318+
3319+
def restore(self, snapshot):
3320+
"""Restore the event from a snapshot."""
3321+
super().restore(snapshot)
3322+
self.old_mtls_cert = snapshot["old_mtls_cert"]
3323+
33033324

33043325
class TopicRequestedEvent(KafkaProvidesEvent, ExtraRoleEvent):
33053326
"""Event emitted when a new topic is requested for use on this relation."""
@@ -3312,6 +3333,7 @@ class KafkaProvidesEvents(CharmEvents):
33123333
"""
33133334

33143335
topic_requested = EventSource(TopicRequestedEvent)
3336+
mtls_cert_updated = EventSource(KafkaClientMtlsCertUpdatedEvent)
33153337

33163338

33173339
class KafkaRequiresEvent(RelationEvent):
@@ -3429,6 +3451,13 @@ def __init__(self, charm: CharmBase, relation_data: KafkaProviderData) -> None:
34293451
def _on_relation_changed_event(self, event: RelationChangedEvent) -> None:
34303452
"""Event emitted when the relation has changed."""
34313453
super()._on_relation_changed_event(event)
3454+
3455+
new_data_keys = list(event.relation.data[event.app].keys())
3456+
if any(newval for newval in new_data_keys if self.relation_data._is_secret_field(newval)):
3457+
self.relation_data._register_secrets_to_relation(event.relation, new_data_keys)
3458+
3459+
getattr(self.on, "mtls_cert_updated").emit(event.relation, app=event.app, unit=event.unit)
3460+
34323461
# Leader only
34333462
if not self.relation_data.local_unit.is_leader():
34343463
return
@@ -3443,6 +3472,33 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None:
34433472
event.relation, app=event.app, unit=event.unit
34443473
)
34453474

3475+
def _on_secret_changed_event(self, event: SecretChangedEvent):
3476+
"""Event notifying about a new value of a secret."""
3477+
if not event.secret.label:
3478+
return
3479+
3480+
relation = self.relation_data._relation_from_secret_label(event.secret.label)
3481+
if not relation:
3482+
logging.info(
3483+
f"Received secret {event.secret.label} but couldn't parse, seems irrelevant"
3484+
)
3485+
return
3486+
3487+
if relation.app == self.charm.app:
3488+
logging.info("Secret changed event ignored for Secret Owner")
3489+
3490+
remote_unit = None
3491+
for unit in relation.units:
3492+
if unit.app != self.charm.app:
3493+
remote_unit = unit
3494+
3495+
old_mtls_cert = event.secret.get_content().get("mtls-cert")
3496+
# mtls-cert is the only secret that can be updated
3497+
logger.info("mtls-cert updated")
3498+
getattr(self.on, "mtls_cert_updated").emit(
3499+
relation, app=relation.app, unit=remote_unit, old_mtls_cert=old_mtls_cert
3500+
)
3501+
34463502

34473503
class KafkaProvides(KafkaProviderData, KafkaProviderEventHandlers):
34483504
"""Provider-side of the Kafka relation."""
@@ -3463,11 +3519,13 @@ def __init__(
34633519
extra_user_roles: Optional[str] = None,
34643520
consumer_group_prefix: Optional[str] = None,
34653521
additional_secret_fields: Optional[List[str]] = [],
3522+
mtls_cert: Optional[str] = None,
34663523
):
34673524
"""Manager of Kafka client relations."""
34683525
super().__init__(model, relation_name, extra_user_roles, additional_secret_fields)
34693526
self.topic = topic
34703527
self.consumer_group_prefix = consumer_group_prefix or ""
3528+
self.mtls_cert = mtls_cert
34713529

34723530
@property
34733531
def topic(self):
@@ -3481,6 +3539,15 @@ def topic(self, value):
34813539
raise ValueError(f"Error on topic '{value}', cannot be a wildcard.")
34823540
self._topic = value
34833541

3542+
def set_mtls_cert(self, relation_id: int, mtls_cert: str) -> None:
3543+
"""Set the mtls cert in the application relation databag / secret.
3544+
3545+
Args:
3546+
relation_id: the identifier for a particular relation.
3547+
mtls_cert: mtls cert.
3548+
"""
3549+
self.update_relation_data(relation_id, {"mtls-cert": mtls_cert})
3550+
34843551

34853552
class KafkaRequirerEventHandlers(RequirerEventHandlers):
34863553
"""Requires-side of the Kafka relation."""
@@ -3502,6 +3569,9 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None:
35023569
# Sets topic, extra user roles, and "consumer-group-prefix" in the relation
35033570
relation_data = {"topic": self.relation_data.topic}
35043571

3572+
if self.relation_data.mtls_cert:
3573+
relation_data["mtls-cert"] = self.relation_data.mtls_cert
3574+
35053575
if self.relation_data.extra_user_roles:
35063576
relation_data["extra-user-roles"] = self.relation_data.extra_user_roles
35073577

@@ -3560,15 +3630,17 @@ def __init__(
35603630
extra_user_roles: Optional[str] = None,
35613631
consumer_group_prefix: Optional[str] = None,
35623632
additional_secret_fields: Optional[List[str]] = [],
3633+
mtls_cert: Optional[str] = None,
35633634
) -> None:
35643635
KafkaRequirerData.__init__(
35653636
self,
35663637
charm.model,
35673638
relation_name,
35683639
topic,
3569-
extra_user_roles,
3570-
consumer_group_prefix,
3571-
additional_secret_fields,
3640+
extra_user_roles=extra_user_roles,
3641+
consumer_group_prefix=consumer_group_prefix,
3642+
additional_secret_fields=additional_secret_fields,
3643+
mtls_cert=mtls_cert,
35723644
)
35733645
KafkaRequirerEventHandlers.__init__(self, charm, self)
35743646

lib/charms/data_platform_libs/v0/upgrade.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ def restart(self, event) -> None:
285285

286286
# Increment this PATCH version before using `charmcraft publish-lib` or reset
287287
# to 0 if you are raising the major API version
288-
LIBPATCH = 18
288+
LIBPATCH = 19
289289

290290
PYDEPS = ["pydantic>=1.10,<2", "poetry-core"]
291291

@@ -929,7 +929,7 @@ def _on_upgrade_charm(self, event: UpgradeCharmEvent) -> None:
929929
# for k8s run version checks only on highest ordinal unit
930930
if (
931931
self.charm.unit.name
932-
== f"{self.charm.app.name}/{self.charm.app.planned_units() -1}"
932+
== f"{self.charm.app.name}/{self.charm.app.planned_units() - 1}"
933933
):
934934
try:
935935
self._upgrade_supported_check()

lib/charms/grafana_k8s/v0/grafana_dashboard.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ def __init__(self, *args):
219219
# Increment this PATCH version before using `charmcraft publish-lib` or reset
220220
# to 0 if you are raising the major API version
221221

222-
LIBPATCH = 43
222+
LIBPATCH = 44
223223

224224
PYDEPS = ["cosl >= 0.0.50"]
225225

@@ -1676,14 +1676,22 @@ def _set_default_data(self) -> None:
16761676

16771677
def set_peer_data(self, key: str, data: Any) -> None:
16781678
"""Put information into the peer data bucket instead of `StoredState`."""
1679-
self._charm.peers.data[self._charm.app][key] = json.dumps(data) # type: ignore[attr-defined]
1679+
peers = self._charm.peers # type: ignore[attr-defined]
1680+
if not peers or not peers.data:
1681+
logger.info("set_peer_data: no peer relation. Is the charm being installed/removed?")
1682+
return
1683+
peers.data[self._charm.app][key] = json.dumps(data) # type: ignore[attr-defined]
16801684

16811685
def get_peer_data(self, key: str) -> Any:
16821686
"""Retrieve information from the peer data bucket instead of `StoredState`."""
1683-
if rel := self._charm.peers: # type: ignore[attr-defined]
1684-
data = rel.data[self._charm.app].get(key, "")
1685-
return json.loads(data) if data else {}
1686-
return {}
1687+
peers = self._charm.peers # type: ignore[attr-defined]
1688+
if not peers or not peers.data:
1689+
logger.warning(
1690+
"get_peer_data: no peer relation. Is the charm being installed/removed?"
1691+
)
1692+
return {}
1693+
data = peers.data[self._charm.app].get(key, "")
1694+
return json.loads(data) if data else {}
16871695

16881696

16891697
class GrafanaDashboardAggregator(Object):

lib/charms/loki_k8s/v1/loki_push_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ def __init__(self, ...):
546546

547547
# Increment this PATCH version before using `charmcraft publish-lib` or reset
548548
# to 0 if you are raising the major API version
549-
LIBPATCH = 16
549+
LIBPATCH = 17
550550

551551
PYDEPS = ["cosl"]
552552

@@ -1354,7 +1354,7 @@ def _url(self) -> str:
13541354
13551355
Return url to loki, including port number, but without the endpoint subpath.
13561356
"""
1357-
return "http://{}:{}".format(socket.getfqdn(), self.port)
1357+
return f"{self.scheme}://{socket.getfqdn()}:{self.port}"
13581358

13591359
def _endpoint(self, url) -> dict:
13601360
"""Get Loki push API endpoint for a given url.

lib/charms/prometheus_k8s/v0/prometheus_scrape.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ def _on_scrape_targets_changed(self, event):
362362

363363
# Increment this PATCH version before using `charmcraft publish-lib` or reset
364364
# to 0 if you are raising the major API version
365-
LIBPATCH = 52
365+
LIBPATCH = 53
366366

367367
# Version 0.0.53 needed for cosl.rules.generic_alert_groups
368368
PYDEPS = ["cosl>=0.0.53"]
@@ -1265,6 +1265,15 @@ def _dedupe_job_names(jobs: List[dict]):
12651265
return deduped_jobs
12661266

12671267

1268+
def _dedupe_list(items: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
1269+
"""Deduplicate items in the list via object identity."""
1270+
unique_items = []
1271+
for item in items:
1272+
if item not in unique_items:
1273+
unique_items.append(item)
1274+
return unique_items
1275+
1276+
12681277
def _resolve_dir_against_charm_path(charm: CharmBase, *path_elements: str) -> str:
12691278
"""Resolve the provided path items against the directory of the main file.
12701279
@@ -1538,7 +1547,7 @@ def set_scrape_job_spec(self, _=None):
15381547
if self._forward_alert_rules:
15391548
alert_rules.add_path(self._alert_rules_path, recursive=True)
15401549
alert_rules.add(
1541-
generic_alert_groups.application_rules, group_name_prefix=self.topology.identifier
1550+
copy.deepcopy(generic_alert_groups.application_rules), group_name_prefix=self.topology.identifier
15421551
)
15431552
alert_rules_as_dict = alert_rules.as_dict()
15441553

@@ -1889,6 +1898,9 @@ def _set_prometheus_data(self, event: Optional[RelationJoinedEvent] = None):
18891898
)
18901899
groups.extend(alert_rules.as_dict()["groups"])
18911900

1901+
groups = _dedupe_list(groups)
1902+
jobs = _dedupe_list(jobs)
1903+
18921904
# Set scrape jobs and alert rules in relation data
18931905
relations = [event.relation] if event else self.model.relations[self._prometheus_relation]
18941906
for rel in relations:
@@ -2141,10 +2153,12 @@ def _on_alert_rules_changed(self, event):
21412153
self.set_alert_rule_data(app_name, unit_rules)
21422154

21432155
def set_alert_rule_data(self, name: str, unit_rules: dict, label_rules: bool = True) -> None:
2144-
"""Update alert rule data.
2156+
"""Consolidate incoming alert rules (from stored-state or event) with those from relation data.
21452157
2146-
The unit rules should be a dict, which is has additional Juju topology labels added. For
2158+
The unit rules should be a dict, which have additional Juju topology labels added. For
21472159
rules generated by the NRPE exporter, they are pre-labeled so lookups can be performed.
2160+
The unit rules are combined with the alert rules from relation data before being written
2161+
back to relation data and stored-state.
21482162
"""
21492163
if not self._charm.unit.is_leader():
21502164
return
@@ -2166,6 +2180,9 @@ def set_alert_rule_data(self, name: str, unit_rules: dict, label_rules: bool = T
21662180

21672181
if updated_group["name"] not in [g["name"] for g in groups]:
21682182
groups.append(updated_group)
2183+
2184+
groups = _dedupe_list(groups)
2185+
21692186
relation.data[self._charm.app]["alert_rules"] = json.dumps(
21702187
{"groups": groups if self._forward_alert_rules else []}
21712188
)
@@ -2216,6 +2233,8 @@ def remove_alert_rules(self, group_name: str, unit_name: str) -> None:
22162233
changed_group["rules"] = rules_kept # type: ignore
22172234
groups.append(changed_group)
22182235

2236+
groups = _dedupe_list(groups)
2237+
22192238
relation.data[self._charm.app]["alert_rules"] = json.dumps(
22202239
{"groups": groups if self._forward_alert_rules else []}
22212240
)

0 commit comments

Comments
 (0)