@@ -8,11 +8,11 @@ use snafu::{OptionExt, ResultExt, Snafu};
88use stackable_operator:: {
99 cli:: OperatorEnvironmentOptions ,
1010 cluster_resources:: { ClusterResourceApplyStrategy , ClusterResources } ,
11- commons:: product_image_selection:: { self , ResolvedProductImage } ,
11+ commons:: product_image_selection:: ResolvedProductImage ,
1212 crd:: listener,
1313 k8s_openapi:: api:: core:: v1:: ConfigMap ,
1414 kube:: {
15- self , Resource ,
15+ Resource ,
1616 api:: ObjectMeta ,
1717 core:: { DeserializeGuard , DynamicObject , error_boundary} ,
1818 runtime:: { controller, finalizer, reflector:: ObjectRef } ,
@@ -26,11 +26,14 @@ use tracing::{debug, info};
2626
2727use crate :: {
2828 APP_NAME , OPERATOR_NAME ,
29- crd:: { CONTAINER_IMAGE_BASE_NAME , ZookeeperRole , security:: ZookeeperSecurity , v1alpha1} ,
29+ crd:: { ZookeeperRole , security:: ZookeeperSecurity , v1alpha1} ,
3030 discovery:: { self , build_discovery_configmap} ,
3131 listener:: role_listener_name,
3232} ;
3333
34+ mod dereference;
35+ mod validate;
36+
3437pub const ZNODE_CONTROLLER_NAME : & str = "znode" ;
3538pub const ZNODE_FULL_CONTROLLER_NAME : & str = concatcp ! ( ZNODE_CONTROLLER_NAME , '.' , OPERATOR_NAME ) ;
3639
@@ -48,25 +51,17 @@ pub enum Error {
4851 source : error_boundary:: InvalidObject ,
4952 } ,
5053
54+ #[ snafu( display( "failed to dereference resources" ) ) ]
55+ Dereference { source : dereference:: Error } ,
56+
57+ #[ snafu( display( "failed to validate cluster" ) ) ]
58+ ValidateCluster { source : validate:: Error } ,
59+
5160 #[ snafu( display(
5261 "object is missing metadata that should be created by the Kubernetes cluster" ,
5362 ) ) ]
5463 ObjectMissingMetadata ,
5564
56- #[ snafu( display( "object does not refer to ZookeeperCluster" ) ) ]
57- InvalidZkReference ,
58-
59- #[ snafu( display( "could not find {zk:?}" ) ) ]
60- FindZk {
61- source : stackable_operator:: client:: Error ,
62- zk : ObjectRef < v1alpha1:: ZookeeperCluster > ,
63- } ,
64-
65- ZkDoesNotExist {
66- source : stackable_operator:: client:: Error ,
67- zk : ObjectRef < v1alpha1:: ZookeeperCluster > ,
68- } ,
69-
7065 #[ snafu( display( "could not find server role service name for {zk:?}" ) ) ]
7166 NoZkSvcName {
7267 zk : ObjectRef < v1alpha1:: ZookeeperCluster > ,
@@ -124,19 +119,11 @@ pub enum Error {
124119 #[ snafu( display( "object has no namespace" ) ) ]
125120 ObjectHasNoNamespace ,
126121
127- #[ snafu( display( "failed to initialize security context" ) ) ]
128- FailedToInitializeSecurityContext { source : crate :: crd:: security:: Error } ,
129-
130122 #[ snafu( display( "Znode {znode:?} missing expected keys (name and/or namespace)" ) ) ]
131123 ZnodeMissingExpectedKeys {
132124 source : stackable_operator:: cluster_resources:: Error ,
133125 znode : ObjectRef < v1alpha1:: ZookeeperZnode > ,
134126 } ,
135-
136- #[ snafu( display( "failed to resolve product image" ) ) ]
137- ResolveProductImage {
138- source : product_image_selection:: Error ,
139- } ,
140127}
141128type Result < T , E = Error > = std:: result:: Result < T , E > ;
142129
@@ -169,10 +156,9 @@ impl ReconcilerError for Error {
169156 fn secondary_object ( & self ) -> Option < ObjectRef < DynamicObject > > {
170157 match self {
171158 Error :: InvalidZookeeperZnode { .. } => None ,
159+ Error :: Dereference { .. } => None ,
160+ Error :: ValidateCluster { .. } => None ,
172161 Error :: ObjectMissingMetadata => None ,
173- Error :: InvalidZkReference => None ,
174- Error :: FindZk { zk, .. } => Some ( zk. clone ( ) . erase ( ) ) ,
175- Error :: ZkDoesNotExist { zk, .. } => Some ( zk. clone ( ) . erase ( ) ) ,
176162 Error :: NoZkSvcName { zk } => Some ( zk. clone ( ) . erase ( ) ) ,
177163 Error :: FindZkSvc { zk, .. } => Some ( zk. clone ( ) . erase ( ) ) ,
178164 Error :: NoZkFqdn { zk } => Some ( zk. clone ( ) . erase ( ) ) ,
@@ -184,9 +170,7 @@ impl ReconcilerError for Error {
184170 Error :: Finalizer { .. } => None ,
185171 Error :: DeleteOrphans { .. } => None ,
186172 Error :: ObjectHasNoNamespace => None ,
187- Error :: FailedToInitializeSecurityContext { .. } => None ,
188173 Error :: ZnodeMissingExpectedKeys { .. } => None ,
189- Error :: ResolveProductImage { .. } => None ,
190174 }
191175 }
192176}
@@ -213,7 +197,8 @@ pub async fn reconcile_znode(
213197 } ;
214198 let client = & ctx. client ;
215199
216- let zk = find_zk_of_znode ( client, znode) . await ;
200+ // dereference (client required) — replaces find_zk_of_znode
201+ let dereferenced_objects = dereference:: dereference ( client, znode) . await ;
217202 let mut default_status_updates: Option < v1alpha1:: ZookeeperZnodeStatus > = None ;
218203 // Store the znode path in the status rather than the object itself, to ensure that only K8s administrators can override it
219204 let znode_path = match znode. status . as_ref ( ) . and_then ( |s| s. znode_path . as_deref ( ) ) {
@@ -251,21 +236,37 @@ pub async fn reconcile_znode(
251236 |ev| async {
252237 match ev {
253238 finalizer:: Event :: Apply ( znode) => {
254- let zk = zk?;
255- let resolved_product_image = zk
256- . spec
257- . image
258- . resolve (
259- CONTAINER_IMAGE_BASE_NAME ,
260- & ctx. operator_environment . image_repository ,
261- crate :: built_info:: PKG_VERSION ,
262- )
263- . context ( ResolveProductImageSnafu ) ?;
264- reconcile_apply ( client, & znode, Ok ( zk) , & znode_path, & resolved_product_image)
265- . await
239+ let dereferenced = dereferenced_objects. context ( DereferenceSnafu ) ?;
240+ let validate:: ValidatedInputs {
241+ resolved_product_image,
242+ zookeeper_security,
243+ } = validate:: validate ( & znode, & dereferenced, & ctx. operator_environment )
244+ . context ( ValidateClusterSnafu ) ?;
245+ reconcile_apply (
246+ client,
247+ & znode,
248+ dereferenced. zk ,
249+ & zookeeper_security,
250+ & znode_path,
251+ & resolved_product_image,
252+ )
253+ . await
266254 }
267- finalizer:: Event :: Cleanup ( _znode) => {
268- reconcile_cleanup ( client, zk, & znode_path) . await
255+ finalizer:: Event :: Cleanup ( znode) => {
256+ let dereferenced = match dereferenced_objects {
257+ Ok ( d) => d,
258+ Err ( dereference:: Error :: ZkDoesNotExist { zk, .. } ) => {
259+ tracing:: info!( %zk, "Tried to clean up ZookeeperZnode bound to a ZookeeperCluster that does not exist, assuming it is already gone" ) ;
260+ return Ok ( controller:: Action :: await_change ( ) ) ;
261+ }
262+ Err ( e) => return Err ( e) . context ( DereferenceSnafu ) ,
263+ } ;
264+ let validate:: ValidatedInputs {
265+ zookeeper_security, ..
266+ } = validate:: validate ( & znode, & dereferenced, & ctx. operator_environment )
267+ . context ( ValidateClusterSnafu ) ?;
268+ reconcile_cleanup ( client, dereferenced. zk , & zookeeper_security, & znode_path)
269+ . await
269270 }
270271 }
271272 } ,
@@ -277,16 +278,11 @@ pub async fn reconcile_znode(
277278async fn reconcile_apply (
278279 client : & stackable_operator:: client:: Client ,
279280 znode : & v1alpha1:: ZookeeperZnode ,
280- zk : Result < v1alpha1:: ZookeeperCluster > ,
281+ zk : v1alpha1:: ZookeeperCluster ,
282+ zookeeper_security : & ZookeeperSecurity ,
281283 znode_path : & str ,
282284 resolved_product_image : & ResolvedProductImage ,
283285) -> Result < controller:: Action > {
284- let zk = zk?;
285-
286- let zookeeper_security = ZookeeperSecurity :: new_from_zookeeper_cluster ( client, & zk)
287- . await
288- . context ( FailedToInitializeSecurityContextSnafu ) ?;
289-
290286 let mut cluster_resources = ClusterResources :: new (
291287 APP_NAME ,
292288 OPERATOR_NAME ,
@@ -298,7 +294,7 @@ async fn reconcile_apply(
298294 . context ( ZnodeMissingExpectedKeysSnafu { znode } ) ?;
299295
300296 znode_mgmt:: ensure_znode_exists (
301- & zk_mgmt_addr ( & zk, & zookeeper_security, & client. kubernetes_cluster_info ) ?,
297+ & zk_mgmt_addr ( & zk, zookeeper_security, & client. kubernetes_cluster_info ) ?,
302298 znode_path,
303299 )
304300 . await
@@ -327,7 +323,7 @@ async fn reconcile_apply(
327323 listener,
328324 Some ( znode_path) ,
329325 resolved_product_image,
330- & zookeeper_security,
326+ zookeeper_security,
331327 )
332328 . context ( BuildDiscoveryConfigMapSnafu ) ?;
333329
@@ -346,24 +342,13 @@ async fn reconcile_apply(
346342
347343async fn reconcile_cleanup (
348344 client : & stackable_operator:: client:: Client ,
349- zk : Result < v1alpha1:: ZookeeperCluster > ,
345+ zk : v1alpha1:: ZookeeperCluster ,
346+ zookeeper_security : & ZookeeperSecurity ,
350347 znode_path : & str ,
351348) -> Result < controller:: Action > {
352- let zk = match zk {
353- Err ( Error :: ZkDoesNotExist { zk, .. } ) => {
354- tracing:: info!( %zk, "Tried to clean up ZookeeperZnode bound to a ZookeeperCluster that does not exist, assuming it is already gone" ) ;
355- return Ok ( controller:: Action :: await_change ( ) ) ;
356- }
357- res => res?,
358- } ;
359-
360- let zookeeper_security = ZookeeperSecurity :: new_from_zookeeper_cluster ( client, & zk)
361- . await
362- . context ( FailedToInitializeSecurityContextSnafu ) ?;
363-
364349 // Clean up znode from the ZooKeeper cluster before letting Kubernetes delete the object
365350 znode_mgmt:: ensure_znode_missing (
366- & zk_mgmt_addr ( & zk, & zookeeper_security, & client. kubernetes_cluster_info ) ?,
351+ & zk_mgmt_addr ( & zk, zookeeper_security, & client. kubernetes_cluster_info ) ?,
367352 znode_path,
368353 )
369354 . await
@@ -403,37 +388,6 @@ fn zk_mgmt_addr(
403388 ) )
404389}
405390
406- async fn find_zk_of_znode (
407- client : & stackable_operator:: client:: Client ,
408- znode : & v1alpha1:: ZookeeperZnode ,
409- ) -> Result < v1alpha1:: ZookeeperCluster > {
410- let zk_ref = & znode. spec . cluster_ref ;
411- if let ( Some ( zk_name) , Some ( zk_ns) ) = (
412- zk_ref. name . as_deref ( ) ,
413- zk_ref. namespace_relative_from ( znode) ,
414- ) {
415- match client
416- . get :: < v1alpha1:: ZookeeperCluster > ( zk_name, zk_ns)
417- . await
418- {
419- Ok ( zk) => Ok ( zk) ,
420- Err ( err) => match & err {
421- stackable_operator:: client:: Error :: GetResource {
422- source : kube:: Error :: Api ( s) ,
423- ..
424- } if s. is_not_found ( ) => Err ( err) . with_context ( |_| ZkDoesNotExistSnafu {
425- zk : ObjectRef :: new ( zk_name) . within ( zk_ns) ,
426- } ) ,
427- _ => Err ( err) . with_context ( |_| FindZkSnafu {
428- zk : ObjectRef :: new ( zk_name) . within ( zk_ns) ,
429- } ) ,
430- } ,
431- }
432- } else {
433- InvalidZkReferenceSnafu . fail ( )
434- }
435- }
436-
437391pub fn error_policy (
438392 _obj : Arc < DeserializeGuard < v1alpha1:: ZookeeperZnode > > ,
439393 _error : & Error ,
0 commit comments