Skip to content

Commit 18026bf

Browse files
committed
Add error handling
1 parent df4abc0 commit 18026bf

File tree

1 file changed

+72
-37
lines changed
  • crates/stackable-operator/src/builder/pod

1 file changed

+72
-37
lines changed

crates/stackable-operator/src/builder/pod/probe.rs

Lines changed: 72 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,28 @@
1+
use std::{i32, num::TryFromIntError};
2+
13
use k8s_openapi::{
24
api::core::v1::{ExecAction, GRPCAction, HTTPGetAction, Probe, TCPSocketAction},
35
apimachinery::pkg::util::intstr::IntOrString,
46
};
7+
use snafu::{ResultExt, Snafu, ensure};
58

69
use crate::time::Duration;
710

11+
#[derive(Debug, Snafu)]
12+
pub enum Error {
13+
#[snafu(display(
14+
"The probe's {field:?} duration of {duration} is too long, as it's seconds doesn't fit into an i32"
15+
))]
16+
DurationTooLong {
17+
source: TryFromIntError,
18+
field: String,
19+
duration: Duration,
20+
},
21+
22+
#[snafu(display("The probe period is zero, but it needs to be a positive duration"))]
23+
PeriodIsZero {},
24+
}
25+
826
#[derive(Debug)]
927
pub struct ProbeBuilder<Action, Period> {
1028
// Mandatory field
@@ -153,14 +171,20 @@ impl ProbeBuilder<ProbeAction, Duration> {
153171

154172
/// The duration the probe needs to succeed before being considered successful.
155173
///
156-
/// This internally calculates the needed success threshold based on the period and passes that
174+
/// This internally calculates the needed failure threshold based on the period and passes that
157175
/// to [`Self::with_success_threshold`].
158-
pub fn with_success_threshold_duration(self, success_threshold_duration: Duration) -> Self {
176+
///
177+
/// This function returns an [`Error::PeriodIsZero`] error in case the period is zero, as it
178+
/// can not divide by zero.
179+
pub fn with_success_threshold_duration(
180+
self,
181+
success_threshold_duration: Duration,
182+
) -> Result<Self, Error> {
183+
ensure!(self.period.as_nanos() != 0, PeriodIsZeroSnafu);
184+
185+
// SAFETY: Period is checked above to be non-zero
159186
let success_threshold = success_threshold_duration.div_duration_f32(*self.period);
160-
// SAFETY: Returning an Result here would hurt the builder ergonomics and having such big
161-
// numbers does not have any real world effect.
162-
let success_threshold = success_threshold.ceil() as i32;
163-
self.with_success_threshold(success_threshold)
187+
Ok(self.with_success_threshold(success_threshold.ceil() as i32))
164188
}
165189

166190
/// How often the probe must fail before being considered failed.
@@ -188,46 +212,54 @@ impl ProbeBuilder<ProbeAction, Duration> {
188212
///
189213
/// This internally calculates the needed failure threshold based on the period and passes that
190214
/// to [`Self::with_failure_threshold`].
191-
pub fn with_failure_threshold_duration(self, failure_threshold_duration: Duration) -> Self {
215+
///
216+
/// This function returns an [`Error::PeriodIsZero`] error in case the period is zero, as it
217+
/// can not divide by zero.
218+
pub fn with_failure_threshold_duration(
219+
self,
220+
failure_threshold_duration: Duration,
221+
) -> Result<Self, Error> {
222+
ensure!(self.period.as_nanos() != 0, PeriodIsZeroSnafu);
223+
224+
// SAFETY: Period is checked above to be non-zero
192225
let failure_threshold = failure_threshold_duration.div_duration_f32(*self.period);
193-
// SAFETY: Returning an Result here would hurt the builder ergonomics and having such big
194-
// numbers does not have any real world effect.
195-
let failure_threshold = failure_threshold.ceil() as i32;
196-
self.with_failure_threshold(failure_threshold)
226+
Ok(self.with_failure_threshold(failure_threshold.ceil() as i32))
197227
}
198228

199-
pub fn build(self) -> Probe {
229+
pub fn build(self) -> Result<Probe, Error> {
200230
let mut probe = Probe {
201231
exec: None,
202232
failure_threshold: Some(self.failure_threshold),
203233
grpc: None,
204234
http_get: None,
205-
initial_delay_seconds: Some(
206-
self.initial_delay
207-
.as_secs()
208-
.try_into()
209-
.expect("TODO Error handling"),
210-
),
211-
period_seconds: Some(
212-
self.period
213-
.as_secs()
214-
.try_into()
215-
.expect("TODO Error handling"),
216-
),
235+
initial_delay_seconds: Some(self.initial_delay.as_secs().try_into().context(
236+
DurationTooLongSnafu {
237+
field: "initialDelay",
238+
duration: self.initial_delay,
239+
},
240+
)?),
241+
period_seconds: Some(self.period.as_secs().try_into().context(
242+
DurationTooLongSnafu {
243+
field: "period",
244+
duration: self.period,
245+
},
246+
)?),
217247
success_threshold: Some(self.success_threshold),
218248
tcp_socket: None,
219249
termination_grace_period_seconds: Some(
220-
self.termination_grace_period
221-
.as_secs()
222-
.try_into()
223-
.expect("TODO Error handling"),
224-
),
225-
timeout_seconds: Some(
226-
self.timeout
227-
.as_secs()
228-
.try_into()
229-
.expect("TODO Error handling"),
250+
self.termination_grace_period.as_secs().try_into().context(
251+
DurationTooLongSnafu {
252+
field: "terminationGracePeriod",
253+
duration: self.termination_grace_period,
254+
},
255+
)?,
230256
),
257+
timeout_seconds: Some(self.timeout.as_secs().try_into().context(
258+
DurationTooLongSnafu {
259+
field: "timeout",
260+
duration: self.timeout,
261+
},
262+
)?),
231263
};
232264

233265
match self.action {
@@ -237,7 +269,7 @@ impl ProbeBuilder<ProbeAction, Duration> {
237269
ProbeAction::TcpSocket(tcp_socket_action) => probe.tcp_socket = Some(tcp_socket_action),
238270
}
239271

240-
probe
272+
Ok(probe)
241273
}
242274
}
243275

@@ -250,7 +282,8 @@ mod tests {
250282
let probe = ProbeBuilder::default()
251283
.with_http_get_action_helper(8080, None, None)
252284
.with_period(Duration::from_secs(10))
253-
.build();
285+
.build()
286+
.expect("Valid inputs must produce a Probe");
254287

255288
assert_eq!(
256289
probe.http_get,
@@ -269,10 +302,12 @@ mod tests {
269302
.with_period(Duration::from_secs(5))
270303
.with_success_threshold(2)
271304
.with_failure_threshold_duration(Duration::from_secs(33))
305+
.expect("The period is always non-zero")
272306
.with_timeout(Duration::from_secs(3))
273307
.with_initial_delay(Duration::from_secs(7))
274308
.with_termination_grace_period(Duration::from_secs(4))
275-
.build();
309+
.build()
310+
.expect("Valid inputs must produce a Probe");
276311

277312
assert_eq!(
278313
probe,

0 commit comments

Comments
 (0)