@@ -23,12 +23,19 @@ use stackable_operator::{
2323 } ,
2424 } ,
2525} ;
26+ use strum:: IntoEnumIterator ;
2627
2728use crate :: {
2829 controller:: {
2930 CONTROLLER_NAME , KubernetesResources , OPERATOR_NAME , PRODUCT_NAME , Prepared ,
3031 ValidatedCluster ,
31- build:: resource:: rbac:: { build_role_binding, build_service_account} ,
32+ build:: {
33+ resource:: rbac:: { build_role_binding, build_service_account} ,
34+ role_group:: {
35+ RoleGroupBuilder , build_datanode_role_group, build_journalnode_role_group,
36+ build_namenode_role_group,
37+ } ,
38+ } ,
3239 } ,
3340 crd:: {
3441 HdfsNodeRole , HdfsPodRef ,
@@ -57,61 +64,19 @@ pub mod jvm;
5764pub mod kerberos;
5865pub mod opa;
5966pub mod properties;
60- pub mod resolve;
6167pub mod resource;
68+ pub mod role_group;
6269
6370#[ derive( Snafu , Debug ) ]
6471pub enum Error {
65- #[ snafu( display( "failed to build Service for role {role} role group {role_group}" , role = role. as_ref( ) ) ) ]
66- Service {
67- source : resource:: service:: Error ,
68- role : HdfsNodeRole ,
69- role_group : RoleGroupName ,
70- } ,
71-
72- #[ snafu( display( "failed to build ConfigMap for role {role} role group {role_group}" , role = role. as_ref( ) ) ) ]
73- ConfigMap {
74- source : resource:: config_map:: Error ,
75- role : HdfsNodeRole ,
76- role_group : RoleGroupName ,
77- } ,
78-
79- #[ snafu( display( "failed to build StatefulSet for role {role} role group {role_group}" , role = role. as_ref( ) ) ) ]
80- StatefulSet {
81- source : resource:: statefulset:: Error ,
82- role : HdfsNodeRole ,
83- role_group : RoleGroupName ,
84- } ,
72+ #[ snafu( display( "failed to build the resources of a role group" ) ) ]
73+ RoleGroup { source : role_group:: Error } ,
8574
8675 #[ snafu( display( "failed to build the discovery ConfigMap" ) ) ]
8776 DiscoveryConfigMap { source : resource:: discovery:: Error } ,
88-
89- #[ snafu( display( "failed to build selector labels for role {role} role group {role_group}" , role = role. as_ref( ) ) ) ]
90- RoleGroupSelectorLabels {
91- source : LabelError ,
92- role : HdfsNodeRole ,
93- role_group : RoleGroupName ,
94- } ,
95-
96- #[ snafu( display( "failed to build volume claim templates for role {role} role group {role_group}" , role = role. as_ref( ) ) ) ]
97- VolumeClaimTemplates {
98- source : container:: Error ,
99- role : HdfsNodeRole ,
100- role_group : RoleGroupName ,
101- } ,
102-
103- #[ snafu( display( "failed to build listener volume for role {role} role group {role_group}" , role = role. as_ref( ) ) ) ]
104- ListenerVolume {
105- source : container:: Error ,
106- role : HdfsNodeRole ,
107- role_group : RoleGroupName ,
108- } ,
10977}
11078
111- pub ( crate ) use resolve:: RoleGroupResolver ;
112- pub use resolve:: { ResolvedRoleGroup , RoleGroupLogging , RoleSpecificValues } ;
113-
114- /// The resources of every role, accumulated one role at a time by [`build_role`].
79+ /// The resources of every role, accumulated one role group at a time by [`build`].
11580#[ derive( Default ) ]
11681struct RoleGroupResources {
11782 services : Vec < Service > ,
@@ -122,63 +87,18 @@ struct RoleGroupResources {
12287 pod_disruption_budgets : Vec < PodDisruptionBudget > ,
12388}
12489
125- /// Builds every resource of every role group of one role, plus that role's PDB, appending them to
126- /// `rg_resources`.
127- fn build_role < C : RoleGroupResolver > (
128- cluster : & ValidatedCluster ,
129- cluster_info : & KubernetesClusterInfo ,
130- role_group_configs : & BTreeMap <
131- RoleGroupName ,
132- RoleGroupConfig < C , JavaCommonConfig , v1alpha1:: HdfsConfigOverrides > ,
133- > ,
134- rg_resources : & mut RoleGroupResources ,
135- ) -> Result < ( ) , Error > {
136- let role = & C :: ROLE ;
137-
138- for ( role_group_name, rg_config) in role_group_configs {
139- build_role_group_services ( cluster, role, role_group_name, & mut rg_resources. services ) ?;
140-
141- let selector_labels = rolegroup_selector_labels ( cluster, role, role_group_name) . context (
142- RoleGroupSelectorLabelsSnafu {
143- role : * role,
144- role_group : role_group_name. clone ( ) ,
145- } ,
146- ) ?;
147- let resolved = rg_config. config . resolve ( role_group_name, selector_labels) ?;
148-
149- rg_resources. config_maps . push (
150- resource:: config_map:: build_rolegroup_config_map (
151- cluster,
152- cluster_info,
153- role_group_name,
154- rg_config,
155- & resolved,
156- )
157- . context ( ConfigMapSnafu {
158- role : * role,
159- role_group : role_group_name. clone ( ) ,
160- } ) ?,
161- ) ;
162- rg_resources. stateful_sets . entry ( C :: ROLE ) . or_default ( ) . push (
163- resource:: statefulset:: build_rolegroup_statefulset (
164- cluster,
165- cluster_info,
166- role_group_name,
167- rg_config,
168- & resolved,
169- )
170- . context ( StatefulSetSnafu {
171- role : * role,
172- role_group : role_group_name. clone ( ) ,
173- } ) ?,
174- ) ;
90+ impl RoleGroupResources {
91+ /// Builds the Services, ConfigMap and StatefulSet of one role group and adds them to the
92+ /// collections.
93+ fn add ( & mut self , builder : & RoleGroupBuilder ) -> Result < ( ) , role_group:: Error > {
94+ self . services . extend ( builder. build_services ( ) ?) ;
95+ self . config_maps . push ( builder. build_config_map ( ) ?) ;
96+ self . stateful_sets
97+ . entry ( builder. role )
98+ . or_default ( )
99+ . push ( builder. build_statefulset ( ) ?) ;
100+ Ok ( ( ) )
175101 }
176-
177- if let Some ( pdb) = resource:: pdb:: build_pdb ( cluster, role) {
178- rg_resources. pod_disruption_budgets . push ( pdb) ;
179- }
180-
181- Ok ( ( ) )
182102}
183103
184104/// Builds every Kubernetes resource for the given validated cluster.
@@ -188,6 +108,11 @@ fn build_role<C: RoleGroupResolver>(
188108/// `cluster_info` carries static cluster information resolved at operator startup (e.g. the
189109/// cluster domain used to build Kerberos principals), not a live client.
190110///
111+ /// Each of the three loops hands its role group's typed config to that role's builder, which is
112+ /// where everything specific to the role lives. The loops are free to be reordered: the
113+ /// StatefulSets are keyed by role, and the apply step does not depend on the order of the other
114+ /// three collections.
115+ ///
191116/// The resources are returned as flat collections. `stateful_sets` comes out in [`HdfsNodeRole`]
192117/// order, which the apply step depends on; that is structural, from a [`BTreeMap`] flattened in
193118/// key order, not from the order the roles are built in.
@@ -200,26 +125,33 @@ pub fn build(
200125) -> Result < KubernetesResources < Prepared > , Error > {
201126 let mut built = RoleGroupResources :: default ( ) ;
202127
203- // These three calls are free to be reordered: the StatefulSets are keyed by role, and the
204- // apply step does not depend on the order of the other three collections.
205- build_role (
206- cluster,
207- cluster_info,
208- & cluster. journalnode_role_group_configs ,
209- & mut built,
210- ) ?;
211- build_role (
212- cluster,
213- cluster_info,
214- & cluster. namenode_role_group_configs ,
215- & mut built,
216- ) ?;
217- build_role (
218- cluster,
219- cluster_info,
220- & cluster. datanode_role_group_configs ,
221- & mut built,
222- ) ?;
128+ for ( role_group_name, rg_config) in & cluster. journalnode_role_group_configs {
129+ let builder =
130+ build_journalnode_role_group ( cluster, cluster_info, role_group_name, rg_config)
131+ . context ( RoleGroupSnafu ) ?;
132+
133+ built. add ( & builder) . context ( RoleGroupSnafu ) ?;
134+ }
135+
136+ for ( role_group_name, rg_config) in & cluster. namenode_role_group_configs {
137+ let builder = build_namenode_role_group ( cluster, cluster_info, role_group_name, rg_config)
138+ . context ( RoleGroupSnafu ) ?;
139+
140+ built. add ( & builder) . context ( RoleGroupSnafu ) ?;
141+ }
142+
143+ for ( role_group_name, rg_config) in & cluster. datanode_role_group_configs {
144+ let builder = build_datanode_role_group ( cluster, cluster_info, role_group_name, rg_config)
145+ . context ( RoleGroupSnafu ) ?;
146+
147+ built. add ( & builder) . context ( RoleGroupSnafu ) ?;
148+ }
149+
150+ for role in HdfsNodeRole :: iter ( ) {
151+ if let Some ( pdb) = resource:: pdb:: build_pdb ( cluster, & role) {
152+ built. pod_disruption_budgets . push ( pdb) ;
153+ }
154+ }
223155
224156 let RoleGroupResources {
225157 services,
@@ -250,34 +182,6 @@ pub fn build(
250182 } )
251183}
252184
253- /// Builds the two Services for one role group. Role-agnostic: it reads nothing from the role
254- /// config.
255- fn build_role_group_services (
256- cluster : & ValidatedCluster ,
257- role : & HdfsNodeRole ,
258- role_group_name : & RoleGroupName ,
259- services : & mut Vec < Service > ,
260- ) -> Result < ( ) , Error > {
261- services. push (
262- resource:: service:: rolegroup_headless_service ( cluster, role, role_group_name) . context (
263- ServiceSnafu {
264- role : * role,
265- role_group : role_group_name. clone ( ) ,
266- } ,
267- ) ?,
268- ) ;
269- services. push (
270- resource:: service:: rolegroup_metrics_service ( cluster, role, role_group_name) . context (
271- ServiceSnafu {
272- role : * role,
273- role_group : role_group_name. clone ( ) ,
274- } ,
275- ) ?,
276- ) ;
277-
278- Ok ( ( ) )
279- }
280-
281185/// The replica count a role group gets when it does not set one: Kubernetes runs a single pod for
282186/// a `StatefulSet` with `replicas: null`.
283187pub ( crate ) const DEFAULT_REPLICAS : u16 = 1 ;
@@ -456,8 +360,19 @@ pub(crate) fn native_metrics_port(cluster: &ValidatedCluster, role: &HdfsNodeRol
456360 }
457361}
458362
459- /// The deprecated JMX exporter metrics port for the given `role`.
460- fn jmx_metrics_port ( role : & HdfsNodeRole ) -> Port {
363+ /// The name of the port the given `role` serves IPC/RPC on, which its readiness probe checks.
364+ ///
365+ /// The datanodes call theirs `ipc`, the other two `rpc`; the same names [`role_data_ports`]
366+ /// exposes them under.
367+ pub ( crate ) fn ipc_port_name ( role : & HdfsNodeRole ) -> & ' static str {
368+ match role {
369+ HdfsNodeRole :: Name | HdfsNodeRole :: Journal => SERVICE_PORT_NAME_RPC ,
370+ HdfsNodeRole :: Data => SERVICE_PORT_NAME_IPC ,
371+ }
372+ }
373+
374+ /// The deprecated JMX Exporter metrics port for the given `role`.
375+ pub ( crate ) fn jmx_metrics_port ( role : & HdfsNodeRole ) -> Port {
461376 match role {
462377 HdfsNodeRole :: Name => DEFAULT_NAME_NODE_METRICS_PORT ,
463378 HdfsNodeRole :: Data => DEFAULT_DATA_NODE_METRICS_PORT ,
0 commit comments