diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d3a1113..9cd9e784 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,10 +12,14 @@ All notable changes to this project will be documented in this file. functions and carry the full set of recommended labels ([#731]). - BREAKING: The `metastore` role is now required by the CRD; a HiveCluster without it was previously accepted by the API server but failed reconciliation ([#731]). -- Bump stackable-operator to 0.114.0 ([#735]). +- Bump stackable-operator to 0.116.0 ([#735], [#748]). - The reconciler now applies resources and derives the cluster status in discrete apply and update_status steps ([#737]). - All product containers now run with `securityContext.runAsNonRoot` set to `true` to improve security ([#741]). +- `envOverrides` names are now validated by the shared `EnvVarName` type rather than by + operator-specific validation code ([#748]). +- 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) ([#748]). ### Fixed @@ -31,6 +35,7 @@ All notable changes to this project will be documented in this file. [#736]: https://github.com/stackabletech/hive-operator/pull/736 [#737]: https://github.com/stackabletech/hive-operator/pull/737 [#741]: https://github.com/stackabletech/hive-operator/pull/741 +[#748]: https://github.com/stackabletech/hive-operator/pull/748 ## [26.7.0] - 2026-07-21 diff --git a/Cargo.lock b/Cargo.lock index 2c007571..66847b82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1714,7 +1714,7 @@ dependencies = [ [[package]] name = "k8s-version" version = "0.1.3" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "darling 0.24.0", "regex", @@ -3155,7 +3155,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stackable-certs" version = "0.4.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "const-oid", "ecdsa", @@ -3202,8 +3202,8 @@ dependencies = [ [[package]] name = "stackable-operator" -version = "0.115.0" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +version = "0.116.0" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "base64 0.23.1", "clap", @@ -3247,7 +3247,7 @@ dependencies = [ [[package]] name = "stackable-operator-derive" version = "0.3.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "darling 0.24.0", "proc-macro2", @@ -3258,7 +3258,7 @@ dependencies = [ [[package]] name = "stackable-shared" version = "0.1.2" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "jiff", "k8s-openapi", @@ -3275,7 +3275,7 @@ dependencies = [ [[package]] name = "stackable-telemetry" version = "0.6.5" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "axum", "clap", @@ -3299,7 +3299,7 @@ dependencies = [ [[package]] name = "stackable-versioned" version = "0.11.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "kube", "schemars", @@ -3313,7 +3313,7 @@ dependencies = [ [[package]] name = "stackable-versioned-macros" version = "0.11.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "convert_case", "convert_case_extras", @@ -3331,7 +3331,7 @@ dependencies = [ [[package]] name = "stackable-webhook" version = "0.9.2" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "arc-swap", "async-trait", diff --git a/Cargo.nix b/Cargo.nix index 6af6d669..6c600f85 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -5433,8 +5433,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "k8s_version"; authors = [ @@ -10331,8 +10331,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_certs"; authors = [ @@ -10530,13 +10530,13 @@ rec { }; "stackable-operator" = rec { crateName = "stackable-operator"; - version = "0.115.0"; + version = "0.116.0"; edition = "2024"; workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_operator"; authors = [ @@ -10716,7 +10716,8 @@ rec { "client-feature-gates" = [ "dep:winnow" ]; "crds" = [ "dep:stackable-versioned" ]; "default" = [ "crds" ]; - "full" = [ "client-feature-gates" "crds" "certs" "test-support" "time" "webhook" "kube-ws" ]; + "full" = [ "client-feature-gates" "crds" "certs" "test-support" "time" "webhook" "kube-ws" "kube-cel" ]; + "kube-cel" = [ "kube/cel" ]; "kube-ws" = [ "kube/ws" ]; "time" = [ "stackable-shared/time" ]; "webhook" = [ "dep:stackable-webhook" ]; @@ -10730,8 +10731,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; procMacro = true; libName = "stackable_operator_derive"; @@ -10765,8 +10766,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_shared"; authors = [ @@ -10846,8 +10847,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_telemetry"; authors = [ @@ -10956,8 +10957,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_versioned"; authors = [ @@ -11006,8 +11007,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; procMacro = true; libName = "stackable_versioned_macros"; @@ -11074,8 +11075,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_webhook"; authors = [ diff --git a/Cargo.toml b/Cargo.toml index 568ea611..f0aac06e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ edition = "2024" repository = "https://github.com/stackabletech/hive-operator" [workspace.dependencies] -stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.115.0", features = ["crds", "webhook"] } +stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.116.0", features = ["crds", "webhook"] } anyhow = "1.0" built = { version = "0.8", features = ["chrono", "git2"] } diff --git a/crate-hashes.json b/crate-hashes.json index 43cd4b72..3fae0f9f 100644 --- a/crate-hashes.json +++ b/crate-hashes.json @@ -1,11 +1,11 @@ { - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#k8s-version@0.1.3": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-certs@0.4.1": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-operator-derive@0.3.1": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-operator@0.115.0": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-shared@0.1.2": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-telemetry@0.6.5": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-versioned-macros@0.11.1": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-versioned@0.11.1": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-webhook@0.9.2": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb" + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#k8s-version@0.1.3": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-certs@0.4.1": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-operator-derive@0.3.1": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-operator@0.116.0": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-shared@0.1.2": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-telemetry@0.6.5": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-versioned-macros@0.11.1": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-versioned@0.11.1": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-webhook@0.9.2": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9" } \ No newline at end of file diff --git a/extra/crds.yaml b/extra/crds.yaml index 4a91c210..87a3f692 100644 --- a/extra/crds.yaml +++ b/extra/crds.yaml @@ -821,7 +821,8 @@ spec: default: {} description: |- `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. + It is a map from environment variable names to their values. The names are validated to be + valid environment variable names. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about @@ -1273,7 +1274,8 @@ spec: default: {} description: |- `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. + It is a map from environment variable names to their values. The names are validated to be + valid environment variable names. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 08e22833..710ebfd7 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -19,6 +19,7 @@ use stackable_operator::{ product_image_selection::ResolvedProductImage, resources::{NoRuntimeLimits, Resources}, }, + constant, crd::{listener::v1alpha1::Listener, s3}, database_connections::drivers::jdbc::JdbcDatabaseConnectionDetails, k8s_openapi::api::{ @@ -33,32 +34,32 @@ use stackable_operator::{ core::{DeserializeGuard, error_boundary}, runtime::controller::Action, }, - kvp::Labels, logging::controller::ReconcilerError, shared::time::Duration, v2::{ HasName, HasUid, NameIsValidLabelValue, - kvp::label::{recommended_labels, role_group_selector}, role_group_utils::ResourceNames, role_utils, types::{ kubernetes::{ListenerClassName, SecretClassName}, - operator::{ControllerName, OperatorName, ProductName, ProductVersion, RoleName}, + operator::{ControllerName, OperatorName, ProductName, ProductVersion}, }, }, }; use strum::EnumDiscriminants; use crate::{ - OPERATOR_NAME, - controller::{ - apply::Applier, build::UNVERSIONED_PRODUCT_VERSION, update_status::update_status, - }, + controller::{apply::Applier, update_status::update_status}, crd::{APP_NAME, HdfsConnection, HiveRole, MetaStoreConfig, v1alpha1}, }; pub const HIVE_CONTROLLER_NAME: &str = "hivecluster"; -pub const HIVE_FULL_CONTROLLER_NAME: &str = concatcp!(HIVE_CONTROLLER_NAME, '.', OPERATOR_NAME); +pub const HIVE_FULL_CONTROLLER_NAME: &str = + concatcp!(HIVE_CONTROLLER_NAME, '.', crate::OPERATOR_NAME); + +constant!(PRODUCT_NAME: ProductName = APP_NAME); +constant!(OPERATOR_NAME: OperatorName = crate::OPERATOR_NAME); +constant!(CONTROLLER_NAME: ControllerName = HIVE_CONTROLLER_NAME); pub struct Ctx { pub client: stackable_operator::client::Client, @@ -227,7 +228,7 @@ impl ValidatedCluster { pub fn cluster_resource_names(&self) -> role_utils::ResourceNames { role_utils::ResourceNames { cluster_name: self.name.clone(), - product_name: product_name(), + product_name: PRODUCT_NAME.clone(), } } @@ -238,64 +239,11 @@ impl ValidatedCluster { ) -> ResourceNames { ResourceNames { cluster_name: self.name.clone(), - role_name: HiveRole::MetaStore.into(), + role_name: (*HiveRole::MetaStore).clone(), role_group_name: role_group_name.clone(), } } - /// Recommended labels for a resource that is not tied to a concrete role, - /// using a free-form role/role-group label value. - pub fn recommended_labels_for( - &self, - role_name: &RoleName, - role_group_name: &RoleGroupName, - ) -> Labels { - self.recommended_labels_with(&self.product_version, role_name, role_group_name) - } - - /// Recommended labels with the constant [`UNVERSIONED_PRODUCT_VERSION`], for PVC templates - /// that cannot be modified after deployment (keeps the labels stable across version upgrades). - pub fn unversioned_recommended_labels(&self, role_group_name: &RoleGroupName) -> Labels { - self.recommended_labels_with( - &UNVERSIONED_PRODUCT_VERSION, - &HiveRole::MetaStore.into(), - role_group_name, - ) - } - - /// Recommended labels for a role-group resource, using the given product version. - fn recommended_labels_with( - &self, - product_version: &ProductVersion, - role_name: &RoleName, - role_group_name: &RoleGroupName, - ) -> Labels { - recommended_labels( - self, - &product_name(), - product_version, - &operator_name(), - &controller_name(), - role_name, - role_group_name, - ) - } - - /// Recommended labels for a role-group resource. - pub fn recommended_labels(&self, role_group_name: &RoleGroupName) -> Labels { - self.recommended_labels_for(&HiveRole::MetaStore.into(), role_group_name) - } - - /// Selector labels matching the pods of a role group. - pub fn role_group_selector(&self, role_group_name: &RoleGroupName) -> Labels { - role_group_selector( - self, - &product_name(), - &HiveRole::MetaStore.into(), - role_group_name, - ) - } - /// Whether Kerberos is enabled for this cluster (a Kerberos `SecretClass` was configured). pub fn has_kerberos_enabled(&self) -> bool { self.cluster_config.kerberos_secret_class.is_some() @@ -352,22 +300,6 @@ impl NameIsValidLabelValue for ValidatedCluster { } } -/// The product name (`hive`) as a type-safe label value. -pub(crate) fn product_name() -> ProductName { - ProductName::from_str(APP_NAME).expect("'hive' is a valid product name") -} - -/// The operator name as a type-safe label value. -pub(crate) fn operator_name() -> OperatorName { - OperatorName::from_str(OPERATOR_NAME).expect("the operator name is a valid label value") -} - -/// The controller name as a type-safe label value. -pub(crate) fn controller_name() -> ControllerName { - ControllerName::from_str(HIVE_CONTROLLER_NAME) - .expect("the controller name is a valid label value") -} - /// Cluster-wide settings resolved during validation and dereferencing. /// /// Everything the config-file builders need is resolved here so they never have to @@ -545,18 +477,13 @@ pub(crate) mod test_support { #[cfg(test)] mod tests { - use stackable_operator::v2::types::operator::RoleName; - use strum::IntoEnumIterator; - - use crate::crd::HiveRole; + use super::*; - /// Locks the invariant behind the `expect` in the `From for RoleName` impls: - /// every `HiveRole` variant (present and future) must serialise to a valid `RoleName`. #[test] - fn every_hive_role_serialises_to_a_valid_role_name() { - for role in HiveRole::iter() { - let _: RoleName = (&role).into(); - let _: RoleName = role.into(); - } + fn test_constants() { + // Test that dereferencing the constants does not panic. + let _ = *PRODUCT_NAME; + let _ = *OPERATOR_NAME; + let _ = *CONTROLLER_NAME; } } diff --git a/rust/operator-binary/src/controller/apply.rs b/rust/operator-binary/src/controller/apply.rs index 98cd8a5e..cf9ba95e 100644 --- a/rust/operator-binary/src/controller/apply.rs +++ b/rust/operator-binary/src/controller/apply.rs @@ -12,8 +12,8 @@ use stackable_operator::{ use strum::{EnumDiscriminants, IntoStaticStr}; use crate::controller::{ - Applied, KubernetesResources, Prepared, ValidatedCluster, controller_name, operator_name, - product_name, + Applied, CONTROLLER_NAME, KubernetesResources, OPERATOR_NAME, PRODUCT_NAME, Prepared, + ValidatedCluster, }; #[derive(Snafu, Debug, EnumDiscriminants)] @@ -49,9 +49,9 @@ impl<'a> Applier<'a> { object_overrides: &'a ObjectOverrides, ) -> Applier<'a> { let cluster_resources = cluster_resources_new( - &product_name(), - &operator_name(), - &controller_name(), + &PRODUCT_NAME, + &OPERATOR_NAME, + &CONTROLLER_NAME, &cluster.name, &cluster.namespace, &cluster.uid, diff --git a/rust/operator-binary/src/controller/build/mod.rs b/rust/operator-binary/src/controller/build/mod.rs index 316ea47d..3d4591a1 100644 --- a/rust/operator-binary/src/controller/build/mod.rs +++ b/rust/operator-binary/src/controller/build/mod.rs @@ -1,20 +1,22 @@ //! Builders that turn a `ValidatedCluster` into Kubernetes resources. -use std::{marker::PhantomData, str::FromStr}; +use std::marker::PhantomData; use snafu::{ResultExt, Snafu}; use stackable_operator::{ builder::meta::ObjectMetaBuilder, + kvp::Labels, utils::cluster_info::KubernetesClusterInfo, v2::{ builder::meta::ownerreference_from_resource, - types::operator::{ProductVersion, RoleGroupName}, + types::operator::{RoleGroupName, RoleName}, }, }; use crate::{ controller::{ - KubernetesResources, Prepared, ValidatedCluster, + CONTROLLER_NAME, KubernetesResources, OPERATOR_NAME, PRODUCT_NAME, Prepared, + ValidatedCluster, build::resource::{ config_map::build_metastore_rolegroup_config_map, discovery::build_discovery_configmap, @@ -28,18 +30,6 @@ use crate::{ crd::HiveRole, }; -// Placeholder role-group name used for the recommended labels of the role-level discovery -// `ConfigMap` (which is not tied to a single role group). -stackable_operator::constant!(pub(crate) PLACEHOLDER_DISCOVERY_ROLE_GROUP: RoleGroupName = "discovery"); - -// Placeholder role-group name used for the recommended labels of the role-level `Listener` -// (which is not tied to a single role group). -stackable_operator::constant!(pub(crate) PLACEHOLDER_LISTENER_ROLE_GROUP: RoleGroupName = "none"); - -// Placeholder product version used for labels on PVC templates, which cannot be modified once -// deployed. A constant value keeps the labels stable across version upgrades. -stackable_operator::constant!(pub(crate) UNVERSIONED_PRODUCT_VERSION: ProductVersion = "none"); - pub mod command; pub mod graceful_shutdown; pub mod jvm; @@ -139,17 +129,86 @@ pub fn build( pub(crate) fn object_meta( cluster: &ValidatedCluster, name: impl Into, - role_group_name: &RoleGroupName, + labels: Labels, ) -> ObjectMetaBuilder { let mut builder = ObjectMetaBuilder::new(); builder .name_and_namespace(cluster) .name(name) .ownerreference(ownerreference_from_resource(cluster, None, Some(true))) - .with_labels(cluster.recommended_labels(role_group_name)); + .with_labels(labels); builder } +pub(crate) fn recommended_labels_for_cluster_resources(cluster: &ValidatedCluster) -> Labels { + stackable_operator::v2::kvp::label::recommended_labels_for_cluster_resources( + &cluster.name, + &PRODUCT_NAME, + &cluster.product_version, + &OPERATOR_NAME, + &CONTROLLER_NAME, + ) +} + +pub(crate) fn recommended_labels_for_role_resources( + cluster: &ValidatedCluster, + role_name: &RoleName, +) -> Labels { + stackable_operator::v2::kvp::label::recommended_labels_for_role_resources( + &cluster.name, + &PRODUCT_NAME, + &cluster.product_version, + &OPERATOR_NAME, + &CONTROLLER_NAME, + role_name, + ) +} + +pub(crate) fn recommended_labels_for_role_group_resources( + cluster: &ValidatedCluster, + role_name: &RoleName, + role_group_name: &RoleGroupName, +) -> Labels { + stackable_operator::v2::kvp::label::recommended_labels_for_role_group_resources( + &cluster.name, + &PRODUCT_NAME, + &cluster.product_version, + &OPERATOR_NAME, + &CONTROLLER_NAME, + role_name, + role_group_name, + ) +} + +pub(crate) fn recommended_labels_for_unversioned_role_group_resources( + cluster: &ValidatedCluster, + role_name: &RoleName, + role_group_name: &RoleGroupName, +) -> Labels { + stackable_operator::v2::kvp::label::recommended_labels_for_unversioned_role_group_resources( + &cluster.name, + &PRODUCT_NAME, + &OPERATOR_NAME, + &CONTROLLER_NAME, + role_name, + role_group_name, + ) +} + +/// Selector labels matching the pods of a role group. +pub(crate) fn role_group_selector( + cluster: &ValidatedCluster, + role_name: &RoleName, + role_group_name: &RoleGroupName, +) -> Labels { + stackable_operator::v2::kvp::label::role_group_selector( + &cluster.name, + &PRODUCT_NAME, + role_name, + role_group_name, + ) +} + #[cfg(test)] mod tests { use std::{collections::BTreeMap, str::FromStr}; @@ -164,8 +223,11 @@ mod tests { use super::{KubernetesResources, Prepared, RoleGroupName, build, object_meta}; use crate::{ - controller::test_support::{DERBY_YAML, minimal_hive, validated_cluster}, - crd::HIVE_PORT_NAME, + controller::{ + build::recommended_labels_for_role_group_resources, + test_support::{DERBY_YAML, minimal_hive, validated_cluster}, + }, + crd::{HIVE_PORT_NAME, HiveRole}, }; fn test_cluster_info() -> KubernetesClusterInfo { @@ -359,7 +421,16 @@ mod tests { let cluster = validated_cluster(&hive); let role_group_name = RoleGroupName::from_str("default").expect("valid role group name"); - let meta = object_meta(&cluster, "test-name", &role_group_name).build(); + let meta = object_meta( + &cluster, + "test-name", + recommended_labels_for_role_group_resources( + &cluster, + &HiveRole::MetaStore, + &role_group_name, + ), + ) + .build(); assert_eq!(meta.name.as_deref(), Some("test-name")); assert_eq!(meta.namespace.as_deref(), Some(cluster.namespace.as_ref())); diff --git a/rust/operator-binary/src/controller/build/resource/config_map.rs b/rust/operator-binary/src/controller/build/resource/config_map.rs index d57d748f..a04a4e8e 100644 --- a/rust/operator-binary/src/controller/build/resource/config_map.rs +++ b/rust/operator-binary/src/controller/build/resource/config_map.rs @@ -9,13 +9,19 @@ use stackable_operator::{ v2::config_file_writer::{PropertiesWriterError, to_hadoop_xml, to_java_properties_string}, }; -use crate::controller::{ - HiveRoleGroupConfig, RoleGroupName, ValidatedCluster, - build::{ - kerberos::kerberos_config_properties, - object_meta, - properties::{ConfigFileName, core_site, hive_site, product_logging, security_properties}, +use crate::{ + controller::{ + HiveRoleGroupConfig, RoleGroupName, ValidatedCluster, + build::{ + kerberos::kerberos_config_properties, + object_meta, + properties::{ + ConfigFileName, core_site, hive_site, product_logging, security_properties, + }, + recommended_labels_for_role_group_resources, + }, }, + crd::HiveRole, }; #[derive(Debug, Snafu)] @@ -79,7 +85,11 @@ pub fn build_metastore_rolegroup_config_map( .role_group_resource_names(role_group_name) .role_group_config_map() .to_string(), - role_group_name, + recommended_labels_for_role_group_resources( + cluster, + &HiveRole::MetaStore, + role_group_name, + ), ) .build(), ) diff --git a/rust/operator-binary/src/controller/build/resource/discovery.rs b/rust/operator-binary/src/controller/build/resource/discovery.rs index 7a48fb36..a5e6befe 100644 --- a/rust/operator-binary/src/controller/build/resource/discovery.rs +++ b/rust/operator-binary/src/controller/build/resource/discovery.rs @@ -12,7 +12,7 @@ use crate::{ controller::{ ValidatedCluster, build::{ - PLACEHOLDER_DISCOVERY_ROLE_GROUP, object_meta, + object_meta, recommended_labels_for_role_resources, resource::listener::build_listener_connection_string, }, }, @@ -114,7 +114,7 @@ fn discovery_config_map_meta(cluster: &ValidatedCluster) -> ObjectMeta { object_meta( cluster, discovery_config_map_name(&cluster.name), - &PLACEHOLDER_DISCOVERY_ROLE_GROUP, + recommended_labels_for_role_resources(cluster, &HiveRole::MetaStore), ) .build() } diff --git a/rust/operator-binary/src/controller/build/resource/listener.rs b/rust/operator-binary/src/controller/build/resource/listener.rs index 87e57bc8..613758b5 100644 --- a/rust/operator-binary/src/controller/build/resource/listener.rs +++ b/rust/operator-binary/src/controller/build/resource/listener.rs @@ -12,7 +12,7 @@ use stackable_operator::{ use crate::{ controller::{ ValidatedCluster, - build::{PLACEHOLDER_LISTENER_ROLE_GROUP, object_meta}, + build::{object_meta, recommended_labels_for_role_resources}, }, crd::{HIVE_PORT, HIVE_PORT_NAME, HiveRole}, }; @@ -48,8 +48,11 @@ pub fn build_listener_connection_string( /// Takes the bare cluster name (not [`ValidatedCluster`]) so the dereference step, which runs /// before validation, can derive the same name. pub fn role_listener_name(cluster_name: &ClusterName, hive_role: &HiveRole) -> ListenerName { - ListenerName::from_str(&format!("{cluster_name}-{hive_role}")) - .expect("the role listener name is a valid Listener name") + ListenerName::from_str(&format!( + "{cluster_name}-{hive_role}", + hive_role = **hive_role + )) + .expect("the role listener name is a valid Listener name") } // Designed to build a listener per role @@ -64,7 +67,7 @@ pub fn build_role_listener( let metadata = object_meta( cluster, role_listener_name(&cluster.name, hive_role), - &PLACEHOLDER_LISTENER_ROLE_GROUP, + recommended_labels_for_role_resources(cluster, hive_role), ) .build(); diff --git a/rust/operator-binary/src/controller/build/resource/pdb.rs b/rust/operator-binary/src/controller/build/resource/pdb.rs index c3c0426c..68e1820e 100644 --- a/rust/operator-binary/src/controller/build/resource/pdb.rs +++ b/rust/operator-binary/src/controller/build/resource/pdb.rs @@ -4,7 +4,7 @@ use stackable_operator::{ }; use crate::{ - controller::{ValidatedCluster, controller_name, operator_name, product_name}, + controller::{CONTROLLER_NAME, OPERATOR_NAME, PRODUCT_NAME, ValidatedCluster}, crd::HiveRole, }; @@ -22,10 +22,10 @@ pub fn build_pdb( }); let pdb = pod_disruption_budget_builder_with_role( cluster, - &product_name(), - &role.into(), - &operator_name(), - &controller_name(), + &PRODUCT_NAME, + role, + &OPERATOR_NAME, + &CONTROLLER_NAME, ) .with_max_unavailable(max_unavailable) .build(); diff --git a/rust/operator-binary/src/controller/build/resource/rbac.rs b/rust/operator-binary/src/controller/build/resource/rbac.rs index bce7548e..4db85234 100644 --- a/rust/operator-binary/src/controller/build/resource/rbac.rs +++ b/rust/operator-binary/src/controller/build/resource/rbac.rs @@ -1,27 +1,18 @@ //! Builds the RBAC resources (ServiceAccount + RoleBinding) shared by all role groups. -use std::str::FromStr; - use stackable_operator::{ k8s_openapi::api::{core::v1::ServiceAccount, rbac::v1::RoleBinding}, - kvp::Labels, - v2::{ - rbac, - types::operator::{RoleGroupName, RoleName}, - }, + v2::rbac, }; -use crate::controller::ValidatedCluster; - -stackable_operator::constant!(NONE_ROLE_NAME: RoleName = "none"); -stackable_operator::constant!(NONE_ROLE_GROUP_NAME: RoleGroupName = "none"); +use crate::controller::{ValidatedCluster, build::recommended_labels_for_cluster_resources}; /// Builds the [`ServiceAccount`] that the role-group Pods run under. pub fn build_service_account(cluster: &ValidatedCluster) -> ServiceAccount { rbac::build_service_account( cluster, &cluster.cluster_resource_names(), - rbac_labels(cluster), + recommended_labels_for_cluster_resources(cluster), ) } @@ -31,16 +22,10 @@ pub fn build_role_binding(cluster: &ValidatedCluster) -> RoleBinding { rbac::build_role_binding( cluster, &cluster.cluster_resource_names(), - rbac_labels(cluster), + recommended_labels_for_cluster_resources(cluster), ) } -/// Both resources are shared by the whole cluster rather than tied to a role or role group, so -/// the recommended labels carry `none` for both values. -fn rbac_labels(cluster: &ValidatedCluster) -> Labels { - cluster.recommended_labels_for(&NONE_ROLE_NAME, &NONE_ROLE_GROUP_NAME) -} - #[cfg(test)] mod tests { use serde_json::json; @@ -64,11 +49,9 @@ mod tests { "metadata": { // The RBAC resources are cluster-shared, so role and role group are `none`. "labels": { - "app.kubernetes.io/component": "none", "app.kubernetes.io/instance": "simple-hive", "app.kubernetes.io/managed-by": "hive.stackable.tech_hivecluster", "app.kubernetes.io/name": "hive", - "app.kubernetes.io/role-group": "none", "app.kubernetes.io/version": app_version_label("4.0.0"), "stackable.tech/vendor": "Stackable" }, @@ -100,11 +83,9 @@ mod tests { "kind": "RoleBinding", "metadata": { "labels": { - "app.kubernetes.io/component": "none", "app.kubernetes.io/instance": "simple-hive", "app.kubernetes.io/managed-by": "hive.stackable.tech_hivecluster", "app.kubernetes.io/name": "hive", - "app.kubernetes.io/role-group": "none", "app.kubernetes.io/version": app_version_label("4.0.0"), "stackable.tech/vendor": "Stackable" }, diff --git a/rust/operator-binary/src/controller/build/resource/service.rs b/rust/operator-binary/src/controller/build/resource/service.rs index 504f1bc0..688212cd 100644 --- a/rust/operator-binary/src/controller/build/resource/service.rs +++ b/rust/operator-binary/src/controller/build/resource/service.rs @@ -4,8 +4,11 @@ use stackable_operator::{ }; use crate::{ - controller::{RoleGroupName, ValidatedCluster, build::object_meta}, - crd::{HIVE_PORT, HIVE_PORT_NAME, METRICS_PORT, METRICS_PORT_NAME}, + controller::{ + RoleGroupName, ValidatedCluster, + build::{object_meta, recommended_labels_for_role_group_resources, role_group_selector}, + }, + crd::{HIVE_PORT, HIVE_PORT_NAME, HiveRole, METRICS_PORT, METRICS_PORT_NAME}, }; /// The rolegroup [`Service`] is a headless service that allows direct access to the instances of a certain rolegroup @@ -22,7 +25,11 @@ pub fn build_rolegroup_headless_service( .role_group_resource_names(role_group_name) .headless_service_name() .to_string(), - role_group_name, + recommended_labels_for_role_group_resources( + cluster, + &HiveRole::MetaStore, + role_group_name, + ), ) .build(), spec: Some(ServiceSpec { @@ -31,7 +38,9 @@ pub fn build_rolegroup_headless_service( cluster_ip: Some("None".to_string()), // Expecting same ports as on listener service, just as a headless, internal service ports: Some(service_ports()), - selector: Some(cluster.role_group_selector(role_group_name).into()), + selector: Some( + role_group_selector(cluster, &HiveRole::MetaStore, role_group_name).into(), + ), publish_not_ready_addresses: Some(true), ..ServiceSpec::default() }), @@ -51,7 +60,11 @@ pub fn build_rolegroup_metrics_service( .role_group_resource_names(role_group_name) .metrics_service_name() .to_string(), - role_group_name, + recommended_labels_for_role_group_resources( + cluster, + &HiveRole::MetaStore, + role_group_name, + ), ) .with_labels(prometheus_labels(&Scraping::Enabled)) .with_annotations(prometheus_annotations( @@ -66,7 +79,9 @@ pub fn build_rolegroup_metrics_service( type_: Some("ClusterIP".to_string()), cluster_ip: Some("None".to_string()), ports: Some(metrics_ports()), - selector: Some(cluster.role_group_selector(role_group_name).into()), + selector: Some( + role_group_selector(cluster, &HiveRole::MetaStore, role_group_name).into(), + ), publish_not_ready_addresses: Some(true), ..ServiceSpec::default() }), diff --git a/rust/operator-binary/src/controller/build/resource/statefulset.rs b/rust/operator-binary/src/controller/build/resource/statefulset.rs index be6bc464..d745c162 100644 --- a/rust/operator-binary/src/controller/build/resource/statefulset.rs +++ b/rust/operator-binary/src/controller/build/resource/statefulset.rs @@ -55,7 +55,10 @@ use crate::{ object_meta, opa::{OPA_TLS_VOLUME_NAME, build_opa_tls_ca_cert_mount_path}, properties::product_logging::MAX_HIVE_LOG_FILES_SIZE, + recommended_labels_for_role_group_resources, + recommended_labels_for_unversioned_role_group_resources, resource::listener::role_listener_name, + role_group_selector, }, }, crd::{ @@ -165,7 +168,6 @@ pub(crate) fn build_metastore_rolegroup_statefulset( database_connection_details.add_to_container(&mut container_builder); // Environment variable overrides (highest precedence), merged from role and role group. - // Names are validated during cluster validation, so they can be applied directly here. container_builder.add_env_vars(rg.env_overrides.clone()); let mut pod_builder = PodBuilder::new(); @@ -322,13 +324,18 @@ pub(crate) fn build_metastore_rolegroup_statefulset( ); } - let recommended_object_labels = cluster.recommended_labels(role_group_name); + let recommended_object_labels = + recommended_labels_for_role_group_resources(cluster, &HiveRole::MetaStore, role_group_name); // Used for PVC templates that cannot be modified once they are deployed. A version value is // required, so a constant "none" is used to keep the labels stable across version upgrades. - let unversioned_recommended_labels = cluster.unversioned_recommended_labels(role_group_name); + let unversioned_recommended_labels = recommended_labels_for_unversioned_role_group_resources( + cluster, + &HiveRole::MetaStore, + role_group_name, + ); let metadata = ObjectMetaBuilder::new() - .with_labels(recommended_object_labels) + .with_labels(recommended_object_labels.clone()) .build(); let listener_name = role_listener_name(&cluster.name, hive_role); @@ -435,7 +442,7 @@ pub(crate) fn build_metastore_rolegroup_statefulset( metadata: object_meta( cluster, resource_names.stateful_set_name().to_string(), - role_group_name, + recommended_object_labels, ) .with_label(RESTART_CONTROLLER_ENABLED_LABEL.to_owned()) .build(), @@ -445,7 +452,9 @@ pub(crate) fn build_metastore_rolegroup_statefulset( // HorizontalPodAutoscaler can manage it. replicas: rg.replicas.map(i32::from), selector: LabelSelector { - match_labels: Some(cluster.role_group_selector(role_group_name).into()), + match_labels: Some( + role_group_selector(cluster, &HiveRole::MetaStore, role_group_name).into(), + ), ..LabelSelector::default() }, service_name: Some(resource_names.headless_service_name().to_string()), diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index 14838df8..c8473815 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -7,7 +7,6 @@ use stackable_operator::{ product_logging::spec::Logging, role_utils::GenericRoleConfig, v2::{ - builder::pod::container::{EnvVarName, EnvVarSet}, controller_utils::{get_cluster_name, get_namespace, get_uid}, product_logging::framework::{ ValidatedContainerLogConfigChoice, VectorContainerLogConfig, @@ -66,12 +65,6 @@ pub enum Error { role_group: RoleGroupName, }, - #[snafu(display("invalid environment variable override name in role group {role_group}"))] - ParseEnvVarName { - source: stackable_operator::v2::macros::attributed_string_type::Error, - role_group: RoleGroupName, - }, - #[snafu(display("invalid metadata database connection"))] InvalidMetadataDatabaseConnection { source: stackable_operator::database_connections::Error, @@ -257,16 +250,6 @@ fn validate_role_group_config( role_group: role_group_name.clone(), })?; - let mut env_overrides = EnvVarSet::new(); - for (env_var_name, env_var_value) in merged.config.env_overrides { - env_overrides = env_overrides.with_value( - &EnvVarName::from_str(&env_var_name).with_context(|_| ParseEnvVarNameSnafu { - role_group: role_group_name.clone(), - })?, - env_var_value, - ); - } - let logging = validate_logging( &merged.config.config.logging, vector_aggregator_config_map_name, @@ -276,7 +259,7 @@ fn validate_role_group_config( replicas: merged.replicas, config: ValidatedMetaStoreConfig::from_merged(merged.config.config, logging), config_overrides: merged.config.config_overrides, - env_overrides, + env_overrides: merged.config.env_overrides.into(), // Hive does not use CLI overrides; the field is carried through the merge but unused. cli_overrides: merged.config.cli_overrides, pod_overrides: merged.config.pod_overrides, @@ -286,6 +269,8 @@ fn validate_role_group_config( #[cfg(test)] mod tests { + use stackable_operator::v2::builder::pod::container::EnvVarSet; + use super::*; use crate::controller::test_support::{DERBY_YAML, app_version_label, minimal_hive}; @@ -412,39 +397,6 @@ mod tests { ); } - #[test] - fn validate_rejects_invalid_env_var_override_name() { - // A copy of `DERBY_YAML` with an invalid `envOverrides` name: `EnvVarName` allows any - // printable ASCII except `=` (the Kubernetes rule), so a leading digit is fine; the - // embedded `=` is what gets rejected. - let yaml = r#" - apiVersion: hive.stackable.tech/v1alpha1 - kind: HiveCluster - metadata: - name: simple-hive - namespace: default - uid: 12345678-1234-1234-1234-123456789012 - spec: - image: - productVersion: "4.0.0" - clusterConfig: - metadataDatabase: - derby: {} - metastore: - roleGroups: - default: - replicas: 1 - envOverrides: - "BAD=NAME": value - "#; - - let error = expect_validate_err(yaml); - assert!( - matches!(&error, Error::ParseEnvVarName { role_group, .. } if role_group.as_ref() == "default"), - "unexpected error: {error:?}" - ); - } - #[test] fn validate_logging_rejects_invalid_custom_config_map_name() { use crate::crd::{ diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 20a9d837..18f019e6 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -1,4 +1,4 @@ -use std::str::FromStr; +use std::{ops::Deref, str::FromStr}; use databases::MetadataDatabaseConnection; /// Re-export of the shared product-logging spec data types (test-only). @@ -21,18 +21,19 @@ use stackable_operator::{ }, }, config::{fragment::Fragment, merge::Merge}, + constant, crd::s3, deep_merger::ObjectOverrides, k8s_openapi::apimachinery::pkg::api::resource::Quantity, kube::CustomResource, product_logging::{self, spec::Logging}, - role_utils::{GenericRoleConfig, Role, RoleGroup}, + role_utils::GenericRoleConfig, schemars::{self, JsonSchema}, shared::time::Duration, status::condition::{ClusterCondition, HasStatusCondition}, v2::{ config_overrides::KeyValueConfigOverrides, - role_utils::JavaCommonConfig, + role_utils::{JavaCommonConfig, Role, RoleGroup}, types::{ common::Port, kubernetes::{ @@ -43,7 +44,7 @@ use stackable_operator::{ }, versioned::versioned, }; -use strum::{Display, EnumIter, EnumString}; +use strum::{Display, EnumIter}; use v1alpha1::HiveMetastoreRoleConfig; use crate::crd::affinity::get_affinity; @@ -87,6 +88,8 @@ pub fn metastore_default_listener_class() -> ListenerClassName { const DEFAULT_METASTORE_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_minutes_unchecked(5); +constant!(METASTORE_ROLE_NAME: RoleName = "metastore"); + pub type HiveRoleType = Role< MetaStoreConfigFragment, v1alpha1::HiveConfigOverrides, @@ -254,25 +257,11 @@ pub struct HdfsConnection { pub config_map: ConfigMapName, } -#[derive(Clone, Debug, Display, EnumString, EnumIter, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[strum(serialize_all = "camelCase")] +#[derive(Clone, Debug, EnumIter, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum HiveRole { - #[strum(serialize = "metastore")] MetaStore, } -impl From for RoleName { - fn from(value: HiveRole) -> Self { - RoleName::from_str(&value.to_string()).expect("a HiveRole is a valid role name") - } -} - -impl From<&HiveRole> for RoleName { - fn from(value: &HiveRole) -> Self { - RoleName::from_str(&value.to_string()).expect("a HiveRole is a valid role name") - } -} - impl HiveRole { /// A Kerberos principal has three parts, with the form username/fully.qualified.domain.name@YOUR-REALM.COM. /// We only have one role and will use "hive" everywhere (which e.g. differs from the current hdfs implementation). @@ -281,6 +270,16 @@ impl HiveRole { } } +impl Deref for HiveRole { + type Target = RoleName; + + fn deref(&self) -> &Self::Target { + match self { + HiveRole::MetaStore => &METASTORE_ROLE_NAME, + } + } +} + #[derive( Clone, Debug, @@ -405,7 +404,13 @@ pub struct HiveClusterStatus { mod tests { use stackable_operator::versioned::test_utils::RoundtripTestData; - use super::v1alpha1; + use super::*; + + #[test] + fn test_constants() { + // Test that dereferencing the constants does not panic. + let _ = *METASTORE_ROLE_NAME; + } impl RoundtripTestData for v1alpha1::HiveClusterSpec { fn roundtrip_test_data() -> Vec { diff --git a/tests/templates/kuttl/smoke/60-assert.yaml.j2 b/tests/templates/kuttl/smoke/60-assert.yaml.j2 index 7546d188..d98d3af5 100644 --- a/tests/templates/kuttl/smoke/60-assert.yaml.j2 +++ b/tests/templates/kuttl/smoke/60-assert.yaml.j2 @@ -11,7 +11,6 @@ metadata: app.kubernetes.io/instance: hive-metastore app.kubernetes.io/managed-by: listeners.stackable.tech_listener app.kubernetes.io/name: listener - app.kubernetes.io/role-group: none stackable.tech/vendor: Stackable name: hive-metastore ownerReferences: @@ -432,7 +431,6 @@ spec: app.kubernetes.io/managed-by: hive.stackable.tech_hivecluster app.kubernetes.io/name: hive app.kubernetes.io/role-group: default - app.kubernetes.io/version: none stackable.tech/vendor: Stackable name: listener spec: @@ -457,7 +455,6 @@ metadata: app.kubernetes.io/instance: hive app.kubernetes.io/managed-by: hive.stackable.tech_hivecluster app.kubernetes.io/name: hive - app.kubernetes.io/role-group: discovery stackable.tech/vendor: Stackable name: hive ownerReferences: @@ -554,7 +551,6 @@ metadata: app.kubernetes.io/instance: hive app.kubernetes.io/managed-by: hive.stackable.tech_hivecluster app.kubernetes.io/name: hive - app.kubernetes.io/role-group: none stackable.tech/vendor: Stackable name: hive-metastore ownerReferences: