Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make VersionMatch follow upstream + configure list semantics in watcher::Config #1171

Merged
merged 14 commits into from
Apr 3, 2023
4 changes: 4 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,7 @@ name = "syn"
# waiting for pem to bump base64
# https://github.com/jcreekmore/pem-rs/blob/master/Cargo.toml#L16
name = "base64"

[[bans.skip]]
# deep in dependency tree, only dual use via dev dependency
name = "redox_syscall"
109 changes: 70 additions & 39 deletions kube-core/src/params.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,38 @@
//! A port of request parameter *Optionals from apimachinery/types.go
use std::fmt;

use crate::request::Error;
use serde::Serialize;

/// Controls how the resourceVersion parameter is applied
/// Controls how the resource version parameter is applied for list calls
///
/// Not specifying a `VersionMatch` strategy will give you different semantics
/// depending on what `resource_version`, `limit`, `continue_token` you include with the list request.
///
/// This embeds the resource version when using the `NotOlderThan` or `Exact` variants.
/// See <https://kubernetes.io/docs/reference/using-api/api-concepts/#semantics-for-get-and-list> for details.
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum VersionMatch {
/// Matches data with the latest version available in the kube-apiserver database (etcd) (quorum read required).
#[default]
MostRecent,
/// Matches data with the latest version available in the kube-apiserver cache.
Any,
/// Matches data at least as new as the provided resourceVersion.
NotOlderThan(String),
/// Matches data at the exact resourceVersion provided.
Exact(String),
}
/// Returns data at least as new as the provided resource version.
///
/// The newest available data is preferred, but any data not older than the provided resource version may be served.
/// This guarantees that the collection's resource version is not older than the requested resource version,
/// but does not make any guarantee about the resource version of any of the items in that collection.
///
/// ### Any Version
/// A degenerate, but common sub-case of `NotOlderThan` is when used together with `resource_version` "0".
///
/// It is possible for a "0" resource version request to return data at a much older resource version
/// than the client has previously observed, particularly in HA configurations, due to partitions or stale caches.
/// Clients that cannot tolerate this should not use this semantic.
NotOlderThan,

impl fmt::Display for VersionMatch {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
VersionMatch::MostRecent => write!(f, "MostRecent"),
VersionMatch::Any => write!(f, "Any"),
VersionMatch::NotOlderThan(s) => write!(f, "NotOlderThan[{}]", s),
VersionMatch::Exact(s) => write!(f, "Exact[{}]", s),
}
}
/// Return data at the exact resource version provided.
///
/// If the provided resource version is unavailable, the server responds with HTTP 410 "Gone".
/// For list requests to servers that honor the resource version Match parameter, this guarantees that the collection's
/// resource version is the same as the resource version you requested in the query string.
/// That guarantee does not apply to the resource version of any items within that collection.
///
/// Note that `Exact` cannot be used with resource version "0". For the most up-to-date list; use `Unset`.
Exact,
}

/// Common query parameters used in list/delete calls on collections
Expand Down Expand Up @@ -62,23 +65,27 @@ pub struct ListParams {
/// After listing results with a limit, a continue token can be used to fetch another page of results.
pub continue_token: Option<String>,

/// Determines how resourceVersion is applied to list calls.
/// See <https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions> for
/// details.
pub version_match: VersionMatch,
/// Determines how resourceVersion is matched applied to list calls.
pub version_match: Option<VersionMatch>,

/// An explicit resourceVersion using the given `VersionMatch` strategy
///
/// See <https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions> for details.
pub resource_version: Option<String>,
}

impl ListParams {
pub(crate) fn validate(&self) -> Result<(), Error> {
match &self.version_match {
VersionMatch::Exact(resource_version) | VersionMatch::NotOlderThan(resource_version) => {
if resource_version == "0" {
return Err(Error::Validation(
"ListParams::version_match cannot be equal to \"0\" for Exact and NotOlderThan variants.".into(),
));
}
if let Some(rv) = &self.resource_version {
if self.version_match == Some(VersionMatch::Exact) && rv == "0" {
return Err(Error::Validation(
"A non-zero resource_version is required when using an Exact match".into(),
));
}
_ => (),
} else if self.version_match.is_some() {
return Err(Error::Validation(
"A resource_version is required when using an explicit match".into(),
));
}
Ok(())
}
Expand All @@ -90,6 +97,7 @@ impl ListParams {
/// ```
/// use kube::api::ListParams;
/// let lp = ListParams::default()
/// .match_any()
/// .timeout(60)
/// .labels("kubernetes.io/lifecycle=spot");
/// ```
Expand Down Expand Up @@ -139,12 +147,35 @@ impl ListParams {
self
}

/// Sets resource version and resource version match.
/// Sets the resource version
#[must_use]
pub fn version_match(mut self, version_match: VersionMatch) -> Self {
self.version_match = version_match;
pub fn at(mut self, resource_version: &str) -> Self {
self.resource_version = Some(resource_version.into());
self
}

/// Sets an arbitary resource version match strategy
///
/// A non-default strategy such as `VersionMatch::Exact` or `VersionMatch::NotGreaterThan`
/// requires an explicit `resource_version` set to pass request validation.
#[must_use]
pub fn matching(mut self, version_match: VersionMatch) -> Self {
self.version_match = Some(version_match);
self
}

/// Use the semantic "any" resource version strategy
///
/// This is a less taxing variant of the default list, returning data at any resource version.
/// It will prefer the newest avialable resource version, but strong consistency is not required;
/// data at any resource version may be served.
/// It is possible for the request to return data at a much older resource version than the client
/// has previously observed, particularly in high availability configurations, due to partitions or stale caches.
/// Clients that cannot tolerate this should not use this semantic.
#[must_use]
pub fn match_any(self) -> Self {
self.matching(VersionMatch::NotOlderThan).at("0")
}
}

/// The validation directive to use for `fieldValidation` when using server-side apply.
Expand Down
Loading