Skip to content

Commit 0d86d6d

Browse files
authored
[MISC] Use ruff formater (#394)
* Use ruff fromater * Revert upgrade lib
1 parent 28990d4 commit 0d86d6d

24 files changed

+872
-687
lines changed

lib/charms/data_platform_libs/v0/data_interfaces.py

Lines changed: 598 additions & 291 deletions
Large diffs are not rendered by default.

lib/charms/grafana_agent/v0/cos_agent.py

Lines changed: 45 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,14 @@ def __init__(self, *args):
211211
from collections import namedtuple
212212
from itertools import chain
213213
from pathlib import Path
214-
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, List, Optional, Set, Union
214+
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, List, Optional, Set, Tuple, Union
215215

216216
import pydantic
217217
from cosl import GrafanaDashboard, JujuTopology
218218
from cosl.rules import AlertRules
219219
from ops.charm import RelationChangedEvent
220220
from ops.framework import EventBase, EventSource, Object, ObjectEvents
221-
from ops.model import Relation, Unit
221+
from ops.model import Relation
222222
from ops.testing import CharmType
223223

224224
if TYPE_CHECKING:
@@ -234,7 +234,7 @@ class _MetricsEndpointDict(TypedDict):
234234

235235
LIBID = "dc15fa84cef84ce58155fb84f6c6213a"
236236
LIBAPI = 0
237-
LIBPATCH = 7
237+
LIBPATCH = 8
238238

239239
PYDEPS = ["cosl", "pydantic < 2"]
240240

@@ -258,7 +258,9 @@ class CosAgentProviderUnitData(pydantic.BaseModel):
258258
metrics_alert_rules: dict
259259
log_alert_rules: dict
260260
dashboards: List[GrafanaDashboard]
261-
subordinate: Optional[bool]
261+
# subordinate is no longer used but we should keep it until we bump the library to ensure
262+
# we don't break compatibility.
263+
subordinate: Optional[bool] = None
262264

263265
# The following entries may vary across units of the same principal app.
264266
# this data does not need to be forwarded to the gagent leader
@@ -277,9 +279,9 @@ class CosAgentPeersUnitData(pydantic.BaseModel):
277279
# We need the principal unit name and relation metadata to be able to render identifiers
278280
# (e.g. topology) on the leader side, after all the data moves into peer data (the grafana
279281
# agent leader can only see its own principal, because it is a subordinate charm).
280-
principal_unit_name: str
281-
principal_relation_id: str
282-
principal_relation_name: str
282+
unit_name: str
283+
relation_id: str
284+
relation_name: str
283285

284286
# The only data that is forwarded to the leader is data that needs to go into the app databags
285287
# of the outgoing o11y relations.
@@ -299,7 +301,7 @@ def app_name(self) -> str:
299301
TODO: Switch to using `model_post_init` when pydantic v2 is released?
300302
https://github.com/pydantic/pydantic/issues/1729#issuecomment-1300576214
301303
"""
302-
return self.principal_unit_name.split("/")[0]
304+
return self.unit_name.split("/")[0]
303305

304306

305307
class COSAgentProvider(Object):
@@ -375,7 +377,6 @@ def _on_refresh(self, event):
375377
dashboards=self._dashboards,
376378
metrics_scrape_jobs=self._scrape_jobs,
377379
log_slots=self._log_slots,
378-
subordinate=self._charm.meta.subordinate,
379380
)
380381
relation.data[self._charm.unit][data.KEY] = data.json()
381382
except (
@@ -468,12 +469,6 @@ class COSAgentRequirerEvents(ObjectEvents):
468469
validation_error = EventSource(COSAgentValidationError)
469470

470471

471-
class MultiplePrincipalsError(Exception):
472-
"""Custom exception for when there are multiple principal applications."""
473-
474-
pass
475-
476-
477472
class COSAgentRequirer(Object):
478473
"""Integration endpoint wrapper for the Requirer side of the cos_agent interface."""
479474

@@ -559,13 +554,13 @@ def _on_relation_data_changed(self, event: RelationChangedEvent):
559554
if not (provider_data := self._validated_provider_data(raw)):
560555
return
561556

562-
# Copy data from the principal relation to the peer relation, so the leader could
557+
# Copy data from the cos_agent relation to the peer relation, so the leader could
563558
# follow up.
564559
# Save the originating unit name, so it could be used for topology later on by the leader.
565560
data = CosAgentPeersUnitData( # peer relation databag model
566-
principal_unit_name=event.unit.name,
567-
principal_relation_id=str(event.relation.id),
568-
principal_relation_name=event.relation.name,
561+
unit_name=event.unit.name,
562+
relation_id=str(event.relation.id),
563+
relation_name=event.relation.name,
569564
metrics_alert_rules=provider_data.metrics_alert_rules,
570565
log_alert_rules=provider_data.log_alert_rules,
571566
dashboards=provider_data.dashboards,
@@ -592,39 +587,7 @@ def trigger_refresh(self, _):
592587
self.on.data_changed.emit() # pyright: ignore
593588

594589
@property
595-
def _principal_unit(self) -> Optional[Unit]:
596-
"""Return the principal unit for a relation.
597-
598-
Assumes that the relation is of type subordinate.
599-
Relies on the fact that, for subordinate relations, the only remote unit visible to
600-
*this unit* is the principal unit that this unit is attached to.
601-
"""
602-
if relations := self._principal_relations:
603-
# Technically it's a list, but for subordinates there can only be one relation
604-
principal_relation = next(iter(relations))
605-
if units := principal_relation.units:
606-
# Technically it's a list, but for subordinates there can only be one
607-
return next(iter(units))
608-
609-
return None
610-
611-
@property
612-
def _principal_relations(self):
613-
relations = []
614-
for relation in self._charm.model.relations[self._relation_name]:
615-
if not json.loads(relation.data[next(iter(relation.units))]["config"]).get(
616-
["subordinate"], False
617-
):
618-
relations.append(relation)
619-
if len(relations) > 1:
620-
logger.error(
621-
"Multiple applications claiming to be principal. Update the cos-agent library in the client application charms."
622-
)
623-
raise MultiplePrincipalsError("Multiple principal applications.")
624-
return relations
625-
626-
@property
627-
def _remote_data(self) -> List[CosAgentProviderUnitData]:
590+
def _remote_data(self) -> List[Tuple[CosAgentProviderUnitData, JujuTopology]]:
628591
"""Return a list of remote data from each of the related units.
629592
630593
Assumes that the relation is of type subordinate.
@@ -641,7 +604,15 @@ def _remote_data(self) -> List[CosAgentProviderUnitData]:
641604
continue
642605
if not (provider_data := self._validated_provider_data(raw)):
643606
continue
644-
all_data.append(provider_data)
607+
608+
topology = JujuTopology(
609+
model=self._charm.model.name,
610+
model_uuid=self._charm.model.uuid,
611+
application=unit.app.name,
612+
unit=unit.name,
613+
)
614+
615+
all_data.append((provider_data, topology))
645616

646617
return all_data
647618

@@ -711,7 +682,7 @@ def metrics_alerts(self) -> Dict[str, Any]:
711682
def metrics_jobs(self) -> List[Dict]:
712683
"""Parse the relation data contents and extract the metrics jobs."""
713684
scrape_jobs = []
714-
for data in self._remote_data:
685+
for data, topology in self._remote_data:
715686
for job in data.metrics_scrape_jobs:
716687
# In #220, relation schema changed from a simplified dict to the standard
717688
# `scrape_configs`.
@@ -727,6 +698,22 @@ def metrics_jobs(self) -> List[Dict]:
727698
"tls_config": {"insecure_skip_verify": True},
728699
}
729700

