Skip to content
Draft
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
474 changes: 241 additions & 233 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ product-config = { git = "https://github.com/stackabletech/product-config.git",
arc-swap = "1.7.0"
async-trait = "0.1.89"
axum = { version = "0.8.1", features = ["http2"] }
chrono = { version = "0.4.38", default-features = false }
clap = { version = "4.5.17", features = ["derive", "cargo", "env"] }
const_format = "0.2.33"
const-oid = { version = "0.9.6", features = ["db"] }
Expand All @@ -30,17 +29,17 @@ futures-util = "0.3.30"
http = "1.3.1"
indexmap = "2.5.0"
indoc = "2.0.6"
jiff = "0.2.18"
insta = { version = "1.40", features = ["glob"] }
hyper = { version = "1.4.1", features = ["full"] }
hyper-util = "0.1.8"
itertools = "0.14.0"
json-patch = "4.0.0"
# k8s-openapi 0.26.1 doesn't play well with our kube version: https://github.com/kube-rs/kube/issues/1869
k8s-openapi = { version = "=0.26.0", default-features = false, features = ["schemars", "v1_34"] }
k8s-openapi = { version = "0.27.0", default-features = false, features = ["schemars", "v1_35"] }
# We use rustls instead of openssl for easier portability, e.g. so that we can build stackablectl without the need to vendor (build from source) openssl
# We use ring instead of aws-lc-rs, as this currently fails to build in "make run-dev"
# We pin the kube version, as we use a patch for 2.0.1
kube = { git = "https://github.com/stackabletech/kube-rs", branch = "2.0.1-fix-schema-hoisting", version = "=2.0.1", default-features = false, features = ["client", "jsonpatch", "runtime", "derive", "admission", "rustls-tls", "ring"] }
kube = { version = "3.0.0", default-features = false, features = ["client", "jsonpatch", "runtime", "derive", "admission", "rustls-tls", "ring"] }
opentelemetry = "0.31.0"
opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio"] }
opentelemetry-appender-tracing = "0.31.0"
Expand Down
4 changes: 2 additions & 2 deletions crates/stackable-operator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ webhook = ["dep:stackable-webhook"]
[dependencies]
stackable-certs = { path = "../stackable-certs", optional = true }
stackable-operator-derive = { path = "../stackable-operator-derive" }
stackable-shared = { path = "../stackable-shared", features = ["chrono", "time"] }
stackable-shared = { path = "../stackable-shared", features = ["time", "jiff"] }
stackable-telemetry = { path = "../stackable-telemetry", optional = true, features = ["clap"] }
stackable-versioned = { path = "../stackable-versioned", optional = true }
stackable-webhook = { path = "../stackable-webhook", optional = true }

chrono.workspace = true
clap.workspace = true
const_format.workspace = true
delegate.workspace = true
Expand All @@ -36,6 +35,7 @@ educe.workspace = true
futures.workspace = true
http.workspace = true
indexmap.workspace = true
jiff.workspace = true
json-patch.workspace = true
k8s-openapi.workspace = true
kube.workspace = true
Expand Down
1 change: 1 addition & 0 deletions crates/stackable-operator/crds/AuthenticationClass.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ spec:
intended to be used (via the `.well-known` discovery).
enum:
- Keycloak
- null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably also check this against an operator to make sure no other breaking changes happen.

nullable: true
type: string
rootPath:
Expand Down
922 changes: 786 additions & 136 deletions crates/stackable-operator/crds/DummyCluster.yaml

Large diffs are not rendered by default.

37 changes: 27 additions & 10 deletions crates/stackable-operator/crds/ListenerClass.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,35 @@ spec:
description: Annotations that should be added to the Service object.
type: object
serviceExternalTrafficPolicy:
anyOf:
- description: |-
Service Internal Traffic Policy enables internal traffic restrictions to only route internal
traffic to endpoints within the node the traffic originated from. The "internal" traffic
here refers to traffic originated from Pods in the current cluster. This can help to reduce
costs and improve performance. See [Kubernetes docs][k8s-docs].

[k8s-docs]: https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/
enum:
- Cluster
- Local
type: string
- enum:
- null
nullable: true
description: |-
Service Internal Traffic Policy enables internal traffic restrictions to only route internal
traffic to endpoints within the node the traffic originated from. The "internal" traffic
here refers to traffic originated from Pods in the current cluster. This can help to reduce
costs and improve performance. See [Kubernetes docs][k8s-docs].
`externalTrafficPolicy` that should be set on the created Service objects.

[k8s-docs]: https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/
enum:
- Cluster
- Local
nullable: true
type: string
It is a Kubernetes feature that controls how external traffic is routed to a Kubernetes
Service.

* `Cluster`: Kubernetes default. Traffic is routed to any node in the Kubernetes cluster that
has a pod running the service.
* `Local`: Traffic is only routed to pods running on the same node as the Service.

The `Local` mode has better performance as it avoids a network hop, but requires a more
sophisticated LoadBalancer, that respects what Pods run on which nodes and routes traffic only
to these nodes accordingly. Some cloud providers or bare metal installations do not implement
some of the required features.
serviceType:
description: The method used to access the services.
enum:
Expand Down
4 changes: 2 additions & 2 deletions crates/stackable-operator/src/builder/event.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use chrono::Utc;
use k8s_openapi::{
api::core::v1::{Event, EventSource, ObjectReference},
apimachinery::pkg::apis::meta::v1::{MicroTime, ObjectMeta, Time},
jiff::Timestamp,
};
use kube::{Resource, ResourceExt};

Expand Down Expand Up @@ -91,7 +91,7 @@ impl EventBuilder {
}

pub fn build(&self) -> Event {
let time = Utc::now();
let time = Timestamp::now();

let source = Some(EventSource {
component: self.reporting_component.clone(),
Expand Down
6 changes: 3 additions & 3 deletions crates/stackable-operator/src/cluster_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use k8s_openapi::{
},
apimachinery::pkg::apis::meta::v1::{LabelSelector, LabelSelectorRequirement},
};
use kube::{Resource, ResourceExt, core::ErrorResponse};
use kube::{Resource, ResourceExt};
use serde::{Serialize, de::DeserializeOwned};
use snafu::{OptionExt, ResultExt, Snafu};
use strum::Display;
Expand Down Expand Up @@ -744,8 +744,8 @@ impl<'a> ClusterResources<'a> {
Ok(())
}
Err(crate::client::Error::ListResources {
source: kube::Error::Api(ErrorResponse { code: 403, .. }),
}) => {
source: kube::Error::Api(s),
}) if s.is_forbidden() => {
debug!(
"Skipping deletion of orphaned {} because the operator is not allowed to list \
them and is therefore probably not in charge of them.",
Expand Down
34 changes: 17 additions & 17 deletions crates/stackable-operator/src/eos/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use chrono::{DateTime, Utc};
use jiff::{self, Zoned};
use snafu::{ResultExt, Snafu};
use stackable_shared::time::Duration;
use tracing::{Level, instrument};
Expand Down Expand Up @@ -63,12 +63,12 @@ pub enum EndOfSupportCheckMode {
#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("failed to parse built-time"))]
ParseBuiltTime { source: chrono::ParseError },
ParseBuiltTime { source: k8s_openapi::jiff::Error },
}

pub struct EndOfSupportChecker {
built_datetime: DateTime<Utc>,
eos_datetime: DateTime<Utc>,
built_datetime: Zoned,
eos_datetime: Zoned,
interval: Duration,
disabled: bool,
}
Expand All @@ -92,15 +92,13 @@ impl EndOfSupportChecker {
// Parse the built-time from the RFC2822-encoded string when this is compiled as a release
// build. If this is a debug/dev build, use the current datetime instead.
let built_datetime = if cfg!(debug_assertions) {
Utc::now()
Zoned::now()
} else {
DateTime::parse_from_rfc2822(built_time)
.context(ParseBuiltTimeSnafu)?
.to_utc()
jiff::fmt::rfc2822::parse(built_time).context(ParseBuiltTimeSnafu)?
};

// Add the support duration to the built date. This marks the end-of-support date.
let eos_datetime = built_datetime + *support_duration;
let eos_datetime = &built_datetime + *support_duration;

Ok(Self {
built_datetime,
Expand All @@ -127,12 +125,13 @@ impl EndOfSupportChecker {
// TODO: Add way to stop from the outside
// The first tick ticks immediately.
interval.tick().await;
let now = Utc::now();
let now = Zoned::now();

tracing::info_span!(
"checking end-of-support state",
eos.interval = self.interval.to_string(),
eos.now = now.to_rfc3339(),
eos.now = jiff::fmt::rfc2822::to_string(&now)
.expect("Zoned::now() can always be serialized using rfc2822::to_string"),
);

// Continue the loop and wait for the next tick to run the check again.
Expand All @@ -146,18 +145,19 @@ impl EndOfSupportChecker {

/// Emits the end-of-support warning.
#[instrument(level = Level::DEBUG, skip(self))]
fn emit_warning(&self, now: DateTime<Utc>) {
let built_datetime = self.built_datetime.to_rfc3339();
let build_age = Duration::try_from(now - self.built_datetime)
fn emit_warning(&self, now: Zoned) {
let built_datetime = jiff::fmt::rfc2822::to_string(&self.built_datetime)
.expect("The build datetime can always be serialized using rfc2822::to_string");
let build_age = Duration::try_from(&now - &self.built_datetime)
.expect("time delta of now and built datetime must not be less than 0")
.to_string();

tracing::warn!(
eos.built.datetime = built_datetime,
eos.build.age = build_age,
eos.build.age = %build_age,
"This operator version was built on {built_datetime} ({build_age} ago) and may have reached end-of-support. \
Running unsupported versions may contain security vulnerabilities. \
Please upgrade to a supported version as soon as possible."
Running unsupported versions may contain security vulnerabilities. \
Please upgrade to a supported version as soon as possible."
);
}
}
5 changes: 2 additions & 3 deletions crates/stackable-operator/src/status/condition/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ pub mod deployment;
pub mod operations;
pub mod statefulset;

use chrono::Utc;
use k8s_openapi::apimachinery::pkg::apis::meta::v1::Time;
use k8s_openapi::{apimachinery::pkg::apis::meta::v1::Time, jiff::Timestamp};
use schemars::{self, JsonSchema};
use serde::{Deserialize, Serialize};
use strum::EnumCount;
Expand Down Expand Up @@ -345,7 +344,7 @@ fn update_timestamps(
// sanity check
assert_eq!(old_condition.type_, new_condition.type_);

let now = Time(Utc::now());
let now = Time(Timestamp::now());
// No change in status -> keep "last_transition_time"
if old_condition.status == new_condition.status {
ClusterCondition {
Expand Down
6 changes: 3 additions & 3 deletions crates/stackable-shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ edition.workspace = true
repository.workspace = true

[features]
full = ["chrono", "time"]
full = ["jiff", "time"]
default = ["time"]

chrono = ["dep:chrono"]
jiff = ["dep:jiff"]
time = ["dep:time"]

[dependencies]
chrono = { workspace = true, optional = true }
jiff = { workspace = true, optional = true }
k8s-openapi.workspace = true
kube.workspace = true
schemars.workspace = true
Expand Down
18 changes: 0 additions & 18 deletions crates/stackable-shared/src/time/chrono_impl.rs

This file was deleted.

20 changes: 20 additions & 0 deletions crates/stackable-shared/src/time/jiff_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use jiff::Span;

use crate::time::Duration;

impl TryFrom<Span> for Duration {
type Error = jiff::Error;

fn try_from(value: Span) -> Result<Self, Self::Error> {
let std_duration = std::time::Duration::try_from(value)?;
Ok(Self::from(std_duration))
}
}

impl TryFrom<Duration> for Span {
type Error = jiff::Error;

fn try_from(value: Duration) -> Result<Self, Self::Error> {
Span::try_from(Into::<std::time::Duration>::into(value))
}
}
4 changes: 2 additions & 2 deletions crates/stackable-shared/src/time/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
mod duration;
mod serde_impl;

#[cfg(feature = "chrono")]
mod chrono_impl;
#[cfg(feature = "jiff")]
mod jiff_impl;

#[cfg(feature = "time")]
mod time_impl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ impl Struct {
let version_enum_ident = &spec_gen_ctx.kubernetes_idents.version;
let struct_ident = &spec_gen_ctx.kubernetes_idents.kind;

let kube_client_path = &*mod_gen_ctx.crates.kube_client;
let serde_json_path = &*mod_gen_ctx.crates.serde_json;
let kube_core_path = &*mod_gen_ctx.crates.kube_core;
let versioned_path = &*mod_gen_ctx.crates.versioned;
Expand Down Expand Up @@ -381,9 +380,10 @@ impl Struct {
#invalid_conversion_review_event

return #kube_core_path::conversion::ConversionResponse::invalid(
#kube_client_path::Status {
#kube_core_path::Status {
status: Some(#kube_core_path::response::StatusSummary::Failure),
message: err.to_string(),
metadata: None,
reason: err.to_string(),
details: None,
code: 400,
Expand All @@ -405,7 +405,7 @@ impl Struct {
// the result to success and the converted objects to the provided list.
// The below code does the same thing.
#kube_core_path::conversion::ConversionResponse {
result: #kube_client_path::Status::success(),
result: #kube_core_path::Status::success(),
types: request.types,
uid: request.uid,
converted_objects,
Expand All @@ -416,9 +416,10 @@ impl Struct {
let message = err.join_errors();

#kube_core_path::conversion::ConversionResponse {
result: #kube_client_path::Status {
result: #kube_core_path::Status {
status: Some(#kube_core_path::response::StatusSummary::Failure),
message: message.clone(),
metadata: None,
reason: message,
details: None,
code,
Expand Down
8 changes: 5 additions & 3 deletions ...ersioned-macros/tests/snapshots/[email protected]

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading