@@ -67,10 +67,13 @@ func (r *MaasClusterReconciler) ensureLXDInitializerDS(ctx context.Context, clus
6767 if ! r .anyNodeNeedsInitialization (ctx , remoteClient ) {
6868 r .Log .Info ("All nodes already labeled initialized; considering DS cleanup" , "namespace" , dsNamespace , "ds" , dsName )
6969 if done , err := r .maybeShortCircuitDelete (ctx , remoteClient , dsNamespace , desiredCP , dsName ); err != nil {
70+ r .Log .Error (err , "failed to maybe short circuit delete" , "namespace" , dsNamespace , "ds" , dsName )
7071 return err
7172 } else if done {
73+ r .Log .Info ("deleted existing initializer DS - all nodes are ready and initialized" , "namespace" , dsNamespace , "ds" , dsName )
7274 return nil
7375 }
76+ r .Log .Info ("no nodes need initialization; skipping DS creation" , "namespace" , dsNamespace , "ds" , dsName )
7477 return nil
7578 }
7679
@@ -80,28 +83,68 @@ func (r *MaasClusterReconciler) ensureLXDInitializerDS(ctx context.Context, clus
8083 // }
8184
8285 if err := r .deleteExistingInitializerDS (ctx , remoteClient , dsNamespace ); err != nil {
86+ r .Log .Error (err , "failed to delete existing initializer DS" , "namespace" , dsNamespace , "ds" , dsName )
8387 return err
8488 }
8589
8690 // Ensure RBAC resources are created on the target cluster
8791 if err := r .ensureLXDInitializerRBACOnTarget (ctx , remoteClient , dsNamespace ); err != nil {
92+ r .Log .Error (err , "failed to ensure LXD initializer RBAC" , "namespace" , dsNamespace , "ds" , dsName )
8893 return fmt .Errorf ("failed to ensure LXD initializer RBAC: %v" , err )
8994 }
9095
9196 if done , err := r .maybeShortCircuitDelete (ctx , remoteClient , dsNamespace , desiredCP , dsName ); err != nil {
97+ r .Log .Error (err , "failed to maybe short circuit delete" , "namespace" , dsNamespace , "ds" , dsName )
9298 return err
9399 } else if done {
100+ r .Log .Info ("deleted existing initializer DS - all nodes are ready and initialized" , "namespace" , dsNamespace , "ds" , dsName )
94101 return nil
95102 }
96103
97104 ds , err := r .renderDaemonSetForCluster (clusterScope , dsName , dsNamespace )
98105 if err != nil {
106+ r .Log .Error (err , "failed to render DaemonSet for cluster" , "namespace" , dsNamespace , "ds" , dsName )
99107 return err
100108 }
101109
102- // Do not set owner refs across clusters; just create/patch on target cluster
103- _ , err = controllerutil .CreateOrPatch (ctx , remoteClient , ds , func () error { return nil })
104- return err
110+ // Do not set owner refs across clusters; just create/patch on target cluster.
111+ // Mutate existing DaemonSet so changes to template/spec take effect on reconcile.
112+ current := & appsv1.DaemonSet {}
113+ current .Name = dsName
114+ current .Namespace = dsNamespace
115+
116+ _ , err = controllerutil .CreateOrPatch (ctx , remoteClient , current , func () error {
117+ // Preserve immutable selector if already present; align labels.
118+ current .Labels = ds .Labels
119+ current .Annotations = ds .Annotations
120+
121+ // Update pod template and mutable spec fields
122+ current .Spec .Template = ds .Spec .Template
123+ current .Spec .UpdateStrategy = ds .Spec .UpdateStrategy
124+ current .Spec .MinReadySeconds = ds .Spec .MinReadySeconds
125+ current .Spec .RevisionHistoryLimit = ds .Spec .RevisionHistoryLimit
126+
127+ // Initialize selector if missing (only valid on create)
128+ if current .Spec .Selector == nil || len (current .Spec .Selector .MatchLabels ) == 0 {
129+ current .Spec .Selector = ds .Spec .Selector
130+ }
131+ // Ensure template labels include selector labels
132+ if current .Spec .Selector != nil && len (current .Spec .Selector .MatchLabels ) > 0 {
133+ if current .Spec .Template .Labels == nil {
134+ current .Spec .Template .Labels = map [string ]string {}
135+ }
136+ for k , v := range current .Spec .Selector .MatchLabels {
137+ current .Spec .Template .Labels [k ] = v
138+ }
139+ }
140+ return nil
141+ })
142+ if err != nil {
143+ r .Log .Error (err , "failed to create/patch DaemonSet" , "namespace" , dsNamespace , "ds" , dsName )
144+ return err
145+ }
146+ r .Log .Info ("created/patched DaemonSet" , "namespace" , dsNamespace , "ds" , dsName )
147+ return nil
105148}
106149
107150// ensureLXDInitializerRBACOnTarget creates the RBAC resources for lxd-initializer on the target cluster
@@ -295,21 +338,18 @@ func (r *MaasClusterReconciler) maybeShortCircuitDelete(ctx context.Context, rem
295338 }
296339 }
297340
298- // Only delete if:
299- // 1. We have exactly desiredCP nodes (not more, which would indicate maintenance/new nodes)
300- // 2. All nodes are Ready
301- // 3. All nodes are initialized
302- if int64 (len (shortCircuitNodes .Items )) == int64 (desiredCP ) &&
303- int64 (readyCount ) == int64 (desiredCP ) &&
304- int64 (initCount ) >= int64 (desiredCP ) {
341+ // Delete initializer DS only when ALL nodes (control-plane + worker) are initialized.
342+ // This matches the new requirement to register both CP and worker nodes.
343+ totalNodes := len (shortCircuitNodes .Items )
344+ if totalNodes > 0 && initCount == totalNodes {
305345 shortCircuitDSList := & appsv1.DaemonSetList {}
306346 if err := remoteClient .List (ctx , shortCircuitDSList , client .InNamespace (namespace ), client.MatchingLabels {"app" : dsName }); err == nil {
307347 for _ , ds := range shortCircuitDSList .Items {
308348 _ = remoteClient .Delete (ctx , & ds )
309349 }
310350 }
311- r .Log .Info ("Deleted LXD initializer DaemonSet - all nodes are ready and initialized" ,
312- "desiredCP" , desiredCP , "totalNodes" , len ( shortCircuitNodes . Items ) , "readyNodes" , readyCount , "initializedNodes" , initCount )
351+ r .Log .Info ("Deleted LXD initializer DaemonSet - all nodes initialized" ,
352+ "desiredCP" , desiredCP , "totalNodes" , totalNodes , "readyNodes" , readyCount , "initializedNodes" , initCount )
313353 return true , nil
314354 }
315355 return false , nil
0 commit comments