@@ -8,7 +8,10 @@ use std::{borrow::Cow, collections::BTreeMap, str::FromStr};
88use snafu:: { ResultExt , Snafu } ;
99use stackable_operator:: {
1010 cli:: OperatorEnvironmentOptions ,
11- commons:: product_image_selection:: { self , ResolvedProductImage } ,
11+ commons:: {
12+ pdb:: PdbConfig ,
13+ product_image_selection:: { self , ResolvedProductImage } ,
14+ } ,
1215 crd:: s3,
1316 database_connections:: drivers:: jdbc:: { JdbcDatabaseConnection , JdbcDatabaseConnectionDetails } ,
1417 k8s_openapi:: api:: core:: v1:: Volume ,
@@ -18,7 +21,7 @@ use stackable_operator::{
1821 controller_utils:: { get_cluster_name, get_namespace, get_uid} ,
1922 role_group_utils:: ResourceNames ,
2023 types:: {
21- kubernetes:: { NamespaceName , Uid } ,
24+ kubernetes:: { ListenerClassName , NamespaceName , Uid } ,
2225 operator:: { ClusterName , RoleGroupName , RoleName } ,
2326 } ,
2427 } ,
@@ -97,6 +100,16 @@ pub struct ValidatedClusterConfig {
97100 pub extra_volumes : Vec < Volume > ,
98101}
99102
103+ /// Per-role configuration extracted during validation, so the reconcile/build steps consume this
104+ /// instead of re-reading the raw [`v1alpha1::DruidCluster`].
105+ #[ derive( Clone , Debug ) ]
106+ pub struct ValidatedRoleConfig {
107+ pub pdb : PdbConfig ,
108+ /// The role's listener class, or `None` for roles without a listener
109+ /// ([`DruidRole::Historical`]/[`DruidRole::MiddleManager`]).
110+ pub listener_class : Option < ListenerClassName > ,
111+ }
112+
100113/// Synchronous inputs the rest of `reconcile_druid` needs after dereferencing.
101114pub struct ValidatedCluster {
102115 /// Mirrors `name`/`namespace`/`uid` below so that `ValidatedCluster` can implement
@@ -107,6 +120,8 @@ pub struct ValidatedCluster {
107120 pub uid : Uid ,
108121 pub image : ResolvedProductImage ,
109122 pub cluster_config : ValidatedClusterConfig ,
123+ /// The per-role config (PDB and listener class) for every [`DruidRole`].
124+ pub role_configs : BTreeMap < DruidRole , ValidatedRoleConfig > ,
110125 pub role_group_configs : BTreeMap < DruidRole , BTreeMap < RoleGroupName , DruidRoleGroupConfig > > ,
111126}
112127
@@ -118,6 +133,7 @@ impl ValidatedCluster {
118133 uid : Uid ,
119134 image : ResolvedProductImage ,
120135 cluster_config : ValidatedClusterConfig ,
136+ role_configs : BTreeMap < DruidRole , ValidatedRoleConfig > ,
121137 role_group_configs : BTreeMap < DruidRole , BTreeMap < RoleGroupName , DruidRoleGroupConfig > > ,
122138 ) -> Self {
123139 let metadata = ObjectMeta {
@@ -133,10 +149,18 @@ impl ValidatedCluster {
133149 uid,
134150 image,
135151 cluster_config,
152+ role_configs,
136153 role_group_configs,
137154 }
138155 }
139156
157+ /// The validated per-role config (PDB and listener class) for the given role.
158+ pub ( crate ) fn role_config ( & self , role : & DruidRole ) -> & ValidatedRoleConfig {
159+ self . role_configs
160+ . get ( role)
161+ . expect ( "every DruidRole has a validated role config" )
162+ }
163+
140164 /// Type-safe names for the resources of the given role's role group.
141165 pub ( crate ) fn resource_names (
142166 & self ,
@@ -231,12 +255,24 @@ pub fn validate(
231255
232256 let mut role_group_configs: BTreeMap < DruidRole , BTreeMap < RoleGroupName , DruidRoleGroupConfig > > =
233257 BTreeMap :: new ( ) ;
258+ let mut role_configs: BTreeMap < DruidRole , ValidatedRoleConfig > = BTreeMap :: new ( ) ;
234259
235260 for druid_role in DruidRole :: iter ( ) {
236261 let group_map = druid
237262 . merged_role ( & druid_role)
238263 . context ( FailedToResolveConfigSnafu ) ?;
239264 role_group_configs. insert ( druid_role. clone ( ) , group_map) ;
265+
266+ role_configs. insert (
267+ druid_role. clone ( ) ,
268+ ValidatedRoleConfig {
269+ pdb : druid
270+ . generic_role_config ( & druid_role)
271+ . pod_disruption_budget
272+ . clone ( ) ,
273+ listener_class : druid_role. listener_class_name ( druid) ,
274+ } ,
275+ ) ;
240276 }
241277
242278 let name = get_cluster_name ( druid) . context ( ClusterIdentitySnafu ) ?;
@@ -275,6 +311,7 @@ pub fn validate(
275311 deep_storage : druid. spec . cluster_config . deep_storage . clone ( ) ,
276312 extra_volumes : druid. spec . cluster_config . extra_volumes . clone ( ) ,
277313 } ,
314+ role_configs,
278315 role_group_configs,
279316 ) )
280317}
@@ -293,7 +330,7 @@ pub(crate) mod test_support {
293330 } ;
294331 use strum:: IntoEnumIterator ;
295332
296- use super :: { RoleGroupName , ValidatedCluster , ValidatedClusterConfig } ;
333+ use super :: { RoleGroupName , ValidatedCluster , ValidatedClusterConfig , ValidatedRoleConfig } ;
297334 use crate :: {
298335 controller:: CONTAINER_IMAGE_BASE_NAME ,
299336 crd:: {
@@ -377,11 +414,22 @@ spec:
377414
378415 let mut role_group_configs: BTreeMap < DruidRole , BTreeMap < RoleGroupName , _ > > =
379416 BTreeMap :: new ( ) ;
417+ let mut role_configs: BTreeMap < DruidRole , ValidatedRoleConfig > = BTreeMap :: new ( ) ;
380418 for role in DruidRole :: iter ( ) {
381419 role_group_configs. insert (
382420 role. clone ( ) ,
383421 druid. merged_role ( & role) . expect ( "test: merged role" ) ,
384422 ) ;
423+ role_configs. insert (
424+ role. clone ( ) ,
425+ ValidatedRoleConfig {
426+ pdb : druid
427+ . generic_role_config ( & role)
428+ . pod_disruption_budget
429+ . clone ( ) ,
430+ listener_class : role. listener_class_name ( druid) ,
431+ } ,
432+ ) ;
385433 }
386434
387435 let extensions = get_extension_list ( druid, & druid_tls_security, & None ) ;
@@ -416,6 +464,7 @@ spec:
416464 deep_storage : druid. spec . cluster_config . deep_storage . clone ( ) ,
417465 extra_volumes : druid. spec . cluster_config . extra_volumes . clone ( ) ,
418466 } ,
467+ role_configs,
419468 role_group_configs,
420469 )
421470 }
0 commit comments