From 9be8fc9785525ac0c1e7bd29d64c106dfbe799f1 Mon Sep 17 00:00:00 2001 From: Techassi Date: Thu, 2 Oct 2025 16:03:02 +0200 Subject: [PATCH 1/3] chore(operator/eos): Adjust the warning message --- Cargo.lock | 1 + crates/stackable-operator/Cargo.toml | 2 +- crates/stackable-operator/src/eos/mod.rs | 42 ++++++++++--------- crates/stackable-shared/Cargo.toml | 4 +- .../stackable-shared/src/time/chrono_impl.rs | 18 ++++++++ crates/stackable-shared/src/time/mod.rs | 3 ++ 6 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 crates/stackable-shared/src/time/chrono_impl.rs diff --git a/Cargo.lock b/Cargo.lock index 6f76181cd..c28932175 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2963,6 +2963,7 @@ dependencies = [ name = "stackable-shared" version = "0.0.2" dependencies = [ + "chrono", "k8s-openapi", "kube", "rstest", diff --git a/crates/stackable-operator/Cargo.toml b/crates/stackable-operator/Cargo.toml index ca3b68a50..7c587896f 100644 --- a/crates/stackable-operator/Cargo.toml +++ b/crates/stackable-operator/Cargo.toml @@ -21,7 +21,7 @@ webhook = ["dep:stackable-webhook"] [dependencies] stackable-certs = { path = "../stackable-certs", optional = true } stackable-operator-derive = { path = "../stackable-operator-derive" } -stackable-shared = { path = "../stackable-shared" } +stackable-shared = { path = "../stackable-shared", features = ["chrono", "time"]} stackable-telemetry = { path = "../stackable-telemetry", optional = true, features = ["clap"] } stackable-versioned = { path = "../stackable-versioned", optional = true } stackable-webhook = { path = "../stackable-webhook", optional = true } diff --git a/crates/stackable-operator/src/eos/mod.rs b/crates/stackable-operator/src/eos/mod.rs index 3a92da7b9..bedc4794c 100644 --- a/crates/stackable-operator/src/eos/mod.rs +++ b/crates/stackable-operator/src/eos/mod.rs @@ -67,7 +67,8 @@ pub enum Error { } pub struct EndOfSupportChecker { - datetime: DateTime, + built_datetime: DateTime, + eos_datetime: DateTime, interval: Duration, disabled: bool, } @@ -90,7 +91,7 @@ impl EndOfSupportChecker { // Parse the built-time from the RFC2822-encoded string when this is compiled as a release // build. If this is a debug/dev build, use the current datetime instead. - let mut datetime = if cfg!(debug_assertions) { + let built_datetime = if cfg!(debug_assertions) { Utc::now() } else { DateTime::parse_from_rfc2822(built_time) @@ -99,10 +100,11 @@ impl EndOfSupportChecker { }; // Add the support duration to the built date. This marks the end-of-support date. - datetime += *support_duration; + let eos_datetime = built_datetime + *support_duration; Ok(Self { - datetime, + built_datetime, + eos_datetime, interval, disabled, }) @@ -125,37 +127,37 @@ impl EndOfSupportChecker { // TODO: Add way to stop from the outside // The first tick ticks immediately. interval.tick().await; + let now = Utc::now(); + tracing::info_span!( "checking end-of-support state", eos.interval = self.interval.to_string(), + eos.now = now.to_rfc3339(), ); // Continue the loop and wait for the next tick to run the check again. - if !self.is_eos() { + if now <= self.eos_datetime { continue; } - self.emit_warning(); + self.emit_warning(now); } } /// Emits the end-of-support warning. #[instrument(level = Level::DEBUG, skip(self))] - fn emit_warning(&self) { + fn emit_warning(&self, now: DateTime) { + let built_datetime = self.built_datetime.to_rfc3339(); + let build_age = Duration::try_from(now - self.built_datetime) + .expect("time delta of now and built datetime must not be less than 0") + .to_string(); + tracing::warn!( - eos.date = self.datetime.to_rfc3339(), - "the operator reached end-of-support" + eos.built.datetime = built_datetime, + eos.build.age = build_age, + "This operator version was built on {built_datetime} ({build_age} days ago) and may has reached end-of-support. \ +Running unsupported versions may contain security vulnerabilities. \ +Please upgrade to a supported version as soon as possible." ); } - - /// Returns if the operator is considered as end-of-support based on the built-time and the - /// support duration. - #[instrument(level = Level::DEBUG, skip(self), fields(eos.now))] - fn is_eos(&self) -> bool { - let now = Utc::now(); - - tracing::Span::current().record("eos.now", now.to_rfc3339()); - - now > self.datetime - } } diff --git a/crates/stackable-shared/Cargo.toml b/crates/stackable-shared/Cargo.toml index e139cb7b7..881fbfc9a 100644 --- a/crates/stackable-shared/Cargo.toml +++ b/crates/stackable-shared/Cargo.toml @@ -7,12 +7,14 @@ edition.workspace = true repository.workspace = true [features] -full = ["time"] +full = ["chrono", "time"] default = ["time"] +chrono = ["dep:chrono"] time = ["dep:time"] [dependencies] +chrono = { workspace = true, optional = true } k8s-openapi.workspace = true kube.workspace = true schemars.workspace = true diff --git a/crates/stackable-shared/src/time/chrono_impl.rs b/crates/stackable-shared/src/time/chrono_impl.rs new file mode 100644 index 000000000..1f0a6c5e8 --- /dev/null +++ b/crates/stackable-shared/src/time/chrono_impl.rs @@ -0,0 +1,18 @@ +use crate::time::Duration; + +impl TryFrom for Duration { + type Error = chrono::OutOfRangeError; + + fn try_from(value: chrono::TimeDelta) -> Result { + let std_duration = value.to_std()?; + Ok(Self::from(std_duration)) + } +} + +impl TryFrom for chrono::TimeDelta { + type Error = chrono::OutOfRangeError; + + fn try_from(value: Duration) -> Result { + chrono::TimeDelta::from_std(value.into()) + } +} diff --git a/crates/stackable-shared/src/time/mod.rs b/crates/stackable-shared/src/time/mod.rs index 9bd1940b5..63e13a930 100644 --- a/crates/stackable-shared/src/time/mod.rs +++ b/crates/stackable-shared/src/time/mod.rs @@ -1,6 +1,9 @@ mod duration; mod serde_impl; +#[cfg(feature = "chrono")] +mod chrono_impl; + #[cfg(feature = "time")] mod time_impl; From b3f0a8eb16d05dfee06348f7e0e829b4c7a1360d Mon Sep 17 00:00:00 2001 From: Techassi Date: Thu, 2 Oct 2025 16:09:13 +0200 Subject: [PATCH 2/3] chore(operator): Add changelog entry --- crates/stackable-operator/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/stackable-operator/CHANGELOG.md b/crates/stackable-operator/CHANGELOG.md index 812b4a695..158b3c9c4 100644 --- a/crates/stackable-operator/CHANGELOG.md +++ b/crates/stackable-operator/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. ### Changed +- Update the end-of-support warning message ([#1103]) - BREAKING: `ProductOperatorRun` was renamed to `RunArguments` ([#1096]). - BREAKING: The `disable_crd_maintenance` field was moved from `RunArguments` into `MaintenanceOptions`. The CLI interface is unchanged ([#1096]). @@ -26,6 +27,7 @@ All notable changes to this project will be documented in this file. [#1096]: https://github.com/stackabletech/operator-rs/pull/1096 [#1098]: https://github.com/stackabletech/operator-rs/pull/1098 [#1101]: https://github.com/stackabletech/operator-rs/pull/1101 +[#1103]: https://github.com/stackabletech/operator-rs/pull/1103 ## [0.98.0] - 2025-09-22 From eb9317f4710fada40fd82ed3735144464f0ce6a3 Mon Sep 17 00:00:00 2001 From: Techassi Date: Thu, 2 Oct 2025 16:09:31 +0200 Subject: [PATCH 3/3] chore(shared): Add changelog entry --- crates/stackable-shared/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/stackable-shared/CHANGELOG.md b/crates/stackable-shared/CHANGELOG.md index 922b8a77f..5488bb6c9 100644 --- a/crates/stackable-shared/CHANGELOG.md +++ b/crates/stackable-shared/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. +## Unreleased + +### Added + +- Add conversion implementations between `Duration` and `chrono::TimeDelta` ([#1103]). + +[#1103]: https://github.com/stackabletech/operator-rs/pull/1103 + ## [0.0.2] - 2025-08-21 ### Added