Merge pull request #2346 from RainbowMango/pr_add_graceful_evict_helper

Enable graceful eviction in taint manager
This commit is contained in:
karmada-bot 2022-08-09 16:43:08 +08:00 committed by GitHub
commit 67fd394e5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 184 additions and 2 deletions

View File

@ -40,3 +40,35 @@ func (s *ResourceBindingSpec) RemoveCluster(name string) {
s.Clusters = append(s.Clusters[:i], s.Clusters[i+1:]...)
}
// GracefulEvictCluster removes specific cluster from the target list in a graceful way by
// building a graceful eviction task.
// This function no-opts if the cluster does not exist.
func (s *ResourceBindingSpec) GracefulEvictCluster(name, producer, reason, message string) {
// find the cluster index
var i int
for i = 0; i < len(s.Clusters); i++ {
if s.Clusters[i].Name == name {
break
}
}
// not found, do nothing
if i >= len(s.Clusters) {
return
}
// build eviction task
evictingCluster := s.Clusters[i].DeepCopy()
evictionTask := GracefulEvictionTask{
FromCluster: evictingCluster.Name,
Reason: reason,
Message: message,
Producer: producer,
}
if evictingCluster.Replicas > 0 {
evictionTask.Replicas = &evictingCluster.Replicas
}
s.GracefulEvictionTasks = append(s.GracefulEvictionTasks, evictionTask)
s.Clusters = append(s.Clusters[:i], s.Clusters[i+1:]...)
}

View File

@ -3,6 +3,8 @@ package v1alpha2
import (
"reflect"
"testing"
"k8s.io/utils/pointer"
)
func TestResourceBindingSpec_TargetContains(t *testing.T) {
@ -129,3 +131,142 @@ func TestResourceBindingSpec_RemoveCluster(t *testing.T) {
})
}
}
func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) {
tests := []struct {
Name string
InputSpec ResourceBindingSpec
EvictEvent GracefulEvictionTask
ExpectSpec ResourceBindingSpec
}{
{
Name: "cluster not exist should do nothing",
InputSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m1"}, {Name: "m2"}, {Name: "m3"}},
},
EvictEvent: GracefulEvictionTask{FromCluster: "non-exist"},
ExpectSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m1"}, {Name: "m2"}, {Name: "m3"}},
},
},
{
Name: "evict cluster from head",
InputSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m1", Replicas: 1}, {Name: "m2", Replicas: 2}, {Name: "m3", Replicas: 3}},
},
EvictEvent: GracefulEvictionTask{
FromCluster: "m1",
Reason: EvictionReasonTaintUntolerated,
Message: "graceful eviction",
Producer: EvictionProducerTaintManager,
},
ExpectSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m2", Replicas: 2}, {Name: "m3", Replicas: 3}},
GracefulEvictionTasks: []GracefulEvictionTask{
{
FromCluster: "m1",
Replicas: pointer.Int32Ptr(1),
Reason: EvictionReasonTaintUntolerated,
Message: "graceful eviction",
Producer: EvictionProducerTaintManager,
},
},
},
},
{
Name: "remove cluster from middle",
InputSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m1", Replicas: 1}, {Name: "m2", Replicas: 2}, {Name: "m3", Replicas: 3}},
},
EvictEvent: GracefulEvictionTask{
FromCluster: "m2",
Reason: EvictionReasonTaintUntolerated,
Message: "graceful eviction",
Producer: EvictionProducerTaintManager,
},
ExpectSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m1", Replicas: 1}, {Name: "m3", Replicas: 3}},
GracefulEvictionTasks: []GracefulEvictionTask{
{
FromCluster: "m2",
Replicas: pointer.Int32Ptr(2),
Reason: EvictionReasonTaintUntolerated,
Message: "graceful eviction",
Producer: EvictionProducerTaintManager,
},
},
},
},
{
Name: "remove cluster from tail",
InputSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m1", Replicas: 1}, {Name: "m2", Replicas: 2}, {Name: "m3", Replicas: 3}},
},
EvictEvent: GracefulEvictionTask{
FromCluster: "m3",
Reason: EvictionReasonTaintUntolerated,
Message: "graceful eviction",
Producer: EvictionProducerTaintManager,
},
ExpectSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m1", Replicas: 1}, {Name: "m2", Replicas: 2}},
GracefulEvictionTasks: []GracefulEvictionTask{
{
FromCluster: "m3",
Replicas: pointer.Int32Ptr(3),
Reason: EvictionReasonTaintUntolerated,
Message: "graceful eviction",
Producer: EvictionProducerTaintManager,
},
},
},
},
{
Name: "eviction task should be appended to non-empty tasks",
InputSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m1", Replicas: 1}, {Name: "m2", Replicas: 2}, {Name: "m3", Replicas: 3}},
GracefulEvictionTasks: []GracefulEvictionTask{{FromCluster: "original-cluster"}},
},
EvictEvent: GracefulEvictionTask{
FromCluster: "m3",
Reason: EvictionReasonTaintUntolerated,
Message: "graceful eviction",
Producer: EvictionProducerTaintManager,
},
ExpectSpec: ResourceBindingSpec{
Clusters: []TargetCluster{{Name: "m1", Replicas: 1}, {Name: "m2", Replicas: 2}},
GracefulEvictionTasks: []GracefulEvictionTask{
{
FromCluster: "original-cluster",
},
{
FromCluster: "m3",
Replicas: pointer.Int32Ptr(3),
Reason: EvictionReasonTaintUntolerated,
Message: "graceful eviction",
Producer: EvictionProducerTaintManager,
},
},
},
},
{
Name: "remove cluster from empty list",
InputSpec: ResourceBindingSpec{Clusters: []TargetCluster{}},
ExpectSpec: ResourceBindingSpec{Clusters: []TargetCluster{}},
},
}
for _, test := range tests {
tc := test
t.Run(tc.Name, func(t *testing.T) {
tc.InputSpec.GracefulEvictCluster(tc.EvictEvent.FromCluster, tc.EvictEvent.Producer, tc.EvictEvent.Reason, tc.EvictEvent.Message)
if !reflect.DeepEqual(tc.InputSpec.Clusters, tc.ExpectSpec.Clusters) {
t.Fatalf("expect clusters: %v, but got: %v", tc.ExpectSpec.Clusters, tc.InputSpec.Clusters)
}
if !reflect.DeepEqual(tc.InputSpec.GracefulEvictionTasks, tc.ExpectSpec.GracefulEvictionTasks) {
t.Fatalf("expect tasks: %v, but got: %v", tc.ExpectSpec.GracefulEvictionTasks, tc.InputSpec.GracefulEvictionTasks)
}
})
}
}

