diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b5817e5..ae18c75a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,11 +42,8 @@ All notable changes to this project will be documented in this file. 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 handling ([#1011]). -- 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). - Broker StatefulSets created by older operator versions cannot be updated in place: after the - operator upgrade, delete each broker StatefulSet so that the operator immediately recreates it - with the new labels ([#1011]). +- Remove the `app.kubernetes.io/component` and `app.kubernetes.io/role-group` labels from the + resources they don't apply to ([#1011], [#1052]). - Make operations infallible where dependent on static inputs ([#1017]). - Internal operator refactoring: build each role group through per-role modules (brokers, controllers) and a shared role group builder, with the broker and controller configuration held @@ -103,6 +100,7 @@ All notable changes to this project will be documented in this file. [#1046]: https://github.com/stackabletech/kafka-operator/pull/1046 [#1047]: https://github.com/stackabletech/kafka-operator/pull/1047 [#1049]: https://github.com/stackabletech/kafka-operator/pull/1049 +[#1052]: https://github.com/stackabletech/kafka-operator/pull/1052 ## [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 33775c00..9a17d584 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 for kafka rolegroups. -use std::marker::PhantomData; +use std::{marker::PhantomData, str::FromStr}; use snafu::{ResultExt, Snafu}; use stackable_operator::{ @@ -10,7 +10,7 @@ use stackable_operator::{ policy::v1::PodDisruptionBudget, }, kvp::Labels, - v2::kvp::label, + v2::{kvp::label, types::operator::ProductVersion}, }; use strum::IntoEnumIterator; @@ -40,6 +40,10 @@ pub mod resource; pub mod role_group; pub mod security; +// 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 broker role group {role_group}"))] @@ -195,14 +199,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, @@ -231,7 +246,7 @@ mod tests { use strum::IntoEnumIterator; use super::{ - build, + UNVERSIONED_PRODUCT_VERSION, build, kerberos::KERBEROS_VOLUME_NAME, properties::ConfigFileName, role_group::controller::QUORUM_MANAGER_CONTAINER_NAME, @@ -452,6 +467,12 @@ mod tests { ) } + #[test] + fn test_constants() { + // Test that dereferencing the constant does not panic. + let _ = *UNVERSIONED_PRODUCT_VERSION; + } + #[test] fn build_succeeds_when_every_kraft_role_group_is_scaled_to_zero() { let kafka = minimal_kafka( diff --git a/rust/operator-binary/src/controller/build/role_group/broker.rs b/rust/operator-binary/src/controller/build/role_group/broker.rs index 10ea1abb..7b840aad 100644 --- a/rust/operator-binary/src/controller/build/role_group/broker.rs +++ b/rust/operator-binary/src/controller/build/role_group/broker.rs @@ -196,8 +196,7 @@ fn volume_claim_templates( role_group_name: &RoleGroupName, config: &ValidatedBrokerConfig, ) -> Vec { - // 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 templates are immutable once deployed, so their labels must stay stable. let unversioned_recommended_labels = recommended_labels_for_unversioned_role_group_resources(cluster, &ROLE, role_group_name);