diff --git a/lib/charms/data_platform_libs/v0/s3.py b/lib/charms/data_platform_libs/v0/s3.py index 7beb113b6d..f5614aaf6b 100644 --- a/lib/charms/data_platform_libs/v0/s3.py +++ b/lib/charms/data_platform_libs/v0/s3.py @@ -137,7 +137,7 @@ def _on_credential_gone(self, event: CredentialsGoneEvent): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 4 +LIBPATCH = 5 logger = logging.getLogger(__name__) @@ -212,7 +212,7 @@ class S3CredentialEvents(CharmEvents): class S3Provider(Object): """A provider handler for communicating S3 credentials to consumers.""" - on = S3CredentialEvents() # pyright: ignore [reportGeneralTypeIssues] + on = S3CredentialEvents() # pyright: ignore [reportAssignmentType] def __init__( self, @@ -481,6 +481,18 @@ def set_s3_api_version(self, relation_id: int, s3_api_version: str) -> None: """ self.update_connection_info(relation_id, {"s3-api-version": s3_api_version}) + def set_delete_older_than_days(self, relation_id: int, days: int) -> None: + """Sets the retention days for full backups in application databag. + + This function writes in the application data bag, therefore, + only the leader unit can call it. + + Args: + relation_id: the identifier for a particular relation. + days: the value. + """ + self.update_connection_info(relation_id, {"delete-older-than-days": str(days)}) + def set_attributes(self, relation_id: int, attributes: List[str]) -> None: """Sets the connection attributes in application databag. @@ -580,6 +592,17 @@ def s3_api_version(self) -> Optional[str]: return self.relation.data[self.relation.app].get("s3-api-version") + @property + def delete_older_than_days(self) -> Optional[int]: + """Returns the retention days for full backups.""" + if not self.relation.app: + return None + + days = self.relation.data[self.relation.app].get("delete-older-than-days") + if days is None: + return None + return int(days) + @property def attributes(self) -> Optional[List[str]]: """Returns the attributes.""" @@ -613,7 +636,7 @@ class S3CredentialRequiresEvents(ObjectEvents): class S3Requirer(Object): """Requires-side of the s3 relation.""" - on = S3CredentialRequiresEvents() # pyright: ignore[reportGeneralTypeIssues] + on = S3CredentialRequiresEvents() # pyright: ignore[reportAssignmentType] def __init__( self, charm: ops.charm.CharmBase, relation_name: str, bucket_name: Optional[str] = None diff --git a/src/backups.py b/src/backups.py index 49ac87b84d..b1785b3a1b 100644 --- a/src/backups.py +++ b/src/backups.py @@ -832,6 +832,7 @@ def _render_pgbackrest_conf_file(self) -> bool: stanza=self.stanza_name, storage_path=self.charm._storage_path, user=BACKUP_USER, + retention_full=s3_parameters["delete-older-than-days"], ) # Render pgBackRest config file. self.charm._patroni.render_file(f"{PGBACKREST_CONF_PATH}/pgbackrest.conf", rendered, 0o644) @@ -866,6 +867,7 @@ def _retrieve_s3_parameters(self) -> Tuple[Dict, List[str]]: s3_parameters.setdefault("region") s3_parameters.setdefault("path", "") s3_parameters.setdefault("s3-uri-style", "host") + s3_parameters.setdefault("delete-older-than-days", "9999999") # Strip whitespaces from all parameters. for key, value in s3_parameters.items(): diff --git a/templates/pgbackrest.conf.j2 b/templates/pgbackrest.conf.j2 index 3c2d023ba4..fcd7dea00c 100644 --- a/templates/pgbackrest.conf.j2 +++ b/templates/pgbackrest.conf.j2 @@ -2,7 +2,8 @@ backup-standby=y lock-path=/tmp log-path={{ log_path }} -repo1-retention-full=9999999 +repo1-retention-full-type=time +repo1-retention-full={{ retention_full }} repo1-type=s3 repo1-path={{ path }} repo1-s3-region={{ region }} diff --git a/tests/unit/test_backups.py b/tests/unit/test_backups.py index cc1a0fc25d..06229f7cdb 100644 --- a/tests/unit/test_backups.py +++ b/tests/unit/test_backups.py @@ -1453,6 +1453,7 @@ def test_render_pgbackrest_conf_file(harness): "path": "test-path/", "region": "us-east-1", "s3-uri-style": "path", + "delete-older-than-days": "30", }, [], ) @@ -1476,6 +1477,7 @@ def test_render_pgbackrest_conf_file(harness): stanza=harness.charm.backup.stanza_name, storage_path=harness.charm._storage_path, user="backup", + retention_full=30, ) # Patch the `open` method with our mock. @@ -1539,6 +1541,7 @@ def test_retrieve_s3_parameters(harness): { "access-key": "test-access-key", "bucket": "test-bucket", + "delete-older-than-days": "9999999", "endpoint": "https://s3.amazonaws.com", "path": "/", "region": None, @@ -1558,6 +1561,7 @@ def test_retrieve_s3_parameters(harness): "path": " test-path/ ", "region": " us-east-1 ", "s3-uri-style": " path ", + "delete-older-than-days": "30", } tc.assertEqual( harness.charm.backup._retrieve_s3_parameters(), @@ -1570,6 +1574,7 @@ def test_retrieve_s3_parameters(harness): "region": "us-east-1", "s3-uri-style": "path", "secret-key": "test-secret-key", + "delete-older-than-days": "30", }, [], ),