From 9d8457bdc4c214598d474744bb9d9a5d79074228 Mon Sep 17 00:00:00 2001 From: Alex Lutay <1928266+taurus-forever@users.noreply.github.com> Date: Mon, 27 May 2024 10:31:03 +0200 Subject: [PATCH] [DPE-4416] Fetch charm libs to the latest LIBPATCH --- lib/charms/data_platform_libs/v0/s3.py | 29 ++++++++++++++++++--- lib/charms/data_platform_libs/v0/upgrade.py | 27 ++++++++++++++----- lib/charms/operator_libs_linux/v2/snap.py | 9 ++++--- lib/charms/rolling_ops/v0/rollingops.py | 18 ++++++++++--- 4 files changed, 66 insertions(+), 17 deletions(-) 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/lib/charms/data_platform_libs/v0/upgrade.py b/lib/charms/data_platform_libs/v0/upgrade.py index 4ee2e9ff88..ef74644de4 100644 --- a/lib/charms/data_platform_libs/v0/upgrade.py +++ b/lib/charms/data_platform_libs/v0/upgrade.py @@ -285,7 +285,7 @@ def restart(self, event) -> None: # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 15 +LIBPATCH = 16 PYDEPS = ["pydantic>=1.10,<2", "poetry-core"] @@ -501,7 +501,7 @@ class DataUpgrade(Object, ABC): STATES = ["recovery", "failed", "idle", "ready", "upgrading", "completed"] - on = UpgradeEvents() # pyright: ignore [reportGeneralTypeIssues] + on = UpgradeEvents() # pyright: ignore [reportAssignmentType] def __init__( self, @@ -606,6 +606,21 @@ def upgrade_stack(self, stack: List[int]) -> None: self.peer_relation.data[self.charm.app].update({"upgrade-stack": json.dumps(stack)}) self._upgrade_stack = stack + @property + def other_unit_states(self) -> list: + """Current upgrade state for other units. + + Returns: + Unsorted list of upgrade states for other units. + """ + if not self.peer_relation: + return [] + + return [ + self.peer_relation.data[unit].get("state", "") + for unit in list(self.peer_relation.units) + ] + @property def unit_states(self) -> list: """Current upgrade state for all units. @@ -926,11 +941,8 @@ def on_upgrade_changed(self, event: EventBase) -> None: return if self.substrate == "vm" and self.cluster_state == "recovery": - # Only defer for vm, that will set unit states to "ready" on upgrade-charm - # on k8s only the upgrading unit will receive the upgrade-charm event - # and deferring will prevent the upgrade stack from being popped - logger.debug("Cluster in recovery, deferring...") - event.defer() + # skip run while in recovery. The event will be retrigged when the cluster is ready + logger.debug("Cluster in recovery, skip...") return # if all units completed, mark as complete @@ -981,6 +993,7 @@ def on_upgrade_changed(self, event: EventBase) -> None: self.charm.unit == top_unit and top_state in ["ready", "upgrading"] and self.cluster_state == "ready" + and "upgrading" not in self.other_unit_states ): logger.debug( f"{top_unit.name} is next to upgrade, emitting `upgrade_granted` event and upgrading..." diff --git a/lib/charms/operator_libs_linux/v2/snap.py b/lib/charms/operator_libs_linux/v2/snap.py index ef426775d8..6d4dc385a6 100644 --- a/lib/charms/operator_libs_linux/v2/snap.py +++ b/lib/charms/operator_libs_linux/v2/snap.py @@ -83,7 +83,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 5 +LIBPATCH = 6 # Regex to locate 7-bit C1 ANSI sequences @@ -584,13 +584,16 @@ def ensure( "Installing snap %s, revision %s, tracking %s", self._name, revision, channel ) self._install(channel, cohort, revision) - else: + logger.info("The snap installation completed successfully") + elif revision is None or revision != self._revision: # The snap is installed, but we are changing it (e.g., switching channels). logger.info( "Refreshing snap %s, revision %s, tracking %s", self._name, revision, channel ) self._refresh(channel=channel, cohort=cohort, revision=revision, devmode=devmode) - logger.info("The snap installation completed successfully") + logger.info("The snap refresh completed successfully") + else: + logger.info("Refresh of snap %s was unnecessary", self._name) self._update_snap_apps() self._state = state diff --git a/lib/charms/rolling_ops/v0/rollingops.py b/lib/charms/rolling_ops/v0/rollingops.py index 5a7d4ce306..57aa9bf352 100644 --- a/lib/charms/rolling_ops/v0/rollingops.py +++ b/lib/charms/rolling_ops/v0/rollingops.py @@ -49,7 +49,7 @@ def _restart(self, event): To kick off the rolling restart, emit this library's AcquireLock event. The simplest way to do so would be with an action, though it might make sense to acquire the lock in -response to another event. +response to another event. ```python def _on_trigger_restart(self, event): @@ -88,7 +88,7 @@ def _on_trigger_restart(self, event): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 5 +LIBPATCH = 7 class LockNoRelationError(Exception): @@ -182,6 +182,7 @@ def _state(self) -> LockState: # Active acquire request. return LockState.ACQUIRE + logger.debug("Lock state: %s %s", unit_state, app_state) return app_state # Granted or unset/released @_state.setter @@ -202,21 +203,27 @@ def _state(self, state: LockState): if state is LockState.IDLE: self.relation.data[self.app].update({str(self.unit): state.value}) + logger.debug("state: %s", state.value) + def acquire(self): """Request that a lock be acquired.""" self._state = LockState.ACQUIRE + logger.debug("Lock acquired.") def release(self): """Request that a lock be released.""" self._state = LockState.RELEASE + logger.debug("Lock released.") def clear(self): """Unset a lock.""" self._state = LockState.IDLE + logger.debug("Lock cleared.") def grant(self): """Grant a lock to a unit.""" self._state = LockState.GRANTED + logger.debug("Lock granted.") def is_held(self): """This unit holds the lock.""" @@ -266,9 +273,11 @@ def __init__(self, handle, callback_override: Optional[str] = None): self.callback_override = callback_override or "" def snapshot(self): + """Snapshot of lock event.""" return {"callback_override": self.callback_override} def restore(self, snapshot): + """Restores lock event.""" self.callback_override = snapshot["callback_override"] @@ -288,7 +297,7 @@ def __init__(self, charm: CharmBase, relation: AnyStr, callback: Callable): charm: the charm we are attaching this to. relation: an identifier, by convention based on the name of the relation in the metadata.yaml, which identifies this instance of RollingOperatorsFactory, - distinct from other instances that may be hanlding other events. + distinct from other instances that may be handling other events. callback: a closure to run when we have a lock. (It must take a CharmBase object and EventBase object as args.) """ @@ -309,6 +318,7 @@ def __init__(self, charm: CharmBase, relation: AnyStr, callback: Callable): self.framework.observe(charm.on[self.name].acquire_lock, self._on_acquire_lock) self.framework.observe(charm.on[self.name].run_with_lock, self._on_run_with_lock) self.framework.observe(charm.on[self.name].process_locks, self._on_process_locks) + self.framework.observe(charm.on.leader_elected, self._on_process_locks) def _callback(self: CharmBase, event: EventBase) -> None: """Placeholder for the function that actually runs our event. @@ -381,7 +391,7 @@ def _on_acquire_lock(self: CharmBase, event: ActionEvent): """Request a lock.""" try: Lock(self).acquire() # Updates relation data - # emit relation changed event in the edge case where aquire does not + # emit relation changed event in the edge case where acquire does not relation = self.model.get_relation(self.name) # persist callback override for eventual run