Skip to content

Commit 82bd3ad

Browse files
committed
update to workapplier to use foreground deletion and to update owner reference when co-ownership is allowed
Signed-off-by: Britania Rodriguez Reyes <britaniar@microsoft.com>
1 parent 3b17212 commit 82bd3ad

File tree

7 files changed

+663
-101
lines changed

7 files changed

+663
-101
lines changed

pkg/controllers/workapplier/controller.go

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
66
You 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
1010
Unless required by applicable law or agreed to in writing, software
1111
distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,7 +21,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
2121
you may not use this file except in compliance with the License.
2222
You 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
2626
Unless required by applicable law or agreed to in writing, software
2727
distributed 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.
489489
func (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

Comments
 (0)