Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/stackable-operator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
42 changes: 22 additions & 20 deletions crates/stackable-operator/src/eos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ pub enum Error {
}

pub struct EndOfSupportChecker {
datetime: DateTime<Utc>,
built_datetime: DateTime<Utc>,
eos_datetime: DateTime<Utc>,
interval: Duration,
disabled: bool,
}
Expand All @@ -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)
Expand All @@ -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,
})
Expand All @@ -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<Utc>) {
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
}
}
4 changes: 3 additions & 1 deletion crates/stackable-shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions crates/stackable-shared/src/time/chrono_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use crate::time::Duration;

impl TryFrom<chrono::TimeDelta> for Duration {
type Error = chrono::OutOfRangeError;

fn try_from(value: chrono::TimeDelta) -> Result<Self, Self::Error> {
let std_duration = value.to_std()?;
Ok(Self::from(std_duration))
}
}

impl TryFrom<Duration> for chrono::TimeDelta {
type Error = chrono::OutOfRangeError;

fn try_from(value: Duration) -> Result<Self, Self::Error> {
chrono::TimeDelta::from_std(value.into())
}
}
3 changes: 3 additions & 0 deletions crates/stackable-shared/src/time/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
mod duration;
mod serde_impl;

#[cfg(feature = "chrono")]
mod chrono_impl;

#[cfg(feature = "time")]
mod time_impl;

Expand Down
Loading