@@ -9,7 +9,6 @@ use snafu::{ResultExt, Snafu};
99use stackable_operator:: {
1010 cli:: OperatorEnvironmentOptions ,
1111 cluster_resources:: ClusterResourceApplyStrategy ,
12- commons:: random_secret_creation,
1312 k8s_openapi:: api:: core:: v1:: EnvVar ,
1413 kube:: {
1514 core:: { DeserializeGuard , error_boundary} ,
@@ -21,19 +20,15 @@ use stackable_operator::{
2120 compute_conditions, operations:: ClusterOperationsConditionBuilder ,
2221 statefulset:: StatefulSetConditionBuilder ,
2322 } ,
24- v2:: cluster_resources:: cluster_resources_new,
2523} ;
2624use strum:: { EnumDiscriminants , IntoStaticStr } ;
2725
2826use crate :: {
29- controller:: { ValidatedCluster , build, controller_name, operator_name, product_name} ,
30- crd:: {
31- AirflowClusterStatus , OPERATOR_NAME ,
32- internal_secret:: {
33- FERNET_KEY_SECRET_KEY , INTERNAL_SECRET_SECRET_KEY , JWT_SECRET_SECRET_KEY ,
34- } ,
35- v1alpha2,
27+ controller:: {
28+ apply:: { self , Applier , ensure_random_secrets} ,
29+ build,
3630 } ,
31+ crd:: { AirflowClusterStatus , OPERATOR_NAME , v1alpha2} ,
3732} ;
3833
3934pub const AIRFLOW_CONTROLLER_NAME : & str = "airflowcluster" ;
@@ -51,29 +46,20 @@ pub struct Ctx {
5146#[ strum_discriminants( derive( IntoStaticStr ) ) ]
5247#[ snafu( visibility( pub ( crate ) ) ) ]
5348pub enum Error {
54- #[ snafu( display( "failed to apply Kubernetes resource" ) ) ]
55- ApplyResource {
56- source : stackable_operator:: cluster_resources:: Error ,
57- } ,
49+ #[ snafu( display( "failed to apply the Kubernetes resources" ) ) ]
50+ ApplyResources { source : apply:: Error } ,
5851
5952 #[ snafu( display( "failed to build the Kubernetes resources" ) ) ]
6053 BuildResources { source : build:: Error } ,
6154
62- #[ snafu( display( "failed to delete orphaned resources" ) ) ]
63- DeleteOrphanedResources {
64- source : stackable_operator:: cluster_resources:: Error ,
65- } ,
55+ #[ snafu( display( "failed to ensure the shared random Secrets exist" ) ) ]
56+ EnsureSecrets { source : apply:: Error } ,
6657
6758 #[ snafu( display( "failed to update status" ) ) ]
6859 ApplyStatus {
6960 source : stackable_operator:: client:: Error ,
7061 } ,
7162
72- #[ snafu( display( "failed to create internal secret" ) ) ]
73- InternalSecret {
74- source : random_secret_creation:: Error ,
75- } ,
76-
7763 #[ snafu( display( "failed to dereference cluster resources" ) ) ]
7864 Dereference {
7965 source : crate :: controller:: dereference:: Error ,
@@ -126,75 +112,25 @@ pub async fn reconcile_airflow(
126112 )
127113 . context ( ValidateSnafu ) ?;
128114
129- ensure_random_secrets ( client , & validated_cluster) . await ?;
115+ let resources = build :: build ( & validated_cluster) . context ( BuildResourcesSnafu ) ?;
130116
131- let mut cluster_resources = cluster_resources_new (
132- & product_name ( ) ,
133- & operator_name ( ) ,
134- & controller_name ( ) ,
135- & validated_cluster. name ,
136- & validated_cluster. namespace ,
137- & validated_cluster. uid ,
117+ ensure_random_secrets ( client, & validated_cluster)
118+ . await
119+ . context ( EnsureSecretsSnafu ) ?;
120+ let applied = Applier :: new (
121+ client,
122+ & validated_cluster,
138123 ClusterResourceApplyStrategy :: from ( & airflow. spec . cluster_operation ) ,
139124 & airflow. spec . object_overrides ,
140- ) ;
141-
142- let resources = build:: build ( & validated_cluster) . context ( BuildResourcesSnafu ) ?;
125+ )
126+ . apply ( resources)
127+ . await
128+ . context ( ApplyResourcesSnafu ) ?;
143129
144130 let mut ss_cond_builder = StatefulSetConditionBuilder :: default ( ) ;
145-
146- // Apply order is: StatefulSets last (a changed mounted ConfigMap/Secret
147- // must exist first, else Pods restart -- commons-operator#111). The ServiceAccount comes
148- // first because the Pods reference it at creation time.
149- for service_account in resources. service_accounts {
150- cluster_resources
151- . add ( client, service_account)
152- . await
153- . context ( ApplyResourceSnafu ) ?;
154- }
155- for role_binding in resources. role_bindings {
156- cluster_resources
157- . add ( client, role_binding)
158- . await
159- . context ( ApplyResourceSnafu ) ?;
160- }
161- for service in resources. services {
162- cluster_resources
163- . add ( client, service)
164- . await
165- . context ( ApplyResourceSnafu ) ?;
166- }
167- for listener in resources. listeners {
168- cluster_resources
169- . add ( client, listener)
170- . await
171- . context ( ApplyResourceSnafu ) ?;
172- }
173- for config_map in resources. config_maps {
174- cluster_resources
175- . add ( client, config_map)
176- . await
177- . context ( ApplyResourceSnafu ) ?;
178- }
179- for pdb in resources. pod_disruption_budgets {
180- cluster_resources
181- . add ( client, pdb)
182- . await
183- . context ( ApplyResourceSnafu ) ?;
131+ for statefulset in applied. stateful_sets {
132+ ss_cond_builder. add ( statefulset) ;
184133 }
185- for statefulset in resources. stateful_sets {
186- ss_cond_builder. add (
187- cluster_resources
188- . add ( client, statefulset)
189- . await
190- . context ( ApplyResourceSnafu ) ?,
191- ) ;
192- }
193-
194- cluster_resources
195- . delete_orphaned_resources ( client)
196- . await
197- . context ( DeleteOrphanedResourcesSnafu ) ?;
198134
199135 let status = AirflowClusterStatus {
200136 conditions : compute_conditions (
@@ -211,50 +147,6 @@ pub async fn reconcile_airflow(
211147 Ok ( Action :: await_change ( ) )
212148}
213149
214- /// Ensures the three shared random Secrets (internal / JWT / Fernet) exist, creating any that are
215- /// missing. These are read-or-create client operations, so they cannot be part of the client-free
216- /// `build()` step.
217- async fn ensure_random_secrets (
218- client : & stackable_operator:: client:: Client ,
219- cluster : & ValidatedCluster ,
220- ) -> Result < ( ) , Error > {
221- random_secret_creation:: create_random_secret_if_not_exists (
222- cluster. internal_secret_name ( ) . as_ref ( ) ,
223- INTERNAL_SECRET_SECRET_KEY ,
224- 256 ,
225- cluster,
226- client,
227- )
228- . await
229- . context ( InternalSecretSnafu ) ?;
230-
231- random_secret_creation:: create_random_secret_if_not_exists (
232- cluster. jwt_secret_name ( ) . as_ref ( ) ,
233- JWT_SECRET_SECRET_KEY ,
234- 256 ,
235- cluster,
236- client,
237- )
238- . await
239- . context ( InternalSecretSnafu ) ?;
240-
241- // https://airflow.apache.org/docs/apache-airflow/stable/security/secrets/fernet.html#security-fernet
242- // does not document how long the fernet key should be, but recommends using
243- // python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
244- // which returns 32 bytes.
245- random_secret_creation:: create_random_secret_if_not_exists (
246- cluster. fernet_key_name ( ) . as_ref ( ) ,
247- FERNET_KEY_SECRET_KEY ,
248- 32 ,
249- cluster,
250- client,
251- )
252- . await
253- . context ( InternalSecretSnafu ) ?;
254-
255- Ok ( ( ) )
256- }
257-
258150pub fn error_policy (
259151 _obj : Arc < DeserializeGuard < v1alpha2:: AirflowCluster > > ,
260152 error : & Error ,
0 commit comments