Skip to content

Commit 99f1d95

Browse files
committed
refactor: switch to EnvVarSet
1 parent 08a00b2 commit 99f1d95

3 files changed

Lines changed: 60 additions & 52 deletions

File tree

rust/operator-binary/src/framework/role_utils.rs

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
//! zookeeper-operator.
44
//!
55
//! Differences from upstream:
6-
//! - `env_overrides` is `BTreeMap<String, String>` instead of `EnvVarSet`.
76
//! - No `cli_overrides_to_vec` helper, `ResourceNames`, or service-account helpers.
87
//! - The `CommonConfig` (a.k.a. `product_specific_common_config`) does NOT need to
98
//! implement `Merge`. ZooKeeper uses `JavaCommonConfig`, which intentionally does
@@ -14,9 +13,13 @@
1413
//! Replace with `stackable_operator::v2::role_utils::*` once upstream publishes
1514
//! the module.
1615
17-
use std::collections::BTreeMap;
16+
use std::{
17+
collections::{BTreeMap, HashMap},
18+
str::FromStr,
19+
};
1820

1921
use serde::Serialize;
22+
use snafu::{ResultExt, Snafu};
2023
use stackable_operator::{
2124
config::{
2225
fragment::{self, FromFragment},
@@ -25,19 +28,28 @@ use stackable_operator::{
2528
k8s_openapi::{DeepMerge, api::core::v1::PodTemplateSpec},
2629
role_utils::{Role, RoleGroup},
2730
schemars::JsonSchema,
31+
v2::builder::pod::container::{self, EnvVarName, EnvVarSet},
2832
};
2933

34+
#[derive(Snafu, Debug)]
35+
pub enum Error {
36+
#[snafu(display("failed to validate the role group config"))]
37+
ValidateConfig { source: fragment::ValidationError },
38+
39+
#[snafu(display("invalid environment variable override name"))]
40+
ParseEnvVarName { source: container::Error },
41+
}
42+
3043
/// A validated, merged view of a `RoleGroup`.
3144
///
3245
/// Mirrors `stackable_operator::v2::role_utils::RoleGroupConfig` on the
33-
/// `smooth-operator` branch, with `env_overrides: BTreeMap<String, String>`
34-
/// instead of the upstream `EnvVarSet`.
46+
/// `smooth-operator` branch.
3547
#[derive(Clone, Debug, PartialEq)]
3648
pub struct RoleGroupConfig<Config, CommonConfig, ConfigOverrides> {
3749
pub replicas: u16,
3850
pub config: Config,
3951
pub config_overrides: ConfigOverrides,
40-
pub env_overrides: BTreeMap<String, String>,
52+
pub env_overrides: EnvVarSet,
4153
pub cli_overrides: BTreeMap<String, String>,
4254
pub pod_overrides: PodTemplateSpec,
4355
pub product_specific_common_config: CommonConfig,
@@ -58,18 +70,16 @@ pub fn with_validated_config<ValidatedConfig, CommonConfig, Config, RoleConfig,
5870
role_group: &RoleGroup<Config, CommonConfig, ConfigOverrides>,
5971
role: &Role<Config, ConfigOverrides, RoleConfig, CommonConfig>,
6072
default_config: &Config,
61-
) -> Result<
62-
RoleGroupConfig<ValidatedConfig, CommonConfig, ConfigOverrides>,
63-
fragment::ValidationError,
64-
>
73+
) -> Result<RoleGroupConfig<ValidatedConfig, CommonConfig, ConfigOverrides>, Error>
6574
where
6675
ValidatedConfig: FromFragment<Fragment = Config>,
6776
CommonConfig: Clone + Default + JsonSchema + Serialize,
6877
Config: Clone + Merge,
6978
RoleConfig: Default + JsonSchema + Serialize,
7079
ConfigOverrides: Clone + Default + JsonSchema + Merge + Serialize,
7180
{
72-
let validated_config = validate_config(role_group, role, default_config)?;
81+
let validated_config =
82+
validate_config(role_group, role, default_config).context(ValidateConfigSnafu)?;
7383
Ok(RoleGroupConfig {
7484
replicas: role_group.replicas.unwrap_or(1),
7585
config: validated_config,
@@ -78,18 +88,9 @@ where
7888
role_group.config.config_overrides.clone(),
7989
),
8090
env_overrides: merged_env_overrides(
81-
role.config
82-
.env_overrides
83-
.iter()
84-
.map(|(k, v)| (k.clone(), v.clone()))
85-
.collect(),
86-
role_group
87-
.config
88-
.env_overrides
89-
.iter()
90-
.map(|(k, v)| (k.clone(), v.clone()))
91-
.collect(),
92-
),
91+
&role.config.env_overrides,
92+
&role_group.config.env_overrides,
93+
)?,
9394
cli_overrides: merged_cli_overrides(
9495
role.config.cli_overrides.clone(),
9596
role_group.config.cli_overrides.clone(),
@@ -128,12 +129,22 @@ where
128129
}
129130

130131
fn merged_env_overrides(
131-
role_env_overrides: BTreeMap<String, String>,
132-
role_group_env_overrides: BTreeMap<String, String>,
133-
) -> BTreeMap<String, String> {
134-
let mut merged = role_env_overrides;
135-
merged.extend(role_group_env_overrides);
136-
merged
132+
role_env_overrides: &HashMap<String, String>,
133+
role_group_env_overrides: &HashMap<String, String>,
134+
) -> Result<EnvVarSet, Error> {
135+
// Process the role first, then the role group, so that role-group overrides win on key
136+
// collisions (`EnvVarSet::with_value` overrides earlier entries with the same name).
137+
let mut env_overrides = EnvVarSet::new();
138+
for (name, value) in role_env_overrides
139+
.iter()
140+
.chain(role_group_env_overrides.iter())
141+
{
142+
env_overrides = env_overrides.with_value(
143+
&EnvVarName::from_str(name).context(ParseEnvVarNameSnafu)?,
144+
value.clone(),
145+
);
146+
}
147+
Ok(env_overrides)
137148
}
138149

139150
fn merged_cli_overrides(

rust/operator-binary/src/zk_controller.rs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Ensures that `Pod`s are configured and running for each [`v1alpha1::ZookeeperCluster`]
2-
use std::{collections::BTreeMap, hash::Hasher, sync::Arc};
2+
use std::{hash::Hasher, sync::Arc};
33

44
use const_format::concatcp;
55
use fnv::FnvHasher;
@@ -58,6 +58,7 @@ use stackable_operator::{
5858
statefulset::StatefulSetConditionBuilder,
5959
},
6060
utils::COMMON_BASH_TRAP_FUNCTIONS,
61+
v2::builder::pod::container::{EnvVarName, EnvVarSet},
6162
};
6263
use strum::{EnumDiscriminants, IntoStaticStr};
6364

@@ -507,7 +508,7 @@ fn build_server_rolegroup_statefulset(
507508
zk: &v1alpha1::ZookeeperCluster,
508509
zk_role: &ZookeeperRole,
509510
rolegroup_ref: &RoleGroupRef<v1alpha1::ZookeeperCluster>,
510-
env_overrides: &BTreeMap<String, String>,
511+
env_overrides: &EnvVarSet,
511512
zookeeper_security: &ZookeeperSecurity,
512513
resolved_product_image: &ResolvedProductImage,
513514
merged_config: &v1alpha1::ZookeeperConfig,
@@ -526,23 +527,18 @@ fn build_server_rolegroup_statefulset(
526527
// The operator-injected environment variables (formerly produced by the
527528
// product-config `Configuration::compute_env` implementation) plus the
528529
// user-provided `envOverrides` (which win on conflict).
529-
let mut env_map: BTreeMap<String, String> = BTreeMap::new();
530-
env_map.insert(
531-
v1alpha1::ZookeeperConfig::MYID_OFFSET.to_string(),
532-
merged_config.myid_offset.to_string(),
533-
);
534-
// Used by zkEnv.sh and the shell scripts in bin/. If unset it tries to find the
535-
// conf directory automatically and that fails.
536-
env_map.insert("ZOOCFGDIR".to_string(), STACKABLE_RW_CONFIG_DIR.to_string());
537-
env_map.extend(env_overrides.clone());
538-
let env_vars = env_map
539-
.into_iter()
540-
.map(|(name, value)| EnvVar {
541-
name,
542-
value: Some(value),
543-
..EnvVar::default()
544-
})
545-
.collect::<Vec<_>>();
530+
let env_vars = EnvVarSet::new()
531+
.with_value(
532+
&EnvVarName::from_str_unsafe(v1alpha1::ZookeeperConfig::MYID_OFFSET),
533+
merged_config.myid_offset.to_string(),
534+
)
535+
// Used by zkEnv.sh and the shell scripts in bin/. If unset it tries to find the
536+
// conf directory automatically and that fails.
537+
.with_value(
538+
&EnvVarName::from_str_unsafe("ZOOCFGDIR"),
539+
STACKABLE_RW_CONFIG_DIR,
540+
)
541+
.merge(env_overrides.clone());
546542

547543
let (original_pvcs, resources) = zk
548544
.resources(zk_role, rolegroup_ref)
@@ -885,6 +881,8 @@ pub fn error_policy(
885881

886882
#[cfg(test)]
887883
mod tests {
884+
use std::collections::BTreeMap;
885+
888886
use stackable_operator::{
889887
commons::networking::DomainName,
890888
k8s_openapi::api::core::v1::ConfigMap,

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use snafu::{ResultExt, Snafu};
1313
use stackable_operator::{
1414
cli::OperatorEnvironmentOptions,
1515
commons::product_image_selection::{self, ResolvedProductImage},
16-
config::fragment,
1716
k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta,
1817
kube::{Resource, ResourceExt},
1918
role_utils::JavaCommonConfig,
@@ -59,9 +58,9 @@ pub enum Error {
5958
#[snafu(display("failed to list expected pods"))]
6059
ListPods { source: crate::crd::Error },
6160

62-
#[snafu(display("invalid config fragment for role group {role_group:?}"))]
63-
InvalidConfigFragment {
64-
source: fragment::ValidationError,
61+
#[snafu(display("invalid config for role group {role_group:?}"))]
62+
InvalidRoleGroupConfig {
63+
source: crate::framework::role_utils::Error,
6564
role_group: String,
6665
},
6766

@@ -221,7 +220,7 @@ pub fn validate(
221220
_,
222221
ZookeeperConfigOverrides,
223222
>(rg, role, &default_config)
224-
.with_context(|_| InvalidConfigFragmentSnafu {
223+
.with_context(|_| InvalidRoleGroupConfigSnafu {
225224
role_group: rg_name.clone(),
226225
})?;
227226
groups.insert(rg_name.clone(), validated_rg);

0 commit comments

Comments
 (0)