Skip to content

Commit 7657b43

Browse files
committed
refactor: introduce ValidatedLoggingConfig
1 parent 7ece0d7 commit 7657b43

6 files changed

Lines changed: 102 additions & 76 deletions

File tree

rust/operator-binary/src/controller/build/properties/product_logging/mod.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@
22
33
use stackable_operator::{
44
memory::BinaryMultiple,
5-
product_logging::{
6-
self,
7-
spec::{ContainerLogConfig, ContainerLogConfigChoice, Logging},
8-
},
9-
v2::product_logging::framework::STACKABLE_LOG_DIR,
5+
product_logging,
6+
v2::product_logging::framework::{STACKABLE_LOG_DIR, ValidatedContainerLogConfigChoice},
107
};
118

129
use crate::crd::{Container, MAX_NIFI_LOG_FILES_SIZE};
@@ -49,12 +46,10 @@ const ADDITIONAL_LOGBACK_CONFIG: &str = r#" <appender name="PASSTHROUGH" class=
4946
///
5047
/// Returns `None` when the container uses a custom log ConfigMap instead of the operator's
5148
/// automatic logging configuration.
52-
pub fn build_logback_config(logging: &Logging<Container>) -> Option<String> {
53-
let ContainerLogConfig {
54-
choice: Some(ContainerLogConfigChoice::Automatic(log_config)),
55-
} = logging.containers.get(&Container::Nifi)?
56-
else {
57-
return None;
49+
pub fn build_logback_config(nifi_container: &ValidatedContainerLogConfigChoice) -> Option<String> {
50+
let log_config = match nifi_container {
51+
ValidatedContainerLogConfigChoice::Automatic(log_config) => log_config,
52+
ValidatedContainerLogConfigChoice::Custom(_) => return None,
5853
};
5954

6055
Some(product_logging::framework::create_logback_config(

rust/operator-binary/src/controller/build/properties/security_properties.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@ mod tests {
3030

3131
use super::*;
3232
use crate::{
33-
controller::ValidatedRoleGroupConfig,
33+
controller::{ValidatedLogging, ValidatedRoleGroupConfig},
3434
crd::{NifiConfig, v1alpha1::NifiConfigOverrides},
3535
};
3636

3737
fn make_rg(overrides: Option<BTreeMap<String, String>>) -> ValidatedRoleGroupConfig {
3838
use std::str::FromStr as _;
3939

4040
use stackable_operator::v2::{
41+
product_logging::framework::ValidatedContainerLogConfigChoice,
4142
role_utils::JavaCommonConfig, types::operator::RoleGroupName,
4243
};
4344
ValidatedRoleGroupConfig {
@@ -53,7 +54,11 @@ mod tests {
5354
env_overrides: EnvVarSet::new(),
5455
pod_overrides: Default::default(),
5556
product_specific_common_config: JavaCommonConfig::default(),
56-
vector_container: None,
57+
logging: ValidatedLogging {
58+
nifi_container: ValidatedContainerLogConfigChoice::Automatic(Default::default()),
59+
vector_container: None,
60+
enable_vector_agent: false,
61+
},
5762
git_sync_resources: Default::default(),
5863
}
5964
}

rust/operator-binary/src/controller/build/resource/config_map.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,12 @@ pub fn build_rolegroup_config_map(
113113
})?,
114114
);
115115

116-
if let Some(logback_config) = product_logging::build_logback_config(&rg.config.logging) {
116+
if let Some(logback_config) = product_logging::build_logback_config(&rg.logging.nifi_container)
117+
{
117118
cm_builder.add_data(ConfigFileName::Logback.to_string(), logback_config);
118119
}
119120

120-
if rg.config.logging.enable_vector_agent {
121+
if rg.logging.enable_vector_agent {
121122
cm_builder.add_data(
122123
VECTOR_CONFIG_FILE,
123124
product_logging::vector_config_file_content(),

rust/operator-binary/src/controller/build/resource/statefulset.rs

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,14 @@ use stackable_operator::{
3131
product_logging::{
3232
self,
3333
framework::{create_vector_shutdown_file_command, remove_vector_shutdown_file_command},
34-
spec::{
35-
ConfigMapLogConfig, ContainerLogConfig, ContainerLogConfigChoice,
36-
CustomContainerLogConfig,
37-
},
34+
spec::{ContainerLogConfig, ContainerLogConfigChoice},
3835
},
3936
utils::{COMMON_BASH_TRAP_FUNCTIONS, cluster_info::KubernetesClusterInfo},
4037
v2::{
4138
builder::pod::container::{EnvVarSet, new_container_builder},
42-
product_logging::framework::{STACKABLE_LOG_DIR, vector_container},
39+
product_logging::framework::{
40+
STACKABLE_LOG_DIR, ValidatedContainerLogConfigChoice, vector_container,
41+
},
4342
types::kubernetes::{ContainerName, VolumeName},
4443
},
4544
};
@@ -502,41 +501,30 @@ pub(crate) async fn build_node_rolegroup_statefulset(
502501
.add_volumes(git_sync_resources.git_ca_cert_volumes.to_owned())
503502
.context(AddVolumeSnafu)?;
504503

505-
if let Some(ContainerLogConfig {
506-
choice:
507-
Some(ContainerLogConfigChoice::Custom(CustomContainerLogConfig {
508-
custom: ConfigMapLogConfig { config_map },
509-
})),
510-
}) = merged_config.logging.containers.get(&Container::Nifi)
511-
{
512-
pod_builder
513-
.add_volume(Volume {
514-
name: LOG_CONFIG_VOLUME_NAME.to_string(),
515-
config_map: Some(ConfigMapVolumeSource {
516-
name: config_map.clone(),
517-
..ConfigMapVolumeSource::default()
518-
}),
519-
..Volume::default()
520-
})
521-
.context(AddVolumeSnafu)?;
522-
} else {
523-
pod_builder
524-
.add_volume(Volume {
525-
name: LOG_CONFIG_VOLUME_NAME.to_string(),
526-
config_map: Some(ConfigMapVolumeSource {
527-
name: resource_names.role_group_config_map().to_string(),
528-
..ConfigMapVolumeSource::default()
529-
}),
530-
..Volume::default()
531-
})
532-
.context(AddVolumeSnafu)?;
533-
}
504+
// The NiFi `log-config` volume sources from the custom log ConfigMap when one is configured,
505+
// otherwise from this rolegroup's ConfigMap (which carries the operator-generated `logback.xml`).
506+
let log_config_map_name = match &rg.logging.nifi_container {
507+
ValidatedContainerLogConfigChoice::Custom(config_map) => config_map.to_string(),
508+
ValidatedContainerLogConfigChoice::Automatic(_) => {
509+
resource_names.role_group_config_map().to_string()
510+
}
511+
};
512+
pod_builder
513+
.add_volume(Volume {
514+
name: LOG_CONFIG_VOLUME_NAME.to_string(),
515+
config_map: Some(ConfigMapVolumeSource {
516+
name: log_config_map_name,
517+
..ConfigMapVolumeSource::default()
518+
}),
519+
..Volume::default()
520+
})
521+
.context(AddVolumeSnafu)?;
534522

535523
// The Vector logging config was validated up-front in the `validate` step. The static
536524
// `vector.yaml` is shipped in the rolegroup `ConfigMap`; the per-rolegroup values (namespace,
537525
// cluster/role/role-group, aggregator address, log levels) are injected as environment
538526
// variables here and substituted by Vector at runtime.
539-
if let Some(vector_log_config) = &rg.vector_container {
527+
if let Some(vector_log_config) = &rg.logging.vector_container {
540528
pod_builder.add_container(vector_container(
541529
&VECTOR_CONTAINER_NAME,
542530
resolved_product_image,

rust/operator-binary/src/controller/mod.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use stackable_operator::{
1717
HasName, HasUid, NameIsValidLabelValue,
1818
builder::pod::container::EnvVarSet,
1919
kvp::label::{recommended_labels, role_group_selector, role_selector},
20-
product_logging::framework::VectorContainerLogConfig,
20+
product_logging::framework::{ValidatedContainerLogConfigChoice, VectorContainerLogConfig},
2121
role_group_utils::ResourceNames,
2222
role_utils::JavaCommonConfig,
2323
types::{
@@ -74,17 +74,33 @@ pub struct ValidatedRoleGroupConfig {
7474
/// The merged (role <- role group) JVM argument overrides, applied on top of the
7575
/// operator-generated JVM arguments when building `bootstrap.conf`.
7676
pub product_specific_common_config: JavaCommonConfig,
77-
/// The validated Vector container logging config (log config choice + aggregator discovery
78-
/// ConfigMap name), validated up-front in the [`validate`] step. `None` when the Vector agent
79-
/// is disabled for this role group.
80-
pub vector_container: Option<VectorContainerLogConfig>,
77+
/// The validated logging configuration (NiFi and optional Vector container), validated up-front
78+
/// in the [`validate`] step (mirroring hive/opensearch).
79+
pub logging: ValidatedLogging,
8180
/// The git-sync resources (containers, volumes, mounts) for this role group, resolved from the
8281
/// cluster's `customComponentsGitSync` specs up-front in the [`validate`] step. The env vars and
8382
/// logging config differ per role group, so these are computed per role group. Consumed by both
8483
/// the StatefulSet builder and the `nifi.properties` builder.
8584
pub git_sync_resources: git_sync::v1alpha2::GitSyncResources,
8685
}
8786

87+
/// Validated logging configuration for the NiFi and (optional) Vector container.
88+
///
89+
/// Produced up-front by the [`validate`] step (mirroring hive/opensearch) so that an invalid custom
90+
/// log ConfigMap name, or a missing Vector aggregator discovery ConfigMap name, fails reconciliation
91+
/// during validation rather than at resource-build time.
92+
#[derive(Clone, Debug)]
93+
pub struct ValidatedLogging {
94+
/// The NiFi container log config choice (automatic logging vs a custom log ConfigMap). Consumed
95+
/// by the `logback.xml` builder and the StatefulSet's `log-config` volume.
96+
pub nifi_container: ValidatedContainerLogConfigChoice,
97+
/// The Vector container log config (log config choice + aggregator discovery ConfigMap name).
98+
/// `None` when the Vector agent is disabled for this role group.
99+
pub vector_container: Option<VectorContainerLogConfig>,
100+
/// Whether the Vector log agent is enabled for this role group.
101+
pub enable_vector_agent: bool,
102+
}
103+
88104
/// The validated NifiCluster: everything `reconcile_nifi` needs after dereferencing,
89105
/// in fail-safe / resolved form. This is the single resolved representation of the cluster;
90106
/// downstream builders should source everything from here and never touch the raw `NifiCluster`.

rust/operator-binary/src/controller/validate.rs

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use stackable_operator::{
1111
commons::product_image_selection,
1212
config::fragment,
1313
kube::ResourceExt as _,
14+
product_logging::spec::Logging,
1415
role_utils::CommonConfiguration,
1516
v2::{
1617
builder::pod::container::{self, EnvVarName, EnvVarSet},
@@ -28,7 +29,8 @@ use stackable_operator::{
2829
use strum::{EnumDiscriminants, IntoStaticStr};
2930

3031
use super::{
31-
ValidatedCluster, ValidatedClusterConfig, ValidatedRoleConfig, ValidatedRoleGroupConfig,
32+
ValidatedCluster, ValidatedClusterConfig, ValidatedLogging, ValidatedRoleConfig,
33+
ValidatedRoleGroupConfig,
3234
};
3335
use crate::{
3436
controller::{build::git_sync::build_git_sync_resources, dereference::DereferencedObjects},
@@ -236,24 +238,11 @@ pub(crate) fn build_role_group_configs(
236238
);
237239
}
238240

239-
// Validate the Vector container logging config up-front (mirroring the opensearch- and
240-
// hive-operators) so an invalid log ConfigMap name, or a missing aggregator discovery
241-
// ConfigMap name, fails before any resources are built.
242-
let vector_container = if config.logging.enable_vector_agent {
243-
let vector_aggregator_config_map_name = vector_aggregator_config_map_name
244-
.clone()
245-
.context(MissingVectorAggregatorConfigMapNameSnafu)?;
246-
Some(VectorContainerLogConfig {
247-
log_config: validate_logging_configuration_for_container(
248-
&config.logging,
249-
&Container::Vector,
250-
)
251-
.context(ValidateLoggingConfigSnafu)?,
252-
vector_aggregator_config_map_name,
253-
})
254-
} else {
255-
None
256-
};
241+
// Validate the logging config (NiFi + optional Vector container) up-front (mirroring the
242+
// opensearch- and hive-operators) so an invalid custom log ConfigMap name, or a missing
243+
// Vector aggregator discovery ConfigMap name, fails during validation rather than at
244+
// resource-build time.
245+
let logging = validate_logging(&config.logging, vector_aggregator_config_map_name)?;
257246

258247
// The git-sync resources depend on this role group's env-var overrides and logging config,
259248
// so they are resolved (and validated) per role group up-front rather than at build time.
@@ -275,7 +264,7 @@ pub(crate) fn build_role_group_configs(
275264
env_overrides: env_overrides_set,
276265
pod_overrides,
277266
product_specific_common_config,
278-
vector_container,
267+
logging,
279268
git_sync_resources,
280269
},
281270
);
@@ -286,6 +275,37 @@ pub(crate) fn build_role_group_configs(
286275
Ok(role_group_configs)
287276
}
288277

278+
/// Validates the logging configuration for the NiFi (and optional Vector) container.
279+
///
280+
/// `vector_aggregator_config_map_name` is the discovery ConfigMap name of the Vector aggregator;
281+
/// it is required (and validated) only when the Vector agent is enabled.
282+
fn validate_logging(
283+
logging: &Logging<Container>,
284+
vector_aggregator_config_map_name: &Option<ConfigMapName>,
285+
) -> Result<ValidatedLogging> {
286+
let nifi_container = validate_logging_configuration_for_container(logging, &Container::Nifi)
287+
.context(ValidateLoggingConfigSnafu)?;
288+
289+
let vector_container = if logging.enable_vector_agent {
290+
let vector_aggregator_config_map_name = vector_aggregator_config_map_name
291+
.clone()
292+
.context(MissingVectorAggregatorConfigMapNameSnafu)?;
293+
Some(VectorContainerLogConfig {
294+
log_config: validate_logging_configuration_for_container(logging, &Container::Vector)
295+
.context(ValidateLoggingConfigSnafu)?,
296+
vector_aggregator_config_map_name,
297+
})
298+
} else {
299+
None
300+
};
301+
302+
Ok(ValidatedLogging {
303+
nifi_container,
304+
vector_container,
305+
enable_vector_agent: logging.enable_vector_agent,
306+
})
307+
}
308+
289309
/// A minimal resolved product image (NiFi 2.9.0) for tests that need to build role-group configs.
290310
#[cfg(test)]
291311
pub(crate) fn test_resolved_product_image() -> product_image_selection::ResolvedProductImage {
@@ -370,6 +390,7 @@ mod tests {
370390
.expect("role group configs should validate");
371391

372392
let vector = default_rg(&configs)
393+
.logging
373394
.vector_container
374395
.as_ref()
375396
.expect("the Vector container config should be present when the agent is enabled");
@@ -402,6 +423,6 @@ mod tests {
402423
let configs = build_role_group_configs(&nifi, &test_resolved_product_image(), &None)
403424
.expect("role group configs should validate");
404425

405-
assert!(default_rg(&configs).vector_container.is_none());
426+
assert!(default_rg(&configs).logging.vector_container.is_none());
406427
}
407428
}

0 commit comments

Comments
 (0)