Skip to content

Commit

Permalink
Try defining runtime Condition in terms of option functions
Browse files Browse the repository at this point in the history
Takes advantage of `?` on `Option` to allow simpler `Condition` impls.

Not a huge change internally, but it is a breaking change.

Signed-off-by: clux <[email protected]>
  • Loading branch information
clux committed May 22, 2024
1 parent c30ce34 commit a06ed2c
Showing 1 changed file with 42 additions and 51 deletions.
93 changes: 42 additions & 51 deletions kube-runtime/src/wait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use thiserror::Error;

use crate::watcher::{self, watch_object};

/// Wait errors from [`await_condition`]
#[derive(Debug, Error)]
pub enum Error {
#[error("failed to probe for whether the condition is fulfilled yet: {0}")]
Expand Down Expand Up @@ -79,21 +80,18 @@ where
/// use k8s_openapi::api::core::v1::Pod;
/// fn my_custom_condition(my_cond: &str) -> impl Condition<Pod> + '_ {
/// move |obj: Option<&Pod>| {
/// if let Some(pod) = &obj {
/// if let Some(status) = &pod.status {
/// if let Some(conds) = &status.conditions {
/// if let Some(pcond) = conds.iter().find(|c| c.type_ == my_cond) {
/// return pcond.status == "True";
/// }
/// }
/// }
/// }
/// false
/// let cond = obj.status.as_ref()?.conditions.as_ref()?.iter().find(|c| c.type_ == my_cond);
/// Some(cond.status == "True")
/// }
/// }
/// ```
pub trait Condition<K> {
fn matches_object(&self, obj: Option<&K>) -> bool;
/// Condition function giving a clear answer
fn matches_object(&self, obj: Option<&K>) -> bool {
self.matches_object_option(obj).unwrap_or_default()
}
/// Condition function giving an option wrapped answer
fn matches_object_option(&self, _obj: Option<&K>) -> Option<bool>;

/// Returns a `Condition` that holds if `self` does not
///
Expand Down Expand Up @@ -153,8 +151,13 @@ pub trait Condition<K> {
}
}

impl<K, F: Fn(Option<&K>) -> bool> Condition<K> for F {
fn matches_object(&self, obj: Option<&K>) -> bool {
//impl<K, F: Fn(Option<&K>) -> bool> Condition<K> for F {
// fn matches_object(&self, obj: Option<&K>) -> bool {
// (self)(obj)
// }
//}
impl<K, F: Fn(Option<&K>) -> Option<bool>> Condition<K> for F {
fn matches_object_option(&self, obj: Option<&K>) -> Option<bool> {
(self)(obj)
}
}
Expand All @@ -176,12 +179,12 @@ pub mod conditions {
#[must_use]
pub fn is_deleted<K: Resource>(uid: &str) -> impl Condition<K> + '_ {
move |obj: Option<&K>| {
obj.map_or(
Some(obj.map_or(
// Object is not found, success!
true,
// Object is found, but a changed uid would mean that it was deleted and recreated
|obj| obj.meta().uid.as_deref() != Some(uid),
)
))
}
}

Expand All @@ -192,57 +195,45 @@ pub mod conditions {
#[must_use]
pub fn is_crd_established() -> impl Condition<CustomResourceDefinition> {
|obj: Option<&CustomResourceDefinition>| {
if let Some(o) = obj {
if let Some(s) = &o.status {
if let Some(conds) = &s.conditions {
if let Some(pcond) = conds.iter().find(|c| c.type_ == "Established") {
return pcond.status == "True";
}
}
}
}
false
let cond = obj
.as_ref()?
.status
.as_ref()?
.conditions
.as_ref()?
.iter()
.find(|c| c.type_ == "Established")?;
Some(cond.status == "True")
}
}

/// An await condition for `Pod` that returns `true` once it is running
#[must_use]
pub fn is_pod_running() -> impl Condition<Pod> {
|obj: Option<&Pod>| {
if let Some(pod) = &obj {
if let Some(status) = &pod.status {
if let Some(phase) = &status.phase {
return phase == "Running";
}
}
}
false
}
|obj: Option<&Pod>| Some(obj?.status.as_ref()?.phase.as_ref()? == "Running")
}

/// An await condition for `Job` that returns `true` once it is completed
#[must_use]
pub fn is_job_completed() -> impl Condition<Job> {
|obj: Option<&Job>| {
if let Some(job) = &obj {
if let Some(s) = &job.status {
if let Some(conds) = &s.conditions {
if let Some(pcond) = conds.iter().find(|c| c.type_ == "Complete") {
return pcond.status == "True";
}
}
}
}
false
let cond = obj?
.status
.as_ref()?
.conditions
.as_ref()?
.iter()
.find(|c| c.type_ == "Complete")?;
Some(cond.status == "True")
}
}

/// See [`Condition::not`]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Not<A>(pub(super) A);
impl<A: Condition<K>, K> Condition<K> for Not<A> {
fn matches_object(&self, obj: Option<&K>) -> bool {
!self.0.matches_object(obj)
fn matches_object_option(&self, obj: Option<&K>) -> Option<bool> {
Some(!self.0.matches_object(obj))
}
}

Expand All @@ -254,8 +245,8 @@ pub mod conditions {
A: Condition<K>,
B: Condition<K>,
{
fn matches_object(&self, obj: Option<&K>) -> bool {
self.0.matches_object(obj) && self.1.matches_object(obj)
fn matches_object_option(&self, obj: Option<&K>) -> Option<bool> {
Some(self.0.matches_object(obj) && self.1.matches_object(obj))
}
}

Expand All @@ -267,8 +258,8 @@ pub mod conditions {
A: Condition<K>,
B: Condition<K>,
{
fn matches_object(&self, obj: Option<&K>) -> bool {
self.0.matches_object(obj) || self.1.matches_object(obj)
fn matches_object_option(&self, obj: Option<&K>) -> Option<bool> {
Some(self.0.matches_object(obj) || self.1.matches_object(obj))
}
}
}
Expand Down

0 comments on commit a06ed2c

Please sign in to comment.