Skip to content

Commit 48339a5

Browse files
committed
feat(stackable-operator): Add EoS checker
1 parent 69bd3d6 commit 48339a5

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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+
#[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+
#[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. The default
33+
/// value is provided by [`Self::default_support_duration()`].
34+
#[arg(skip = Self::default_support_duration())]
35+
pub support_duration: Duration,
36+
}
37+
38+
impl EndOfSupportOptions {
39+
fn default_interval() -> Duration {
40+
Duration::from_days_unchecked(1)
41+
}
42+
43+
fn default_support_duration() -> Duration {
44+
Duration::from_days_unchecked(365)
45+
}
46+
}
47+
48+
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
49+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
50+
pub enum EndOfSupportCheckMode {
51+
#[default]
52+
Offline,
53+
}
54+
55+
#[derive(Debug, Snafu)]
56+
pub enum Error {
57+
#[snafu(display("failed to parse built-time"))]
58+
ParseBuiltTime { source: chrono::ParseError },
59+
}
60+
61+
pub struct EndOfSupportChecker {
62+
datetime: DateTime<Utc>,
63+
interval: Duration,
64+
}
65+
66+
impl EndOfSupportChecker {
67+
/// Creates and returns a new end-of-support checker.
68+
///
69+
/// - The `built_time` string indicates when a specific operator was built. It is recommended
70+
/// to use `built`'s `BUILT_TIME_UTC` constant.
71+
/// - The `options` allow customizing the checker. It is recommended to use values provided by
72+
/// CLI args, see [`EndOfSupportOptions`], [`MaintenanceOptions`](crate::cli::MaintenanceOptions),
73+
/// and [`RunArguments`](crate::cli::RunArguments).
74+
pub fn new(built_time: &str, options: EndOfSupportOptions) -> Result<Self, Error> {
75+
let EndOfSupportOptions {
76+
interval,
77+
support_duration,
78+
..
79+
} = options;
80+
81+
// Parse the built-time from the RFC2822-encoded string and add the support duration to it.
82+
// This is datetime marks the end-of-support date.
83+
let datetime = DateTime::parse_from_rfc2822(built_time)
84+
.context(ParseBuiltTimeSnafu)?
85+
.to_utc()
86+
+ *support_duration;
87+
88+
Ok(Self { datetime, interval })
89+
}
90+
91+
/// Run the end-of-support checker.
92+
///
93+
/// It is recommended to run the end-of-support checker via [`futures::try_join!`].
94+
pub async fn run(self) {
95+
// Construct an interval which can be polled.
96+
let mut interval = tokio::time::interval(self.interval.into());
97+
98+
loop {
99+
// TODO: Add way to stop from the outside
100+
// The first tick ticks immediately.
101+
interval.tick().await;
102+
103+
// Continue the loop and wait for the next tick to run the check again.
104+
if !self.is_eos() {
105+
continue;
106+
}
107+
108+
self.emit_warning();
109+
}
110+
}
111+
112+
/// Emits the end-of-support warning.
113+
fn emit_warning(&self) {
114+
tracing::warn!(
115+
eos.date = self.datetime.to_rfc3339(),
116+
"the operator reached end-of-support"
117+
);
118+
}
119+
120+
/// Returns if the operator is considered as end-of-support based on the built-time and the
121+
/// support duration.
122+
fn is_eos(&self) -> bool {
123+
let now = Utc::now();
124+
now > self.datetime
125+
}
126+
}

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)