Skip to content

Commit 4097911

Browse files
committed
refactor: Use typed constants, remove duplicated merge
1 parent 064e3f4 commit 4097911

11 files changed

Lines changed: 224 additions & 264 deletions

File tree

rust/operator-binary/src/controller/build/jvm.rs

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ fn is_heap_jvm_argument(jvm_argument: &str) -> bool {
100100
#[cfg(test)]
101101
mod tests {
102102
use super::*;
103-
use crate::crd::{HbaseRole, v1alpha1};
103+
use crate::{crd::HbaseRole, test_utils};
104104

105105
#[test]
106106
fn test_construct_jvm_arguments_defaults() {
@@ -109,6 +109,8 @@ mod tests {
109109
kind: HbaseCluster
110110
metadata:
111111
name: simple-hbase
112+
namespace: default
113+
uid: 12345678-1234-1234-1234-123456789012
112114
spec:
113115
image:
114116
productVersion: 2.6.4
@@ -124,16 +126,20 @@ mod tests {
124126
default:
125127
replicas: 1
126128
"#;
127-
let (hbase, merged_config, merged_jvm_argument_overrides) = construct_boilerplate(input);
129+
let hbase = test_utils::hbase_from_yaml(input);
130+
let validated_cluster = test_utils::validated_cluster_from(&hbase);
131+
let region_server = &validated_cluster.role_group_configs[&HbaseRole::RegionServer]
132+
[&test_utils::role_group_name("default")];
128133

129-
let global_jvm_args = construct_global_jvm_args(false);
130-
let role_specific_non_heap_jvm_args =
131-
construct_role_specific_non_heap_jvm_args(&hbase, &merged_jvm_argument_overrides);
132-
let hbase_heapsize_env = construct_hbase_heapsize_env(&merged_config).unwrap();
134+
let global_jvm_args = construct_global_jvm_args(hbase.has_kerberos_enabled());
135+
let hbase_heapsize_env =
136+
construct_hbase_heapsize_env(&region_server.config.config).unwrap();
133137

134138
assert_eq!(global_jvm_args, "");
139+
// `non_heap_jvm_args` is the output of `construct_role_specific_non_heap_jvm_args`,
140+
// pre-resolved during validation.
135141
assert_eq!(
136-
role_specific_non_heap_jvm_args,
142+
region_server.non_heap_jvm_args,
137143
"-Djava.security.properties=/stackable/conf/security.properties"
138144
);
139145
assert_eq!(hbase_heapsize_env, "819m");
@@ -146,6 +152,8 @@ mod tests {
146152
kind: HbaseCluster
147153
metadata:
148154
name: simple-hbase
155+
namespace: default
156+
uid: 12345678-1234-1234-1234-123456789012
149157
spec:
150158
image:
151159
productVersion: 2.6.4
@@ -180,19 +188,21 @@ mod tests {
180188
- -Xmx40000m # This has no effect!
181189
- -Dhttps.proxyPort=1234
182190
"#;
183-
let (hbase, merged_config, merged_jvm_argument_overrides) = construct_boilerplate(input);
191+
let hbase = test_utils::hbase_from_yaml(input);
192+
let validated_cluster = test_utils::validated_cluster_from(&hbase);
193+
let region_server = &validated_cluster.role_group_configs[&HbaseRole::RegionServer]
194+
[&test_utils::role_group_name("default")];
184195

185196
let global_jvm_args = construct_global_jvm_args(hbase.has_kerberos_enabled());
186-
let role_specific_non_heap_jvm_args =
187-
construct_role_specific_non_heap_jvm_args(&hbase, &merged_jvm_argument_overrides);
188-
let hbase_heapsize_env = construct_hbase_heapsize_env(&merged_config).unwrap();
197+
let hbase_heapsize_env =
198+
construct_hbase_heapsize_env(&region_server.config.config).unwrap();
189199

190200
assert_eq!(
191201
global_jvm_args,
192202
"-Djava.security.krb5.conf=/stackable/kerberos/krb5.conf"
193203
);
194204
assert_eq!(
195-
role_specific_non_heap_jvm_args,
205+
region_server.non_heap_jvm_args,
196206
"-Djava.security.properties=/stackable/conf/security.properties \
197207
-Djava.security.krb5.conf=/stackable/kerberos/krb5.conf \
198208
-Dhttps.proxyHost=proxy.my.corp \
@@ -201,28 +211,4 @@ mod tests {
201211
);
202212
assert_eq!(hbase_heapsize_env, "34406m");
203213
}
204-
205-
fn construct_boilerplate(
206-
hbase_cluster: &str,
207-
) -> (
208-
v1alpha1::HbaseCluster,
209-
AnyServiceConfig,
210-
JvmArgumentOverrides,
211-
) {
212-
let hbase: v1alpha1::HbaseCluster =
213-
serde_yaml::from_str(hbase_cluster).expect("illegal test input");
214-
215-
// Merge + validate the region server `default` role group via the real
216-
// `with_validated_config` path, returning the merged config (for heap sizing) and the
217-
// merged JVM argument overrides.
218-
let (merged_config, merged_jvm_argument_overrides) =
219-
crate::crd::test_helpers::merged_role_group_config(
220-
&hbase,
221-
&HbaseRole::RegionServer,
222-
"default",
223-
"my-hdfs",
224-
);
225-
226-
(hbase, merged_config, merged_jvm_argument_overrides)
227-
}
228214
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub fn build(
6262
#[cfg(test)]
6363
mod tests {
6464
use super::*;
65-
use crate::controller::build::properties::test_support::{merged_config, validated_cluster};
65+
use crate::test_utils::{merged_config, validated_cluster};
6666

6767
#[test]
6868
fn renders_operator_defaults() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub fn build(
112112
#[cfg(test)]
113113
mod tests {
114114
use super::*;
115-
use crate::controller::build::properties::test_support::{merged_config, validated_cluster};
115+
use crate::test_utils::{merged_config, validated_cluster};
116116

117117
#[test]
118118
fn renders_operator_defaults() {

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

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -57,89 +57,3 @@ mod tests {
5757
assert_eq!(ConfigFileName::Log4j2.to_string(), "log4j2.properties");
5858
}
5959
}
60-
61-
#[cfg(test)]
62-
pub(crate) mod test_support {
63-
use std::str::FromStr;
64-
65-
use stackable_operator::{
66-
commons::networking::DomainName, utils::cluster_info::KubernetesClusterInfo,
67-
};
68-
69-
use crate::{
70-
controller::{
71-
ValidatedCluster, dereference::DereferencedObjects, validate::validate_cluster,
72-
zookeeper::ZookeeperConnectionInformation,
73-
},
74-
crd::{AnyServiceConfig, HbaseRole, v1alpha1},
75-
};
76-
77-
/// A minimal three-role HbaseCluster used to drive the per-file builder tests.
78-
pub const MINIMAL_HBASE_YAML: &str = r#"
79-
---
80-
apiVersion: hbase.stackable.tech/v1alpha1
81-
kind: HbaseCluster
82-
metadata:
83-
name: hbase
84-
namespace: default
85-
uid: c2c8c5c0-0b5a-4b1e-9f3e-1a2b3c4d5e6f
86-
spec:
87-
image:
88-
productVersion: 2.6.3
89-
clusterConfig:
90-
hdfsConfigMapName: simple-hdfs
91-
zookeeperConfigMapName: simple-znode
92-
masters:
93-
roleGroups:
94-
default:
95-
replicas: 1
96-
regionServers:
97-
roleGroups:
98-
default:
99-
replicas: 1
100-
restServers:
101-
roleGroups:
102-
default:
103-
replicas: 1
104-
"#;
105-
106-
pub fn minimal_hbase() -> v1alpha1::HbaseCluster {
107-
serde_yaml::from_str(MINIMAL_HBASE_YAML).expect("invalid test HbaseCluster YAML")
108-
}
109-
110-
pub fn cluster_info() -> KubernetesClusterInfo {
111-
KubernetesClusterInfo {
112-
cluster_domain: DomainName::try_from("cluster.local").unwrap(),
113-
}
114-
}
115-
116-
/// Runs the real validation pipeline once over [`minimal_hbase`], with a fixed
117-
/// dereferenced ZooKeeper connection (and no OPA), so the per-file builder tests can
118-
/// pull merged configs straight from the [`ValidatedCluster`] instead of re-merging by
119-
/// hand via `crd::merged_config`.
120-
pub fn validated_cluster() -> ValidatedCluster {
121-
validate_cluster(
122-
&minimal_hbase(),
123-
"oci.example.org",
124-
&cluster_info(),
125-
DereferencedObjects {
126-
zookeeper_connection_information: ZookeeperConnectionInformation::for_tests(),
127-
hbase_opa_config: None,
128-
},
129-
)
130-
.expect("validate should succeed for the minimal fixture")
131-
}
132-
133-
/// The merged [`AnyServiceConfig`] for the `default` role group of `role`.
134-
pub fn merged_config<'a>(
135-
validated_cluster: &'a ValidatedCluster,
136-
role: &HbaseRole,
137-
) -> &'a AnyServiceConfig {
138-
let default_role_group =
139-
stackable_operator::v2::types::operator::RoleGroupName::from_str("default")
140-
.expect("'default' is a valid role group name");
141-
&validated_cluster.role_group_configs[role][&default_role_group]
142-
.config
143-
.config
144-
}
145-
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,10 @@ fn prometheus_annotations(hbase: &v1alpha1::HbaseCluster, hbase_role: &HbaseRole
137137

138138
#[cfg(test)]
139139
mod test {
140-
use std::str::FromStr;
141-
142140
use rstest::rstest;
143-
use stackable_operator::v2::types::operator::RoleGroupName;
144141

145142
use super::*;
146-
use crate::controller::build::properties::test_support;
143+
use crate::test_utils;
147144

148145
#[rstest]
149146
#[case("2.6.3", HbaseRole::Master, vec!["master", "ui-http"])]
@@ -187,8 +184,8 @@ mod test {
187184
let hbase: v1alpha1::HbaseCluster =
188185
serde_yaml::from_str(&input).expect("illegal test input");
189186

190-
let cluster = test_support::validated_cluster();
191-
let role_group_name = RoleGroupName::from_str("default").expect("valid role group name");
187+
let cluster = test_utils::validated_cluster();
188+
let role_group_name = test_utils::role_group_name("default");
192189
let service = build_rolegroup_service(&hbase, &cluster, &role, &role_group_name);
193190

194191
assert_eq!(

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

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ use crate::{
4848

4949
stackable_operator::constant!(VECTOR_CONTAINER_NAME: ContainerName = "vector");
5050

51-
// The Vector container reads `vector.yaml` from the rolegroup ConfigMap (mounted as the
52-
// `hbase-config` volume) and writes to the shared `log` volume. These reuse the existing
53-
// volume-name string values so the produced volume mounts match the rest of the Pod.
54-
stackable_operator::constant!(VECTOR_LOG_CONFIG_VOLUME_NAME: VolumeName = "hbase-config");
55-
stackable_operator::constant!(VECTOR_LOG_VOLUME_NAME: VolumeName = "log");
51+
// Pod volume names. The Vector container reuses the `hbase-config` (rolegroup ConfigMap, which
52+
// carries `vector.yaml`) and `log` volumes, so the produced volume mounts match the rest of the
53+
// Pod.
54+
stackable_operator::constant!(HBASE_CONFIG_VOLUME_NAME: VolumeName = "hbase-config");
55+
stackable_operator::constant!(HDFS_DISCOVERY_VOLUME_NAME: VolumeName = "hdfs-discovery");
56+
stackable_operator::constant!(LOG_CONFIG_VOLUME_NAME: VolumeName = "log-config");
57+
stackable_operator::constant!(LOG_VOLUME_NAME: VolumeName = "log");
5658

5759
pub static CONTAINERDEBUG_LOG_DIRECTORY: std::sync::LazyLock<String> =
5860
std::sync::LazyLock::new(|| format!("{STACKABLE_LOG_DIR}/containerdebug"));
@@ -192,13 +194,13 @@ pub fn build_rolegroup_statefulset(
192194
"CONTAINERDEBUG_LOG_DIRECTORY",
193195
&*CONTAINERDEBUG_LOG_DIRECTORY,
194196
)
195-
.add_volume_mount("hbase-config", HBASE_CONFIG_TMP_DIR)
197+
.add_volume_mount(&*HBASE_CONFIG_VOLUME_NAME, HBASE_CONFIG_TMP_DIR)
196198
.context(AddVolumeMountSnafu)?
197-
.add_volume_mount("hdfs-discovery", HDFS_DISCOVERY_TMP_DIR)
199+
.add_volume_mount(&*HDFS_DISCOVERY_VOLUME_NAME, HDFS_DISCOVERY_TMP_DIR)
198200
.context(AddVolumeMountSnafu)?
199-
.add_volume_mount("log-config", HBASE_LOG_CONFIG_TMP_DIR)
201+
.add_volume_mount(&*LOG_CONFIG_VOLUME_NAME, HBASE_LOG_CONFIG_TMP_DIR)
200202
.context(AddVolumeMountSnafu)?
201-
.add_volume_mount("log", STACKABLE_LOG_DIR)
203+
.add_volume_mount(&*LOG_VOLUME_NAME, STACKABLE_LOG_DIR)
202204
.context(AddVolumeMountSnafu)?
203205
.add_volume_mount(LISTENER_VOLUME_NAME, LISTENER_VOLUME_DIR)
204206
.context(AddVolumeMountSnafu)?
@@ -221,7 +223,7 @@ pub fn build_rolegroup_statefulset(
221223
.image_pull_secrets_from_product_image(resolved_product_image)
222224
.affinity(merged_config.affinity())
223225
.add_volume(Volume {
224-
name: "hbase-config".to_string(),
226+
name: HBASE_CONFIG_VOLUME_NAME.to_string(),
225227
config_map: Some(ConfigMapVolumeSource {
226228
name: resource_names.role_group_config_map().to_string(),
227229
..Default::default()
@@ -230,7 +232,7 @@ pub fn build_rolegroup_statefulset(
230232
})
231233
.context(AddVolumeSnafu)?
232234
.add_volume(Volume {
233-
name: "hdfs-discovery".to_string(),
235+
name: HDFS_DISCOVERY_VOLUME_NAME.to_string(),
234236
config_map: Some(ConfigMapVolumeSource {
235237
name: hbase.spec.cluster_config.hdfs_config_map_name.clone(),
236238
..Default::default()
@@ -239,7 +241,7 @@ pub fn build_rolegroup_statefulset(
239241
})
240242
.context(AddVolumeSnafu)?
241243
.add_empty_dir_volume(
242-
"log",
244+
&*LOG_VOLUME_NAME,
243245
Some(product_logging::framework::calculate_log_volume_size_limit(
244246
&[MAX_HBASE_LOG_FILES_SIZE],
245247
)),
@@ -259,7 +261,7 @@ pub fn build_rolegroup_statefulset(
259261
};
260262
pod_builder
261263
.add_volume(Volume {
262-
name: "log-config".to_string(),
264+
name: LOG_CONFIG_VOLUME_NAME.to_string(),
263265
config_map: Some(ConfigMapVolumeSource {
264266
name: log_config_config_map,
265267
..ConfigMapVolumeSource::default()
@@ -290,8 +292,8 @@ pub fn build_rolegroup_statefulset(
290292
resolved_product_image,
291293
vector_log_config,
292294
&resource_names,
293-
&VECTOR_LOG_CONFIG_VOLUME_NAME,
294-
&VECTOR_LOG_VOLUME_NAME,
295+
&HBASE_CONFIG_VOLUME_NAME,
296+
&LOG_VOLUME_NAME,
295297
EnvVarSet::new(),
296298
));
297299
}

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,4 +426,58 @@ spec:
426426
assert_eq!(env.get("TEST_VAR_FROM_MASTER"), Some(&"MASTER".to_string()));
427427
assert_eq!(env.get("TEST_VAR_FROM_MRG"), Some(&"MASTER".to_string()));
428428
}
429+
430+
/// A custom log ConfigMap name that is not a valid Kubernetes name is rejected up-front.
431+
#[test]
432+
fn validate_logging_rejects_invalid_custom_config_map_name() {
433+
use stackable_operator::product_logging::spec::{
434+
ConfigMapLogConfig, ContainerLogConfig, ContainerLogConfigChoice,
435+
CustomContainerLogConfig,
436+
};
437+
438+
let logging = Logging {
439+
enable_vector_agent: false,
440+
containers: [(
441+
Container::Hbase,
442+
ContainerLogConfig {
443+
choice: Some(ContainerLogConfigChoice::Custom(CustomContainerLogConfig {
444+
custom: ConfigMapLogConfig {
445+
config_map: "invalid ConfigMap name".to_owned(),
446+
},
447+
})),
448+
},
449+
)]
450+
.into(),
451+
};
452+
453+
assert!(validate_logging(&logging, &None).is_err());
454+
}
455+
456+
/// Enabling the Vector agent without a Vector aggregator discovery ConfigMap name fails, but
457+
/// succeeds once a valid name is provided.
458+
#[test]
459+
fn validate_logging_requires_vector_aggregator_when_enabled() {
460+
use stackable_operator::product_logging::spec::{
461+
AutomaticContainerLogConfig, ContainerLogConfig, ContainerLogConfigChoice,
462+
};
463+
464+
let automatic = || ContainerLogConfig {
465+
choice: Some(ContainerLogConfigChoice::Automatic(
466+
AutomaticContainerLogConfig::default(),
467+
)),
468+
};
469+
let logging = Logging {
470+
enable_vector_agent: true,
471+
containers: [
472+
(Container::Hbase, automatic()),
473+
(Container::Vector, automatic()),
474+
]
475+
.into(),
476+
};
477+
478+
assert!(validate_logging(&logging, &None).is_err());
479+
480+
let aggregator = ConfigMapName::from_str("vector-aggregator").expect("valid name");
481+
assert!(validate_logging(&logging, &Some(aggregator)).is_ok());
482+
}
429483
}

0 commit comments

Comments
 (0)