|
| 1 | +//! Vendored variant of `stackable_operator::v2::role_utils` from the |
| 2 | +//! `smooth-operator` branch, with simplifications appropriate for hive-operator. |
| 3 | +//! |
| 4 | +//! Differences from upstream: |
| 5 | +//! - `env_overrides` is `BTreeMap<String, String>` instead of `EnvVarSet`. |
| 6 | +//! - No `cli_overrides_to_vec` helper, `ResourceNames`, or service-account helpers. |
| 7 | +//! - The `CommonConfig` (a.k.a. `product_specific_common_config`) does NOT need to |
| 8 | +//! implement `Merge`. Hive uses `JavaCommonConfig`, which intentionally does not |
| 9 | +//! implement `Merge` because its inner `JvmArgumentOverrides::try_merge` is |
| 10 | +//! fallible (regex validation). The `RoleGroupConfig::product_specific_common_config` |
| 11 | +//! field here simply carries the role-group level value through. |
| 12 | +//! |
| 13 | +//! Replace with `stackable_operator::v2::role_utils::*` once upstream relaxes the |
| 14 | +//! `Merge` bound. |
| 15 | +
|
| 16 | +use std::collections::BTreeMap; |
| 17 | + |
| 18 | +use serde::Serialize; |
| 19 | +use stackable_operator::{ |
| 20 | + config::{ |
| 21 | + fragment::{self, FromFragment}, |
| 22 | + merge::{Merge, merge}, |
| 23 | + }, |
| 24 | + k8s_openapi::{DeepMerge, api::core::v1::PodTemplateSpec}, |
| 25 | + role_utils::{Role, RoleGroup}, |
| 26 | + schemars::JsonSchema, |
| 27 | +}; |
| 28 | + |
| 29 | +/// Hive-friendly view of a validated, merged `RoleGroup`. |
| 30 | +#[derive(Clone, Debug, PartialEq)] |
| 31 | +pub struct RoleGroupConfig<Config, CommonConfig, ConfigOverrides> { |
| 32 | + pub replicas: u16, |
| 33 | + pub config: Config, |
| 34 | + pub config_overrides: ConfigOverrides, |
| 35 | + pub env_overrides: BTreeMap<String, String>, |
| 36 | + pub cli_overrides: BTreeMap<String, String>, |
| 37 | + pub pod_overrides: PodTemplateSpec, |
| 38 | + pub product_specific_common_config: CommonConfig, |
| 39 | +} |
| 40 | + |
| 41 | +/// Merges and validates the `RoleGroup` with the given `role` and `default_config`. |
| 42 | +pub fn with_validated_config<ValidatedConfig, CommonConfig, Config, RoleConfig, ConfigOverrides>( |
| 43 | + role_group: &RoleGroup<Config, CommonConfig, ConfigOverrides>, |
| 44 | + role: &Role<Config, ConfigOverrides, RoleConfig, CommonConfig>, |
| 45 | + default_config: &Config, |
| 46 | +) -> Result< |
| 47 | + RoleGroupConfig<ValidatedConfig, CommonConfig, ConfigOverrides>, |
| 48 | + fragment::ValidationError, |
| 49 | +> |
| 50 | +where |
| 51 | + ValidatedConfig: FromFragment<Fragment = Config>, |
| 52 | + CommonConfig: Clone + Default + JsonSchema + Serialize, |
| 53 | + Config: Clone + Merge, |
| 54 | + RoleConfig: Default + JsonSchema + Serialize, |
| 55 | + ConfigOverrides: Clone + Default + JsonSchema + Merge + Serialize, |
| 56 | +{ |
| 57 | + let validated_config = validate_config(role_group, role, default_config)?; |
| 58 | + Ok(RoleGroupConfig { |
| 59 | + replicas: role_group.replicas.unwrap_or(1), |
| 60 | + config: validated_config, |
| 61 | + config_overrides: merged_config_overrides( |
| 62 | + &role.config.config_overrides, |
| 63 | + role_group.config.config_overrides.clone(), |
| 64 | + ), |
| 65 | + env_overrides: merged_env_overrides( |
| 66 | + role.config |
| 67 | + .env_overrides |
| 68 | + .iter() |
| 69 | + .map(|(k, v)| (k.clone(), v.clone())) |
| 70 | + .collect(), |
| 71 | + role_group |
| 72 | + .config |
| 73 | + .env_overrides |
| 74 | + .iter() |
| 75 | + .map(|(k, v)| (k.clone(), v.clone())) |
| 76 | + .collect(), |
| 77 | + ), |
| 78 | + cli_overrides: merged_cli_overrides( |
| 79 | + role.config.cli_overrides.clone(), |
| 80 | + role_group.config.cli_overrides.clone(), |
| 81 | + ), |
| 82 | + pod_overrides: merged_pod_overrides( |
| 83 | + role.config.pod_overrides.clone(), |
| 84 | + role_group.config.pod_overrides.clone(), |
| 85 | + ), |
| 86 | + product_specific_common_config: role_group.config.product_specific_common_config.clone(), |
| 87 | + }) |
| 88 | +} |
| 89 | + |
| 90 | +fn validate_config<ValidatedConfig, CommonConfig, Config, RoleConfig, ConfigOverrides>( |
| 91 | + role_group: &RoleGroup<Config, CommonConfig, ConfigOverrides>, |
| 92 | + role: &Role<Config, ConfigOverrides, RoleConfig, CommonConfig>, |
| 93 | + default_config: &Config, |
| 94 | +) -> Result<ValidatedConfig, fragment::ValidationError> |
| 95 | +where |
| 96 | + ValidatedConfig: FromFragment<Fragment = Config>, |
| 97 | + CommonConfig: Default + JsonSchema + Serialize, |
| 98 | + Config: Clone + Merge, |
| 99 | + RoleConfig: Default + JsonSchema + Serialize, |
| 100 | + ConfigOverrides: Default + JsonSchema + Serialize, |
| 101 | +{ |
| 102 | + role_group.validate_config(role, default_config) |
| 103 | +} |
| 104 | + |
| 105 | +fn merged_config_overrides<ConfigOverrides>( |
| 106 | + role_config_overrides: &ConfigOverrides, |
| 107 | + role_group_config_overrides: ConfigOverrides, |
| 108 | +) -> ConfigOverrides |
| 109 | +where |
| 110 | + ConfigOverrides: Merge, |
| 111 | +{ |
| 112 | + merge(role_group_config_overrides, role_config_overrides) |
| 113 | +} |
| 114 | + |
| 115 | +fn merged_env_overrides( |
| 116 | + role_env_overrides: BTreeMap<String, String>, |
| 117 | + role_group_env_overrides: BTreeMap<String, String>, |
| 118 | +) -> BTreeMap<String, String> { |
| 119 | + let mut merged = role_env_overrides; |
| 120 | + merged.extend(role_group_env_overrides); |
| 121 | + merged |
| 122 | +} |
| 123 | + |
| 124 | +fn merged_cli_overrides( |
| 125 | + role_cli_overrides: BTreeMap<String, String>, |
| 126 | + role_group_cli_overrides: BTreeMap<String, String>, |
| 127 | +) -> BTreeMap<String, String> { |
| 128 | + let mut merged = role_cli_overrides; |
| 129 | + merged.extend(role_group_cli_overrides); |
| 130 | + merged |
| 131 | +} |
| 132 | + |
| 133 | +fn merged_pod_overrides( |
| 134 | + role_pod_overrides: PodTemplateSpec, |
| 135 | + role_group_pod_overrides: PodTemplateSpec, |
| 136 | +) -> PodTemplateSpec { |
| 137 | + let mut merged = role_pod_overrides; |
| 138 | + merged.merge_from(role_group_pod_overrides); |
| 139 | + merged |
| 140 | +} |
0 commit comments