@@ -197,6 +197,7 @@ type Reconciler struct {
197197
198198 availabilityCheckRequeueAfter time.Duration
199199 driftCheckRequeueAfter time.Duration
200+ deletionWaitTime time.Duration
200201}
201202
202203func NewReconciler (
@@ -207,6 +208,7 @@ func NewReconciler(
207208 workerCount int ,
208209 availabilityCheckRequestAfter time.Duration ,
209210 driftCheckRequestAfter time.Duration ,
211+ deletionWaitTime time.Duration ,
210212 watchWorkWithPriorityQueue bool ,
211213 watchWorkReconcileAgeMinutes int ,
212214) * Reconciler {
@@ -236,6 +238,7 @@ func NewReconciler(
236238 joined : atomic .NewBool (false ),
237239 availabilityCheckRequeueAfter : acRequestAfter ,
238240 driftCheckRequeueAfter : dcRequestAfter ,
241+ deletionWaitTime : deletionWaitTime ,
239242 }
240243}
241244
@@ -470,74 +473,78 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
470473 return ctrl.Result {RequeueAfter : r .driftCheckRequeueAfter }, nil
471474}
472475
473- // garbageCollectAppliedWork deletes the appliedWork and all the manifests associated with it from the cluster.
474476func (r * Reconciler ) garbageCollectAppliedWork (ctx context.Context , work * fleetv1beta1.Work ) (ctrl.Result , error ) {
475477 deletePolicy := metav1 .DeletePropagationForeground
476478 if ! controllerutil .ContainsFinalizer (work , fleetv1beta1 .WorkFinalizer ) {
477479 return ctrl.Result {}, nil
478480 }
479- // Delete the appliedWork which will remove all the manifests associated with it, unless they have
480- // other owner references.
481- appliedWork := fleetv1beta1.AppliedWork {
481+ appliedWork := & fleetv1beta1.AppliedWork {
482482 ObjectMeta : metav1.ObjectMeta {Name : work .Name },
483483 }
484484 // Get the AppliedWork object
485- if err := r .spokeClient .Get (ctx , types.NamespacedName {Name : work .Name }, & appliedWork ); err != nil {
485+ if err := r .spokeClient .Get (ctx , types.NamespacedName {Name : work .Name }, appliedWork ); err != nil {
486486 if apierrors .IsNotFound (err ) {
487487 klog .V (2 ).InfoS ("The appliedWork is already deleted, removing the finalizer from the work" , "appliedWork" , work .Name )
488488 return r .removeWorkFinalizer (ctx , work )
489489 }
490490 klog .ErrorS (err , "Failed to get AppliedWork" , "appliedWork" , work .Name )
491- return ctrl.Result {Requeue : true }, controller .NewAPIServerError (false , err )
491+ return ctrl.Result {}, controller .NewAPIServerError (false , err )
492492 }
493493
494- // Delete the appliedWork object .
495- if appliedWork .DeletionTimestamp .IsZero () {
496- // Update the owner reference in the AppliedWork object.
497- if err := r .updateOwnerReference (ctx , & appliedWork ); err != nil {
498- klog .ErrorS (err , "Failed to update owner reference in the appliedWork " , "appliedWork" , work .Name )
494+ // Handle stuck deletion after 5 minutes where the other owner references might not exist or are invalid .
495+ if ! appliedWork .DeletionTimestamp .IsZero () && time . Since ( appliedWork . DeletionTimestamp . Time ) >= r . deletionWaitTime {
496+ klog . V ( 2 ). InfoS ( "AppliedWork deletion appears stuck; attempting to patch owner references" , "appliedWork" , work . Name )
497+ if err := r .updateOwnerReference (ctx , work , appliedWork ); err != nil {
498+ klog .ErrorS (err , "Failed to update owner references for AppliedWork " , "appliedWork" , work .Name )
499499 return ctrl.Result {}, controller .NewAPIServerError (false , err )
500500 }
501- klog .V (2 ).InfoS ("Deleting the appliedWork" , "appliedWork" , work .Name )
502- if err := r .spokeClient .Delete (ctx , & appliedWork , & client.DeleteOptions {PropagationPolicy : & deletePolicy }); err != nil {
503- if apierrors .IsNotFound (err ) {
504- klog .V (2 ).InfoS ("The appliedWork is already deleted" , "appliedWork" , work .Name )
505- return r .removeWorkFinalizer (ctx , work )
506- }
507- klog .V (2 ).ErrorS (err , "Failed to delete the appliedWork" , "appliedWork" , work .Name )
508- return ctrl.Result {}, controller .NewAPIServerError (false , err )
501+ }
502+
503+ if err := r .spokeClient .Delete (ctx , appliedWork , & client.DeleteOptions {PropagationPolicy : & deletePolicy }); err != nil {
504+ if apierrors .IsNotFound (err ) {
505+ klog .V (2 ).InfoS ("AppliedWork already deleted" , "appliedWork" , work .Name )
506+ return r .removeWorkFinalizer (ctx , work )
509507 }
508+ klog .V (2 ).ErrorS (err , "Failed to delete the appliedWork" , "appliedWork" , work .Name )
509+ return ctrl.Result {}, controller .NewAPIServerError (false , err )
510510 }
511+
511512 klog .V (2 ).InfoS ("AppliedWork deletion in progress" , "appliedWork" , work .Name )
512- return ctrl.Result {Requeue : true }, fmt .Errorf ("AppliedWork %s is being deleted, waiting for the deletion to complete" , work .Name )
513+ return ctrl.Result {}, fmt .Errorf ("AppliedWork %s is being deleted, waiting for the deletion to complete" , work .Name )
513514}
514515
515516// updateOwnerReference updates the AppliedWork owner reference in the manifest objects.
516- // It changes the ` blockOwnerDeletion` field to true , so that the AppliedWork can be deleted in cases where
517+ // It changes the blockOwnerDeletion field to false , so that the AppliedWork can be deleted in cases where
517518// the other owner references do not exist or are invalid.
518519// https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/#owner-references-in-object-specifications
519- func (r * Reconciler ) updateOwnerReference (ctx context.Context , appliedWork * fleetv1beta1.AppliedWork ) error {
520+ func (r * Reconciler ) updateOwnerReference (ctx context.Context , work * fleetv1beta1. Work , appliedWork * fleetv1beta1.AppliedWork ) error {
520521 appliedWorkOwnerRef := & metav1.OwnerReference {
521522 APIVersion : fleetv1beta1 .GroupVersion .String (),
522523 Kind : "AppliedWork" ,
523524 Name : appliedWork .Name ,
524525 UID : appliedWork .UID ,
525526 }
526527
527- for _ , res := range appliedWork .Status .AppliedResources {
528+ if err := r .hubClient .Get (ctx , types.NamespacedName {Name : work .Name , Namespace : work .Namespace }, work ); err != nil {
529+ if apierrors .IsNotFound (err ) {
530+ klog .V (2 ).InfoS ("Work object not found, skipping owner reference update" , "work" , work .Name , "namespace" , work .Namespace )
531+ return nil
532+ }
533+ klog .ErrorS (err , "Failed to get Work object for owner reference update" , "work" , work .Name , "namespace" , work .Namespace )
534+ return controller .NewAPIServerError (false , err )
535+ }
536+
537+ for _ , cond := range work .Status .ManifestConditions {
538+ res := cond .Identifier
528539 gvr := schema.GroupVersionResource {
529540 Group : res .Group ,
530541 Version : res .Version ,
531542 Resource : res .Resource ,
532543 }
544+
533545 var obj * unstructured.Unstructured
534546 var err error
535- if res .Namespace != "" {
536- obj , err = r .spokeDynamicClient .Resource (gvr ).Namespace (res .Namespace ).Get (ctx , res .Name , metav1.GetOptions {})
537- } else {
538- obj , err = r .spokeDynamicClient .Resource (gvr ).Get (ctx , res .Name , metav1.GetOptions {})
539- }
540- if err != nil {
547+ if obj , err = r .spokeDynamicClient .Resource (gvr ).Namespace (res .Namespace ).Get (ctx , res .Name , metav1.GetOptions {}); err != nil {
541548 if apierrors .IsNotFound (err ) {
542549 continue
543550 }
@@ -548,37 +555,20 @@ func (r *Reconciler) updateOwnerReference(ctx context.Context, appliedWork *flee
548555 // Otherwise, at least one other owner reference exists, and we need to leave resource alone.
549556 if len (obj .GetOwnerReferences ()) > 1 {
550557 ownerRefs := obj .GetOwnerReferences ()
551-
552- // Re-build the owner reference; update the blockOwnerDeletion field to false.
553558 updated := false
554559 for idx := range ownerRefs {
555- if ownerRefs [idx ].UID == appliedWorkOwnerRef .UID &&
556- ownerRefs [idx ].Name == appliedWorkOwnerRef .Name &&
557- ownerRefs [idx ].Kind == appliedWorkOwnerRef .Kind &&
558- ownerRefs [idx ].APIVersion == appliedWorkOwnerRef .APIVersion &&
559- * ownerRefs [idx ].BlockOwnerDeletion {
560+ if ownerRefEqualsExpected (& ownerRefs [idx ], appliedWorkOwnerRef ) {
560561 ownerRefs [idx ].BlockOwnerDeletion = ptr .To (false )
561562 updated = true
562563 }
563564 }
564565 if updated {
565566 obj .SetOwnerReferences (ownerRefs )
566-
567- if res .Namespace != "" {
568- _ , err = r .spokeDynamicClient .Resource (gvr ).Namespace (res .Namespace ).Update (ctx , obj , metav1.UpdateOptions {})
569- if err != nil {
570- klog .ErrorS (err , "Failed to update manifest owner references" , "gvr" , gvr , "name" , res .Name , "namespace" , res .Namespace )
571- return err
572- }
573- klog .V (4 ).InfoS ("Updated manifest owner references" , "gvr" , gvr , "name" , res .Name , "namespace" , res .Namespace )
574- } else {
575- _ , err = r .spokeDynamicClient .Resource (gvr ).Update (ctx , obj , metav1.UpdateOptions {})
576- if err != nil {
577- klog .ErrorS (err , "Failed to update manifest owner references" , "gvr" , gvr , "name" , res .Name )
578- return err
579- }
580- klog .V (4 ).InfoS ("Updated manifest owner references" , "gvr" , gvr , "name" , res .Name )
567+ if _ , err = r .spokeDynamicClient .Resource (gvr ).Namespace (obj .GetNamespace ()).Update (ctx , obj , metav1.UpdateOptions {}); err != nil {
568+ klog .ErrorS (err , "Failed to update manifest owner references" , "gvr" , gvr , "name" , res .Name , "namespace" , res .Namespace )
569+ return err
581570 }
571+ klog .V (4 ).InfoS ("Patched manifest owner references" , "gvr" , gvr , "name" , res .Name , "namespace" , res .Namespace )
582572 }
583573 }
584574 }
0 commit comments