701+
# Apply labels to the scrape jobs
702+
for static_config in job.get("static_configs", []):
703+
topo_as_dict = topology.as_dict(excluded_keys=["charm_name"])
704+
static_config["labels"] = {
705+
# Be sure to keep labels from static_config
706+
**static_config.get("labels", {}),
707+
# TODO: We should add a new method in juju_topology.py
708+
# that like `as_dict` method, returns the keys with juju_ prefix
709+
# https://github.com/canonical/cos-lib/issues/18
710+
**{
711+
"juju_{}".format(key): value
712+
for key, value in topo_as_dict.items()
713+
if value
714+
},
715+
}
716+
730717
scrape_jobs.append(job)
731718

732719
return scrape_jobs
@@ -735,7 +722,7 @@ def metrics_jobs(self) -> List[Dict]:
735722
def snap_log_endpoints(self) -> List[SnapEndpoint]:
736723
"""Fetch logging endpoints exposed by related snaps."""
737724
plugs = []
738-
for data in self._remote_data:
725+
for data, _ in self._remote_data:
739726
targets = data.log_slots
740727
if targets:
741728
for target in targets:
@@ -775,7 +762,7 @@ def logs_alerts(self) -> Dict[str, Any]:
775762
model=self._charm.model.name,
776763
model_uuid=self._charm.model.uuid,
777764
application=app_name,
778-
# For the topology unit, we could use `data.principal_unit_name`, but that unit
765+
# For the topology unit, we could use `data.unit_name`, but that unit
779766
# name may not be very stable: `_gather_peer_data` de-duplicates by app name so
780767
# the exact unit name that turns up first in the iterator may vary from time to
781768
# time. So using the grafana-agent unit name instead.
@@ -808,9 +795,9 @@ def dashboards(self) -> List[Dict[str, str]]:
808795

809796
dashboards.append(
810797
{
811-
"relation_id": data.principal_relation_id,
798+
"relation_id": data.relation_id,
812799
# We have the remote charm name - use it for the identifier
813-
"charm": f"{data.principal_relation_name}-{app_name}",
800+
"charm": f"{data.relation_name}-{app_name}",
814801
"content": content,
815802
"title": title,
816803
}

0 commit comments

Comments
 (0)