Skip to content

Commit b276088

Browse files
authored
Merge pull request kubernetes#124287 from sanposhiho/tainttoleration
implement QueueingHint in TaintToleration
2 parents 8bd39b8 + a4bfaae commit b276088

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

pkg/scheduler/framework/plugins/tainttoleration/taint_toleration.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ import (
2323
v1 "k8s.io/api/core/v1"
2424
"k8s.io/apimachinery/pkg/runtime"
2525
v1helper "k8s.io/component-helpers/scheduling/corev1"
26+
"k8s.io/klog/v2"
2627
"k8s.io/kubernetes/pkg/scheduler/framework"
2728
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper"
2829
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
30+
"k8s.io/kubernetes/pkg/scheduler/util"
2931
)
3032

3133
// TaintToleration is a plugin that checks if a pod tolerates a node's taints.
@@ -56,10 +58,35 @@ func (pl *TaintToleration) Name() string {
5658
// failed by this plugin schedulable.
5759
func (pl *TaintToleration) EventsToRegister() []framework.ClusterEventWithHint {
5860
return []framework.ClusterEventWithHint{
59-
{Event: framework.ClusterEvent{Resource: framework.Node, ActionType: framework.Add | framework.Update}},
61+
{Event: framework.ClusterEvent{Resource: framework.Node, ActionType: framework.Add | framework.Update}, QueueingHintFn: pl.isSchedulableAfterNodeChange},
6062
}
6163
}
6264

65+
// isSchedulableAfterNodeChange is invoked for all node events reported by
66+
// an informer. It checks whether that change made a previously unschedulable
67+
// pod schedulable.
68+
func (pl *TaintToleration) isSchedulableAfterNodeChange(logger klog.Logger, pod *v1.Pod, oldObj, newObj interface{}) (framework.QueueingHint, error) {
69+
originalNode, modifiedNode, err := util.As[*v1.Node](oldObj, newObj)
70+
if err != nil {
71+
return framework.Queue, err
72+
}
73+
74+
wasUntolerated := true
75+
if originalNode != nil {
76+
_, wasUntolerated = v1helper.FindMatchingUntoleratedTaint(originalNode.Spec.Taints, pod.Spec.Tolerations, helper.DoNotScheduleTaintsFilterFunc())
77+
}
78+
79+
_, isUntolerated := v1helper.FindMatchingUntoleratedTaint(modifiedNode.Spec.Taints, pod.Spec.Tolerations, helper.DoNotScheduleTaintsFilterFunc())
80+
81+
if wasUntolerated && !isUntolerated {
82+
logger.V(5).Info("node was created or updated, and this may make the Pod rejected by TaintToleration plugin in the previous scheduling cycle schedulable", "pod", klog.KObj(pod), "node", klog.KObj(modifiedNode))
83+
return framework.Queue, nil
84+
}
85+
86+
logger.V(5).Info("node was created or updated, but it doesn't change the TaintToleration plugin's decision", "pod", klog.KObj(pod), "node", klog.KObj(modifiedNode))
87+
return framework.QueueSkip, nil
88+
}
89+
6390
// Filter invoked at the filter extension point.
6491
func (pl *TaintToleration) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
6592
node := nodeInfo.Node()

pkg/scheduler/framework/plugins/tainttoleration/taint_toleration_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,3 +353,68 @@ func TestTaintTolerationFilter(t *testing.T) {
353353
})
354354
}
355355
}
356+
357+
func TestIsSchedulableAfterNodeChange(t *testing.T) {
358+
tests := []struct {
359+
name string
360+
pod *v1.Pod
361+
oldObj interface{}
362+
newObj interface{}
363+
expectedHint framework.QueueingHint
364+
wantErr bool
365+
}{
366+
{
367+
name: "backoff-wrong-new-object",
368+
newObj: "not-a-node",
369+
expectedHint: framework.Queue,
370+
wantErr: true,
371+
},
372+
{
373+
name: "backoff-wrong-old-object",
374+
newObj: nodeWithTaints("nodeA", []v1.Taint{{Key: "dedicated", Value: "user1", Effect: "NoSchedule"}}),
375+
oldObj: "not-a-node",
376+
expectedHint: framework.Queue,
377+
wantErr: true,
378+
},
379+
{
380+
name: "skip-queue-on-untoleratedtaint-node-added",
381+
pod: podWithTolerations("pod1", []v1.Toleration{{Key: "dedicated", Operator: "Equal", Value: "user2", Effect: "NoSchedule"}}),
382+
newObj: nodeWithTaints("nodeA", []v1.Taint{{Key: "dedicated", Value: "user1", Effect: "NoSchedule"}}),
383+
expectedHint: framework.QueueSkip,
384+
},
385+
{
386+
name: "queue-on-toleratedtaint-node-added",
387+
pod: podWithTolerations("pod1", []v1.Toleration{{Key: "dedicated", Operator: "Equal", Value: "user2", Effect: "NoSchedule"}}),
388+
newObj: nodeWithTaints("nodeA", []v1.Taint{{Key: "dedicated", Value: "user2", Effect: "NoSchedule"}}),
389+
expectedHint: framework.Queue,
390+
},
391+
{
392+
name: "skip-unrelated-change",
393+
pod: podWithTolerations("pod1", []v1.Toleration{{Key: "dedicated", Operator: "Equal", Value: "user2", Effect: "NoSchedule"}}),
394+
newObj: nodeWithTaints("nodeA", []v1.Taint{{Key: "dedicated", Value: "user1", Effect: "NoSchedule"}, {Key: "dedicated", Value: "user3", Effect: "NoSchedule"}}),
395+
oldObj: nodeWithTaints("nodeA", []v1.Taint{{Key: "dedicated", Value: "user1", Effect: "NoSchedule"}}),
396+
expectedHint: framework.QueueSkip,
397+
},
398+
{
399+
name: "queue-on-taint-change",
400+
pod: podWithTolerations("pod1", []v1.Toleration{{Key: "dedicated", Operator: "Equal", Value: "user2", Effect: "NoSchedule"}}),
401+
newObj: nodeWithTaints("nodeA", []v1.Taint{{Key: "dedicated", Value: "user2", Effect: "NoSchedule"}}),
402+
oldObj: nodeWithTaints("nodeA", []v1.Taint{{Key: "dedicated", Value: "user1", Effect: "NoSchedule"}}),
403+
expectedHint: framework.Queue,
404+
},
405+
}
406+
407+
for _, test := range tests {
408+
t.Run(test.name, func(t *testing.T) {
409+
logger, _ := ktesting.NewTestContext(t)
410+
pl := &TaintToleration{}
411+
got, err := pl.isSchedulableAfterNodeChange(logger, test.pod, test.oldObj, test.newObj)
412+
if (err != nil) != test.wantErr {
413+
t.Errorf("isSchedulableAfterNodeChange() error = %v, wantErr %v", err, test.wantErr)
414+
}
415+
if got != test.expectedHint {
416+
t.Errorf("isSchedulableAfterNodeChange() = %v, want %v", got, test.expectedHint)
417+
}
418+
})
419+
}
420+
}

0 commit comments

Comments
 (0)