From 514d07d90d2c2338c5eb5bb5e520a46c7248c349 Mon Sep 17 00:00:00 2001 From: Monokaix Date: Thu, 2 Jan 2025 09:30:37 +0800 Subject: [PATCH] Feat: scheduler supports binging suspension Signed-off-by: Monokaix --- pkg/scheduler/event_handler.go | 6 ++ pkg/scheduler/event_handler_test.go | 41 +++++++--- pkg/util/binding.go | 16 ++++ pkg/util/binding_test.go | 114 ++++++++++++++++++++++++++++ 4 files changed, 166 insertions(+), 11 deletions(-) diff --git a/pkg/scheduler/event_handler.go b/pkg/scheduler/event_handler.go index c400eae5eee4..a37af1f029be 100644 --- a/pkg/scheduler/event_handler.go +++ b/pkg/scheduler/event_handler.go @@ -101,10 +101,16 @@ func (s *Scheduler) resourceBindingEventFilter(obj interface{}) bool { if !schedulerNameFilter(s.schedulerName, t.Spec.SchedulerName) { return false } + if util.IsBindingSuspendScheduling(t) { + return false + } case *workv1alpha2.ClusterResourceBinding: if !schedulerNameFilter(s.schedulerName, t.Spec.SchedulerName) { return false } + if util.IsClusterBindingSuspendScheduling(t) { + return false + } } return util.GetLabelValue(accessor.GetLabels(), policyv1alpha1.PropagationPolicyPermanentIDLabel) != "" || diff --git a/pkg/scheduler/event_handler_test.go b/pkg/scheduler/event_handler_test.go index fbf7088aeb7c..92f844c2909e 100644 --- a/pkg/scheduler/event_handler_test.go +++ b/pkg/scheduler/event_handler_test.go @@ -24,6 +24,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/cache" + "k8s.io/utils/ptr" clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" @@ -40,13 +41,13 @@ func TestResourceBindingEventFilter(t *testing.T) { { name: "ResourceBinding: Matching scheduler name, no labels", schedulerName: "test-scheduler", - obj: createResourceBinding("test-rb", "test-scheduler", nil), + obj: createResourceBinding("test-rb", "test-scheduler", nil, nil), expectedResult: false, }, { name: "ResourceBinding: Non-matching scheduler name", schedulerName: "test-scheduler", - obj: createResourceBinding("test-rb", "other-scheduler", nil), + obj: createResourceBinding("test-rb", "other-scheduler", nil, nil), expectedResult: false, }, { @@ -54,7 +55,7 @@ func TestResourceBindingEventFilter(t *testing.T) { schedulerName: "test-scheduler", obj: createResourceBinding("test-rb", "test-scheduler", map[string]string{ policyv1alpha1.PropagationPolicyPermanentIDLabel: "test-id", - }), + }, nil), expectedResult: true, }, { @@ -62,7 +63,7 @@ func TestResourceBindingEventFilter(t *testing.T) { schedulerName: "test-scheduler", obj: createResourceBinding("test-rb", "test-scheduler", map[string]string{ policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "test-id", - }), + }, nil), expectedResult: true, }, { @@ -70,7 +71,7 @@ func TestResourceBindingEventFilter(t *testing.T) { schedulerName: "test-scheduler", obj: createResourceBinding("test-rb", "test-scheduler", map[string]string{ workv1alpha2.BindingManagedByLabel: "test-manager", - }), + }, nil), expectedResult: true, }, { @@ -78,19 +79,19 @@ func TestResourceBindingEventFilter(t *testing.T) { schedulerName: "test-scheduler", obj: createResourceBinding("test-rb", "test-scheduler", map[string]string{ policyv1alpha1.PropagationPolicyPermanentIDLabel: "", - }), + }, nil), expectedResult: false, }, { name: "ClusterResourceBinding: Matching scheduler name, no labels", schedulerName: "test-scheduler", - obj: createClusterResourceBinding("test-crb", "test-scheduler", nil), + obj: createClusterResourceBinding("test-crb", "test-scheduler", nil, nil), expectedResult: false, }, { name: "ClusterResourceBinding: Non-matching scheduler name", schedulerName: "test-scheduler", - obj: createClusterResourceBinding("test-crb", "other-scheduler", nil), + obj: createClusterResourceBinding("test-crb", "other-scheduler", nil, nil), expectedResult: false, }, { @@ -98,7 +99,7 @@ func TestResourceBindingEventFilter(t *testing.T) { schedulerName: "test-scheduler", obj: createClusterResourceBinding("test-crb", "test-scheduler", map[string]string{ policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "test-id", - }), + }, nil), expectedResult: true, }, { @@ -113,6 +114,22 @@ func TestResourceBindingEventFilter(t *testing.T) { obj: "not-a-valid-object", expectedResult: false, }, + { + name: "ResourceBinding suspended", + schedulerName: "test-scheduler", + obj: createResourceBinding("test-rb", "test-scheduler", map[string]string{ + workv1alpha2.BindingManagedByLabel: "test-manager", + }, &workv1alpha2.Suspension{Scheduling: ptr.To(true)}), + expectedResult: false, + }, + { + name: "ClusterResourceBinding suspended", + schedulerName: "test-scheduler", + obj: createClusterResourceBinding("test-crb", "test-scheduler", map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "test-id", + }, &workv1alpha2.Suspension{Scheduling: ptr.To(true)}), + expectedResult: false, + }, } for _, tc := range testCases { @@ -404,7 +421,7 @@ func createCluster(name string, generation int64, labels map[string]string) *clu } } -func createResourceBinding(name, schedulerName string, labels map[string]string) *workv1alpha2.ResourceBinding { +func createResourceBinding(name, schedulerName string, labels map[string]string, suspension *workv1alpha2.Suspension) *workv1alpha2.ResourceBinding { return &workv1alpha2.ResourceBinding{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -412,11 +429,12 @@ func createResourceBinding(name, schedulerName string, labels map[string]string) }, Spec: workv1alpha2.ResourceBindingSpec{ SchedulerName: schedulerName, + Suspension: suspension, }, } } -func createClusterResourceBinding(name, schedulerName string, labels map[string]string) *workv1alpha2.ClusterResourceBinding { +func createClusterResourceBinding(name, schedulerName string, labels map[string]string, suspension *workv1alpha2.Suspension) *workv1alpha2.ClusterResourceBinding { return &workv1alpha2.ClusterResourceBinding{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -424,6 +442,7 @@ func createClusterResourceBinding(name, schedulerName string, labels map[string] }, Spec: workv1alpha2.ResourceBindingSpec{ SchedulerName: schedulerName, + Suspension: suspension, }, } } diff --git a/pkg/util/binding.go b/pkg/util/binding.go index 6811984f0ec8..ba4631ab6f34 100644 --- a/pkg/util/binding.go +++ b/pkg/util/binding.go @@ -110,3 +110,19 @@ func RescheduleRequired(rescheduleTriggeredAt, lastScheduledTime *metav1.Time) b } return rescheduleTriggeredAt.After(lastScheduledTime.Time) } + +// IsBindingSuspendScheduling tells whether resource binding is scheduling suspended. +func IsBindingSuspendScheduling(rb *workv1alpha2.ResourceBinding) bool { + if rb == nil || rb.Spec.Suspension == nil || rb.Spec.Suspension.Scheduling == nil { + return false + } + return *rb.Spec.Suspension.Scheduling +} + +// IsClusterBindingSuspendScheduling tells whether cluster resource binding is scheduling suspended. +func IsClusterBindingSuspendScheduling(crb *workv1alpha2.ClusterResourceBinding) bool { + if crb == nil || crb.Spec.Suspension == nil || crb.Spec.Suspension.Scheduling == nil { + return false + } + return *crb.Spec.Suspension.Scheduling +} diff --git a/pkg/util/binding_test.go b/pkg/util/binding_test.go index 79355978ba98..48ac8790d48c 100644 --- a/pkg/util/binding_test.go +++ b/pkg/util/binding_test.go @@ -21,8 +21,10 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/utils/ptr" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" @@ -419,3 +421,115 @@ func TestRescheduleRequired(t *testing.T) { }) } } + +func TestIsBindingSuspendScheduling(t *testing.T) { + tests := []struct { + name string + rb *workv1alpha2.ResourceBinding + expected bool + }{ + { + name: "rb is nil", + rb: nil, + expected: false, + }, + { + name: "rb.Spec.Suspension is nil", + rb: &workv1alpha2.ResourceBinding{}, + expected: false, + }, + { + name: "rb.Spec.Suspension.Scheduling is nil", + rb: &workv1alpha2.ResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Suspension: &workv1alpha2.Suspension{}, + }, + }, + expected: false, + }, + { + name: "rb.Spec.Suspension.Scheduling is false", + rb: &workv1alpha2.ResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Suspension: &workv1alpha2.Suspension{ + Scheduling: ptr.To(false), + }, + }, + }, + expected: false, + }, + { + name: "rb.Spec.Suspension.Scheduling is true", + rb: &workv1alpha2.ResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Suspension: &workv1alpha2.Suspension{ + Scheduling: ptr.To(true), + }, + }, + }, + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, IsBindingSuspendScheduling(tt.rb)) + }) + } +} + +func TestIsClusterBindingSuspendScheduling(t *testing.T) { + tests := []struct { + name string + crb *workv1alpha2.ClusterResourceBinding + expected bool + }{ + { + name: "crb is nil", + crb: nil, + expected: false, + }, + { + name: "crb.Spec.Suspension is nil", + crb: &workv1alpha2.ClusterResourceBinding{}, + expected: false, + }, + { + name: "crb.Spec.Suspension.Scheduling is nil", + crb: &workv1alpha2.ClusterResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Suspension: &workv1alpha2.Suspension{}, + }, + }, + expected: false, + }, + { + name: "crb.Spec.Suspension.Scheduling is false", + crb: &workv1alpha2.ClusterResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Suspension: &workv1alpha2.Suspension{ + Scheduling: ptr.To(false), + }, + }, + }, + expected: false, + }, + { + name: "crb.Spec.Suspension.Scheduling is true", + crb: &workv1alpha2.ClusterResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Suspension: &workv1alpha2.Suspension{ + Scheduling: ptr.To(true), + }, + }, + }, + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, IsClusterBindingSuspendScheduling(tt.crb)) + }) + } +}