|
| 1 | +//! Tools for managing rollouts of Pod controllers (such as [`StatefulSet`]). |
| 2 | +
|
| 3 | +use std::borrow::Cow; |
| 4 | + |
| 5 | +use k8s_openapi::api::apps::v1::StatefulSet; |
| 6 | +use snafu::Snafu; |
| 7 | + |
| 8 | +/// The reason for why a [`StatefulSet`] is still rolling out. Returned by [`check_statefulset_rollout_complete`]. |
| 9 | +#[derive(Debug, Snafu)] |
| 10 | +#[snafu(module(outdated_statefulset))] |
| 11 | +pub enum StatefulSetRolloutInProgress { |
| 12 | + /// Indicates that the latest version of the [`StatefulSet`] has not yet been observed by Kubernetes' StatefulSet controller. |
| 13 | + /// |
| 14 | + /// Kubernetes' controllers run asynchronously in the background, so this is expected when the `spec` has just been modified. |
| 15 | + #[snafu(display("generation {current_generation:?} not yet observed by statefulset controller, last seen was {observed_generation:?}"))] |
| 16 | + NotYetObserved { |
| 17 | + current_generation: Option<i64>, |
| 18 | + observed_generation: Option<i64>, |
| 19 | + }, |
| 20 | + |
| 21 | + /// Indicates that outdated replicas still exist. |
| 22 | + #[snafu(display("only {updated_replicas} out of {total_replicas} are updated"))] |
| 23 | + HasOutdatedReplicas { |
| 24 | + total_replicas: i32, |
| 25 | + updated_replicas: i32, |
| 26 | + }, |
| 27 | +} |
| 28 | + |
| 29 | +/// Checks whether all ReplicaSet replicas are up-to-date according to `sts.spec`. |
| 30 | +/// |
| 31 | +/// "Success" here means that there are no replicas running an old version, |
| 32 | +/// *not* that all updated replicas are available yet. |
| 33 | +pub fn check_statefulset_rollout_complete( |
| 34 | + sts: &StatefulSet, |
| 35 | +) -> Result<(), StatefulSetRolloutInProgress> { |
| 36 | + use outdated_statefulset::*; |
| 37 | + |
| 38 | + let status = sts.status.as_ref().map_or_else(Cow::default, Cow::Borrowed); |
| 39 | + |
| 40 | + let current_generation = sts.metadata.generation; |
| 41 | + let observed_generation = status.observed_generation; |
| 42 | + if current_generation != observed_generation { |
| 43 | + return NotYetObservedSnafu { |
| 44 | + current_generation, |
| 45 | + observed_generation, |
| 46 | + } |
| 47 | + .fail(); |
| 48 | + } |
| 49 | + |
| 50 | + let total_replicas = status.replicas; |
| 51 | + let updated_replicas = status.updated_replicas.unwrap_or(0); |
| 52 | + if total_replicas != updated_replicas { |
| 53 | + return HasOutdatedReplicasSnafu { |
| 54 | + total_replicas, |
| 55 | + updated_replicas, |
| 56 | + } |
| 57 | + .fail(); |
| 58 | + } |
| 59 | + |
| 60 | + Ok(()) |
| 61 | +} |
0 commit comments