Skip to content

Commit 95a4b9b

Browse files
[DPE-6652] Refresh all charm libs (#400)
1 parent fff0127 commit 95a4b9b

File tree

8 files changed

+631
-468
lines changed

8 files changed

+631
-468
lines changed

lib/charms/data_platform_libs/v0/data_interfaces.py

Lines changed: 2 additions & 3 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 = 40
334+
LIBPATCH = 41
335335

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

@@ -609,7 +609,7 @@ def get_group(self, group: str) -> Optional[SecretGroup]:
609609
class CachedSecret:
610610
"""Locally cache a secret.
611611
612-
The data structure is precisely re-using/simulating as in the actual Secret Storage
612+
The data structure is precisely reusing/simulating as in the actual Secret Storage
613613
"""
614614

615615
KNOWN_MODEL_ERRORS = [MODEL_ERRORS["no_label_and_uri"], MODEL_ERRORS["owner_no_refresh"]]
@@ -2363,7 +2363,6 @@ def _update_relation_data(self, relation: Relation, data: Dict[str, str]) -> Non
23632363
def _delete_relation_data(self, relation: Relation, fields: List[str]) -> None:
23642364
"""Delete data available (directily or indirectly -- i.e. secrets) from the relation for owner/this_app."""
23652365
if self.secret_fields and self.deleted_label:
2366-
23672366
_, normal_fields = self._process_secret_fields(
23682367
relation,
23692368
self.secret_fields,

lib/charms/grafana_k8s/v0/grafana_dashboard.py

Lines changed: 489 additions & 393 deletions
Large diffs are not rendered by default.

lib/charms/loki_k8s/v1/loki_push_api.py

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
This document explains how to use the two principal objects this library provides:
1010
1111
- `LokiPushApiProvider`: This object is meant to be used by any Charmed Operator that needs to
12-
implement the provider side of the `loki_push_api` relation interface. For instance, a Loki charm.
12+
implement the provider side of the `loki_push_api` relation interface: for instance, a Loki charm.
1313
The provider side of the relation represents the server side, to which logs are being pushed.
1414
1515
- `LokiPushApiConsumer`: This object is meant to be used by any Charmed Operator that needs to
@@ -533,7 +533,7 @@ def __init__(self, ...):
533533
RelationRole,
534534
WorkloadEvent,
535535
)
536-
from ops.framework import EventBase, EventSource, Object, ObjectEvents
536+
from ops.framework import BoundEvent, EventBase, EventSource, Object, ObjectEvents
537537
from ops.jujuversion import JujuVersion
538538
from ops.model import Container, ModelError, Relation
539539
from ops.pebble import APIError, ChangeError, Layer, PathError, ProtocolError
@@ -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 = 13
549+
LIBPATCH = 15
550550

551551
PYDEPS = ["cosl"]
552552

@@ -1543,10 +1543,13 @@ def __init__(
15431543
alert_rules_path: str = DEFAULT_ALERT_RULES_RELATIVE_PATH,
15441544
recursive: bool = False,
15451545
skip_alert_topology_labeling: bool = False,
1546+
*,
1547+
forward_alert_rules: bool = True,
15461548
):
15471549
super().__init__(charm, relation_name)
15481550
self._charm = charm
15491551
self._relation_name = relation_name
1552+
self._forward_alert_rules = forward_alert_rules
15501553
self.topology = JujuTopology.from_charm(charm)
15511554

15521555
try:
@@ -1569,7 +1572,8 @@ def _handle_alert_rules(self, relation):
15691572
alert_rules = (
15701573
AlertRules(None) if self._skip_alert_topology_labeling else AlertRules(self.topology)
15711574
)
1572-
alert_rules.add_path(self._alert_rules_path, recursive=self._recursive)
1575+
if self._forward_alert_rules:
1576+
alert_rules.add_path(self._alert_rules_path, recursive=self._recursive)
15731577
alert_rules_as_dict = alert_rules.as_dict()
15741578

15751579
relation.data[self._charm.app]["metadata"] = json.dumps(self.topology.as_dict())
@@ -1617,6 +1621,9 @@ def __init__(
16171621
alert_rules_path: str = DEFAULT_ALERT_RULES_RELATIVE_PATH,
16181622
recursive: bool = True,
16191623
skip_alert_topology_labeling: bool = False,
1624+
*,
1625+
refresh_event: Optional[Union[BoundEvent, List[BoundEvent]]] = None,
1626+
forward_alert_rules: bool = True,
16201627
):
16211628
"""Construct a Loki charm client.
16221629
@@ -1642,6 +1649,9 @@ def __init__(
16421649
alert_rules_path: a string indicating a path where alert rules can be found
16431650
recursive: Whether to scan for rule files recursively.
16441651
skip_alert_topology_labeling: whether to skip the alert topology labeling.
1652+
forward_alert_rules: a boolean flag to toggle forwarding of charmed alert rules.
1653+
refresh_event: an optional bound event or list of bound events which
1654+
will be observed to re-set scrape job data (IP address and others)
16451655
16461656
Raises:
16471657
RelationNotFoundError: If there is no relation in the charm's metadata.yaml
@@ -1667,14 +1677,26 @@ def __init__(
16671677
charm, relation_name, RELATION_INTERFACE_NAME, RelationRole.requires
16681678
)
16691679
super().__init__(
1670-
charm, relation_name, alert_rules_path, recursive, skip_alert_topology_labeling
1680+
charm,
1681+
relation_name,
1682+
alert_rules_path,
1683+
recursive,
1684+
skip_alert_topology_labeling,
1685+
forward_alert_rules=forward_alert_rules,
16711686
)
16721687
events = self._charm.on[relation_name]
16731688
self.framework.observe(self._charm.on.upgrade_charm, self._on_lifecycle_event)
1689+
self.framework.observe(self._charm.on.config_changed, self._on_lifecycle_event)
16741690
self.framework.observe(events.relation_joined, self._on_logging_relation_joined)
16751691
self.framework.observe(events.relation_changed, self._on_logging_relation_changed)
16761692
self.framework.observe(events.relation_departed, self._on_logging_relation_departed)
16771693

1694+
if refresh_event:
1695+
if not isinstance(refresh_event, list):
1696+
refresh_event = [refresh_event]
1697+
for ev in refresh_event:
1698+
self.framework.observe(ev, self._on_lifecycle_event)
1699+
16781700
def _on_lifecycle_event(self, _: HookEvent):
16791701
"""Update require relation data on charm upgrades and other lifecycle events.
16801702
@@ -2550,10 +2572,17 @@ def __init__(
25502572
alert_rules_path: str = DEFAULT_ALERT_RULES_RELATIVE_PATH,
25512573
recursive: bool = True,
25522574
skip_alert_topology_labeling: bool = False,
2575+
refresh_event: Optional[Union[BoundEvent, List[BoundEvent]]] = None,
2576+
forward_alert_rules: bool = True,
25532577
):
25542578
_PebbleLogClient.check_juju_version()
25552579
super().__init__(
2556-
charm, relation_name, alert_rules_path, recursive, skip_alert_topology_labeling
2580+
charm,
2581+
relation_name,
2582+
alert_rules_path,
2583+
recursive,
2584+
skip_alert_topology_labeling,
2585+
forward_alert_rules=forward_alert_rules,
25572586
)
25582587
self._charm = charm
25592588
self._relation_name = relation_name
@@ -2564,6 +2593,12 @@ def __init__(
25642593
self.framework.observe(on.relation_departed, self._update_logging)
25652594
self.framework.observe(on.relation_broken, self._update_logging)
25662595

2596+
if refresh_event:
2597+
if not isinstance(refresh_event, list):
2598+
refresh_event = [refresh_event]
2599+
for ev in refresh_event:
2600+
self.framework.observe(ev, self._update_logging)
2601+
25672602
for container_name in self._charm.meta.containers.keys():
25682603
snake_case_container_name = container_name.replace("-", "_")
25692604
self.framework.observe(

lib/charms/prometheus_k8s/v0/prometheus_scrape.py

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,8 @@ def _on_scrape_targets_changed(self, event):
340340

341341
import yaml
342342
from cosl import JujuTopology
343-
from cosl.rules import AlertRules
344-
from ops.charm import CharmBase, RelationRole
343+
from cosl.rules import AlertRules, generic_alert_groups
344+
from ops.charm import CharmBase, RelationJoinedEvent, RelationRole
345345
from ops.framework import (
346346
BoundEvent,
347347
EventBase,
@@ -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 = 47
365+
LIBPATCH = 50
366366

367367
PYDEPS = ["cosl"]
368368

@@ -1309,6 +1309,8 @@ def __init__(
13091309
refresh_event: Optional[Union[BoundEvent, List[BoundEvent]]] = None,
13101310
external_url: str = "",
13111311
lookaside_jobs_callable: Optional[Callable] = None,
1312+
*,
1313+
forward_alert_rules: bool = True,
13121314
):
13131315
"""Construct a metrics provider for a Prometheus charm.
13141316
@@ -1411,6 +1413,7 @@ def __init__(
14111413
files. Defaults to "./prometheus_alert_rules",
14121414
resolved relative to the directory hosting the charm entry file.
14131415
The alert rules are automatically updated on charm upgrade.
1416+
forward_alert_rules: a boolean flag to toggle forwarding of charmed alert rules.
14141417
refresh_event: an optional bound event or list of bound events which
14151418
will be observed to re-set scrape job data (IP address and others)
14161419
external_url: an optional argument that represents an external url that
@@ -1449,6 +1452,7 @@ def __init__(
14491452

14501453
self._charm = charm
14511454
self._alert_rules_path = alert_rules_path
1455+
self._forward_alert_rules = forward_alert_rules
14521456
self._relation_name = relation_name
14531457
# sanitize job configurations to the supported subset of parameters
14541458
jobs = [] if jobs is None else jobs
@@ -1530,7 +1534,11 @@ def set_scrape_job_spec(self, _=None):
15301534
return
15311535

15321536
alert_rules = AlertRules(query_type="promql", topology=self.topology)
1533-
alert_rules.add_path(self._alert_rules_path, recursive=True)
1537+
if self._forward_alert_rules:
1538+
alert_rules.add_path(self._alert_rules_path, recursive=True)
1539+
alert_rules.add(
1540+
generic_alert_groups.application_rules, group_name_prefix=self.topology.identifier
1541+
)
15341542
alert_rules_as_dict = alert_rules.as_dict()
15351543

15361544
for relation in self._charm.model.relations[self._relation_name]:
@@ -1776,6 +1784,9 @@ def __init__(
17761784
relation_names: Optional[dict] = None,
17771785
relabel_instance=True,
17781786
resolve_addresses=False,
1787+
path_to_own_alert_rules: Optional[str] = None,
1788+
*,
1789+
forward_alert_rules: bool = True,
17791790
):
17801791
"""Construct a `MetricsEndpointAggregator`.
17811792
@@ -1795,6 +1806,8 @@ def __init__(
17951806
resolve_addresses: A boolean flag indiccating if the aggregator
17961807
should attempt to perform DNS lookups of targets and append
17971808
a `dns_name` label
1809+
path_to_own_alert_rules: Optionally supply a path for alert rule files
1810+
forward_alert_rules: a boolean flag to toggle forwarding of charmed alert rules
17981811
"""
17991812
self._charm = charm
18001813

@@ -1807,15 +1820,21 @@ def __init__(
18071820
self._alert_rules_relation = relation_names.get("alert_rules", "prometheus-rules")
18081821

18091822
super().__init__(charm, self._prometheus_relation)
1823+
self.topology = JujuTopology.from_charm(charm)
1824+
18101825
self._stored.set_default(jobs=[], alert_rules=[])
18111826

18121827
self._relabel_instance = relabel_instance
18131828
self._resolve_addresses = resolve_addresses
18141829

1830+
self._forward_alert_rules = forward_alert_rules
1831+
18151832
# manage Prometheus charm relation events
18161833
prometheus_events = self._charm.on[self._prometheus_relation]
18171834
self.framework.observe(prometheus_events.relation_joined, self._set_prometheus_data)
18181835

1836+
self.path_to_own_alert_rules = path_to_own_alert_rules
1837+
18191838
# manage list of Prometheus scrape jobs from related scrape targets
18201839
target_events = self._charm.on[self._target_relation]
18211840
self.framework.observe(target_events.relation_changed, self._on_prometheus_targets_changed)
@@ -1828,7 +1847,7 @@ def __init__(
18281847
self.framework.observe(alert_rule_events.relation_changed, self._on_alert_rules_changed)
18291848
self.framework.observe(alert_rule_events.relation_departed, self._on_alert_rules_departed)
18301849

1831-
def _set_prometheus_data(self, event):
1850+
def _set_prometheus_data(self, event: Optional[RelationJoinedEvent] = None):
18321851
"""Ensure every new Prometheus instances is updated.
18331852
18341853
Any time a new Prometheus unit joins the relation with
@@ -1838,6 +1857,7 @@ def _set_prometheus_data(self, event):
18381857
if not self._charm.unit.is_leader():
18391858
return
18401859

1860+
# Gather the scrape jobs
18411861
jobs = [] + _type_convert_stored(
18421862
self._stored.jobs # pyright: ignore
18431863
) # list of scrape jobs, one per relation
@@ -1846,6 +1866,7 @@ def _set_prometheus_data(self, event):
18461866
if targets and relation.app:
18471867
jobs.append(self._static_scrape_job(targets, relation.app.name))
18481868

1869+
# Gather the alert rules
18491870
groups = [] + _type_convert_stored(
18501871
self._stored.alert_rules # pyright: ignore
18511872
) # list of alert rule groups
@@ -1856,9 +1877,23 @@ def _set_prometheus_data(self, event):
18561877
rules = self._label_alert_rules(unit_rules, appname)
18571878
group = {"name": self.group_name(appname), "rules": rules}
18581879
groups.append(group)
1859-
1860-
event.relation.data[self._charm.app]["scrape_jobs"] = json.dumps(jobs)
1861-
event.relation.data[self._charm.app]["alert_rules"] = json.dumps({"groups": groups})
1880+
alert_rules = AlertRules(query_type="promql", topology=self.topology)
1881+
# Add alert rules from file
1882+
if self.path_to_own_alert_rules:
1883+
alert_rules.add_path(self.path_to_own_alert_rules, recursive=True)
1884+
# Add generic alert rules
1885+
alert_rules.add(
1886+
generic_alert_groups.application_rules, group_name_prefix=self.topology.identifier
1887+
)
1888+
groups.extend(alert_rules.as_dict()["groups"])
1889+
1890+
# Set scrape jobs and alert rules in relation data
1891+
relations = [event.relation] if event else self.model.relations[self._prometheus_relation]
1892+
for rel in relations:
1893+
rel.data[self._charm.app]["scrape_jobs"] = json.dumps(jobs) # type: ignore
1894+
rel.data[self._charm.app]["alert_rules"] = json.dumps( # type: ignore
1895+
{"groups": groups if self._forward_alert_rules else []}
1896+
)
18621897

18631898
def _on_prometheus_targets_changed(self, event):
18641899
"""Update scrape jobs in response to scrape target changes.
@@ -2129,7 +2164,9 @@ def set_alert_rule_data(self, name: str, unit_rules: dict, label_rules: bool = T
21292164

21302165
if updated_group["name"] not in [g["name"] for g in groups]:
21312166
groups.append(updated_group)
2132-
relation.data[self._charm.app]["alert_rules"] = json.dumps({"groups": groups})
2167+
relation.data[self._charm.app]["alert_rules"] = json.dumps(
2168+
{"groups": groups if self._forward_alert_rules else []}
2169+
)
21332170

21342171
if not _type_convert_stored(self._stored.alert_rules) == groups: # pyright: ignore
21352172
self._stored.alert_rules = groups
@@ -2177,8 +2214,8 @@ def remove_alert_rules(self, group_name: str, unit_name: str) -> None:
21772214
changed_group["rules"] = rules_kept # type: ignore
21782215
groups.append(changed_group)
21792216

2180-
relation.data[self._charm.app]["alert_rules"] = (
2181-
json.dumps({"groups": groups}) if groups else "{}"
2217+
relation.data[self._charm.app]["alert_rules"] = json.dumps(
2218+
{"groups": groups if self._forward_alert_rules else []}
21822219
)
21832220

21842221
if not _type_convert_stored(self._stored.alert_rules) == groups: # pyright: ignore
@@ -2364,12 +2401,9 @@ def _get_tool_path(self) -> Optional[Path]:
23642401
arch = "amd64" if arch == "x86_64" else arch
23652402
res = "cos-tool-{}".format(arch)
23662403
try:
2367-
path = Path(res).resolve()
2368-
path.chmod(0o777)
2404+
path = Path(res).resolve(strict=True)
23692405
return path
2370-
except NotImplementedError:
2371-
logger.debug("System lacks support for chmod")
2372-
except FileNotFoundError:
2406+
except (FileNotFoundError, OSError):
23732407
logger.debug('Could not locate cos-tool at: "{}"'.format(res))
23742408
return None
23752409

0 commit comments

Comments
 (0)