Skip to content

Commit 7e7193b

Browse files
Merge remote-tracking branch 'origin/master' into release-1.28
2 parents 4a83749 + 201f807 commit 7e7193b

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

pkg/scheduler/internal/queue/scheduling_queue.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,10 @@ func (p *PriorityQueue) AddUnschedulableIfNotPresent(logger klog.Logger, pInfo *
732732
// In this case, we try to requeue this Pod to activeQ/backoffQ.
733733
queue := p.requeuePodViaQueueingHint(logger, pInfo, schedulingHint, ScheduleAttemptFailure)
734734
logger.V(6).Info("Pod moved to an internal scheduling queue", "pod", klog.KObj(pod), "event", ScheduleAttemptFailure, "queue", queue, "schedulingCycle", podSchedulingCycle)
735+
if queue == activeQ {
736+
// When the Pod is moved to activeQ, need to let p.cond know so that the Pod will be pop()ed out.
737+
p.cond.Broadcast()
738+
}
735739

736740
p.addNominatedPodUnlocked(logger, pInfo.PodInfo, nil)
737741
return nil

test/integration/scheduler/queue_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ import (
4444
"k8s.io/kubernetes/pkg/scheduler"
4545
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
4646
"k8s.io/kubernetes/pkg/scheduler/framework"
47+
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
48+
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
4749
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
4850
st "k8s.io/kubernetes/pkg/scheduler/testing"
4951
testfwk "k8s.io/kubernetes/test/integration/framework"
@@ -439,3 +441,94 @@ func TestCustomResourceEnqueue(t *testing.T) {
439441
t.Errorf("Expected the Pod to be attempted 2 times, but got %v", podInfo.Attempts)
440442
}
441443
}
444+
445+
// TestRequeueByBindFailure verify Pods failed by bind plugin are
446+
// put back to the queue regardless of whether event happens or not.
447+
func TestRequeueByBindFailure(t *testing.T) {
448+
registry := frameworkruntime.Registry{
449+
"firstFailBindPlugin": newFirstFailBindPlugin,
450+
}
451+
cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{
452+
Profiles: []configv1.KubeSchedulerProfile{{
453+
SchedulerName: pointer.String(v1.DefaultSchedulerName),
454+
Plugins: &configv1.Plugins{
455+
MultiPoint: configv1.PluginSet{
456+
Enabled: []configv1.Plugin{
457+
{Name: "firstFailBindPlugin"},
458+
},
459+
Disabled: []configv1.Plugin{
460+
{Name: names.DefaultBinder},
461+
},
462+
},
463+
},
464+
}}})
465+
466+
// Use zero backoff seconds to bypass backoffQ.
467+
testCtx := testutils.InitTestSchedulerWithOptions(
468+
t,
469+
testutils.InitTestAPIServer(t, "core-res-enqueue", nil),
470+
0,
471+
scheduler.WithPodInitialBackoffSeconds(0),
472+
scheduler.WithPodMaxBackoffSeconds(0),
473+
scheduler.WithProfiles(cfg.Profiles...),
474+
scheduler.WithFrameworkOutOfTreeRegistry(registry),
475+
)
476+
testutils.SyncSchedulerInformerFactory(testCtx)
477+
478+
go testCtx.Scheduler.Run(testCtx.Ctx)
479+
480+
cs, ns, ctx := testCtx.ClientSet, testCtx.NS.Name, testCtx.Ctx
481+
node := st.MakeNode().Name("fake-node").Obj()
482+
if _, err := cs.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{}); err != nil {
483+
t.Fatalf("Failed to create Node %q: %v", node.Name, err)
484+
}
485+
// create a pod.
486+
pod := st.MakePod().Namespace(ns).Name("pod-1").Container(imageutils.GetPauseImageName()).Obj()
487+
if _, err := cs.CoreV1().Pods(ns).Create(ctx, pod, metav1.CreateOptions{}); err != nil {
488+
t.Fatalf("Failed to create Pod %q: %v", pod.Name, err)
489+
}
490+
491+
// first binding try should fail.
492+
err := wait.Poll(200*time.Millisecond, wait.ForeverTestTimeout, testutils.PodSchedulingError(cs, ns, "pod-1"))
493+
if err != nil {
494+
t.Fatalf("Expect pod-1 to be rejected by the bind plugin")
495+
}
496+
497+
// The pod should be enqueued to activeQ/backoffQ without any event.
498+
// The pod should be scheduled in the second binding try.
499+
err = wait.Poll(200*time.Millisecond, wait.ForeverTestTimeout, testutils.PodScheduled(cs, ns, "pod-1"))
500+
if err != nil {
501+
t.Fatalf("Expect pod-1 to be scheduled by the bind plugin in the second binding try")
502+
}
503+
}
504+
505+
// firstFailBindPlugin rejects the Pod in the first Bind call.
506+
type firstFailBindPlugin struct {
507+
counter int
508+
defaultBinderPlugin framework.BindPlugin
509+
}
510+
511+
func newFirstFailBindPlugin(_ runtime.Object, handle framework.Handle) (framework.Plugin, error) {
512+
binder, err := defaultbinder.New(nil, handle)
513+
if err != nil {
514+
return nil, err
515+
}
516+
517+
return &firstFailBindPlugin{
518+
defaultBinderPlugin: binder.(framework.BindPlugin),
519+
}, nil
520+
}
521+
522+
func (*firstFailBindPlugin) Name() string {
523+
return "firstFailBindPlugin"
524+
}
525+
526+
func (p *firstFailBindPlugin) Bind(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodename string) *framework.Status {
527+
if p.counter == 0 {
528+
// fail in the first Bind call.
529+
p.counter++
530+
return framework.NewStatus(framework.Error, "firstFailBindPlugin rejects the Pod")
531+
}
532+
533+
return p.defaultBinderPlugin.Bind(ctx, state, pod, nodename)
534+
}

0 commit comments

Comments
 (0)