@@ -155,11 +155,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req controllerruntime.Reques
155155
156156 workUpdated := false
157157 overrideSucceeded := false
158+ workDeleted := false
158159 // list all the corresponding works
159160 works , syncErr := r .listAllWorksAssociated (ctx , & resourceBinding )
160161 if syncErr == nil {
161162 // generate and apply the workUpdated works if we have all the works
162- overrideSucceeded , workUpdated , syncErr = r .syncAllWork (ctx , & resourceBinding , works , & cluster )
163+ overrideSucceeded , workUpdated , workDeleted , syncErr = r .syncAllWork (ctx , & resourceBinding , works , & cluster )
163164 }
164165 // Reset the conditions and failed/drifted/diffed placements.
165166 for i := condition .OverriddenCondition ; i < condition .TotalCondition ; i ++ {
@@ -220,10 +221,16 @@ func (r *Reconciler) Reconcile(ctx context.Context, req controllerruntime.Reques
220221 Message : "All of the works are synchronized to the latest" ,
221222 })
222223 switch {
224+ case workDeleted :
225+ // Some Work object(s) are being deleted; set a False Applied condition which signals
226+ // that resources are in the process of being applied.
227+ klog .V (2 ).InfoS ("Some work being deleted" , "resourceBinding" , bindingRef )
228+ setBindingStatus (workDeleted , works , & resourceBinding )
229+ syncErr = controller .NewUserError (fmt .Errorf ("some work objects are being deleted" ))
223230 case ! workUpdated :
224231 // The Work object itself is unchanged; refresh the cluster resource binding status
225232 // based on the status information reported on the Work object(s).
226- setBindingStatus (works , & resourceBinding )
233+ setBindingStatus (workDeleted , works , & resourceBinding )
227234 case resourceBinding .Spec .ApplyStrategy == nil || resourceBinding .Spec .ApplyStrategy .Type != fleetv1beta1 .ApplyStrategyTypeReportDiff :
228235 // The Work object itself has changed; set a False Applied condition which signals
229236 // that resources are in the process of being applied.
@@ -409,8 +416,9 @@ func (r *Reconciler) listAllWorksAssociated(ctx context.Context, resourceBinding
409416// it returns
410417// 1: if we apply the overrides successfully
411418// 2: if we actually made any changes on the hub cluster
412- func (r * Reconciler ) syncAllWork (ctx context.Context , resourceBinding * fleetv1beta1.ClusterResourceBinding , existingWorks map [string ]* fleetv1beta1.Work , cluster * clusterv1beta1.MemberCluster ) (bool , bool , error ) {
419+ func (r * Reconciler ) syncAllWork (ctx context.Context , resourceBinding * fleetv1beta1.ClusterResourceBinding , existingWorks map [string ]* fleetv1beta1.Work , cluster * clusterv1beta1.MemberCluster ) (bool , bool , bool , error ) {
413420 updateAny := atomic .NewBool (false )
421+ deletedAny := atomic .NewBool (false )
414422 resourceBindingRef := klog .KObj (resourceBinding )
415423
416424 // Refresh the apply strategy for all existing works.
@@ -435,17 +443,17 @@ func (r *Reconciler) syncAllWork(ctx context.Context, resourceBinding *fleetv1be
435443 })
436444 }
437445 if updateErr := errs .Wait (); updateErr != nil {
438- return false , false , updateErr
446+ return false , false , false , updateErr
439447 }
440448
441449 // the hash256 function can handle empty list https://go.dev/play/p/_4HW17fooXM
442450 resourceOverrideSnapshotHash , err := resource .HashOf (resourceBinding .Spec .ResourceOverrideSnapshots )
443451 if err != nil {
444- return false , false , controller .NewUnexpectedBehaviorError (err )
452+ return false , false , false , controller .NewUnexpectedBehaviorError (err )
445453 }
446454 clusterResourceOverrideSnapshotHash , err := resource .HashOf (resourceBinding .Spec .ClusterResourceOverrideSnapshots )
447455 if err != nil {
448- return false , false , controller .NewUnexpectedBehaviorError (err )
456+ return false , false , false , controller .NewUnexpectedBehaviorError (err )
449457 }
450458 // TODO: check all work synced first before fetching the snapshots after we put ParentResourceOverrideSnapshotHashAnnotation and ParentClusterResourceOverrideSnapshotHashAnnotation in all the work objects
451459
@@ -456,22 +464,22 @@ func (r *Reconciler) syncAllWork(ctx context.Context, resourceBinding *fleetv1be
456464 // the resourceIndex is deleted but the works might still be up to date with the binding.
457465 if areAllWorkSynced (existingWorks , resourceBinding , resourceOverrideSnapshotHash , clusterResourceOverrideSnapshotHash ) {
458466 klog .V (2 ).InfoS ("All the works are synced with the resourceBinding even if the resource snapshot index is removed" , "resourceBinding" , resourceBindingRef )
459- return true , updateAny .Load (), nil
467+ return true , updateAny .Load (), deletedAny . Load (), nil
460468 }
461- return false , false , controller .NewUserError (err )
469+ return false , false , false , controller .NewUserError (err )
462470 }
463471 // TODO(RZ): handle errResourceNotFullyCreated error so we don't need to wait for all the snapshots to be created
464- return false , false , err
472+ return false , false , false , err
465473 }
466474
467475 croMap , err := r .fetchClusterResourceOverrideSnapshots (ctx , resourceBinding )
468476 if err != nil {
469- return false , false , err
477+ return false , false , false , err
470478 }
471479
472480 roMap , err := r .fetchResourceOverrideSnapshots (ctx , resourceBinding )
473481 if err != nil {
474- return false , false , err
482+ return false , false , false , err
475483 }
476484
477485 // issue all the create/update requests for the corresponding works for each snapshot in parallel
@@ -484,15 +492,15 @@ func (r *Reconciler) syncAllWork(ctx context.Context, resourceBinding *fleetv1be
484492 workNamePrefix , err := getWorkNamePrefixFromSnapshotName (snapshot )
485493 if err != nil {
486494 klog .ErrorS (err , "Encountered a mal-formatted resource snapshot" , "resourceSnapshot" , klog .KObj (snapshot ))
487- return false , false , err
495+ return false , false , false , err
488496 }
489497 var simpleManifests []fleetv1beta1.Manifest
490498 for j := range snapshot .Spec .SelectedResources {
491499 selectedResource := snapshot .Spec .SelectedResources [j ].DeepCopy ()
492500 // TODO: override the content of the wrapped resource instead of the envelope itself
493501 resourceDeleted , overrideErr := r .applyOverrides (selectedResource , cluster , croMap , roMap )
494502 if overrideErr != nil {
495- return false , false , overrideErr
503+ return false , false , false , overrideErr
496504 }
497505 if resourceDeleted {
498506 klog .V (2 ).InfoS ("The resource is deleted by the override rules" , "snapshot" , klog .KObj (snapshot ), "selectedResource" , snapshot .Spec .SelectedResources [j ])
@@ -503,14 +511,14 @@ func (r *Reconciler) syncAllWork(ctx context.Context, resourceBinding *fleetv1be
503511 var uResource unstructured.Unstructured
504512 if unMarshallErr := uResource .UnmarshalJSON (selectedResource .Raw ); unMarshallErr != nil {
505513 klog .ErrorS (unMarshallErr , "work has invalid content" , "snapshot" , klog .KObj (snapshot ), "selectedResource" , selectedResource .Raw )
506- return true , false , controller .NewUnexpectedBehaviorError (unMarshallErr )
514+ return true , false , false , controller .NewUnexpectedBehaviorError (unMarshallErr )
507515 }
508516 if uResource .GetObjectKind ().GroupVersionKind () == utils .ConfigMapGVK &&
509517 len (uResource .GetAnnotations ()[fleetv1beta1 .EnvelopeConfigMapAnnotation ]) != 0 {
510518 // get a work object for the enveloped configMap
511519 work , err := r .getConfigMapEnvelopWorkObj (ctx , workNamePrefix , resourceBinding , snapshot , & uResource , resourceOverrideSnapshotHash , clusterResourceOverrideSnapshotHash )
512520 if err != nil {
513- return true , false , err
521+ return true , false , false , err
514522 }
515523 activeWork [work .Name ] = work
516524 newWork = append (newWork , work )
@@ -545,6 +553,7 @@ func (r *Reconciler) syncAllWork(ctx context.Context, resourceBinding *fleetv1be
545553 }
546554
547555 // delete the works that are not associated with any resource snapshot
556+ deletedWork := make ([]* fleetv1beta1.Work , len (existingWorks ))
548557 for i := range existingWorks {
549558 work := existingWorks [i ]
550559 if _ , exist := activeWork [work .Name ]; exist {
@@ -557,18 +566,20 @@ func (r *Reconciler) syncAllWork(ctx context.Context, resourceBinding *fleetv1be
557566 return controller .NewAPIServerError (false , err )
558567 }
559568 }
569+ deletedWork = append (deletedWork , work )
560570 klog .V (2 ).InfoS ("Deleted the work that is not associated with any resource snapshot" , "work" , klog .KObj (work ))
561- updateAny .Store (true )
571+ //updateAny.Store(true)
572+ deletedAny .Store (true )
562573 return nil
563574 })
564575 }
565576
566577 // wait for all the create/update/delete requests to finish
567578 if updateErr := errs .Wait (); updateErr != nil {
568- return true , false , updateErr
579+ return true , false , false , updateErr
569580 }
570- klog .V (2 ).InfoS ("Successfully synced all the work associated with the resourceBinding" , "updateAny" , updateAny .Load (), "resourceBinding" , resourceBindingRef )
571- return true , updateAny .Load (), nil
581+ klog .V (2 ).InfoS ("Successfully synced all the work associated with the resourceBinding" , "updateAny" , updateAny .Load (), "deletedAny" , deletedAny . Load (), " resourceBinding" , resourceBindingRef )
582+ return true , updateAny .Load (), deletedAny . Load (), nil
572583}
573584
574585// syncApplyStrategy syncs the apply strategy specified on a ClusterResourceBinding object
@@ -845,7 +856,7 @@ const (
845856)
846857
847858// setBindingStatus sets the binding status based on the works associated with the binding.
848- func setBindingStatus (works map [string ]* fleetv1beta1.Work , resourceBinding * fleetv1beta1.ClusterResourceBinding ) {
859+ func setBindingStatus (workDeleted bool , works map [string ]* fleetv1beta1.Work , resourceBinding * fleetv1beta1.ClusterResourceBinding ) {
849860 bindingRef := klog .KObj (resourceBinding )
850861
851862 // Note (chenyu1): the work generator will refresh the status of a ClusterResourceBinding using
@@ -871,7 +882,7 @@ func setBindingStatus(works map[string]*fleetv1beta1.Work, resourceBinding *flee
871882 } else {
872883 // Set the Applied and Available condition if (and only if) a ClientSideApply or ServerSideApply
873884 // apply strategy is currently being used.
874- appliedSummarizedStatus = setAllWorkAppliedCondition (works , resourceBinding )
885+ appliedSummarizedStatus = setAllWorkAppliedCondition (workDeleted , works , resourceBinding )
875886 // Note that Fleet will only set the Available condition if the apply op itself is successful, i.e.,
876887 // the Applied condition is True.
877888 availabilitySummarizedStatus = setAllWorkAvailableCondition (works , resourceBinding )
@@ -1007,7 +1018,7 @@ func setBindingStatus(works map[string]*fleetv1beta1.Work, resourceBinding *flee
10071018//
10081019// The Applied condition of a ClusterResourceBinding object is set to True if and only if all the
10091020// related Work objects have their Applied condition set to True.
1010- func setAllWorkAppliedCondition (works map [string ]* fleetv1beta1.Work , binding * fleetv1beta1.ClusterResourceBinding ) workConditionSummarizedStatus {
1021+ func setAllWorkAppliedCondition (workDeleted bool , works map [string ]* fleetv1beta1.Work , binding * fleetv1beta1.ClusterResourceBinding ) workConditionSummarizedStatus {
10111022 // Fleet here makes a clear distinction between incomplete, failed, and successful apply operations.
10121023 // This is to ensure that stale apply information (esp. those set before
10131024 // an apply strategy change) will not leak into the current apply operations.
@@ -1038,9 +1049,20 @@ func setAllWorkAppliedCondition(works map[string]*fleetv1beta1.Work, binding *fl
10381049 }
10391050
10401051 switch {
1052+ case workDeleted :
1053+ // Some work objects are being deleted.
1054+ klog .V (2 ).InfoS ("Some works have not yet completed the apply op as some are deleting" , "binding" , klog .KObj (binding ))
1055+ binding .SetConditions (metav1.Condition {
1056+ Status : metav1 .ConditionFalse ,
1057+ Type : string (fleetv1beta1 .ResourceBindingApplied ),
1058+ Reason : condition .WorkNotAppliedReason ,
1059+ Message : "Some work objects have been deleted. Some works have not yet completed the apply op." ,
1060+ ObservedGeneration : binding .GetGeneration (),
1061+ })
1062+ return workConditionSummarizedStatusFalse
10411063 case ! areAllWorksApplyOpsCompleted :
10421064 // Not all Work objects have completed the apply op.
1043- klog .V (2 ).InfoS ("Some works are not yet completed the apply op" , "binding" , klog .KObj (binding ), "firstWorkWithIncompleteApplyOp" , klog .KObj (firstWorkWithIncompleteApplyOp ))
1065+ klog .V (2 ).InfoS ("Some works have not yet completed the apply op" , "binding" , klog .KObj (binding ), "firstWorkWithIncompleteApplyOp" , klog .KObj (firstWorkWithIncompleteApplyOp ))
10441066 binding .SetConditions (metav1.Condition {
10451067 Status : metav1 .ConditionFalse ,
10461068 Type : string (fleetv1beta1 .ResourceBindingApplied ),
0 commit comments