Skip to content

Commit a016000

Browse files
authored
[DPE-7549] Add compression and restore max-process (#1009)
* Add compression and restore max-process * Update libs
1 parent d8e90be commit a016000

File tree

4 files changed

+102
-6
lines changed

4 files changed

+102
-6
lines changed

lib/charms/data_platform_libs/v0/data_interfaces.py

Lines changed: 95 additions & 6 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 = 46
334+
LIBPATCH = 48
335335

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

@@ -2569,7 +2569,7 @@ def __init__(
25692569

25702570

25712571
################################################################################
2572-
# Cross-charm Relatoins Data Handling and Evenets
2572+
# Cross-charm Relations Data Handling and Events
25732573
################################################################################
25742574

25752575
# Generic events
@@ -3268,7 +3268,7 @@ def __init__(
32683268
# Kafka Events
32693269

32703270

3271-
class KafkaProvidesEvent(RelationEvent):
3271+
class KafkaProvidesEvent(RelationEventWithSecret):
32723272
"""Base class for Kafka events."""
32733273

32743274
@property
@@ -3287,6 +3287,40 @@ def consumer_group_prefix(self) -> Optional[str]:
32873287

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

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+
32903324

32913325
class TopicRequestedEvent(KafkaProvidesEvent, ExtraRoleEvent):
32923326
"""Event emitted when a new topic is requested for use on this relation."""
@@ -3299,6 +3333,7 @@ class KafkaProvidesEvents(CharmEvents):
32993333
"""
33003334

33013335
topic_requested = EventSource(TopicRequestedEvent)
3336+
mtls_cert_updated = EventSource(KafkaClientMtlsCertUpdatedEvent)
33023337

33033338

33043339
class KafkaRequiresEvent(RelationEvent):
@@ -3416,6 +3451,13 @@ def __init__(self, charm: CharmBase, relation_data: KafkaProviderData) -> None:
34163451
def _on_relation_changed_event(self, event: RelationChangedEvent) -> None:
34173452
"""Event emitted when the relation has changed."""
34183453
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+
34193461
# Leader only
34203462
if not self.relation_data.local_unit.is_leader():
34213463
return
@@ -3430,6 +3472,33 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None:
34303472
event.relation, app=event.app, unit=event.unit
34313473
)
34323474

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+
34333502

34343503
class KafkaProvides(KafkaProviderData, KafkaProviderEventHandlers):
34353504
"""Provider-side of the Kafka relation."""
@@ -3450,11 +3519,13 @@ def __init__(
34503519
extra_user_roles: Optional[str] = None,
34513520
consumer_group_prefix: Optional[str] = None,
34523521
additional_secret_fields: Optional[List[str]] = [],
3522+
mtls_cert: Optional[str] = None,
34533523
):
34543524
"""Manager of Kafka client relations."""
34553525
super().__init__(model, relation_name, extra_user_roles, additional_secret_fields)
34563526
self.topic = topic
34573527
self.consumer_group_prefix = consumer_group_prefix or ""
3528+
self.mtls_cert = mtls_cert
34583529

34593530
@property
34603531
def topic(self):
@@ -3468,6 +3539,15 @@ def topic(self, value):
34683539
raise ValueError(f"Error on topic '{value}', cannot be a wildcard.")
34693540
self._topic = value
34703541

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+
34713551

34723552
class KafkaRequirerEventHandlers(RequirerEventHandlers):
34733553
"""Requires-side of the Kafka relation."""
@@ -3489,6 +3569,9 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None:
34893569
# Sets topic, extra user roles, and "consumer-group-prefix" in the relation
34903570
relation_data = {"topic": self.relation_data.topic}
34913571

3572+
if self.relation_data.mtls_cert:
3573+
relation_data["mtls-cert"] = self.relation_data.mtls_cert
3574+
34923575
if self.relation_data.extra_user_roles:
34933576
relation_data["extra-user-roles"] = self.relation_data.extra_user_roles
34943577

@@ -3547,15 +3630,17 @@ def __init__(
35473630
extra_user_roles: Optional[str] = None,
35483631
consumer_group_prefix: Optional[str] = None,
35493632
additional_secret_fields: Optional[List[str]] = [],
3633+
mtls_cert: Optional[str] = None,
35503634
) -> None:
35513635
KafkaRequirerData.__init__(
35523636
self,
35533637
charm.model,
35543638
relation_name,
35553639
topic,
3556-
extra_user_roles,
3557-
consumer_group_prefix,
3558-
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,
35593644
)
35603645
KafkaRequirerEventHandlers.__init__(self, charm, self)
35613646

@@ -3675,6 +3760,10 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None:
36753760
event.relation, app=event.app, unit=event.unit
36763761
)
36773762

3763+
def _on_secret_changed_event(self, event: SecretChangedEvent) -> None:
3764+
"""Event emitted when the relation data has changed."""
3765+
pass
3766+
36783767

36793768
class OpenSearchProvides(OpenSearchProvidesData, OpenSearchProvidesEventHandlers):
36803769
"""Provider-side of the OpenSearch relation."""

src/backups.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,7 @@ def _render_pgbackrest_conf_file(self) -> bool:
12621262
storage_path=self.charm._storage_path,
12631263
user=BACKUP_USER,
12641264
retention_full=s3_parameters["delete-older-than-days"],
1265+
process_max=max(os.cpu_count() - 2, 1),
12651266
)
12661267
# Render pgBackRest config file.
12671268
self.charm._patroni.render_file(f"{PGBACKREST_CONF_PATH}/pgbackrest.conf", rendered, 0o644)

templates/pgbackrest.conf.j2

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[global]
22
backup-standby=y
3+
compress-type=zst
34
lock-path=/tmp
45
log-path={{ log_path }}
56
repo1-retention-full-type=time
@@ -47,3 +48,6 @@ pg{{ ns.count }}-user={{ user }}
4748
{% set ns.count = ns.count + 1 %}
4849
{%- endfor %}
4950
{%- endif %}
51+
52+
[global:restore]
53+
process-max={{process_max}}

tests/unit/test_backups.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright 2023 Canonical Ltd.
22
# See LICENSE file for licensing details.
3+
from os import cpu_count
34
from pathlib import PosixPath
45
from subprocess import CompletedProcess, TimeoutExpired
56
from unittest.mock import ANY, MagicMock, PropertyMock, call, mock_open, patch
@@ -1754,6 +1755,7 @@ def test_render_pgbackrest_conf_file(harness, tls_ca_chain_filename):
17541755
storage_path=harness.charm._storage_path,
17551756
user="backup",
17561757
retention_full=30,
1758+
process_max=max(cpu_count() - 2, 1),
17571759
)
17581760

17591761
# Patch the `open` method with our mock.

0 commit comments

Comments
 (0)