@@ -279,9 +279,8 @@ func (r *Reconciler) getOrCreateSchedulingPolicySnapshot(ctx context.Context, pl
279279 return nil , controller .NewUnexpectedBehaviorError (err )
280280 }
281281
282- // Use the unified helper function to fetch the latest policy snapshot
283- placementKey := types.NamespacedName {Name : placementObj .GetName (), Namespace : placementObj .GetNamespace ()}
284- latestPolicySnapshot , latestPolicySnapshotIndex , err := controller .FetchLatestPolicySnapshot (ctx , r .Client , placementKey )
282+ // latestPolicySnapshotIndex should be -1 when there is no snapshot.
283+ latestPolicySnapshot , latestPolicySnapshotIndex , err := r .lookupLatestSchedulingPolicySnapshot (ctx , placementObj )
285284 if err != nil {
286285 return nil , err
287286 }
@@ -338,8 +337,102 @@ func (r *Reconciler) getOrCreateSchedulingPolicySnapshot(ctx context.Context, pl
338337 return newPolicySnapshot , nil
339338}
340339
340+ // lookupLatestSchedulingPolicySnapshot finds the latest snapshots and its policy index.
341+ // There will be only one active policy snapshot if exists.
342+ // It first checks whether there is an active policy snapshot.
343+ // If not, it finds the one whose policyIndex label is the largest.
344+ // The policy index will always start from 0.
345+ // Return error when 1) cannot list the snapshots 2) there are more than one active policy snapshots 3) snapshot has the
346+ // invalid label value.
347+ // 2 & 3 should never happen.
348+ func (r * Reconciler ) lookupLatestSchedulingPolicySnapshot (ctx context.Context , placement fleetv1beta1.PlacementObj ) (fleetv1beta1.PolicySnapshotObj , int , error ) {
349+ placementKey := types.NamespacedName {Name : placement .GetName (), Namespace : placement .GetNamespace ()}
350+ snapshotList , err := controller .FetchLatestPolicySnapshot (ctx , r .Client , placementKey )
351+ if err != nil {
352+ return nil , - 1 , err
353+ }
354+ placementKObj := klog .KObj (placement )
355+ if err != nil {
356+ klog .ErrorS (err , "Failed to list active schedulingPolicySnapshots" , "placement" , placementKObj )
357+ // Placement controller needs a scheduling policy snapshot watcher to enqueue the placement request.
358+ // So the snapshots should be read from cache.
359+ return nil , - 1 , controller .NewAPIServerError (true , err )
360+ }
361+ policySnapshotItems := snapshotList .GetPolicySnapshotObjs ()
362+ if len (policySnapshotItems ) == 1 {
363+ policyIndex , err := labels .ParsePolicyIndexFromLabel (policySnapshotItems [0 ])
364+ if err != nil {
365+ klog .ErrorS (err , "Failed to parse the policy index label" , "placement" , placementKObj , "policySnapshot" , klog .KObj (policySnapshotItems [0 ]))
366+ return nil , - 1 , controller .NewUnexpectedBehaviorError (err )
367+ }
368+ return policySnapshotItems [0 ], policyIndex , nil
369+ } else if len (policySnapshotItems ) > 1 {
370+ // It means there are multiple active snapshots and should never happen.
371+ err := fmt .Errorf ("there are %d active schedulingPolicySnapshots owned by placement %v" , len (policySnapshotItems ), placementKey )
372+ klog .ErrorS (err , "Invalid schedulingPolicySnapshots" , "placement" , placementKObj )
373+ return nil , - 1 , controller .NewUnexpectedBehaviorError (err )
374+ }
375+ // When there are no active snapshots, find the one who has the largest policy index.
376+ // It should be rare only when placement controller is crashed before creating the new active snapshot.
377+ sortedList , err := r .listSortedSchedulingPolicySnapshots (ctx , placement )
378+ if err != nil {
379+ return nil , - 1 , err
380+ }
381+
382+ if len (sortedList .GetPolicySnapshotObjs ()) == 0 {
383+ // The policy index of the first snapshot will start from 0.
384+ return nil , - 1 , nil
385+ }
386+ latestSnapshot := sortedList .GetPolicySnapshotObjs ()[len (sortedList .GetPolicySnapshotObjs ())- 1 ]
387+ policyIndex , err := labels .ParsePolicyIndexFromLabel (latestSnapshot )
388+ if err != nil {
389+ klog .ErrorS (err , "Failed to parse the policy index label" , "placement" , placementKObj , "policySnapshot" , klog .KObj (latestSnapshot ))
390+ return nil , - 1 , controller .NewUnexpectedBehaviorError (err )
391+ }
392+ return latestSnapshot , policyIndex , nil
393+ }
394+
395+ // listSortedSchedulingPolicySnapshots returns the policy snapshots sorted by the policy index.
396+ // Now works with both cluster-scoped and namespaced policy snapshots using interface types.
397+ func (r * Reconciler ) listSortedSchedulingPolicySnapshots (ctx context.Context , placementObj fleetv1beta1.PlacementObj ) (fleetv1beta1.PolicySnapshotList , error ) {
398+ placementKey := types.NamespacedName {
399+ Namespace : placementObj .GetNamespace (),
400+ Name : placementObj .GetName (),
401+ }
402+
403+ snapshotList , err := controller .ListPolicySnapshots (ctx , r .Client , placementKey )
404+ if err != nil {
405+ klog .ErrorS (err , "Failed to list all policySnapshots" , "placement" , klog .KObj (placementObj ))
406+ // CRP controller needs a scheduling policy snapshot watcher to enqueue the CRP request.
407+ // So the snapshots should be read from cache.
408+ return nil , controller .NewAPIServerError (true , err )
409+ }
410+
411+ items := snapshotList .GetPolicySnapshotObjs ()
412+ var errs []error
413+ sort .Slice (items , func (i , j int ) bool {
414+ ii , err := labels .ParsePolicyIndexFromLabel (items [i ])
415+ if err != nil {
416+ klog .ErrorS (err , "Failed to parse the policy index label" , "placement" , klog .KObj (placementObj ), "policySnapshot" , klog .KObj (items [i ]))
417+ errs = append (errs , err )
418+ }
419+ ji , err := labels .ParsePolicyIndexFromLabel (items [j ])
420+ if err != nil {
421+ klog .ErrorS (err , "Failed to parse the policy index label" , "placement" , klog .KObj (placementObj ), "policySnapshot" , klog .KObj (items [j ]))
422+ errs = append (errs , err )
423+ }
424+ return ii < ji
425+ })
426+
427+ if len (errs ) > 0 {
428+ return nil , controller .NewUnexpectedBehaviorError (utilerrors .NewAggregate (errs ))
429+ }
430+
431+ return snapshotList , nil
432+ }
433+
341434func (r * Reconciler ) deleteRedundantSchedulingPolicySnapshots (ctx context.Context , placementObj fleetv1beta1.PlacementObj , revisionHistoryLimit int ) error {
342- sortedList , err := r .listSortedClusterSchedulingPolicySnapshots (ctx , placementObj )
435+ sortedList , err := r .listSortedSchedulingPolicySnapshots (ctx , placementObj )
343436 if err != nil {
344437 return err
345438 }
@@ -756,45 +849,6 @@ func (r *Reconciler) ensureLatestResourceSnapshot(ctx context.Context, latest fl
756849 return nil
757850}
758851
759- // listSortedClusterSchedulingPolicySnapshots returns the policy snapshots sorted by the policy index.
760- // Now works with both cluster-scoped and namespaced policy snapshots using interface types.
761- func (r * Reconciler ) listSortedClusterSchedulingPolicySnapshots (ctx context.Context , placementObj fleetv1beta1.PlacementObj ) (fleetv1beta1.PolicySnapshotList , error ) {
762- placementKey := types.NamespacedName {
763- Namespace : placementObj .GetNamespace (),
764- Name : placementObj .GetName (),
765- }
766-
767- snapshotList , err := controller .ListPolicySnapshots (ctx , r .Client , placementKey )
768- if err != nil {
769- klog .ErrorS (err , "Failed to list all policySnapshots" , "placement" , klog .KObj (placementObj ))
770- // CRP controller needs a scheduling policy snapshot watcher to enqueue the CRP request.
771- // So the snapshots should be read from cache.
772- return nil , controller .NewAPIServerError (true , err )
773- }
774-
775- items := snapshotList .GetPolicySnapshotObjs ()
776- var errs []error
777- sort .Slice (items , func (i , j int ) bool {
778- ii , err := labels .ParsePolicyIndexFromLabel (items [i ])
779- if err != nil {
780- klog .ErrorS (err , "Failed to parse the policy index label" , "placement" , klog .KObj (placementObj ), "policySnapshot" , klog .KObj (items [i ]))
781- errs = append (errs , err )
782- }
783- ji , err := labels .ParsePolicyIndexFromLabel (items [j ])
784- if err != nil {
785- klog .ErrorS (err , "Failed to parse the policy index label" , "placement" , klog .KObj (placementObj ), "policySnapshot" , klog .KObj (items [j ]))
786- errs = append (errs , err )
787- }
788- return ii < ji
789- })
790-
791- if len (errs ) > 0 {
792- return nil , controller .NewUnexpectedBehaviorError (utilerrors .NewAggregate (errs ))
793- }
794-
795- return snapshotList , nil
796- }
797-
798852// lookupLatestResourceSnapshot finds the latest snapshots and.
799853// There will be only one active resource snapshot if exists.
800854// It first checks whether there is an active resource snapshot.
0 commit comments