From 8550c24587f0da4e3d5678680a461ad26c0fd36e Mon Sep 17 00:00:00 2001 From: Techassi Date: Tue, 10 Mar 2026 12:26:34 +0100 Subject: [PATCH 1/3] feat(operator): Add CRD established signal This function can be used to wait for a CRD to be established. This is useful to delay the startup of operators until this is supported by upstream kube. --- crates/stackable-operator/src/utils/signal.rs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/crates/stackable-operator/src/utils/signal.rs b/crates/stackable-operator/src/utils/signal.rs index 59c68e17f..e4b9be5d2 100644 --- a/crates/stackable-operator/src/utils/signal.rs +++ b/crates/stackable-operator/src/utils/signal.rs @@ -1,9 +1,14 @@ +use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition; +use kube::runtime::wait; use snafu::{ResultExt, Snafu}; +use stackable_shared::time::Duration; use tokio::{ signal::unix::{SignalKind, signal}, sync::watch, }; +use crate::client::Client; + #[derive(Debug, Snafu)] #[snafu(display("failed to construct signal watcher"))] pub struct SignalError { @@ -71,3 +76,46 @@ impl SignalWatcher<()> { Ok(Self { watch_rx }) } } + +pub const DEFAULT_CRD_ESTABLISHED_TIMEOUT: Duration = Duration::from_secs(5); + +#[derive(Debug, Snafu)] +pub enum CrdEstablishedError { + #[snafu(display("failed to meet CRD established condition before the timeout elapsed"))] + TimeoutElapsed { source: tokio::time::error::Elapsed }, + + #[snafu(display("failed to await CRD established condition due to api error"))] + Api { source: kube::runtime::wait::Error }, +} + +/// Waits for a CRD named `crd_name` to be established before `timeout_duration` (or by default +/// [`DEFAULT_CRD_ESTABLISHED_TIMEOUT`]) is elapsed. +/// +/// The same caveats from [`conditions::is_crd_established`](wait::conditions::is_crd_established) +/// apply here as well. +/// +/// ### Errors +/// +/// This function returns errors either if the timeout elapsed without the condition being met or +/// when the underlying API returned errors (CRD is unknown to the Kubernetes API server or due to +/// missing permissions). +pub async fn crd_established( + client: Client, + crd_name: &str, + timeout_duration: impl Into>, +) -> Result<(), CrdEstablishedError> { + let api: kube::Api = client.get_api(&()); + let crd_established = + wait::await_condition(api, crd_name, wait::conditions::is_crd_established()); + let _ = tokio::time::timeout( + *timeout_duration + .into() + .unwrap_or(DEFAULT_CRD_ESTABLISHED_TIMEOUT), + crd_established, + ) + .await + .context(TimeoutElapsedSnafu)? + .context(ApiSnafu)?; + + Ok(()) +} From 736e2022398fc2b9d5bdda5c8f3e4aeb0ebea4c5 Mon Sep 17 00:00:00 2001 From: Techassi Date: Tue, 10 Mar 2026 12:38:00 +0100 Subject: [PATCH 2/3] chore: Add changelog entry --- crates/stackable-operator/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/stackable-operator/CHANGELOG.md b/crates/stackable-operator/CHANGELOG.md index 7d7346a6b..55fa43aec 100644 --- a/crates/stackable-operator/CHANGELOG.md +++ b/crates/stackable-operator/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added + +- Add CRD established signal/helper ([#1167]). + +[#1167]: https://github.com/stackabletech/operator-rs/pull/1167 + ## [0.107.0] - 2026-03-09 ### Added From b5eed96b750acf4a03ad1f727a3af2e8b18d32e8 Mon Sep 17 00:00:00 2001 From: Techassi Date: Tue, 10 Mar 2026 12:46:33 +0100 Subject: [PATCH 3/3] refactor: Pass client by reference --- crates/stackable-operator/src/utils/signal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stackable-operator/src/utils/signal.rs b/crates/stackable-operator/src/utils/signal.rs index e4b9be5d2..135952426 100644 --- a/crates/stackable-operator/src/utils/signal.rs +++ b/crates/stackable-operator/src/utils/signal.rs @@ -100,7 +100,7 @@ pub enum CrdEstablishedError { /// when the underlying API returned errors (CRD is unknown to the Kubernetes API server or due to /// missing permissions). pub async fn crd_established( - client: Client, + client: &Client, crd_name: &str, timeout_duration: impl Into>, ) -> Result<(), CrdEstablishedError> {