Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM docker.io/rust:1.85.0-bullseye
FROM docker.io/rust:1.88.0-bullseye

ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt upgrade -y
Expand Down Expand Up @@ -41,7 +41,7 @@ RUN export K8S_VERSION="$(scurl https://dl.k8s.io/release/stable.txt)" \
RUN scurl https://raw.githubusercontent.com/rancher/k3d/main/install.sh \
| USE_SUDO=false K3D_INSTALL_DIR=$HOME/bin bash

RUN rustup component add clippy rls rust-src rustfmt
RUN rustup component add clippy rust-analysis rust-src rustfmt

# Install cargo-deny
ARG CARGO_DENY_VERSION=0.16.1
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ repository = "https://github.com/kube-rs/kube"
readme = "README.md"
license = "Apache-2.0"
edition = "2024"
rust-version = "1.85.0"
rust-version = "1.88.0"

[workspace.lints.rust]
unsafe_code = "forbid"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# kube-rs

[![Crates.io](https://img.shields.io/crates/v/kube.svg)](https://crates.io/crates/kube)
[![Rust 1.85](https://img.shields.io/badge/MSRV-1.85-dea584.svg)](https://github.com/rust-lang/rust/releases/tag/1.85.0)
[![Rust 1.88](https://img.shields.io/badge/MSRV-1.88-dea584.svg)](https://github.com/rust-lang/rust/releases/tag/1.88.0)
[![Tested against Kubernetes v1.30 and above](https://img.shields.io/badge/MK8SV-v1.30-326ce5.svg)](https://kube.rs/kubernetes-version)
[![Best Practices](https://bestpractices.coreinfrastructure.org/projects/5413/badge)](https://bestpractices.coreinfrastructure.org/projects/5413)
[![Discord chat](https://img.shields.io/discord/500028886025895936.svg?logo=discord&style=plastic)](https://discord.gg/tokio)
Expand Down
17 changes: 8 additions & 9 deletions kube-client/src/client/auth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,6 @@ impl TryFrom<&AuthInfo> for Auth {
.transpose()
.map_err(Error::MalformedTokenExpirationDate)?;


if let (Some(client_certificate_data), Some(client_key_data)) =
(status.client_certificate_data, status.client_key_data)
{
Expand Down Expand Up @@ -431,14 +430,14 @@ fn token_from_gcp_provider(provider: &AuthProviderConfig) -> Result<ProviderToke
}

// Return cached access token if it's still valid
if let Some(access_token) = provider.config.get("access-token") {
if let Some(expiry) = provider.config.get("expiry") {
let expiry_date = expiry
.parse::<DateTime<Utc>>()
.map_err(Error::MalformedTokenExpirationDate)?;
if Utc::now() + SIXTY_SEC < expiry_date {
return Ok(ProviderToken::GcpCommand(access_token.clone(), Some(expiry_date)));
}
if let Some(access_token) = provider.config.get("access-token")
&& let Some(expiry) = provider.config.get("expiry")
{
let expiry_date = expiry
.parse::<DateTime<Utc>>()
.map_err(Error::MalformedTokenExpirationDate)?;
if Utc::now() + SIXTY_SEC < expiry_date {
return Ok(ProviderToken::GcpCommand(access_token.clone(), Some(expiry_date)));
}
}

Expand Down
35 changes: 17 additions & 18 deletions kube-client/src/config/file_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,30 +359,29 @@ impl Kubeconfig {
for mut config in kubeconfig_from_yaml(&data)? {
if let Some(dir) = path.as_ref().parent() {
for named in config.clusters.iter_mut() {
if let Some(cluster) = &mut named.cluster {
if let Some(path) = &cluster.certificate_authority {
if let Some(abs_path) = to_absolute(dir, path) {
cluster.certificate_authority = Some(abs_path);
}
}
if let Some(cluster) = &mut named.cluster
&& let Some(path) = &cluster.certificate_authority
&& let Some(abs_path) = to_absolute(dir, path)
{
cluster.certificate_authority = Some(abs_path);
}
}
for named in config.auth_infos.iter_mut() {
if let Some(auth_info) = &mut named.auth_info {
if let Some(path) = &auth_info.client_certificate {
if let Some(abs_path) = to_absolute(dir, path) {
auth_info.client_certificate = Some(abs_path);
}
if let Some(path) = &auth_info.client_certificate
&& let Some(abs_path) = to_absolute(dir, path)
{
auth_info.client_certificate = Some(abs_path);
}
if let Some(path) = &auth_info.client_key {
if let Some(abs_path) = to_absolute(dir, path) {
auth_info.client_key = Some(abs_path);
}
if let Some(path) = &auth_info.client_key
&& let Some(abs_path) = to_absolute(dir, path)
{
auth_info.client_key = Some(abs_path);
}
if let Some(path) = &auth_info.token_file {
if let Some(abs_path) = to_absolute(dir, path) {
auth_info.token_file = Some(abs_path);
}
if let Some(path) = &auth_info.token_file
&& let Some(abs_path) = to_absolute(dir, path)
{
auth_info.token_file = Some(abs_path);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions kube-client/src/config/file_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ impl ConfigLoader {
AuthInfo::default()
};

if let Some(exec_config) = &mut auth_info.exec {
if exec_config.provide_cluster_info {
exec_config.cluster = Some((&cluster).try_into()?);
}
if let Some(exec_config) = &mut auth_info.exec
&& exec_config.provide_cluster_info
{
exec_config.cluster = Some((&cluster).try_into()?);
}

Ok(ConfigLoader {
Expand Down
17 changes: 8 additions & 9 deletions kube-core/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,14 @@ fn to_plural(word: &str) -> String {

// Words ending in y that are preceded by a consonant will be pluralized by
// replacing y with -ies (eg. puppies).
if word.ends_with('y') {
if let Some(c) = word.chars().nth(word.len() - 2) {
if !matches!(c, 'a' | 'e' | 'i' | 'o' | 'u') {
// Remove 'y' and add `ies`
let mut chars = word.chars();
chars.next_back();
return format!("{}ies", chars.as_str());
}
}
if word.ends_with('y')
&& let Some(c) = word.chars().nth(word.len() - 2)
&& !matches!(c, 'a' | 'e' | 'i' | 'o' | 'u')
{
// Remove 'y' and add `ies`
let mut chars = word.chars();
chars.next_back();
return format!("{}ies", chars.as_str());
}

// All other words will have "s" added to the end (eg. days).
Expand Down
28 changes: 13 additions & 15 deletions kube-core/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,19 @@ impl ListParams {
}
if let Some(continue_token) = &self.continue_token {
qp.append_pair("continue", continue_token);
} else {
// When there's a continue token, we don't want to set resourceVersion
if let Some(rv) = &self.resource_version {
if rv != "0" || self.limit.is_none() {
qp.append_pair("resourceVersion", rv.as_str());

match &self.version_match {
None => {}
Some(VersionMatch::NotOlderThan) => {
qp.append_pair("resourceVersionMatch", "NotOlderThan");
}
Some(VersionMatch::Exact) => {
qp.append_pair("resourceVersionMatch", "Exact");
}
}
} else if let Some(rv) = &self.resource_version
&& (rv != "0" || self.limit.is_none())
{
// NB: When there's a continue token, we don't want to set resourceVersion
qp.append_pair("resourceVersion", rv.as_str());

match &self.version_match {
None => {}
Some(VersionMatch::NotOlderThan) => {
qp.append_pair("resourceVersionMatch", "NotOlderThan");
}
Some(VersionMatch::Exact) => {
qp.append_pair("resourceVersionMatch", "Exact");
}
}
}
Expand Down
46 changes: 21 additions & 25 deletions kube-core/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,15 +316,14 @@ impl Transform for StructuralSchemaRewriter {

// check for maps without with properties (i.e. flattened maps)
// and allow these to persist dynamically
if let Some(object) = &mut schema.object {
if !object.properties.is_empty()
&& object.additional_properties.as_deref() == Some(&Schema::Bool(true))
{
object.additional_properties = None;
schema
.extensions
.insert("x-kubernetes-preserve-unknown-fields".into(), true.into());
}
if let Some(object) = &mut schema.object
&& !object.properties.is_empty()
&& object.additional_properties.as_deref() == Some(&Schema::Bool(true))
{
object.additional_properties = None;
schema
.extensions
.insert("x-kubernetes-preserve-unknown-fields".into(), true.into());
}

// As of version 1.30 Kubernetes does not support setting `uniqueItems` to `true`,
Expand All @@ -336,10 +335,10 @@ impl Transform for StructuralSchemaRewriter {
array.unique_items = None;
}

if let Ok(schema) = serde_json::to_value(schema) {
if let Ok(transformed) = serde_json::from_value(schema) {
*transform_schema = transformed;
}
if let Ok(schema) = serde_json::to_value(schema)
&& let Ok(transformed) = serde_json::from_value(schema)
{
*transform_schema = transformed;
}
}
}
Expand Down Expand Up @@ -432,18 +431,15 @@ fn hoist_subschema_properties(
{
let common_obj = common_obj.get_or_insert_with(Box::<ObjectValidation>::default);

if let Some(variant_metadata) = variant_metadata {
// Move enum variant description from oneOf clause to its corresponding property
if let Some(description) = std::mem::take(&mut variant_metadata.description) {
if let Some(Schema::Object(variant_object)) =
only_item(variant_obj.properties.values_mut())
{
let metadata = variant_object
.metadata
.get_or_insert_with(Box::<Metadata>::default);
metadata.description = Some(description);
}
}
// Move enum variant description from oneOf clause to its corresponding property
if let Some(variant_metadata) = variant_metadata
&& let Some(description) = std::mem::take(&mut variant_metadata.description)
&& let Some(Schema::Object(variant_object)) = only_item(variant_obj.properties.values_mut())
{
let metadata = variant_object
.metadata
.get_or_insert_with(Box::<Metadata>::default);
metadata.description = Some(description);
}

// Move all properties
Expand Down
52 changes: 24 additions & 28 deletions kube-derive/src/custom_resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,12 @@ struct KVTuple(String, String);

impl FromMeta for KVTuple {
fn from_list(items: &[darling::ast::NestedMeta]) -> darling::Result<Self> {
if items.len() == 2 {
if let (
darling::ast::NestedMeta::Lit(syn::Lit::Str(key)),
darling::ast::NestedMeta::Lit(syn::Lit::Str(value)),
) = (&items[0], &items[1])
{
return Ok(KVTuple(key.value(), value.value()));
}
if let [
darling::ast::NestedMeta::Lit(syn::Lit::Str(key)),
darling::ast::NestedMeta::Lit(syn::Lit::Str(value)),
] = items
{
return Ok(KVTuple(key.value(), value.value()));
}

Err(darling::Error::unsupported_format(
Expand Down Expand Up @@ -345,17 +343,17 @@ impl FromMeta for KubeRootMeta {
const NOT_ALLOWED_ATTRIBUTES: [&str; 3] = ["derive", "serde", "schemars"];

let meta = syn::parse_str::<Meta>(value)?;
if let Some(ident) = meta.path().get_ident() {
if NOT_ALLOWED_ATTRIBUTES.iter().any(|el| ident == el) {
if ident == "derive" {
return Err(darling::Error::custom(
r#"#[derive(CustomResource)] `kube(attr = "...")` does not support to set derives, you likely want to use `kube(derive = "...")`."#,
));
}
return Err(darling::Error::custom(format!(
r#"#[derive(CustomResource)] `kube(attr = "...")` does not support to set the attributes {NOT_ALLOWED_ATTRIBUTES:?} as they might lead to unexpected behaviour.`"#,
)));
if let Some(ident) = meta.path().get_ident()
&& NOT_ALLOWED_ATTRIBUTES.iter().any(|el| ident == el)
{
if ident == "derive" {
return Err(darling::Error::custom(
r#"#[derive(CustomResource)] `kube(attr = "...")` does not support to set derives, you likely want to use `kube(derive = "...")`."#,
));
}
return Err(darling::Error::custom(format!(
r#"#[derive(CustomResource)] `kube(attr = "...")` does not support to set the attributes {NOT_ALLOWED_ATTRIBUTES:?} as they might lead to unexpected behaviour.`"#,
)));
}

Ok(Self(meta))
Expand Down Expand Up @@ -909,15 +907,14 @@ fn to_plural(word: &str) -> String {

// Words ending in y that are preceded by a consonant will be pluralized by
// replacing y with -ies (eg. puppies).
if word.ends_with('y') {
if let Some(c) = word.chars().nth(word.len() - 2) {
if !matches!(c, 'a' | 'e' | 'i' | 'o' | 'u') {
// Remove 'y' and add `ies`
let mut chars = word.chars();
chars.next_back();
return format!("{}ies", chars.as_str());
}
}
if word.ends_with('y')
&& let Some(c) = word.chars().nth(word.len() - 2)
&& !matches!(c, 'a' | 'e' | 'i' | 'o' | 'u')
{
// Remove 'y' and add `ies`
let mut chars = word.chars();
chars.next_back();
return format!("{}ies", chars.as_str());
}

// All other words will have "s" added to the end (eg. days).
Expand Down Expand Up @@ -974,7 +971,6 @@ mod tests {
}
}


#[test]
fn test_derive_crd() {
let path = env::current_dir().unwrap().join("tests").join("crd_enum_test.rs");
Expand Down
18 changes: 9 additions & 9 deletions kube-runtime/src/utils/backoff_reset_timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ impl<B: Backoff> Iterator for ResetTimerBackoff<B> {
type Item = Duration;

fn next(&mut self) -> Option<Duration> {
if let Some(last_backoff) = self.last_backoff {
if tokio::time::Instant::now().into_std() > last_backoff + self.reset_duration {
tracing::debug!(
?last_backoff,
reset_duration = ?self.reset_duration,
"Resetting backoff, since reset duration has expired"
);
self.backoff.reset();
}
if let Some(last_backoff) = self.last_backoff
&& tokio::time::Instant::now().into_std() > last_backoff + self.reset_duration
{
tracing::debug!(
?last_backoff,
reset_duration = ?self.reset_duration,
"Resetting backoff, since reset duration has expired"
);
self.backoff.reset();
}
self.last_backoff = Some(tokio::time::Instant::now().into_std());
self.backoff.next()
Expand Down
Loading
Loading