Skip to content

Commit c249acb

Browse files
authored
Merge branch 'main' into chore/auto-copilot-collections
2 parents f5cc5d8 + d3108fb commit c249acb

3 files changed

Lines changed: 88 additions & 6 deletions

File tree

lib/charms/data_platform_libs/v0/data_interfaces.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ def _on_subject_requested(self, event: SubjectRequestedEvent):
453453

454454
# Increment this PATCH version before using `charmcraft publish-lib` or reset
455455
# to 0 if you are raising the major API version
456-
LIBPATCH = 56
456+
LIBPATCH = 58
457457

458458
PYDEPS = ["ops>=2.0.0"]
459459

@@ -842,6 +842,11 @@ def _legacy_compat_find_secret_by_old_label(self) -> None:
842842
self._secret_meta = self._model.get_secret(label=label)
843843
except SecretNotFoundError:
844844
pass
845+
except ModelError as e:
846+
# Permission denied can be raised if the secret exists but is not yet granted to us.
847+
if "permission denied" in str(e):
848+
return
849+
raise
845850
else:
846851
if label != self.label:
847852
self.current_label = label
@@ -876,6 +881,8 @@ def _legacy_migration_to_new_label_if_needed(self) -> None:
876881
except ModelError as err:
877882
if MODEL_ERRORS["not_leader"] not in str(err):
878883
raise
884+
if "permission denied" not in str(err):
885+
raise
879886
self.current_label = None
880887

881888
##########################################################################
@@ -4268,6 +4275,14 @@ def _on_secret_changed_event(self, event: SecretChangedEvent):
42684275
if relation.app == self.charm.app:
42694276
logging.info("Secret changed event ignored for Secret Owner")
42704277

4278+
if relation.name != self.relation_data.relation_name:
4279+
logger.debug(
4280+
"Ignoring secret-changed from endpoint %s (expected %s)",
4281+
relation.name,
4282+
self.relation_data.relation_name,
4283+
)
4284+
return
4285+
42714286
remote_unit = None
42724287
for unit in relation.units:
42734288
if unit.app != self.charm.app:
@@ -5294,6 +5309,14 @@ def _on_secret_changed_event(self, event: SecretChangedEvent):
52945309
)
52955310
return
52965311

5312+
if relation.name != self.relation_data.relation_name:
5313+
logger.debug(
5314+
"Ignoring secret-changed from endpoint %s (expected %s)",
5315+
relation.name,
5316+
self.relation_data.relation_name,
5317+
)
5318+
return
5319+
52975320
if relation.app == self.charm.app:
52985321
logging.info("Secret changed event ignored for Secret Owner")
52995322

@@ -5556,6 +5579,14 @@ def _on_secret_changed_event(self, event: SecretChangedEvent):
55565579
)
55575580
return
55585581

5582+
if relation.name != self.relation_data.relation_name:
5583+
logger.debug(
5584+
"Ignoring secret-changed from endpoint %s (expected %s)",
5585+
relation.name,
5586+
self.relation_data.relation_name,
5587+
)
5588+
return
5589+
55595590
if relation.app == self.charm.app:
55605591
logging.info("Secret changed event ignored for Secret Owner")
55615592

@@ -5701,6 +5732,14 @@ def _on_secret_changed_event(self, event: SecretChangedEvent):
57015732
if relation.app == self.charm.app:
57025733
logging.info("Secret changed event ignored for Secret Owner")
57035734

5735+
if relation.name != self.relation_data.relation_name:
5736+
logger.debug(
5737+
"Ignoring secret-changed from endpoint %s (expected %s)",
5738+
relation.name,
5739+
self.relation_data.relation_name,
5740+
)
5741+
return
5742+
57045743
remote_unit = None
57055744
for unit in relation.units:
57065745
if unit.app != self.charm.app:

