Skip to content

Commit 778c9ef

Browse files
author
Ryan Zhang
committed
fix comments
Signed-off-by: Ryan Zhang <[email protected]>
1 parent 6cf10bb commit 778c9ef

File tree

4 files changed

+28
-237
lines changed

4 files changed

+28
-237
lines changed

pkg/scheduler/framework/uniquename/uniquename.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func NewBindingName(placementName string, clusterName string) (string, error) {
6262

6363
if errs := validation.IsDNS1123Label(uniqueName); len(errs) != 0 {
6464
// Do a sanity check here; normally this would not occur.
65-
return "", fmt.Errorf("failed to format a unique RFC 1123 label name with CRP name %s, cluster name %s: %v", placementName, clusterName, errs)
65+
return "", fmt.Errorf("failed to format a unique RFC 1123 label name with placement name %s, cluster name %s: %v", placementName, clusterName, errs)
6666
}
6767
return uniqueName, nil
6868
}

pkg/scheduler/scheduler.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ package scheduler
1919

2020
import (
2121
"context"
22+
"errors"
2223
"fmt"
2324
"strconv"
2425
"sync"
2526
"time"
2627

27-
"k8s.io/apimachinery/pkg/api/errors"
28+
apiErrors "k8s.io/apimachinery/pkg/api/errors"
2829
"k8s.io/apimachinery/pkg/labels"
2930
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3031
"k8s.io/client-go/tools/record"
@@ -135,7 +136,7 @@ func (s *Scheduler) scheduleOnce(ctx context.Context, worker int) {
135136
// Retrieve the placement object (either ClusterResourcePlacement or ResourcePlacement).
136137
placement, err := controller.FetchPlacementFromKey(ctx, s.client, placementName)
137138
if err != nil {
138-
if errors.IsNotFound(err) {
139+
if apiErrors.IsNotFound(err) {
139140
// The placement has been gone before the scheduler gets a chance to
140141
// process it; normally this would not happen as sources would not enqueue any placement that
141142
// has been marked for deletion but does not have the scheduler cleanup finalizer to
@@ -144,6 +145,13 @@ func (s *Scheduler) scheduleOnce(ctx context.Context, worker int) {
144145
klog.ErrorS(err, "placement is already deleted", "placement", placementRef)
145146
return
146147
}
148+
if errors.Is(err, controller.ErrUnexpectedBehavior) {
149+
// The placement is in an unexpected state; this is a scheduler-side error, and
150+
// Note that this is a scheduler-side error, so it does not return an error to the caller.
151+
// Raise an alert for it.
152+
klog.ErrorS(err, "Placement is in an unexpected state", "placement", placementRef)
153+
return
154+
}
147155
// Wrap the error for metrics; this method does not return an error.
148156
klog.ErrorS(controller.NewAPIServerError(true, err), "Failed to get placement", "placement", placementRef)
149157

@@ -158,6 +166,10 @@ func (s *Scheduler) scheduleOnce(ctx context.Context, worker int) {
158166
if controllerutil.ContainsFinalizer(placement, fleetv1beta1.SchedulerCleanupFinalizer) {
159167
if err := s.cleanUpAllBindingsFor(ctx, placement); err != nil {
160168
klog.ErrorS(err, "Failed to clean up all bindings for placement", "placement", placementRef)
169+
if errors.Is(err, controller.ErrUnexpectedBehavior) {
170+
// The placement is in an unexpected state; this is a scheduler-side error, and
171+
return
172+
}
161173
// Requeue for later processing.
162174
s.queue.AddRateLimited(placementName)
163175
return
@@ -200,10 +212,18 @@ func (s *Scheduler) scheduleOnce(ctx context.Context, worker int) {
200212
cycleStartTime := time.Now()
201213
res, err := s.framework.RunSchedulingCycleFor(ctx, controller.GetPlacementKeyFromObj(placement), latestPolicySnapshot)
202214
if err != nil {
203-
klog.ErrorS(err, "Failed to run scheduling cycle", "placement", placementRef)
215+
if errors.Is(err, controller.ErrUnexpectedBehavior) {
216+
// The placement is in an unexpected state; this is a scheduler-side error, and
217+
// Note that this is a scheduler-side error, so it does not return an error to the caller.
218+
// Raise an alert for it.
219+
klog.ErrorS(err, "Placement is in an unexpected state", "placement", placementRef)
220+
observeSchedulingCycleMetrics(cycleStartTime, true, false)
221+
return
222+
}
204223
// Requeue for later processing.
224+
klog.ErrorS(err, "Failed to run scheduling cycle", "placement", placementRef)
205225
s.queue.AddRateLimited(placementName)
206-
observeSchedulingCycleMetrics(cycleStartTime, true, false)
226+
observeSchedulingCycleMetrics(cycleStartTime, true, true)
207227
return
208228
}
209229

@@ -289,7 +309,7 @@ func (s *Scheduler) cleanUpAllBindingsFor(ctx context.Context, placement fleetv1
289309
bindings, err := controller.ListBindingsFromKey(ctx, s.uncachedReader, placementKey)
290310
if err != nil {
291311
klog.ErrorS(err, "Failed to list all bindings", "placement", placementRef)
292-
return controller.NewAPIServerError(false, err)
312+
return err
293313
}
294314

295315
// Remove scheduler CRB cleanup finalizer from deleting bindings.
@@ -304,12 +324,12 @@ func (s *Scheduler) cleanUpAllBindingsFor(ctx context.Context, placement fleetv1
304324
binding := bindings[idx]
305325
controllerutil.RemoveFinalizer(binding, fleetv1beta1.SchedulerCRBCleanupFinalizer)
306326
if err := s.client.Update(ctx, binding); err != nil {
307-
klog.ErrorS(err, "Failed to remove scheduler reconcile finalizer from cluster resource binding", "binding", klog.KObj(binding))
327+
klog.ErrorS(err, "Failed to remove scheduler reconcile finalizer from resource binding", "binding", klog.KObj(binding))
308328
return controller.NewUpdateIgnoreConflictError(err)
309329
}
310330
// Delete the binding if it has not been marked for deletion yet.
311331
if binding.GetDeletionTimestamp() == nil {
312-
if err := s.client.Delete(ctx, binding); err != nil && !errors.IsNotFound(err) {
332+
if err := s.client.Delete(ctx, binding); err != nil && !apiErrors.IsNotFound(err) {
313333
klog.ErrorS(err, "Failed to delete binding", "binding", klog.KObj(binding))
314334
return controller.NewAPIServerError(false, err)
315335
}

pkg/utils/controller/binding_resolver.go

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,45 +19,12 @@ package controller
1919
import (
2020
"context"
2121

22-
"k8s.io/apimachinery/pkg/types"
2322
"sigs.k8s.io/controller-runtime/pkg/client"
2423

2524
placementv1beta1 "github.com/kubefleet-dev/kubefleet/apis/placement/v1beta1"
2625
"github.com/kubefleet-dev/kubefleet/pkg/scheduler/queue"
2726
)
2827

29-
// FetchBindingFromKey resolves a specific binding by name using the placement key to determine the type.
30-
// The placement key format determines whether to fetch from ClusterResourceBinding (cluster-scoped)
31-
// or ResourceBinding (namespaced). For namespaced resources, the key format is "namespace/name".
32-
func FetchBindingFromKey(ctx context.Context, c client.Reader, placementKey queue.PlacementKey) (placementv1beta1.BindingObj, error) {
33-
// Extract namespace and name from the placement key
34-
namespace, name, err := ExtractNamespaceNameFromKey(placementKey)
35-
if err != nil {
36-
return nil, err
37-
}
38-
// Check if the placement key contains a namespace separator
39-
if namespace != "" {
40-
// This is a namespaced ResourceBinding
41-
rb := &placementv1beta1.ResourceBinding{}
42-
key := types.NamespacedName{
43-
Namespace: namespace,
44-
Name: name,
45-
}
46-
if err := c.Get(ctx, key, rb); err != nil {
47-
return nil, err
48-
}
49-
return rb, nil
50-
} else {
51-
// This is a cluster-scoped ClusterResourceBinding
52-
crb := &placementv1beta1.ClusterResourceBinding{}
53-
key := types.NamespacedName{Name: name} // name from placement key
54-
if err := c.Get(ctx, key, crb); err != nil {
55-
return nil, err
56-
}
57-
return crb, nil
58-
}
59-
}
60-
6128
// ListBindingsFromKey returns all bindings (either ClusterResourceBinding and ResourceBinding)
6229
// that belong to the specified placement key.
6330
// The placement key format determines whether to list ClusterResourceBindings (cluster-scoped)

pkg/utils/controller/binding_resolver_test.go

Lines changed: 0 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23-
"strings"
2423
"testing"
2524

2625
"github.com/google/go-cmp/cmp"
@@ -341,198 +340,3 @@ type failingListClient struct {
341340
func (c *failingListClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
342341
return fmt.Errorf("simulated client error")
343342
}
344-
345-
func TestFetchBindingFromKey(t *testing.T) {
346-
ctx := context.Background()
347-
348-
tests := []struct {
349-
name string
350-
placementKey queue.PlacementKey
351-
objects []client.Object
352-
wantBinding placementv1beta1.BindingObj
353-
wantErr bool
354-
expectedErr error
355-
}{
356-
{
357-
name: "cluster-scoped binding - found",
358-
placementKey: queue.PlacementKey("test-binding"),
359-
objects: []client.Object{
360-
&placementv1beta1.ClusterResourceBinding{
361-
ObjectMeta: metav1.ObjectMeta{
362-
Name: "test-binding",
363-
Labels: map[string]string{
364-
placementv1beta1.CRPTrackingLabel: "test-placement",
365-
},
366-
},
367-
Spec: placementv1beta1.ResourceBindingSpec{
368-
TargetCluster: "cluster-1",
369-
},
370-
},
371-
},
372-
wantBinding: &placementv1beta1.ClusterResourceBinding{
373-
ObjectMeta: metav1.ObjectMeta{
374-
Name: "test-binding",
375-
Labels: map[string]string{
376-
placementv1beta1.CRPTrackingLabel: "test-placement",
377-
},
378-
},
379-
Spec: placementv1beta1.ResourceBindingSpec{
380-
TargetCluster: "cluster-1",
381-
},
382-
},
383-
wantErr: false,
384-
},
385-
{
386-
name: "cluster-scoped binding - not found",
387-
placementKey: queue.PlacementKey("nonexistent-binding"),
388-
objects: []client.Object{},
389-
wantErr: true,
390-
},
391-
{
392-
name: "namespaced binding - found",
393-
placementKey: queue.PlacementKey("test-namespace/test-binding"),
394-
objects: []client.Object{
395-
&placementv1beta1.ResourceBinding{
396-
ObjectMeta: metav1.ObjectMeta{
397-
Name: "test-binding",
398-
Namespace: "test-namespace",
399-
Labels: map[string]string{
400-
placementv1beta1.CRPTrackingLabel: "test-placement",
401-
},
402-
},
403-
Spec: placementv1beta1.ResourceBindingSpec{
404-
TargetCluster: "cluster-1",
405-
},
406-
},
407-
},
408-
wantBinding: &placementv1beta1.ResourceBinding{
409-
ObjectMeta: metav1.ObjectMeta{
410-
Name: "test-binding",
411-
Namespace: "test-namespace",
412-
Labels: map[string]string{
413-
placementv1beta1.CRPTrackingLabel: "test-placement",
414-
},
415-
},
416-
Spec: placementv1beta1.ResourceBindingSpec{
417-
TargetCluster: "cluster-1",
418-
},
419-
},
420-
wantErr: false,
421-
},
422-
{
423-
name: "namespaced binding - not found",
424-
placementKey: queue.PlacementKey("test-namespace/nonexistent-binding"),
425-
objects: []client.Object{},
426-
wantErr: true,
427-
},
428-
{
429-
name: "namespaced binding - wrong namespace",
430-
placementKey: queue.PlacementKey("wrong-namespace/test-binding"),
431-
objects: []client.Object{
432-
&placementv1beta1.ResourceBinding{
433-
ObjectMeta: metav1.ObjectMeta{
434-
Name: "test-binding",
435-
Namespace: "test-namespace", // different namespace
436-
Labels: map[string]string{
437-
placementv1beta1.CRPTrackingLabel: "test-placement",
438-
},
439-
},
440-
Spec: placementv1beta1.ResourceBindingSpec{
441-
TargetCluster: "cluster-1",
442-
},
443-
},
444-
},
445-
wantErr: true,
446-
},
447-
{
448-
name: "invalid placement key format - too many separators",
449-
placementKey: queue.PlacementKey("namespace/binding/extra"),
450-
objects: []client.Object{},
451-
wantErr: true,
452-
expectedErr: ErrUnexpectedBehavior,
453-
},
454-
{
455-
name: "invalid placement key format - empty parts",
456-
placementKey: queue.PlacementKey("namespace/"),
457-
objects: []client.Object{},
458-
wantErr: true,
459-
expectedErr: ErrUnexpectedBehavior,
460-
},
461-
{
462-
name: "invalid placement key format - empty namespace",
463-
placementKey: queue.PlacementKey("/binding"),
464-
objects: []client.Object{},
465-
wantErr: true,
466-
expectedErr: ErrUnexpectedBehavior,
467-
},
468-
}
469-
470-
for _, tt := range tests {
471-
t.Run(tt.name, func(t *testing.T) {
472-
scheme := runtime.NewScheme()
473-
_ = placementv1beta1.AddToScheme(scheme)
474-
475-
fakeClient := fake.NewClientBuilder().
476-
WithScheme(scheme).
477-
WithObjects(tt.objects...).
478-
Build()
479-
480-
got, err := FetchBindingFromKey(ctx, fakeClient, tt.placementKey)
481-
482-
if tt.wantErr {
483-
if err == nil {
484-
t.Fatalf("Expected error but got nil")
485-
}
486-
if tt.expectedErr != nil && !errors.Is(err, tt.expectedErr) {
487-
t.Fatalf("Expected error: %v, but got: %v", tt.expectedErr, err)
488-
}
489-
return
490-
}
491-
492-
if err != nil {
493-
t.Fatalf("Expected no error but got: %v", err)
494-
}
495-
496-
// Use cmp.Diff to compare the actual result with expected binding
497-
// Ignore resource version and other metadata fields that may differ
498-
if diff := cmp.Diff(got, tt.wantBinding,
499-
cmpopts.IgnoreFields(metav1.ObjectMeta{}, "ResourceVersion")); diff != "" {
500-
t.Errorf("FetchBindingFromKey() diff (-got +want):\n%s", diff)
501-
}
502-
})
503-
}
504-
}
505-
506-
func TestFetchBindingFromKey_ClientError(t *testing.T) {
507-
ctx := context.Background()
508-
509-
// Create a client that will return an error
510-
scheme := runtime.NewScheme()
511-
_ = placementv1beta1.AddToScheme(scheme)
512-
513-
// Use a failing client for Get operations
514-
fakeClient := &failingGetClient{
515-
Client: fake.NewClientBuilder().WithScheme(scheme).Build(),
516-
}
517-
518-
_, err := FetchBindingFromKey(ctx, fakeClient, queue.PlacementKey("test-binding"))
519-
520-
if err == nil {
521-
t.Fatalf("Expected error but got nil")
522-
}
523-
524-
// The error should be the simulated client error, not wrapped as APIServerError
525-
// since FetchBindingFromKey doesn't wrap the Get errors
526-
if !strings.Contains(err.Error(), "simulated get error") {
527-
t.Errorf("Expected error to contain 'simulated get error' but got: %s", err.Error())
528-
}
529-
}
530-
531-
// failingGetClient is a test helper that wraps a client and makes Get calls fail
532-
type failingGetClient struct {
533-
client.Client
534-
}
535-
536-
func (c *failingGetClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
537-
return fmt.Errorf("simulated get error")
538-
}

0 commit comments

Comments
 (0)