@@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
55you may not use this file except in compliance with the License.
66You may obtain a copy of the License at
77
8- http://www.apache.org/licenses/LICENSE-2.0
8+ http://www.apache.org/licenses/LICENSE-2.0
99
1010Unless required by applicable law or agreed to in writing, software
1111distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,7 +21,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
2121you may not use this file except in compliance with the License.
2222You may obtain a copy of the License at
2323
24- http://www.apache.org/licenses/LICENSE-2.0
24+ http://www.apache.org/licenses/LICENSE-2.0
2525
2626Unless required by applicable law or agreed to in writing, software
2727distributed under the License is distributed on an "AS IS" BASIS,
@@ -417,7 +417,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
417417 Kind : fleetv1beta1 .AppliedWorkKind ,
418418 Name : appliedWork .GetName (),
419419 UID : appliedWork .GetUID (),
420- BlockOwnerDeletion : ptr .To (false ),
420+ BlockOwnerDeletion : ptr .To (true ),
421421 }
422422
423423 // Set the default values for the Work object to avoid additional validation logic in the
@@ -487,7 +487,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
487487
488488// garbageCollectAppliedWork deletes the appliedWork and all the manifests associated with it from the cluster.
489489func (r * Reconciler ) garbageCollectAppliedWork (ctx context.Context , work * fleetv1beta1.Work ) (ctrl.Result , error ) {
490- deletePolicy := metav1 .DeletePropagationBackground
490+ deletePolicy := metav1 .DeletePropagationForeground
491491 if ! controllerutil .ContainsFinalizer (work , fleetv1beta1 .WorkFinalizer ) {
492492 return ctrl.Result {}, nil
493493 }
@@ -496,18 +496,98 @@ func (r *Reconciler) garbageCollectAppliedWork(ctx context.Context, work *fleetv
496496 appliedWork := fleetv1beta1.AppliedWork {
497497 ObjectMeta : metav1.ObjectMeta {Name : work .Name },
498498 }
499- err := r .spokeClient .Delete (ctx , & appliedWork , & client.DeleteOptions {PropagationPolicy : & deletePolicy })
500- switch {
501- case apierrors .IsNotFound (err ):
502- klog .V (2 ).InfoS ("The appliedWork is already deleted" , "appliedWork" , work .Name )
503- case err != nil :
504- klog .ErrorS (err , "Failed to delete the appliedWork" , "appliedWork" , work .Name )
499+ if work .Spec .ApplyStrategy != nil {
500+ if work .Spec .ApplyStrategy .AllowCoOwnership {
501+ // If the Work object allows co-ownership, we need to change the blockOwnerDeletion to false
502+ // so that the appliedWork can be deleted without waiting for the object that has another owner to be deleted.
503+ klog .V (2 ).InfoS ("Work object allows co-ownership; updating owner reference to not block deletion" , "work" , work .Name )
504+ if err := r .updateOwnerReference (ctx , work ); ! apierrors .IsNotFound (err ) && err != nil {
505+ klog .ErrorS (err , "Failed to update owner reference for the work" , "work" , work .Name )
506+ return ctrl.Result {}, controller .NewAPIServerError (false , err )
507+ }
508+ }
509+ }
510+ if err := r .spokeClient .Delete (ctx , & appliedWork , & client.DeleteOptions {PropagationPolicy : & deletePolicy }); err != nil {
511+ if apierrors .IsNotFound (err ) {
512+ klog .V (2 ).InfoS ("The appliedWork is already deleted" , "appliedWork" , work .Name )
513+ return r .removeWorkFinalizer (ctx , work )
514+ }
515+ klog .V (2 ).ErrorS (err , "Failed to delete the appliedWork" , "appliedWork" , work .Name )
505516 return ctrl.Result {}, controller .NewAPIServerError (false , err )
506- default :
507- klog .InfoS ("Successfully deleted the appliedWork" , "appliedWork" , work .Name )
508517 }
509- controllerutil .RemoveFinalizer (work , fleetv1beta1 .WorkFinalizer )
510518
519+ klog .V (2 ).InfoS ("Deletion for appliedWork is in progress" , "appliedWork" , work .Name )
520+ return ctrl.Result {RequeueAfter : 5 * time .Second }, nil
521+ }
522+
523+ func (r * Reconciler ) updateOwnerReference (ctx context.Context , work * fleetv1beta1.Work ) error {
524+ // Get the AppliedWork object
525+ var appliedWork fleetv1beta1.AppliedWork
526+ if err := r .spokeClient .Get (ctx , types.NamespacedName {Name : work .Name }, & appliedWork ); err != nil {
527+ if apierrors .IsNotFound (err ) {
528+ klog .V (2 ).InfoS ("AppliedWork not found for updateOwnerReference" , "appliedWork" , work .Name )
529+ return err
530+ }
531+ klog .ErrorS (err , "Failed to get AppliedWork for updateOwnerReference" , "appliedWork" , work .Name )
532+ return err
533+ }
534+
535+ for _ , res := range appliedWork .Status .AppliedResources {
536+ gvr := schema.GroupVersionResource {
537+ Group : res .Group ,
538+ Version : res .Version ,
539+ Resource : res .Resource ,
540+ }
541+ var obj * unstructured.Unstructured
542+ var err error
543+ if res .Namespace != "" {
544+ obj , err = r .spokeDynamicClient .Resource (gvr ).Namespace (res .Namespace ).Get (ctx , res .Name , metav1.GetOptions {})
545+ } else {
546+ obj , err = r .spokeDynamicClient .Resource (gvr ).Get (ctx , res .Name , metav1.GetOptions {})
547+ }
548+ if err != nil {
549+ if apierrors .IsNotFound (err ) {
550+ continue
551+ }
552+ klog .ErrorS (err , "Failed to get manifest for updateOwnerReference" , "gvr" , gvr , "name" , res .Name , "namespace" , res .Namespace )
553+ return err
554+ }
555+ // Check if there is more than one owner reference
556+ if len (obj .GetOwnerReferences ()) > 1 {
557+ owners := obj .GetOwnerReferences ()
558+ updated := false
559+ for i := range owners {
560+ // Check if the owner reference matches the appliedWork UID and has BlockOwnerDeletion set to true
561+ if owners [i ].UID == appliedWork .UID && owners [i ].BlockOwnerDeletion != nil && * owners [i ].BlockOwnerDeletion {
562+ // If we found an owner reference to update, set BlockOwnerDeletion to false
563+ b := false
564+ owners [i ].BlockOwnerDeletion = & b
565+ updated = true
566+ break
567+ }
568+ }
569+ if updated {
570+ obj .SetOwnerReferences (owners )
571+ if res .Namespace != "" {
572+ _ , err = r .spokeDynamicClient .Resource (gvr ).Namespace (res .Namespace ).Update (ctx , obj , metav1.UpdateOptions {})
573+ } else {
574+ _ , err = r .spokeDynamicClient .Resource (gvr ).Update (ctx , obj , metav1.UpdateOptions {})
575+ }
576+ if err != nil {
577+ klog .ErrorS (err , "Failed to update manifest owner reference blockOwnerDeletion" , "gvr" , gvr , "name" , res .Name , "namespace" , res .Namespace )
578+ return err
579+ } else {
580+ klog .InfoS ("Set blockOwnerDeletion=false for owner reference" , "gvr" , gvr , "name" , res .Name , "namespace" , res .Namespace )
581+ }
582+ }
583+ }
584+ }
585+ return nil
586+ }
587+
588+ // removeWorkFinalizer removes the finalizer from the work and updates it in the hub.
589+ func (r * Reconciler ) removeWorkFinalizer (ctx context.Context , work * fleetv1beta1.Work ) (ctrl.Result , error ) {
590+ controllerutil .RemoveFinalizer (work , fleetv1beta1 .WorkFinalizer )
511591 if err := r .hubClient .Update (ctx , work , & client.UpdateOptions {}); err != nil {
512592 klog .ErrorS (err , "Failed to remove the finalizer from the work" , "work" , klog .KObj (work ))
513593 return ctrl.Result {}, controller .NewAPIServerError (false , err )
@@ -557,6 +637,10 @@ func (r *Reconciler) ensureAppliedWork(ctx context.Context, work *fleetv1beta1.W
557637 return nil , controller .NewAPIServerError (false , err )
558638 }
559639 }
640+ if err := r .spokeClient .Get (ctx , types.NamespacedName {Name : workRef .Name }, appliedWork ); err != nil {
641+ klog .ErrorS (err , "Failed to get the appliedWork" , "appliedWork" , appliedWork .Name )
642+ return nil , controller .NewAPIServerError (false , err )
643+ }
560644 klog .InfoS ("Recreated the appliedWork resource" , "appliedWork" , workRef .Name )
561645 return appliedWork , nil
562646}
0 commit comments