lib/charms/grafana_agent/v0/cos_agent.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,9 @@ def __init__(self, *args):
211211
```
212212
"""
213213

214+
import copy
214215
import enum
216+
import hashlib
215217
import json
216218
import logging
217219
import socket
@@ -254,7 +256,7 @@ class _MetricsEndpointDict(TypedDict):
254256

255257
LIBID = "dc15fa84cef84ce58155fb84f6c6213a"
256258
LIBAPI = 0
257-
LIBPATCH = 23
259+
LIBPATCH = 25
258260

259261
PYDEPS = ["cosl >= 0.0.50", "pydantic"]
260262

@@ -308,6 +310,13 @@ def _dedupe_list(items: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
308310
return unique_items
309311

310312

313+
def _dict_hash_except_key(scrape_config: Dict[str, Any], key: Optional[str]):
314+
"""Get a hash of the scrape_config dict, except for the specified key."""
315+
cfg_for_hash = {k: v for k, v in scrape_config.items() if k != key}
316+
serialized = json.dumps(cfg_for_hash, sort_keys=True)
317+
return hashlib.blake2b(serialized.encode(), digest_size=4).hexdigest()
318+
319+
311320
class TracingError(Exception):
312321
"""Base class for custom errors raised by tracing."""
313322

@@ -697,6 +706,27 @@ def _on_refresh(self, event):
697706
) as e:
698707
logger.error("Invalid relation data provided: %s", e)
699708

709+
def _deterministic_scrape_configs(
710+
self, scrape_configs: List[Dict[str, Any]]
711+
) -> List[Dict[str, Any]]:
712+
"""Get deterministic scrape_configs with stable job names.
713+
714+
For stability across serializations, compute a short per-config hash
715+
and append it to the existing job name (or 'default'). Keep the app
716+
name as a prefix: <app>_<job_or_default>_<8hex-hash>.
717+
718+
Hash the whole scrape_config (except any existing job_name) so the
719+
suffix is sensitive to all stable fields. Use deterministic JSON
720+
serialization.
721+
"""
722+
local_scrape_configs = copy.deepcopy(scrape_configs)
723+
for scrape_config in local_scrape_configs:
724+
name = scrape_config.get("job_name", "default")
725+
short_id = _dict_hash_except_key(scrape_config, "job_name")
726+
scrape_config["job_name"] = f"{self._charm.app.name}_{name}_{short_id}"
727+
728+
return sorted(local_scrape_configs, key=lambda c: c.get("job_name", ""))
729+
700730
@property
701731
def _scrape_jobs(self) -> List[Dict]:
702732
"""Return a list of scrape_configs.
@@ -721,7 +751,7 @@ def _scrape_jobs(self) -> List[Dict]:
721751

722752
scrape_configs = scrape_configs or []
723753

724-
return scrape_configs
754+
return self._deterministic_scrape_configs(scrape_configs)
725755

726756
@property
727757
def _metrics_alert_rules(self) -> Dict:
@@ -737,7 +767,7 @@ def _metrics_alert_rules(self) -> Dict:
737767
)
738768
alert_rules.add_path(self._metrics_rules, recursive=self._recursive)
739769
alert_rules.add(
740-
generic_alert_groups.application_rules,
770+
copy.deepcopy(generic_alert_groups.application_rules),
741771
group_name_prefix=JujuTopology.from_charm(self._charm).identifier,
742772
)
743773

lib/charms/operator_libs_linux/v1/systemd.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,20 @@
1313
# limitations under the License.
1414

1515

16-
"""Abstractions for stopping, starting and managing system services via systemd.
16+
"""Legacy Charmhub-hosted systemd library, deprecated in favour of ``charmlibs.systemd``.
17+
18+
WARNING: This library is deprecated and will no longer receive feature updates or bugfixes.
19+
``charmlibs.systemd`` version 1.0 is a bug-for-bug compatible migration of this library.
20+
Add 'charmlibs-systemd~=1.0' to your charm's dependencies, and remove this Charmhub-hosted library.
21+
Then replace `from charms.operator_libs_linux.v0 import systemd` with
22+
`from charmlibs import systemd`.
23+
Read more:
24+
- https://documentation.ubuntu.com/charmlibs
25+
- https://pypi.org/project/charmlibs-systemd
26+
27+
---
28+
29+
Abstractions for stopping, starting and managing system services via systemd.
1730
1831
This library assumes that your charm is running on a platform that uses systemd. E.g.,
1932
Centos 7 or later, Ubuntu Xenial (16.04) or later.
@@ -64,7 +77,7 @@
6477

6578
# Increment this PATCH version before using `charmcraft publish-lib` or reset
6679
# to 0 if you are raising the major API version
67-
LIBPATCH = 4
80+
LIBPATCH = 5
6881

6982

7083
class SystemdError(Exception):

0 commit comments

Comments
 (0)