@@ -18,7 +18,12 @@ use stackable_operator::{
1818 rbac:: build_rbac_resources,
1919 resources:: { NoRuntimeLimits , Resources } ,
2020 } ,
21- k8s_openapi:: api:: core:: v1:: Secret ,
21+ crd:: listener,
22+ k8s_openapi:: api:: {
23+ apps:: v1:: { Deployment , StatefulSet } ,
24+ core:: v1:: { ConfigMap , Secret , Service } ,
25+ policy:: v1:: PodDisruptionBudget ,
26+ } ,
2227 kube:: {
2328 Resource , ResourceExt ,
2429 api:: ObjectMeta ,
@@ -54,14 +59,6 @@ use tracing::instrument;
5459
5560use crate :: {
5661 OPERATOR_NAME ,
57- controller:: build:: resource:: {
58- config_map:: build_rolegroup_config_map,
59- deployment:: build_rolegroup_deployment,
60- listener:: build_group_listener,
61- pdb:: build_pdb,
62- service:: { build_rolegroup_headless_service, build_rolegroup_metrics_service} ,
63- statefulset:: build_node_rolegroup_statefulset,
64- } ,
6562 crd:: {
6663 APP_NAME , INTERNAL_SECRET_SECRET_KEY , SupersetRole ,
6764 authentication:: SupersetClientAuthenticationDetailsResolved ,
@@ -86,6 +83,19 @@ pub struct Ctx {
8683 pub operator_environment : OperatorEnvironmentOptions ,
8784}
8885
86+ /// Every Kubernetes resource produced by the build step.
87+ ///
88+ /// The `Node` role is provisioned via a `StatefulSet` (it serves the Superset web UI), while the
89+ /// `Worker`/`Beat` Celery roles are provisioned via `Deployment`s; the build step collects both.
90+ pub struct KubernetesResources {
91+ pub stateful_sets : Vec < StatefulSet > ,
92+ pub deployments : Vec < Deployment > ,
93+ pub services : Vec < Service > ,
94+ pub listeners : Vec < listener:: v1alpha1:: Listener > ,
95+ pub config_maps : Vec < ConfigMap > ,
96+ pub pod_disruption_budgets : Vec < PodDisruptionBudget > ,
97+ }
98+
8999/// Per-role configuration extracted during validation.
90100#[ derive( Clone , Debug ) ]
91101pub struct ValidatedRoleConfig {
@@ -386,28 +396,12 @@ pub enum Error {
386396 source : stackable_operator:: cluster_resources:: Error ,
387397 } ,
388398
389- #[ snafu( display( "failed to apply Service for role group {role_group_name}" ) ) ]
390- ApplyRoleGroupService {
391- source : stackable_operator:: cluster_resources:: Error ,
392- role_group_name : RoleGroupName ,
393- } ,
394-
395- #[ snafu( display( "failed to apply ConfigMap for role group {role_group_name}" ) ) ]
396- ApplyRoleGroupConfig {
397- source : stackable_operator:: cluster_resources:: Error ,
398- role_group_name : RoleGroupName ,
399- } ,
399+ #[ snafu( display( "failed to build the Kubernetes resources" ) ) ]
400+ BuildResources { source : build:: Error } ,
400401
401- #[ snafu( display( "failed to apply StatefulSet for role group {role_group_name} " ) ) ]
402- ApplyRoleGroupStatefulSet {
402+ #[ snafu( display( "failed to apply Kubernetes resource " ) ) ]
403+ ApplyResource {
403404 source : stackable_operator:: cluster_resources:: Error ,
404- role_group_name : RoleGroupName ,
405- } ,
406-
407- #[ snafu( display( "failed to apply Deployment for role group {role_group_name}" ) ) ]
408- ApplyRoleGroupDeployment {
409- source : stackable_operator:: cluster_resources:: Error ,
410- role_group_name : RoleGroupName ,
411405 } ,
412406
413407 #[ snafu( display( "failed to update status" ) ) ]
@@ -430,11 +424,6 @@ pub enum Error {
430424 source : stackable_operator:: commons:: rbac:: Error ,
431425 } ,
432426
433- #[ snafu( display( "failed to apply PodDisruptionBudget" ) ) ]
434- ApplyPdb {
435- source : stackable_operator:: cluster_resources:: Error ,
436- } ,
437-
438427 #[ snafu( display( "failed to get required Labels" ) ) ]
439428 GetRequiredLabels {
440429 source :
@@ -446,26 +435,6 @@ pub enum Error {
446435 source : error_boundary:: InvalidObject ,
447436 } ,
448437
449- #[ snafu( display( "failed to apply group listener" ) ) ]
450- ApplyGroupListener {
451- source : stackable_operator:: cluster_resources:: Error ,
452- } ,
453-
454- #[ snafu( display( "failed to build statefulset" ) ) ]
455- BuildStatefulSet {
456- source : crate :: controller:: build:: resource:: statefulset:: Error ,
457- } ,
458-
459- #[ snafu( display( "failed to build deployment" ) ) ]
460- BuildDeployment {
461- source : crate :: controller:: build:: resource:: deployment:: Error ,
462- } ,
463-
464- #[ snafu( display( "failed to build configmap" ) ) ]
465- BuildConfigMap {
466- source : crate :: controller:: build:: resource:: config_map:: Error ,
467- } ,
468-
469438 #[ snafu( display( "failed to create SECRET_KEY secret" ) ) ]
470439 CreateSecretKeySecret {
471440 source : random_secret_creation:: Error ,
@@ -567,129 +536,53 @@ pub async fn reconcile_superset(
567536 . await
568537 . context ( CreateSecretKeySecretSnafu ) ?;
569538
539+ let resources = build:: build ( & validated, & rbac_sa. name_any ( ) ) . context ( BuildResourcesSnafu ) ?;
540+
570541 let mut statefulset_cond_builder = StatefulSetConditionBuilder :: default ( ) ;
571542 let mut deployment_cond_builder = DeploymentConditionBuilder :: default ( ) ;
572543
573- for ( superset_role, rolegroup_configs) in & validated. role_groups {
574- for ( rolegroup_name, validated_rolegroup) in rolegroup_configs {
575- let config = & validated_rolegroup. config ;
576-
577- let rg_configmap = build_rolegroup_config_map (
578- & validated,
579- superset_role,
580- rolegroup_name,
581- config,
582- & validated_rolegroup. config_overrides ,
583- )
584- . context ( BuildConfigMapSnafu ) ?;
585-
586- // Every role exposes metrics via the statsd-exporter sidecar, so each rolegroup gets a
587- // metrics Service. The headless Service is built per role below: only the `Node` role's
588- // StatefulSet references one (as its `serviceName`); the `Worker`/`Beat` Deployments have
589- // no `serviceName` and do not serve the HTTP port, so they get no headless Service.
590- let rg_metrics_service =
591- build_rolegroup_metrics_service ( & validated, superset_role, rolegroup_name) ;
592-
544+ // The StatefulSets/Deployments are applied last, so every ConfigMap and Secret they mount
545+ // already exists — otherwise a changed mount would restart the Pods.
546+ // See https://github.com/stackabletech/commons-operator/issues/111 for details.
547+ for service in resources. services {
548+ cluster_resources
549+ . add ( client, service)
550+ . await
551+ . context ( ApplyResourceSnafu ) ?;
552+ }
553+ for config_map in resources. config_maps {
554+ cluster_resources
555+ . add ( client, config_map)
556+ . await
557+ . context ( ApplyResourceSnafu ) ?;
558+ }
559+ for listener in resources. listeners {
560+ cluster_resources
561+ . add ( client, listener)
562+ . await
563+ . context ( ApplyResourceSnafu ) ?;
564+ }
565+ for pdb in resources. pod_disruption_budgets {
566+ cluster_resources
567+ . add ( client, pdb)
568+ . await
569+ . context ( ApplyResourceSnafu ) ?;
570+ }
571+ for statefulset in resources. stateful_sets {
572+ statefulset_cond_builder. add (
593573 cluster_resources
594- . add ( client, rg_metrics_service )
574+ . add ( client, statefulset )
595575 . await
596- . with_context ( |_| ApplyRoleGroupServiceSnafu {
597- role_group_name : rolegroup_name. clone ( ) ,
598- } ) ?;
599-
576+ . context ( ApplyResourceSnafu ) ?,
577+ ) ;
578+ }
579+ for deployment in resources. deployments {
580+ deployment_cond_builder. add (
600581 cluster_resources
601- . add ( client, rg_configmap )
582+ . add ( client, deployment )
602583 . await
603- . with_context ( |_| ApplyRoleGroupConfigSnafu {
604- role_group_name : rolegroup_name. clone ( ) ,
605- } ) ?;
606-
607- match superset_role {
608- SupersetRole :: Node => {
609- let rg_headless_service =
610- build_rolegroup_headless_service ( & validated, superset_role, rolegroup_name) ;
611-
612- cluster_resources
613- . add ( client, rg_headless_service)
614- . await
615- . with_context ( |_| ApplyRoleGroupServiceSnafu {
616- role_group_name : rolegroup_name. clone ( ) ,
617- } ) ?;
618-
619- let rg_statefulset = build_node_rolegroup_statefulset (
620- & validated,
621- superset_role,
622- rolegroup_name,
623- validated_rolegroup,
624- & rbac_sa. name_any ( ) ,
625- )
626- . context ( BuildStatefulSetSnafu ) ?;
627-
628- // Note: The StatefulSet needs to be applied after all ConfigMaps and Secrets it mounts
629- // to prevent unnecessary Pod restarts.
630- // See https://github.com/stackabletech/commons-operator/issues/111 for details.
631- statefulset_cond_builder. add (
632- cluster_resources
633- . add ( client, rg_statefulset)
634- . await
635- . with_context ( |_| ApplyRoleGroupStatefulSetSnafu {
636- role_group_name : rolegroup_name. clone ( ) ,
637- } ) ?,
638- ) ;
639- }
640- SupersetRole :: Worker | SupersetRole :: Beat => {
641- let rg_deployment = build_rolegroup_deployment (
642- & validated,
643- superset_role,
644- rolegroup_name,
645- validated_rolegroup,
646- & rbac_sa. name_any ( ) ,
647- )
648- . context ( BuildDeploymentSnafu ) ?;
649-
650- // Note: The Deployment needs to be applied after all ConfigMaps and Secrets it mounts
651- // to prevent unnecessary Pod restarts.
652- // See https://github.com/stackabletech/commons-operator/issues/111 for details.
653- deployment_cond_builder. add (
654- cluster_resources
655- . add ( client, rg_deployment)
656- . await
657- . with_context ( |_| ApplyRoleGroupDeploymentSnafu {
658- role_group_name : rolegroup_name. clone ( ) ,
659- } ) ?,
660- ) ;
661- }
662- }
663- }
664-
665- // Role-level resources (group listener, PDB) are built once per role, after
666- // its role groups — not once per role group.
667- if let Some ( role_config) = validated. role_configs . get ( superset_role) {
668- if let ( Some ( listener_class) , Some ( listener_group_name) ) = (
669- & role_config. listener_class ,
670- & role_config. group_listener_name ,
671- ) {
672- let group_listener = build_group_listener (
673- & validated,
674- superset_role,
675- listener_class,
676- listener_group_name. to_string ( ) ,
677- ) ;
678- cluster_resources
679- . add ( client, group_listener)
680- . await
681- . context ( ApplyGroupListenerSnafu ) ?;
682- }
683-
684- if let Some ( pdb) = & role_config. pdb
685- && let Some ( pdb) = build_pdb ( pdb, & validated, superset_role)
686- {
687- cluster_resources
688- . add ( client, pdb)
689- . await
690- . context ( ApplyPdbSnafu ) ?;
691- }
692- }
584+ . context ( ApplyResourceSnafu ) ?,
585+ ) ;
693586 }
694587
695588 cluster_resources
0 commit comments