11//! The validate step in the HdfsCluster controller.
22//!
33//! Synchronously merges and validates the cluster spec into the typed [`ValidatedCluster`]
4- //! consumed by `controller::build::*`. Config fragments are merged and validated via
5- //! [`HdfsNodeRole::merged_config`], and the per-file `configOverrides` / `envOverrides`
6- //! are merged here (role group wins).
4+ //! consumed by `controller::build::*`. Each role group is merged and validated via the
5+ //! local-`framework` [`with_validated_config`], which folds the config fragment
6+ //! (default <- role <- role group) together with the `configOverrides`, `envOverrides`,
7+ //! `cliOverrides` and `podOverrides` (role group wins) into a single
8+ //! [`RoleGroupConfig`](crate::framework::role_utils::RoleGroupConfig).
79
810use std:: collections:: BTreeMap ;
911
1012use snafu:: { ResultExt , Snafu } ;
1113use stackable_operator:: {
1214 commons:: product_image_selection,
13- config:: merge:: Merge ,
14- role_utils:: { GenericRoleConfig , JavaCommonConfig , Role , RoleGroup } ,
15+ config:: { fragment :: FromFragment , merge:: Merge } ,
16+ role_utils:: { GenericRoleConfig , JavaCommonConfig , Role } ,
1517 v2:: controller_utils:: { get_cluster_name, get_namespace, get_uid} ,
1618} ;
1719use strum:: IntoEnumIterator ;
1820
1921use crate :: {
2022 controller:: {
2123 ValidatedCluster , ValidatedClusterConfig , ValidatedRoleConfig , ValidatedRoleGroupConfig ,
24+ dereference:: DereferencedObjects ,
2225 } ,
23- crd:: { HdfsNodeRole , v1alpha1} ,
24- security:: opa:: HdfsOpaConfig ,
26+ crd:: {
27+ AnyNodeConfig , DataNodeConfigFragment , HdfsNodeRole , JournalNodeConfigFragment ,
28+ NameNodeConfigFragment , v1alpha1,
29+ } ,
30+ framework:: role_utils:: with_validated_config,
2531} ;
2632
2733const CONTAINER_IMAGE_BASE_NAME : & str = "hadoop" ;
@@ -48,16 +54,18 @@ pub enum Error {
4854 source : stackable_operator:: v2:: controller_utils:: Error ,
4955 } ,
5056
51- #[ snafu( display( "failed to resolve and merge config for role and role group" ) ) ]
52- FailedToResolveConfig { source : crate :: crd:: Error } ,
57+ #[ snafu( display( "failed to merge and validate the role group config" ) ) ]
58+ ValidateRoleGroupConfig {
59+ source : crate :: framework:: role_utils:: Error ,
60+ } ,
5361}
5462
5563pub fn validate_cluster (
5664 hdfs : & v1alpha1:: HdfsCluster ,
5765 image_repository : & str ,
58- hdfs_opa_config : Option < HdfsOpaConfig > ,
66+ dereferenced_objects : DereferencedObjects ,
5967) -> Result < ValidatedCluster , Error > {
60- let resolved_product_image = hdfs
68+ let image : product_image_selection :: ResolvedProductImage = hdfs
6169 . spec
6270 . image
6371 . resolve (
@@ -69,6 +77,7 @@ pub fn validate_cluster(
6977
7078 let mut role_groups = BTreeMap :: new ( ) ;
7179 let mut role_configs = BTreeMap :: new ( ) ;
80+ let cluster_name = get_cluster_name ( hdfs) . context ( GetClusterNameSnafu ) ?;
7281
7382 for hdfs_role in HdfsNodeRole :: iter ( ) {
7483 if let Some ( GenericRoleConfig {
@@ -79,83 +88,87 @@ pub fn validate_cluster(
7988 }
8089
8190 let group_configs = match hdfs_role {
82- HdfsNodeRole :: Name => {
83- validate_role_group_configs ( hdfs, hdfs_role, hdfs. spec . name_nodes . as_ref ( ) ) ?
84- }
85- HdfsNodeRole :: Data => {
86- validate_role_group_configs ( hdfs, hdfs_role, hdfs. spec . data_nodes . as_ref ( ) ) ?
87- }
88- HdfsNodeRole :: Journal => {
89- validate_role_group_configs ( hdfs, hdfs_role, hdfs. spec . journal_nodes . as_ref ( ) ) ?
90- }
91+ HdfsNodeRole :: Name => validate_role_group_configs (
92+ hdfs. spec . name_nodes . as_ref ( ) ,
93+ NameNodeConfigFragment :: default_config ( cluster_name. as_ref ( ) , & hdfs_role) ,
94+ AnyNodeConfig :: Name ,
95+ ) ?,
96+ HdfsNodeRole :: Data => validate_role_group_configs (
97+ hdfs. spec . data_nodes . as_ref ( ) ,
98+ DataNodeConfigFragment :: default_config ( cluster_name. as_ref ( ) , & hdfs_role) ,
99+ AnyNodeConfig :: Data ,
100+ ) ?,
101+ HdfsNodeRole :: Journal => validate_role_group_configs (
102+ hdfs. spec . journal_nodes . as_ref ( ) ,
103+ JournalNodeConfigFragment :: default_config ( cluster_name. as_ref ( ) , & hdfs_role) ,
104+ AnyNodeConfig :: Journal ,
105+ ) ?,
91106 } ;
92107
93108 role_groups. insert ( hdfs_role, group_configs) ;
94109 }
95110
96- let cluster_name = get_cluster_name ( hdfs) . context ( GetClusterNameSnafu ) ?;
97111 let namespace = get_namespace ( hdfs) . context ( GetClusterNamespaceSnafu ) ?;
98112 let uid = get_uid ( hdfs) . context ( GetClusterUidSnafu ) ?;
99113
100114 Ok ( ValidatedCluster :: new (
101115 cluster_name,
102116 namespace,
103117 uid,
104- resolved_product_image ,
105- ValidatedClusterConfig :: resolve ( hdfs, hdfs_opa_config) ,
118+ image ,
119+ ValidatedClusterConfig :: resolve ( hdfs, dereferenced_objects . hdfs_opa_config ) ,
106120 role_groups,
107121 role_configs,
108122 ) )
109123}
110124
111125/// Validates every role group of a role into a map keyed by role group name.
112126///
127+ /// Each role group is merged and validated via the local-`framework`
128+ /// [`with_validated_config`], which folds the CRD config fragment (default <-
129+ /// role <- role group) plus the `configOverrides`, `envOverrides`, `cliOverrides`
130+ /// and `podOverrides` (role group wins) into a single
131+ /// [`RoleGroupConfig`](crate::framework::role_utils::RoleGroupConfig). The
132+ /// concrete per-role validated config is wrapped into [`AnyNodeConfig`] via `wrap`.
133+ ///
113134/// Returns an empty map if the role is not configured.
114- fn validate_role_group_configs < C > (
115- hdfs : & v1alpha1:: HdfsCluster ,
116- hdfs_role : HdfsNodeRole ,
117- role : Option < & Role < C , v1alpha1:: HdfsConfigOverrides , GenericRoleConfig , JavaCommonConfig > > ,
118- ) -> Result < BTreeMap < String , ValidatedRoleGroupConfig > , Error > {
135+ fn validate_role_group_configs < Config , ValidatedConfig > (
136+ role : Option < & Role < Config , v1alpha1:: HdfsConfigOverrides , GenericRoleConfig , JavaCommonConfig > > ,
137+ default_config : Config ,
138+ wrap : fn ( ValidatedConfig ) -> AnyNodeConfig ,
139+ ) -> Result < BTreeMap < String , ValidatedRoleGroupConfig > , Error >
140+ where
141+ Config : Clone + Merge ,
142+ ValidatedConfig : FromFragment < Fragment = Config > ,
143+ {
119144 let Some ( role) = role else {
120145 return Ok ( BTreeMap :: new ( ) ) ;
121146 } ;
122147
123148 role. role_groups
124149 . iter ( )
125150 . map ( |( role_group_name, role_group) | {
126- let validated =
127- validate_role_group_config ( hdfs, hdfs_role, role, role_group_name, role_group) ?;
151+ let validated = with_validated_config :: <
152+ ValidatedConfig ,
153+ JavaCommonConfig ,
154+ Config ,
155+ GenericRoleConfig ,
156+ v1alpha1:: HdfsConfigOverrides ,
157+ > ( role_group, role, & default_config)
158+ . context ( ValidateRoleGroupConfigSnafu ) ?;
159+
160+ // Re-wrap the per-role validated config into the role-agnostic
161+ // `AnyNodeConfig`; the merged overrides carry over unchanged.
162+ let validated = ValidatedRoleGroupConfig {
163+ replicas : validated. replicas ,
164+ config : wrap ( validated. config ) ,
165+ config_overrides : validated. config_overrides ,
166+ env_overrides : validated. env_overrides ,
167+ cli_overrides : validated. cli_overrides ,
168+ pod_overrides : validated. pod_overrides ,
169+ product_specific_common_config : validated. product_specific_common_config ,
170+ } ;
128171 Ok ( ( role_group_name. clone ( ) , validated) )
129172 } )
130173 . collect ( )
131174}
132-
133- /// Validates a single role group into a [`ValidatedRoleGroupConfig`]: merges and
134- /// validates the CRD config via [`HdfsNodeRole::merged_config`] and merges the
135- /// role-level and role-group-level `configOverrides` and `envOverrides` (the role
136- /// group wins).
137- fn validate_role_group_config < C > (
138- hdfs : & v1alpha1:: HdfsCluster ,
139- hdfs_role : HdfsNodeRole ,
140- role : & Role < C , v1alpha1:: HdfsConfigOverrides , GenericRoleConfig , JavaCommonConfig > ,
141- role_group_name : & str ,
142- role_group : & RoleGroup < C , JavaCommonConfig , v1alpha1:: HdfsConfigOverrides > ,
143- ) -> Result < ValidatedRoleGroupConfig , Error > {
144- let config = hdfs_role
145- . merged_config ( hdfs, role_group_name)
146- . context ( FailedToResolveConfigSnafu ) ?;
147-
148- let mut config_overrides = role_group. config . config_overrides . clone ( ) ;
149- config_overrides. merge ( & role. config . config_overrides ) ;
150-
151- let mut env_overrides = BTreeMap :: new ( ) ;
152- env_overrides. extend ( role. config . env_overrides . clone ( ) ) ;
153- env_overrides. extend ( role_group. config . env_overrides . clone ( ) ) ;
154-
155- Ok ( ValidatedRoleGroupConfig {
156- replicas : role_group. replicas . unwrap_or_default ( ) ,
157- config,
158- config_overrides,
159- env_overrides,
160- } )
161- }
0 commit comments