1+ use std:: { i32, num:: TryFromIntError } ;
2+
13use 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
69use 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 ) ]
927pub 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