diff --git a/CHANGELOG.md b/CHANGELOG.md index ee68cc9f..2db7b48d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,20 @@ - BREAKING: The file log directory was set by `HBASE_OPERATOR_LOG_DIRECTORY`, and is now set by `ROLLING_LOGS` (or via `--rolling-logs `). - Replace stackable-operator `print_startup_string` with `tracing::info!` with fields. +- BREAKING: Inject the vector aggregator address into the vector config using the env var `VECTOR_AGGREGATOR_ADDRESS` instead + of having the operator write it to the vector config ([#645]). + +### Fixed + +- Use `json` file extension for log files ([#647]). +- Fix a bug where changes to ConfigMaps that are referenced in the HbaseCluster spec didn't trigger a reconciliation ([#645]). ### Fixed - Use `json` file extension for log files ([#647]). [#640]: https://github.com/stackabletech/hbase-operator/pull/640 +[#645]: https://github.com/stackabletech/hbase-operator/pull/645 [#647]: https://github.com/stackabletech/hbase-operator/pull/647 ## [25.3.0] - 2025-03-21 diff --git a/Cargo.lock b/Cargo.lock index 4bdbff9d..99e2e35c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2654,8 +2654,8 @@ dependencies = [ [[package]] name = "stackable-operator" -version = "0.89.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.89.1#cd73728af410c52972b9a9a3ba1302bcdb574d04" +version = "0.90.0" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.90.0#ea063b4595caa20c82d37c595487c76476c9ab10" dependencies = [ "chrono", "clap", @@ -2690,7 +2690,7 @@ dependencies = [ [[package]] name = "stackable-operator-derive" version = "0.3.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.89.1#cd73728af410c52972b9a9a3ba1302bcdb574d04" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.90.0#ea063b4595caa20c82d37c595487c76476c9ab10" dependencies = [ "darling", "proc-macro2", @@ -2701,7 +2701,7 @@ dependencies = [ [[package]] name = "stackable-shared" version = "0.0.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.89.1#cd73728af410c52972b9a9a3ba1302bcdb574d04" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.90.0#ea063b4595caa20c82d37c595487c76476c9ab10" dependencies = [ "kube", "semver", diff --git a/Cargo.nix b/Cargo.nix index 8d72de83..222887f6 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -8583,13 +8583,13 @@ rec { }; "stackable-operator" = rec { crateName = "stackable-operator"; - version = "0.89.1"; + version = "0.90.0"; edition = "2024"; workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "cd73728af410c52972b9a9a3ba1302bcdb574d04"; - sha256 = "1hrxrybc6197ibx0m2wfxlg5pdg4hanf6xvslzrhsp77a04pb0y9"; + rev = "ea063b4595caa20c82d37c595487c76476c9ab10"; + sha256 = "0fclvpxhchykqd7bl8hscr4v06mbs2v5vjp0xv27nvqr94j63xs2"; }; libName = "stackable_operator"; authors = [ @@ -8734,8 +8734,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "cd73728af410c52972b9a9a3ba1302bcdb574d04"; - sha256 = "1hrxrybc6197ibx0m2wfxlg5pdg4hanf6xvslzrhsp77a04pb0y9"; + rev = "ea063b4595caa20c82d37c595487c76476c9ab10"; + sha256 = "0fclvpxhchykqd7bl8hscr4v06mbs2v5vjp0xv27nvqr94j63xs2"; }; procMacro = true; libName = "stackable_operator_derive"; @@ -8769,8 +8769,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "cd73728af410c52972b9a9a3ba1302bcdb574d04"; - sha256 = "1hrxrybc6197ibx0m2wfxlg5pdg4hanf6xvslzrhsp77a04pb0y9"; + rev = "ea063b4595caa20c82d37c595487c76476c9ab10"; + sha256 = "0fclvpxhchykqd7bl8hscr4v06mbs2v5vjp0xv27nvqr94j63xs2"; }; libName = "stackable_shared"; authors = [ diff --git a/Cargo.toml b/Cargo.toml index a41a06f2..c7c167d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/stackabletech/hbase-operator" [workspace.dependencies] product-config = { git = "https://github.com/stackabletech/product-config.git", tag = "0.7.0" } -stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.89.1" } +stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.90.0" } stackable-telemetry = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-telemetry-0.4.0" } stackable-versioned = { git = "https://github.com/stackabletech/operator-rs.git", features = ["k8s"], tag = "stackable-versioned-0.7.1" } diff --git a/crate-hashes.json b/crate-hashes.json index 0460dbd5..c8a9703a 100644 --- a/crate-hashes.json +++ b/crate-hashes.json @@ -1,7 +1,7 @@ { - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.89.1#stackable-operator-derive@0.3.1": "1hrxrybc6197ibx0m2wfxlg5pdg4hanf6xvslzrhsp77a04pb0y9", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.89.1#stackable-operator@0.89.1": "1hrxrybc6197ibx0m2wfxlg5pdg4hanf6xvslzrhsp77a04pb0y9", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.89.1#stackable-shared@0.0.1": "1hrxrybc6197ibx0m2wfxlg5pdg4hanf6xvslzrhsp77a04pb0y9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.90.0#stackable-operator-derive@0.3.1": "0fclvpxhchykqd7bl8hscr4v06mbs2v5vjp0xv27nvqr94j63xs2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.90.0#stackable-operator@0.90.0": "0fclvpxhchykqd7bl8hscr4v06mbs2v5vjp0xv27nvqr94j63xs2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.90.0#stackable-shared@0.0.1": "0fclvpxhchykqd7bl8hscr4v06mbs2v5vjp0xv27nvqr94j63xs2", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-telemetry-0.4.0#stackable-telemetry@0.4.0": "0hcm64fb2ngyalq8rci5lrr881prg023pq9cd1sfr79iynbr6a26", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-versioned-0.7.1#k8s-version@0.1.2": "16klfwx3kz3ys7afwjicfj8msws9a718izx09jspwwpff3rl6wsi", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-versioned-0.7.1#stackable-versioned-macros@0.7.1": "16klfwx3kz3ys7afwjicfj8msws9a718izx09jspwwpff3rl6wsi", diff --git a/rust/operator-binary/src/hbase_controller.rs b/rust/operator-binary/src/hbase_controller.rs index 3b9c747a..376036c6 100644 --- a/rust/operator-binary/src/hbase_controller.rs +++ b/rust/operator-binary/src/hbase_controller.rs @@ -82,7 +82,6 @@ use crate::{ operations::{graceful_shutdown::add_graceful_shutdown_config, pdb::add_pdbs}, product_logging::{ CONTAINERDEBUG_LOG_DIRECTORY, STACKABLE_LOG_DIR, extend_role_group_config_map, - resolve_vector_aggregator_address, }, security::{self, opa::HbaseOpaConfig}, zookeeper::{self, ZookeeperConnectionInformation}, @@ -235,10 +234,8 @@ pub enum Error { #[snafu(display("failed to resolve and merge config for role and role group"))] FailedToResolveConfig { source: crate::crd::Error }, - #[snafu(display("failed to resolve the Vector aggregator address"))] - ResolveVectorAggregatorAddress { - source: crate::product_logging::Error, - }, + #[snafu(display("vector agent is enabled but vector aggregator ConfigMap is missing"))] + VectorAggregatorConfigMapMissing, #[snafu(display("failed to add the logging configuration to the ConfigMap [{cm_name}]"))] InvalidLoggingConfig { @@ -350,10 +347,6 @@ pub async fn reconcile_hbase( .await .context(RetrieveZookeeperConnectionInformationSnafu)?; - let vector_aggregator_address = resolve_vector_aggregator_address(hbase, client) - .await - .context(ResolveVectorAggregatorAddressSnafu)?; - let roles = hbase.build_role_properties().context(RolePropertiesSnafu)?; let validated_config = validate_all_roles_and_groups_config( @@ -448,7 +441,6 @@ pub async fn reconcile_hbase( &merged_config, &resolved_product_image, hbase_opa_config.as_ref(), - vector_aggregator_address.as_deref(), )?; let rg_statefulset = build_rolegroup_statefulset( hbase, @@ -576,7 +568,6 @@ fn build_rolegroup_config_map( merged_config: &AnyServiceConfig, resolved_product_image: &ResolvedProductImage, hbase_opa_config: Option<&HbaseOpaConfig>, - vector_aggregator_address: Option<&str>, ) -> Result { let mut hbase_site_xml = String::new(); let mut hbase_env_sh = String::new(); @@ -703,7 +694,6 @@ fn build_rolegroup_config_map( extend_role_group_config_map( rolegroup, - vector_aggregator_address, merged_config.logging(), &mut builder, &resolved_product_image.product_version, @@ -1003,21 +993,28 @@ fn build_rolegroup_statefulset( // Vector sidecar shall be the last container in the list if merged_config.logging().enable_vector_agent { - pod_builder.add_container( - product_logging::framework::vector_container( - resolved_product_image, - "hbase-config", - "log", - merged_config.logging().containers.get(&Container::Vector), - ResourceRequirementsBuilder::new() - .with_cpu_request("250m") - .with_cpu_limit("500m") - .with_memory_request("128Mi") - .with_memory_limit("128Mi") - .build(), - ) - .context(ConfigureLoggingSnafu)?, - ); + if let Some(vector_aggregator_config_map_name) = + &hbase.spec.cluster_config.vector_aggregator_config_map_name + { + pod_builder.add_container( + product_logging::framework::vector_container( + resolved_product_image, + "hbase-config", + "log", + merged_config.logging().containers.get(&Container::Vector), + ResourceRequirementsBuilder::new() + .with_cpu_request("250m") + .with_cpu_limit("500m") + .with_memory_request("128Mi") + .with_memory_limit("128Mi") + .build(), + vector_aggregator_config_map_name, + ) + .context(ConfigureLoggingSnafu)?, + ); + } else { + VectorAggregatorConfigMapMissingSnafu.fail()?; + } } let mut pod_template = pod_builder.build_template(); diff --git a/rust/operator-binary/src/main.rs b/rust/operator-binary/src/main.rs index 3a168704..d720ae74 100644 --- a/rust/operator-binary/src/main.rs +++ b/rust/operator-binary/src/main.rs @@ -6,12 +6,17 @@ use hbase_controller::FULL_HBASE_CONTROLLER_NAME; use stackable_operator::{ YamlSchema, cli::{Command, ProductOperatorRun, RollingPeriod}, - k8s_openapi::api::{apps::v1::StatefulSet, core::v1::Service}, + k8s_openapi::api::{ + apps::v1::StatefulSet, + core::v1::{ConfigMap, Service}, + }, kube::{ + ResourceExt, core::DeserializeGuard, runtime::{ Controller, events::{Recorder, Reporter}, + reflector::ObjectRef, watcher, }, }, @@ -128,46 +133,77 @@ async fn main() -> anyhow::Result<()> { instance: None, })); - Controller::new( + let hbase_controller = Controller::new( watch_namespace.get_api::>(&client), watcher::Config::default(), - ) - .owns( - watch_namespace.get_api::(&client), - watcher::Config::default(), - ) - .owns( - watch_namespace.get_api::(&client), - watcher::Config::default(), - ) - .shutdown_on_signal() - .run( - hbase_controller::reconcile_hbase, - hbase_controller::error_policy, - Arc::new(hbase_controller::Ctx { - client: client.clone(), - product_config, - }), - ) - .for_each_concurrent( - 16, // concurrency limit - |result| { - // The event_recorder needs to be shared across all invocations, so that - // events are correctly aggregated - let event_recorder = event_recorder.clone(); - async move { - report_controller_reconciled( - &event_recorder, - FULL_HBASE_CONTROLLER_NAME, - &result, - ) - .await; - } - }, - ) - .await; + ); + let config_map_store = hbase_controller.store(); + hbase_controller + .owns( + watch_namespace.get_api::(&client), + watcher::Config::default(), + ) + .owns( + watch_namespace.get_api::(&client), + watcher::Config::default(), + ) + .shutdown_on_signal() + .watches( + watch_namespace.get_api::>(&client), + watcher::Config::default(), + move |config_map| { + config_map_store + .state() + .into_iter() + .filter(move |hbase| references_config_map(hbase, &config_map)) + .map(|hbase| ObjectRef::from_obj(&*hbase)) + }, + ) + .run( + hbase_controller::reconcile_hbase, + hbase_controller::error_policy, + Arc::new(hbase_controller::Ctx { + client: client.clone(), + product_config, + }), + ) + .for_each_concurrent( + 16, // concurrency limit + |result| { + // The event_recorder needs to be shared across all invocations, so that + // events are correctly aggregated + let event_recorder = event_recorder.clone(); + async move { + report_controller_reconciled( + &event_recorder, + FULL_HBASE_CONTROLLER_NAME, + &result, + ) + .await; + } + }, + ) + .await; } } Ok(()) } + +fn references_config_map( + hbase: &DeserializeGuard, + config_map: &DeserializeGuard, +) -> bool { + let Ok(hbase) = &hbase.0 else { + return false; + }; + + hbase.spec.cluster_config.zookeeper_config_map_name == config_map.name_any() + || hbase.spec.cluster_config.hdfs_config_map_name == config_map.name_any() + || match &hbase.spec.cluster_config.authorization { + Some(hbase_authorization) => { + hbase_authorization.opa.config_map_name == config_map.name_any() + } + None => false, + } +} diff --git a/rust/operator-binary/src/product_logging.rs b/rust/operator-binary/src/product_logging.rs index 094d981f..072493d6 100644 --- a/rust/operator-binary/src/product_logging.rs +++ b/rust/operator-binary/src/product_logging.rs @@ -1,9 +1,6 @@ -use snafu::{OptionExt, ResultExt, Snafu}; +use snafu::Snafu; use stackable_operator::{ builder::configmap::ConfigMapBuilder, - client::Client, - k8s_openapi::api::core::v1::ConfigMap, - kube::ResourceExt, memory::BinaryMultiple, product_logging::{ self, @@ -45,7 +42,6 @@ pub enum Error { type Result = std::result::Result; -const VECTOR_AGGREGATOR_CM_ENTRY: &str = "ADDRESS"; const CONSOLE_CONVERSION_PATTERN: &str = "%d{ISO8601} %-5p [%t] %c{2}: %.1000m%n"; const HBASE_LOG4J_FILE: &str = "hbase.log4j.xml"; const HBASE_LOG4J2_FILE: &str = "hbase.log4j2.xml"; @@ -55,45 +51,9 @@ pub const STACKABLE_LOG_DIR: &str = "/stackable/log"; pub static CONTAINERDEBUG_LOG_DIRECTORY: std::sync::LazyLock = std::sync::LazyLock::new(|| format!("{STACKABLE_LOG_DIR}/containerdebug")); -/// Return the address of the Vector aggregator if the corresponding ConfigMap name is given in the -/// cluster spec -pub async fn resolve_vector_aggregator_address( - hbase: &v1alpha1::HbaseCluster, - client: &Client, -) -> Result> { - let vector_aggregator_address = if let Some(vector_aggregator_config_map_name) = - &hbase.spec.cluster_config.vector_aggregator_config_map_name - { - let vector_aggregator_address = client - .get::( - vector_aggregator_config_map_name, - hbase - .namespace() - .as_deref() - .context(ObjectHasNoNamespaceSnafu)?, - ) - .await - .context(ConfigMapNotFoundSnafu { - cm_name: vector_aggregator_config_map_name.to_string(), - })? - .data - .and_then(|mut data| data.remove(VECTOR_AGGREGATOR_CM_ENTRY)) - .context(MissingConfigMapEntrySnafu { - entry: VECTOR_AGGREGATOR_CM_ENTRY, - cm_name: vector_aggregator_config_map_name.to_string(), - })?; - Some(vector_aggregator_address) - } else { - None - }; - - Ok(vector_aggregator_address) -} - /// Extend the role group ConfigMap with logging and Vector configurations pub fn extend_role_group_config_map( rolegroup: &RoleGroupRef, - vector_aggregator_address: Option<&str>, logging: &Logging, cm_builder: &mut ConfigMapBuilder, hbase_version: &str, @@ -120,11 +80,7 @@ pub fn extend_role_group_config_map( if logging.enable_vector_agent { cm_builder.add_data( product_logging::framework::VECTOR_CONFIG_FILE, - product_logging::framework::create_vector_config( - rolegroup, - vector_aggregator_address.context(MissingVectorAggregatorAddressSnafu)?, - vector_log_config, - ), + product_logging::framework::create_vector_config(rolegroup, vector_log_config), ); }