From cbc089cdea211be6647988fedea6c6ff5a814541 Mon Sep 17 00:00:00 2001 From: Siegfried Weber Date: Thu, 29 Oct 2026 15:15:39 +0100 Subject: [PATCH] fix: Keep the "none" version label on unversioned role-group resources --- CHANGELOG.md | 8 ++--- .../src/controller/build/mod.rs | 29 ++++++++++++++++--- .../controller/build/resource/statefulset.rs | 3 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18f9d52f..5772aa92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,11 +34,8 @@ the logger as well, because a logger discards records before any handler can filter them, so in that direction the UI and the other destinations open up together and cannot be set apart ([#829]). -- BREAKING: Remove the `app.kubernetes.io/component` and `app.kubernetes.io/role-group` labels - from the resources they don't apply to (previously set to `none` or a placeholder value). - StatefulSets created by older operator versions cannot be updated in place: after the - operator upgrade, delete each StatefulSet so that the operator immediately recreates it with - the new labels ([#838]). +- Remove the `app.kubernetes.io/component` and `app.kubernetes.io/role-group` labels from the + resources they don't apply to ([#838], [#887]). - All product containers now run with `securityContext.runAsNonRoot` set to `true` to improve security ([#840]). - `envOverrides` names are now validated by the shared `EnvVarName` type rather than by operator-specific validation code ([#838]). @@ -105,6 +102,7 @@ [#884]: https://github.com/stackabletech/airflow-operator/pull/884 [#885]: https://github.com/stackabletech/airflow-operator/pull/885 [#886]: https://github.com/stackabletech/airflow-operator/pull/886 +[#887]: https://github.com/stackabletech/airflow-operator/pull/887 ## [26.7.0] - 2026-07-21 diff --git a/rust/operator-binary/src/controller/build/mod.rs b/rust/operator-binary/src/controller/build/mod.rs index c5496183..8ef128cc 100644 --- a/rust/operator-binary/src/controller/build/mod.rs +++ b/rust/operator-binary/src/controller/build/mod.rs @@ -1,6 +1,6 @@ //! Builders that assemble Kubernetes resources from the validated cluster. -use std::marker::PhantomData; +use std::{marker::PhantomData, str::FromStr}; use snafu::{ResultExt, Snafu}; use stackable_operator::{ @@ -9,7 +9,7 @@ use stackable_operator::{ v2::{ builder::meta::ownerreference_from_resource, kvp::label, - types::operator::{RoleGroupName, RoleName}, + types::operator::{ProductVersion, RoleGroupName, RoleName}, }, }; @@ -36,6 +36,10 @@ pub mod properties; pub mod resource; pub mod volumes; +// Placeholder value for the `app.kubernetes.io/version` label on resources whose labels are +// immutable once deployed. See `recommended_labels_for_unversioned_role_group_resources`. +stackable_operator::constant!(UNVERSIONED_PRODUCT_VERSION: ProductVersion = "none"); + #[derive(Snafu, Debug)] pub enum Error { #[snafu(display("failed to build ConfigMap for role group {role_group}"))] @@ -242,14 +246,25 @@ pub(crate) fn recommended_labels_for_role_group_resources( ) } +/// The recommended labels for role-group resources that carry no product version. +/// +/// The `app.kubernetes.io/version` label is set to the placeholder `none` rather than being +/// omitted, because that is what operator versions up to 26.7 wrote. Omitting it would change the +/// `volumeClaimTemplates` of already deployed StatefulSets, and since those templates are +/// immutable, Kubernetes rejects the update and the operator can no longer reconcile the +/// StatefulSet. +/// +/// This is also why `label::recommended_labels_for_unversioned_role_group_resources`, which drops +/// the label entirely, is not used here. pub(crate) fn recommended_labels_for_unversioned_role_group_resources( cluster: &ValidatedCluster, role_name: &RoleName, role_group_name: &RoleGroupName, ) -> Labels { - label::recommended_labels_for_unversioned_role_group_resources( + label::recommended_labels_for_role_group_resources( &cluster.name, &PRODUCT_NAME, + &UNVERSIONED_PRODUCT_VERSION, &OPERATOR_NAME, &CONTROLLER_NAME, role_name, @@ -420,7 +435,7 @@ mod tests { use stackable_operator::kube::Resource; use super::{ - build, + UNVERSIONED_PRODUCT_VERSION, build, test_support::{ app_version_label, celery_executor_cluster, cluster_with_trusted_proxies, kubernetes_executor_cluster, validated_cluster_with, @@ -428,6 +443,12 @@ mod tests { }; use crate::controller::ValidatedCluster; + #[test] + fn test_constants() { + // Test that dereferencing the constant does not panic. + let _ = *UNVERSIONED_PRODUCT_VERSION; + } + fn sorted_names(resources: &[impl Resource]) -> Vec<&str> { let mut names: Vec<&str> = resources .iter() diff --git a/rust/operator-binary/src/controller/build/resource/statefulset.rs b/rust/operator-binary/src/controller/build/resource/statefulset.rs index c6b3cedb..012632f6 100644 --- a/rust/operator-binary/src/controller/build/resource/statefulset.rs +++ b/rust/operator-binary/src/controller/build/resource/statefulset.rs @@ -123,8 +123,7 @@ pub fn build_server_rolegroup_statefulset( airflow_role, role_group_name, ); - // Used for PVC templates, which cannot be modified once they are deployed. The version label - // is omitted so the labels stay stable across version upgrades. + // The PVC template is immutable once deployed, so its labels must stay stable. let unversioned_recommended_labels = recommended_labels_for_unversioned_role_group_resources( validated_cluster, airflow_role,