@@ -21,7 +21,10 @@ use stackable_operator::{
21
21
} ,
22
22
} ,
23
23
cluster_resources:: { ClusterResourceApplyStrategy , ClusterResources } ,
24
- commons:: product_image_selection:: ResolvedProductImage ,
24
+ commons:: {
25
+ listener:: { Listener , ListenerPort , ListenerSpec } ,
26
+ product_image_selection:: ResolvedProductImage ,
27
+ } ,
25
28
k8s_openapi:: {
26
29
DeepMerge ,
27
30
api:: {
@@ -56,7 +59,7 @@ use crate::{
56
59
Ctx ,
57
60
crd:: {
58
61
constants:: {
59
- ACCESS_KEY_ID , APP_NAME , HISTORY_CONTROLLER_NAME , HISTORY_ROLE_NAME ,
62
+ ACCESS_KEY_ID , APP_NAME , HISTORY_CONTROLLER_NAME , HISTORY_ROLE_NAME , HISTORY_UI_PORT ,
60
63
JVM_SECURITY_PROPERTIES_FILE , LISTENER_VOLUME_DIR , LISTENER_VOLUME_NAME ,
61
64
MAX_SPARK_LOG_FILES_SIZE , METRICS_PORT , OPERATOR_NAME , SECRET_ACCESS_KEY ,
62
65
SPARK_CLUSTER_ROLE , SPARK_DEFAULTS_FILE_NAME , SPARK_ENV_SH_FILE_NAME ,
@@ -76,6 +79,11 @@ use crate::{
76
79
#[ strum_discriminants( derive( IntoStaticStr ) ) ]
77
80
#[ allow( clippy:: enum_variant_names) ]
78
81
pub enum Error {
82
+ #[ snafu( display( "failed to build object meta data" ) ) ]
83
+ ObjectMeta {
84
+ source : stackable_operator:: builder:: meta:: Error ,
85
+ } ,
86
+
79
87
#[ snafu( display( "failed to build listener volume" ) ) ]
80
88
BuildListenerVolume {
81
89
source : ListenerOperatorVolumeSourceBuilderError ,
@@ -216,9 +224,12 @@ pub enum Error {
216
224
217
225
#[ snafu( display( "failed to merge environment config and/or overrides" ) ) ]
218
226
MergeEnv { source : crate :: crd:: history:: Error } ,
219
- }
220
227
221
- type Result < T , E = Error > = std:: result:: Result < T , E > ;
228
+ #[ snafu( display( "failed to apply group listener" ) ) ]
229
+ ApplyGroupListener {
230
+ source : stackable_operator:: cluster_resources:: Error ,
231
+ } ,
232
+ }
222
233
223
234
impl ReconcilerError for Error {
224
235
fn category ( & self ) -> & ' static str {
@@ -229,7 +240,7 @@ impl ReconcilerError for Error {
229
240
pub async fn reconcile (
230
241
shs : Arc < DeserializeGuard < v1alpha1:: SparkHistoryServer > > ,
231
242
ctx : Arc < Ctx > ,
232
- ) -> Result < Action > {
243
+ ) -> Result < Action , Error > {
233
244
tracing:: info!( "Starting reconcile history server" ) ;
234
245
235
246
let shs = shs
@@ -322,6 +333,17 @@ pub async fn reconcile(
322
333
. add ( client, sts)
323
334
. await
324
335
. context ( ApplyDeploymentSnafu ) ?;
336
+
337
+ let rg_group_listener = build_group_listener (
338
+ shs,
339
+ & resolved_product_image,
340
+ & rgr,
341
+ merged_config. listener_class . to_string ( ) ,
342
+ ) ?;
343
+ cluster_resources
344
+ . add ( client, rg_group_listener)
345
+ . await
346
+ . context ( ApplyGroupListenerSnafu ) ?;
325
347
}
326
348
327
349
let role_config = & shs. spec . nodes . role_config ;
@@ -343,6 +365,50 @@ pub async fn reconcile(
343
365
Ok ( Action :: await_change ( ) )
344
366
}
345
367
368
+ #[ allow( clippy:: result_large_err) ]
369
+ fn build_group_listener (
370
+ shs : & v1alpha1:: SparkHistoryServer ,
371
+ resolved_product_image : & ResolvedProductImage ,
372
+ rolegroup : & RoleGroupRef < v1alpha1:: SparkHistoryServer > ,
373
+ listener_class : String ,
374
+ ) -> Result < Listener , Error > {
375
+ Ok ( Listener {
376
+ metadata : ObjectMetaBuilder :: new ( )
377
+ . name_and_namespace ( shs)
378
+ . name ( shs. group_listener_name ( rolegroup) )
379
+ . ownerreference_from_resource ( shs, None , Some ( true ) )
380
+ . context ( ObjectMissingMetadataForOwnerRefSnafu ) ?
381
+ . with_recommended_labels ( labels (
382
+ shs,
383
+ & resolved_product_image. app_version_label ,
384
+ & rolegroup. role_group ,
385
+ ) )
386
+ . context ( ObjectMetaSnafu ) ?
387
+ . build ( ) ,
388
+ spec : ListenerSpec {
389
+ class_name : Some ( listener_class) ,
390
+ ports : Some ( listener_ports ( ) ) ,
391
+ ..ListenerSpec :: default ( )
392
+ } ,
393
+ status : None ,
394
+ } )
395
+ }
396
+
397
+ fn listener_ports ( ) -> Vec < ListenerPort > {
398
+ vec ! [
399
+ ListenerPort {
400
+ name: "metrics" . to_string( ) ,
401
+ port: METRICS_PORT . into( ) ,
402
+ protocol: Some ( "TCP" . to_string( ) ) ,
403
+ } ,
404
+ ListenerPort {
405
+ name: "http" . to_string( ) ,
406
+ port: HISTORY_UI_PORT . into( ) ,
407
+ protocol: Some ( "TCP" . to_string( ) ) ,
408
+ } ,
409
+ ]
410
+ }
411
+
346
412
pub fn error_policy (
347
413
_obj : Arc < DeserializeGuard < v1alpha1:: SparkHistoryServer > > ,
348
414
error : & Error ,
@@ -528,7 +594,7 @@ fn build_stateful_set(
528
594
"-c" . to_string( ) ,
529
595
] )
530
596
. args ( command_args ( log_dir) )
531
- . add_container_port ( "http" , 18080 )
597
+ . add_container_port ( "http" , HISTORY_UI_PORT . into ( ) )
532
598
. add_container_port ( "metrics" , METRICS_PORT . into ( ) )
533
599
. add_env_vars ( merged_env)
534
600
. add_volume_mounts ( log_dir. volume_mounts ( ) )
@@ -544,28 +610,19 @@ fn build_stateful_set(
544
610
. build ( ) ;
545
611
546
612
// Add listener volume
547
- let listener_class = & shs. spec . cluster_config . listener_class ;
548
- let pvcs = if listener_class. discoverable ( ) {
549
- // externally reachable listener endpoints will use persistent volumes
550
- // so that load balancers can hard-code the target addresses
551
- let pvc = ListenerOperatorVolumeSourceBuilder :: new (
552
- & ListenerReference :: ListenerClass ( listener_class. to_string ( ) ) ,
613
+ // Listener endpoints for the Webserver role will use persistent volumes
614
+ // so that load balancers can hard-code the target addresses. This will
615
+ // be the case even when no class is set (and the value defaults to
616
+ // cluster-internal) as the address should still be consistent.
617
+ let pvcs = Some ( vec ! [
618
+ ListenerOperatorVolumeSourceBuilder :: new(
619
+ & ListenerReference :: ListenerClass ( merged_config. listener_class. to_string( ) ) ,
553
620
& recommended_labels,
554
621
)
555
622
. context( BuildListenerVolumeSnafu ) ?
556
623
. build_pvc( LISTENER_VOLUME_NAME . to_string( ) )
557
- . context ( BuildListenerVolumeSnafu ) ?;
558
- Some ( vec ! [ pvc] )
559
- } else {
560
- // non-reachable endpoints use ephemeral volumes
561
- pb. add_listener_volume_by_listener_class (
562
- LISTENER_VOLUME_NAME ,
563
- & listener_class. to_string ( ) ,
564
- & recommended_labels,
565
- )
566
- . context ( AddVolumeSnafu ) ?;
567
- None
568
- } ;
624
+ . context( BuildListenerVolumeSnafu ) ?,
625
+ ] ) ;
569
626
570
627
pb. add_container ( container) ;
571
628
@@ -642,7 +699,7 @@ fn build_stateful_set(
642
699
fn build_history_role_serviceaccount (
643
700
shs : & v1alpha1:: SparkHistoryServer ,
644
701
app_version_label : & str ,
645
- ) -> Result < ( ServiceAccount , RoleBinding ) > {
702
+ ) -> Result < ( ServiceAccount , RoleBinding ) , Error > {
646
703
let sa = ServiceAccount {
647
704
metadata : ObjectMetaBuilder :: new ( )
648
705
. name_and_namespace ( shs)
@@ -784,11 +841,11 @@ fn build_rolegroup_service(
784
841
shs : & v1alpha1:: SparkHistoryServer ,
785
842
app_version_label : & str ,
786
843
group : & RoleGroupRef < v1alpha1:: SparkHistoryServer > ,
787
- ) -> Result < Service > {
844
+ ) -> Result < Service , Error > {
788
845
let ports = Some ( vec ! [
789
846
ServicePort {
790
847
name: Some ( String :: from( "http" ) ) ,
791
- port: 18080 ,
848
+ port: HISTORY_UI_PORT . into ( ) ,
792
849
..ServicePort :: default ( )
793
850
} ,
794
851
ServicePort {
0 commit comments