From ac55ac6a561a278f35f63eabc7303402dd9a0f0d Mon Sep 17 00:00:00 2001 From: Siegfried Weber Date: Fri, 30 Oct 2026 17:26:49 +0100 Subject: [PATCH] fix: Keep the "none" version label on unversioned role-group resources --- CHANGELOG.md | 9 +++--- .../src/zk_controller/build.rs | 29 ++++++++++++++++--- .../build/resource/statefulset.rs | 3 +- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 947a3ecf..e1d2ca4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,11 +29,9 @@ All notable changes to this project will be documented in this file. - The discovery ConfigMap is now always written, with empty `ZOOKEEPER` and `ZOOKEEPER_HOSTS` while the listener publishes no addresses ([#1069]). - All product containers now run with `securityContext.runAsNonRoot` set to `true` to improve security ([#1070]). -- 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 the placeholder value - `discovery`). - Server StatefulSets created by older operator versions cannot be updated in place: after the operator - upgrade, delete each server StatefulSet so that the operator immediately recreates it with the new labels ([#1077]). +- 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 the placeholder value `discovery`) + ([#1077], [#1102]). - Environment variable overrides (`envOverrides`) are now merged into the operator-set environment variables by name, so an override replaces the operator's value instead of producing a duplicated entry whose precedence depended on Kubernetes' duplicate-name @@ -69,6 +67,7 @@ All notable changes to this project will be documented in this file. [#1099]: https://github.com/stackabletech/zookeeper-operator/pull/1099 [#1100]: https://github.com/stackabletech/zookeeper-operator/pull/1100 [#1101]: https://github.com/stackabletech/zookeeper-operator/pull/1101 +[#1102]: https://github.com/stackabletech/zookeeper-operator/pull/1102 ## [26.7.0] - 2026-07-21 diff --git a/rust/operator-binary/src/zk_controller/build.rs b/rust/operator-binary/src/zk_controller/build.rs index 3db050d5..1f8b837c 100644 --- a/rust/operator-binary/src/zk_controller/build.rs +++ b/rust/operator-binary/src/zk_controller/build.rs @@ -9,7 +9,7 @@ //! remaining submodules ([`command`], [`graceful_shutdown`], [`jvm`], //! [`properties`]) produce fragments that those resource builders assemble. -use std::marker::PhantomData; +use std::{marker::PhantomData, str::FromStr}; use snafu::{ResultExt, Snafu}; use stackable_operator::{ @@ -19,7 +19,7 @@ use stackable_operator::{ v2::{ builder::meta::ownerreference_from_resource, kvp::label, - types::operator::{RoleGroupName, RoleName}, + types::operator::{ProductVersion, RoleGroupName, RoleName}, }, }; @@ -48,6 +48,10 @@ pub mod jvm; pub mod properties; pub mod resource; +// 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 {rolegroup}"))] @@ -211,14 +215,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, @@ -239,7 +254,7 @@ pub(crate) fn role_group_selector( mod tests { use stackable_operator::kube::Resource; - use super::build; + use super::{UNVERSIONED_PRODUCT_VERSION, build}; use crate::zk_controller::test_support::{cluster_info, minimal_zk, validated_cluster}; /// Collects the `.metadata.name`s of the given resources, sorted for stable comparison. @@ -252,6 +267,12 @@ mod tests { names } + #[test] + fn test_constants() { + // Test that dereferencing the constant does not panic. + let _ = *UNVERSIONED_PRODUCT_VERSION; + } + #[test] fn build_produces_expected_resource_names() { let zookeeper_yaml = r#" diff --git a/rust/operator-binary/src/zk_controller/build/resource/statefulset.rs b/rust/operator-binary/src/zk_controller/build/resource/statefulset.rs index a6ab55f8..11c8d09e 100644 --- a/rust/operator-binary/src/zk_controller/build/resource/statefulset.rs +++ b/rust/operator-binary/src/zk_controller/build/resource/statefulset.rs @@ -205,8 +205,7 @@ pub fn build_server_rolegroup_statefulset( let mut cb_zookeeper = new_container_builder(&ZOOKEEPER_CONTAINER_NAME); let mut pod_builder = PodBuilder::new(); - // 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(cluster, zk_role, role_group_name);