View File

@ -18,6 +18,7 @@ import (
clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
"github.com/karmada-io/karmada/pkg/features"
"github.com/karmada-io/karmada/pkg/util"
"github.com/karmada-io/karmada/pkg/util/helper"
"github.com/karmada-io/karmada/pkg/util/informermanager/keys"
@ -153,7 +154,11 @@ func (tc *NoExecuteTaintManager) syncBindingEviction(key util.QueueKey) error {
// Case 3: Tolerate forever, we do nothing.
if needEviction || tolerationTime == 0 {
// update final result to evict the target cluster
binding.Spec.RemoveCluster(cluster)
if features.FeatureGate.Enabled(features.GracefulEviction) {
binding.Spec.GracefulEvictCluster(cluster, workv1alpha2.EvictionProducerTaintManager, workv1alpha2.EvictionReasonTaintUntolerated, "")
} else {
binding.Spec.RemoveCluster(cluster)
}
if err = tc.Update(context.TODO(), binding); err != nil {
klog.ErrorS(err, "Failed to update binding", "binding", klog.KObj(binding))
return err
@ -198,7 +203,11 @@ func (tc *NoExecuteTaintManager) syncClusterBindingEviction(key util.QueueKey) e
// Case 3: Tolerate forever, we do nothing.
if needEviction || tolerationTime == 0 {
// update final result to evict the target cluster
binding.Spec.RemoveCluster(cluster)
if features.FeatureGate.Enabled(features.GracefulEviction) {
binding.Spec.GracefulEvictCluster(cluster, workv1alpha2.EvictionProducerTaintManager, workv1alpha2.EvictionReasonTaintUntolerated, "")
} else {
binding.Spec.RemoveCluster(cluster)
}
if err = tc.Update(context.TODO(), binding); err != nil {
klog.ErrorS(err, "Failed to update cluster binding", "binding", binding.Name)
return err