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
6 changes: 6 additions & 0 deletions crates/stackable-operator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

- BREAKING: Add a new CLI flag/env to disabling CRD maintenance: `--disable-crd-maintenance` ([#1085]).

[#1085]: https://github.com/stackabletech/operator-rs/pull/1085

## [0.96.0] - 2025-08-25

### Added
Expand Down
12 changes: 12 additions & 0 deletions crates/stackable-operator/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ pub enum Command<Run: Args = ProductOperatorRun> {
/// operator_namespace: "stackable-operators".to_string(),
/// operator_service_name: "foo-operator".to_string(),
/// },
/// disable_crd_maintenance: false,
/// },
/// }));
/// ```
Expand Down Expand Up @@ -245,6 +246,17 @@ pub struct ProductOperatorRun {
/// Provides a specific namespace to watch (instead of watching all namespaces)
#[arg(long, env, default_value = "")]
pub watch_namespace: WatchNamespace,

/// Don't maintain the CustomResourceDefinitions (CRDs) the operator is responsible for.
///
/// Maintenance includes creating the CRD initially, adding new versions and keeping the TLS
/// certificate of webhooks up to date. Turning this off can be desirable to reduce the RBAC
/// permissions of the operator.
///
/// WARNING: If you disable CRD maintenance you are responsible for maintaining it, including,
/// but not limited to, the points above.
#[arg(long, env)]
pub disable_crd_maintenance: bool,
}

/// All the CLI arguments that all (or at least most) Stackable applications use.
Expand Down
6 changes: 6 additions & 0 deletions crates/stackable-webhook/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

- BREAKING: Support disabling CRD maintenance using a new boolean flag in `ConversionWebhookOptions` ([#1085]).

[#1085]: https://github.com/stackabletech/operator-rs/pull/1085

## [0.5.0] - 2025-08-21

### Changed
Expand Down
64 changes: 41 additions & 23 deletions crates/stackable-webhook/src/servers/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ pub struct ConversionWebhookOptions {
/// The name of the Kubernetes service which points to the operator/webhook.
pub service_name: String,

/// If the CRDs should be maintained automatically. Use the (negated) value from
/// `stackable_operator::cli::ProductOperatorRun::disable_crd_maintenance`
/// for this.
// # Because of https://github.com/rust-lang/cargo/issues/3475 we can not use a real link here
pub maintain_crds: bool,

/// The field manager used to apply Kubernetes objects, typically the operator name, e.g.
/// `airflow-operator`.
pub field_manager: String,
Expand All @@ -97,11 +103,12 @@ impl ConversionWebhookServer {
/// Creates a new conversion webhook server, which expects POST requests being made to the
/// `/convert/{crd name}` endpoint.
///
/// You need to provide two things for every CRD passed in via the `crds_and_handlers` argument:
/// You need to provide a few things for every CRD passed in via the `crds_and_handlers` argument:
///
/// 1. The CRD
/// 2. A conversion function to convert between CRD versions. Typically you would use the
/// the auto-generated `try_convert` function on CRD spec definition structs for this.
/// the auto-generated `try_convert` function on CRD spec definition structs for this.
/// 3. A [`kube::Client`] used to create/update the CRDs.
///
/// The [`ConversionWebhookServer`] takes care of reconciling the CRDs into the Kubernetes
/// cluster and takes care of adding itself as conversion webhook. This includes TLS
Expand All @@ -119,14 +126,18 @@ impl ConversionWebhookServer {
/// use stackable_operator::{
/// kube::Client,
/// crd::s3::{S3Connection, S3ConnectionVersion},
/// cli::OperatorEnvironmentOptions,
/// cli::ProductOperatorRun,
/// };
///
/// # async fn test() {
/// // Things that should already be in you operator:
/// const OPERATOR_NAME: &str = "product-operator";
/// let client = Client::try_default().await.expect("failed to create Kubernetes client");
/// let operator_environment = OperatorEnvironmentOptions::parse();
/// let ProductOperatorRun {
/// operator_environment,
/// disable_crd_maintenance,
/// ..
/// } = ProductOperatorRun::parse();
///
/// let crds_and_handlers = [
/// (
Expand All @@ -140,9 +151,10 @@ impl ConversionWebhookServer {
/// socket_addr: format!("0.0.0.0:{CONVERSION_WEBHOOK_HTTPS_PORT}")
/// .parse()
/// .expect("static address is always valid"),
/// field_manager: OPERATOR_NAME.to_owned(),
/// namespace: operator_environment.operator_namespace,
/// service_name: operator_environment.operator_service_name,
/// maintain_crds: !disable_crd_maintenance,
/// field_manager: OPERATOR_NAME.to_owned(),
/// };
///
/// // Construct the conversion webhook server
Expand Down Expand Up @@ -205,9 +217,10 @@ impl ConversionWebhookServer {

let ConversionWebhookOptions {
socket_addr,
field_manager,
namespace: operator_namespace,
service_name: operator_service_name,
maintain_crds,
field_manager,
} = &options;

// This is how Kubernetes calls us, so it decides about the naming.
Expand All @@ -233,28 +246,33 @@ impl ConversionWebhookServer {
.recv()
.await
.context(ReceiveCertificateFromChannelSnafu)?;
Self::reconcile_crds(
&client,
field_manager,
&crds,
operator_namespace,
operator_service_name,
current_cert,
)
.await
.context(ReconcileCrdsSnafu)?;

try_join!(
Self::run_webhook_server(server),
Self::run_crd_reconciliation_loop(
cert_rx,

if *maintain_crds {
Self::reconcile_crds(
&client,
field_manager,
&crds,
operator_namespace,
operator_service_name,
),
)?;
current_cert,
)
.await
.context(ReconcileCrdsSnafu)?;

try_join!(
Self::run_webhook_server(server),
Self::run_crd_reconciliation_loop(
cert_rx,
&client,
field_manager,
&crds,
operator_namespace,
operator_service_name,
),
)?;
} else {
Self::run_webhook_server(server).await?;
};

Ok(())
}
Expand Down