Merge pull request #2346 from RainbowMango/pr_add_graceful_evict_helper
Enable graceful eviction in taint manager
This commit is contained in:
commit
67fd394e5e
|
@ -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:]...)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue