Skip to content

Commit 762f2b7

Browse files
committed
feat(stackable-operator): Add EoS checker
1 parent 9c893e0 commit 762f2b7

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use chrono::{DateTime, Utc};
2+
use snafu::{ResultExt, Snafu};
3+
use stackable_shared::time::Duration;
4+
5+
/// Available options to configure a [`EndOfSupportChecker`].
6+
///
7+
/// Additionally, this struct can be used as operator CLI arguments. This functionality is only
8+
/// available if the feature `clap` is enabled.
9+
#[cfg_attr(feature = "clap", derive(clap::Args))]
10+
#[derive(Debug, PartialEq, Eq)]
11+
pub struct EndOfSupportOptions {
12+
/// The end-of-support check mode. Currently, only "offline" is supported.
13+
#[cfg_attr(feature = "clap", arg(
14+
long = "eos-check-mode",
15+
env = "EOS_CHECK_MODE",
16+
default_value_t = EndOfSupportCheckMode::default(),
17+
value_enum
18+
))]
19+
pub check_mode: EndOfSupportCheckMode,
20+
21+
/// The interval in which the end-of-support check should run.
22+
#[cfg_attr(feature = "clap", arg(
23+
long = "eos-interval",
24+
env = "EOS_INTERVAL",
25+
default_value_t = Self::default_interval()
26+
))]
27+
pub interval: Duration,
28+
29+
/// The support duration (how long the operator should be considered supported after
30+
/// it's built-date).
31+
///
32+
/// This field is currently not exposed as a CLI argument or environment variable.
33+
#[cfg_attr(feature = "clap", arg(skip = Self::default_support_duration()))]
34+
pub support_duration: Duration,
35+
}
36+
37+
impl EndOfSupportOptions {
38+
fn default_interval() -> Duration {
39+
Duration::from_days_unchecked(1)
40+
}
41+
42+
fn default_support_duration() -> Duration {
43+
Duration::from_days_unchecked(365)
44+
}
45+
}
46+
47+
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
48+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
49+
pub enum EndOfSupportCheckMode {
50+
#[default]
51+
Offline,
52+
}
53+
54+
#[derive(Debug, Snafu)]
55+
pub enum Error {
56+
#[snafu(display("failed to parse built-time"))]
57+
ParseBuiltTime { source: chrono::ParseError },
58+
}
59+
60+
pub struct EndOfSupportChecker {
61+
datetime: DateTime<Utc>,
62+
interval: Duration,
63+
}
64+
65+
impl EndOfSupportChecker {
66+
/// Creates and returns a new end-of-support checker.
67+
///
68+
/// - The `built_time` string indicates when a specific operator was built. It is recommended
69+
/// to use `built`'s `BUILT_TIME_UTC` constant.
70+
/// - The `options` allow customizing the checker. It is recommended to use values provided by
71+
/// CLI args, see [`EndOfSupportOptions`], [`MaintenanceOptions`](crate::cli::MaintenanceOptions),
72+
/// and [`RunArguments`](crate::cli::RunArguments).
73+
pub fn new(built_time: &str, options: EndOfSupportOptions) -> Result<Self, Error> {
74+
let EndOfSupportOptions {
75+
interval,
76+
support_duration,
77+
..
78+
} = options;
79+
80+
// Parse the built-time from the RFC2822-encoded string and add the support duration to it.
81+
// This is datetime marks the end-of-support date.
82+
let datetime = DateTime::parse_from_rfc2822(built_time)
83+
.context(ParseBuiltTimeSnafu)?
84+
.to_utc()
85+
+ *support_duration;
86+
87+
Ok(Self { datetime, interval })
88+
}
89+
90+
/// Run the end-of-support checker.
91+
///
92+
/// It is recommended to run the end-of-support checker via [`futures::try_join!`].
93+
pub async fn run(self) {
94+
// Construct an interval which can be polled.
95+
let mut interval = tokio::time::interval(self.interval.into());
96+
97+
loop {
98+
// TODO: Add way to stop from the outside
99+
// The first tick ticks immediately.
100+
interval.tick().await;
101+
102+
// Continue the loop and wait for the next tick to run the check again.
103+
if !self.is_eos() {
104+
continue;
105+
}
106+
107+
self.emit_warning();
108+
}
109+
}
110+
111+
/// Emits the end-of-support warning.
112+
fn emit_warning(&self) {
113+
tracing::warn!(
114+
eos.date = self.datetime.to_rfc3339(),
115+
"the operator reached end-of-support"
116+
);
117+
}
118+
119+
/// Returns if the operator is considered as end-of-support based on the built-time and the
120+
/// support duration.
121+
fn is_eos(&self) -> bool {
122+
let now = Utc::now();
123+
now > self.datetime
124+
}
125+
}

crates/stackable-operator/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub mod config;
1515
pub mod constants;
1616
pub mod cpu;
1717
pub mod crd;
18+
pub mod eos;
1819
pub mod helm;
1920
pub mod iter;
2021
pub mod kvp;

0 commit comments

Comments
 (0)