Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/stackable-operator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

- Rollout tracker for `StatefulSet` ([#833]).

[#833]: https://github.com/stackabletech/operator-rs/pull/833

## [0.72.0] - 2024-08-05

### Changed
Expand Down
1 change: 1 addition & 0 deletions crates/stackable-operator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod pod_utils;
pub mod product_config_utils;
pub mod product_logging;
pub mod role_utils;
pub mod rollout;
pub mod status;
pub mod time;
pub mod utils;
Expand Down
61 changes: 61 additions & 0 deletions crates/stackable-operator/src/rollout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Tools for managing rollouts of Pod controllers (such as [`StatefulSet`]).

use std::borrow::Cow;

use k8s_openapi::api::apps::v1::StatefulSet;
use snafu::Snafu;

/// The reason for why a [`StatefulSet`] is still rolling out. Returned by [`check_statefulset_rollout_complete`].
#[derive(Debug, Snafu)]
#[snafu(module(outdated_statefulset))]
pub enum StatefulSetRolloutInProgress {
/// Indicates that the latest version of the [`StatefulSet`] has not yet been observed by Kubernetes' StatefulSet controller.
///
/// Kubernetes' controllers run asynchronously in the background, so this is expected when the `spec` has just been modified.
#[snafu(display("generation {current_generation:?} not yet observed by statefulset controller, last seen was {observed_generation:?}"))]
NotYetObserved {
current_generation: Option<i64>,
observed_generation: Option<i64>,
},

/// Indicates that outdated replicas still exist.
#[snafu(display("only {updated_replicas} out of {total_replicas} are updated"))]
HasOutdatedReplicas {
total_replicas: i32,
updated_replicas: i32,
},
}

/// Checks whether all ReplicaSet replicas are up-to-date according to `sts.spec`.
///
/// "Success" here means that there are no replicas running an old version,
/// *not* that all updated replicas are available yet.
pub fn check_statefulset_rollout_complete(
sts: &StatefulSet,
) -> Result<(), StatefulSetRolloutInProgress> {
use outdated_statefulset::*;

let status = sts.status.as_ref().map_or_else(Cow::default, Cow::Borrowed);

let current_generation = sts.metadata.generation;
let observed_generation = status.observed_generation;
if current_generation != observed_generation {
return NotYetObservedSnafu {
current_generation,
observed_generation,
}
.fail();
}

let total_replicas = status.replicas;
let updated_replicas = status.updated_replicas.unwrap_or(0);
if total_replicas != updated_replicas {
return HasOutdatedReplicasSnafu {
total_replicas,
updated_replicas,
}
.fail();
}

Ok(())
}