mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-19 09:52:49 +00:00
Feat: unify the status handle when return in bindingCycle (#112103)
Signed-off-by: kerthcet <kerthcet@gmail.com> Signed-off-by: kerthcet <kerthcet@gmail.com>
This commit is contained in:
parent
2b2be7fa6b
commit
096dafe757
@ -250,6 +250,9 @@ func NewStatus(code Code, reasons ...string) *Status {
|
||||
|
||||
// AsStatus wraps an error in a Status.
|
||||
func AsStatus(err error) *Status {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Status{
|
||||
code: Error,
|
||||
reasons: []string{err.Error()},
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
"math"
|
||||
"sync/atomic"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework"
|
||||
)
|
||||
|
@ -1003,8 +1003,13 @@ func (f *frameworkImpl) RunPreBindPlugins(ctx context.Context, state *framework.
|
||||
for _, pl := range f.preBindPlugins {
|
||||
status = f.runPreBindPlugin(ctx, pl, state, pod, nodeName)
|
||||
if !status.IsSuccess() {
|
||||
if status.IsUnschedulable() {
|
||||
klog.V(4).InfoS("Pod rejected by PreBind plugin", "pod", klog.KObj(pod), "node", nodeName, "plugin", pl.Name(), "status", status.Message())
|
||||
status.SetFailedPlugin(pl.Name())
|
||||
return status
|
||||
}
|
||||
err := status.AsError()
|
||||
klog.ErrorS(err, "Failed running PreBind plugin", "plugin", pl.Name(), "pod", klog.KObj(pod))
|
||||
klog.ErrorS(err, "Failed running PreBind plugin", "plugin", pl.Name(), "pod", klog.KObj(pod), "node", nodeName)
|
||||
return framework.AsStatus(fmt.Errorf("running PreBind plugin %q: %w", pl.Name(), err))
|
||||
}
|
||||
}
|
||||
@ -1030,15 +1035,20 @@ func (f *frameworkImpl) RunBindPlugins(ctx context.Context, state *framework.Cyc
|
||||
if len(f.bindPlugins) == 0 {
|
||||
return framework.NewStatus(framework.Skip, "")
|
||||
}
|
||||
for _, bp := range f.bindPlugins {
|
||||
status = f.runBindPlugin(ctx, bp, state, pod, nodeName)
|
||||
for _, pl := range f.bindPlugins {
|
||||
status = f.runBindPlugin(ctx, pl, state, pod, nodeName)
|
||||
if status.IsSkip() {
|
||||
continue
|
||||
}
|
||||
if !status.IsSuccess() {
|
||||
if status.IsUnschedulable() {
|
||||
klog.V(4).InfoS("Pod rejected by Bind plugin", "pod", klog.KObj(pod), "node", nodeName, "plugin", pl.Name(), "status", status.Message())
|
||||
status.SetFailedPlugin(pl.Name())
|
||||
return status
|
||||
}
|
||||
err := status.AsError()
|
||||
klog.ErrorS(err, "Failed running Bind plugin", "plugin", bp.Name(), "pod", klog.KObj(pod))
|
||||
return framework.AsStatus(fmt.Errorf("running Bind plugin %q: %w", bp.Name(), err))
|
||||
klog.ErrorS(err, "Failed running Bind plugin", "plugin", pl.Name(), "pod", klog.KObj(pod), "node", nodeName)
|
||||
return framework.AsStatus(fmt.Errorf("running Bind plugin %q: %w", pl.Name(), err))
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
@ -54,6 +54,9 @@ const (
|
||||
|
||||
testProfileName = "test-profile"
|
||||
nodeName = "testNode"
|
||||
|
||||
injectReason = "injected status"
|
||||
injectFilterReason = "injected filter status"
|
||||
)
|
||||
|
||||
// TestScoreWithNormalizePlugin implements ScoreWithNormalizePlugin interface.
|
||||
@ -121,7 +124,7 @@ func (pl *TestScorePlugin) Name() string {
|
||||
}
|
||||
|
||||
func (pl *TestScorePlugin) PreScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status {
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreScoreStatus), "injected status")
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreScoreStatus), injectReason)
|
||||
}
|
||||
|
||||
func (pl *TestScorePlugin) Score(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) (int64, *framework.Status) {
|
||||
@ -150,10 +153,10 @@ type TestPlugin struct {
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) AddPod(ctx context.Context, state *framework.CycleState, podToSchedule *v1.Pod, podInfoToAdd *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status {
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreFilterAddPodStatus), "injected status")
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreFilterAddPodStatus), injectReason)
|
||||
}
|
||||
func (pl *TestPlugin) RemovePod(ctx context.Context, state *framework.CycleState, podToSchedule *v1.Pod, podInfoToRemove *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status {
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreFilterRemovePodStatus), "injected status")
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreFilterRemovePodStatus), injectReason)
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) Name() string {
|
||||
@ -165,7 +168,7 @@ func (pl *TestPlugin) Less(*framework.QueuedPodInfo, *framework.QueuedPodInfo) b
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) Score(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) (int64, *framework.Status) {
|
||||
return 0, framework.NewStatus(framework.Code(pl.inj.ScoreStatus), "injected status")
|
||||
return 0, framework.NewStatus(framework.Code(pl.inj.ScoreStatus), injectReason)
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) ScoreExtensions() framework.ScoreExtensions {
|
||||
@ -173,7 +176,7 @@ func (pl *TestPlugin) ScoreExtensions() framework.ScoreExtensions {
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) PreFilter(ctx context.Context, state *framework.CycleState, p *v1.Pod) (*framework.PreFilterResult, *framework.Status) {
|
||||
return nil, framework.NewStatus(framework.Code(pl.inj.PreFilterStatus), "injected status")
|
||||
return nil, framework.NewStatus(framework.Code(pl.inj.PreFilterStatus), injectReason)
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) PreFilterExtensions() framework.PreFilterExtensions {
|
||||
@ -181,37 +184,37 @@ func (pl *TestPlugin) PreFilterExtensions() framework.PreFilterExtensions {
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
||||
return framework.NewStatus(framework.Code(pl.inj.FilterStatus), "injected filter status")
|
||||
return framework.NewStatus(framework.Code(pl.inj.FilterStatus), injectFilterReason)
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) PostFilter(_ context.Context, _ *framework.CycleState, _ *v1.Pod, _ framework.NodeToStatusMap) (*framework.PostFilterResult, *framework.Status) {
|
||||
return nil, framework.NewStatus(framework.Code(pl.inj.PostFilterStatus), "injected status")
|
||||
return nil, framework.NewStatus(framework.Code(pl.inj.PostFilterStatus), injectReason)
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) PreScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status {
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreScoreStatus), "injected status")
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreScoreStatus), injectReason)
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) Reserve(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) *framework.Status {
|
||||
return framework.NewStatus(framework.Code(pl.inj.ReserveStatus), "injected status")
|
||||
return framework.NewStatus(framework.Code(pl.inj.ReserveStatus), injectReason)
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) Unreserve(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) {
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) PreBind(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) *framework.Status {
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreBindStatus), "injected status")
|
||||
return framework.NewStatus(framework.Code(pl.inj.PreBindStatus), injectReason)
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) PostBind(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) {
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) Permit(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) (*framework.Status, time.Duration) {
|
||||
return framework.NewStatus(framework.Code(pl.inj.PermitStatus), "injected status"), time.Duration(0)
|
||||
return framework.NewStatus(framework.Code(pl.inj.PermitStatus), injectReason), time.Duration(0)
|
||||
}
|
||||
|
||||
func (pl *TestPlugin) Bind(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) *framework.Status {
|
||||
return framework.NewStatus(framework.Code(pl.inj.BindStatus), "injected status")
|
||||
return framework.NewStatus(framework.Code(pl.inj.BindStatus), injectReason)
|
||||
}
|
||||
|
||||
// TestPreFilterPlugin only implements PreFilterPlugin interface.
|
||||
@ -374,8 +377,8 @@ var nodes = []*v1.Node{
|
||||
}
|
||||
|
||||
var (
|
||||
errInjectedStatus = errors.New("injected status")
|
||||
errInjectedFilterStatus = errors.New("injected filter status")
|
||||
errInjectedStatus = errors.New(injectReason)
|
||||
errInjectedFilterStatus = errors.New(injectFilterReason)
|
||||
)
|
||||
|
||||
func newFrameworkWithQueueSortAndBind(r Registry, profile config.KubeSchedulerProfile, stopCh <-chan struct{}, opts ...Option) (framework.Framework, error) {
|
||||
@ -1307,9 +1310,9 @@ func TestFilterPlugins(t *testing.T) {
|
||||
inj: injectedResult{FilterStatus: int(framework.Unschedulable)},
|
||||
},
|
||||
},
|
||||
wantStatus: framework.NewStatus(framework.Unschedulable, "injected filter status").WithFailedPlugin("TestPlugin"),
|
||||
wantStatus: framework.NewStatus(framework.Unschedulable, injectFilterReason).WithFailedPlugin("TestPlugin"),
|
||||
wantStatusMap: framework.PluginToStatus{
|
||||
"TestPlugin": framework.NewStatus(framework.Unschedulable, "injected filter status").WithFailedPlugin("TestPlugin"),
|
||||
"TestPlugin": framework.NewStatus(framework.Unschedulable, injectFilterReason).WithFailedPlugin("TestPlugin"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1321,9 +1324,9 @@ func TestFilterPlugins(t *testing.T) {
|
||||
FilterStatus: int(framework.UnschedulableAndUnresolvable)},
|
||||
},
|
||||
},
|
||||
wantStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, "injected filter status").WithFailedPlugin("TestPlugin"),
|
||||
wantStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, injectFilterReason).WithFailedPlugin("TestPlugin"),
|
||||
wantStatusMap: framework.PluginToStatus{
|
||||
"TestPlugin": framework.NewStatus(framework.UnschedulableAndUnresolvable, "injected filter status").WithFailedPlugin("TestPlugin"),
|
||||
"TestPlugin": framework.NewStatus(framework.UnschedulableAndUnresolvable, injectFilterReason).WithFailedPlugin("TestPlugin"),
|
||||
},
|
||||
},
|
||||
// following tests cover multiple-plugins scenarios
|
||||
@ -1409,9 +1412,9 @@ func TestFilterPlugins(t *testing.T) {
|
||||
inj: injectedResult{FilterStatus: int(framework.Unschedulable)},
|
||||
},
|
||||
},
|
||||
wantStatus: framework.NewStatus(framework.Unschedulable, "injected filter status").WithFailedPlugin("TestPlugin2"),
|
||||
wantStatus: framework.NewStatus(framework.Unschedulable, injectFilterReason).WithFailedPlugin("TestPlugin2"),
|
||||
wantStatusMap: framework.PluginToStatus{
|
||||
"TestPlugin2": framework.NewStatus(framework.Unschedulable, "injected filter status").WithFailedPlugin("TestPlugin2"),
|
||||
"TestPlugin2": framework.NewStatus(framework.Unschedulable, injectFilterReason).WithFailedPlugin("TestPlugin2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -1467,7 +1470,7 @@ func TestPostFilterPlugins(t *testing.T) {
|
||||
inj: injectedResult{PostFilterStatus: int(framework.Success)},
|
||||
},
|
||||
},
|
||||
wantStatus: framework.NewStatus(framework.Success, "injected status"),
|
||||
wantStatus: framework.NewStatus(framework.Success, injectReason),
|
||||
},
|
||||
{
|
||||
name: "plugin1 failed to make a Pod schedulable, followed by plugin2 which makes the Pod schedulable",
|
||||
@ -1481,7 +1484,7 @@ func TestPostFilterPlugins(t *testing.T) {
|
||||
inj: injectedResult{PostFilterStatus: int(framework.Success)},
|
||||
},
|
||||
},
|
||||
wantStatus: framework.NewStatus(framework.Success, "injected status"),
|
||||
wantStatus: framework.NewStatus(framework.Success, injectReason),
|
||||
},
|
||||
{
|
||||
name: "plugin1 makes a Pod schedulable, followed by plugin2 which cannot make the Pod schedulable",
|
||||
@ -1495,7 +1498,7 @@ func TestPostFilterPlugins(t *testing.T) {
|
||||
inj: injectedResult{PostFilterStatus: int(framework.Unschedulable)},
|
||||
},
|
||||
},
|
||||
wantStatus: framework.NewStatus(framework.Success, "injected status"),
|
||||
wantStatus: framework.NewStatus(framework.Success, injectReason),
|
||||
},
|
||||
}
|
||||
|
||||
@ -1712,7 +1715,7 @@ func TestPreBindPlugins(t *testing.T) {
|
||||
inj: injectedResult{PreBindStatus: int(framework.Unschedulable)},
|
||||
},
|
||||
},
|
||||
wantStatus: framework.AsStatus(fmt.Errorf(`running PreBind plugin "TestPlugin": %w`, errInjectedStatus)),
|
||||
wantStatus: framework.NewStatus(framework.Unschedulable, injectReason).WithFailedPlugin("TestPlugin"),
|
||||
},
|
||||
{
|
||||
name: "ErrorPreBindPlugin",
|
||||
@ -1732,7 +1735,7 @@ func TestPreBindPlugins(t *testing.T) {
|
||||
inj: injectedResult{PreBindStatus: int(framework.UnschedulableAndUnresolvable)},
|
||||
},
|
||||
},
|
||||
wantStatus: framework.AsStatus(fmt.Errorf(`running PreBind plugin "TestPlugin": %w`, errInjectedStatus)),
|
||||
wantStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, injectReason).WithFailedPlugin("TestPlugin"),
|
||||
},
|
||||
{
|
||||
name: "SuccessErrorPreBindPlugins",
|
||||
@ -1802,7 +1805,7 @@ func TestPreBindPlugins(t *testing.T) {
|
||||
inj: injectedResult{PreBindStatus: int(framework.Success)},
|
||||
},
|
||||
},
|
||||
wantStatus: framework.AsStatus(fmt.Errorf(`running PreBind plugin "TestPlugin": %w`, errInjectedStatus)),
|
||||
wantStatus: framework.NewStatus(framework.Unschedulable, injectReason).WithFailedPlugin("TestPlugin"),
|
||||
},
|
||||
}
|
||||
|
||||
@ -2028,7 +2031,7 @@ func TestPermitPlugins(t *testing.T) {
|
||||
inj: injectedResult{PermitStatus: int(framework.Unschedulable)},
|
||||
},
|
||||
},
|
||||
want: framework.NewStatus(framework.Unschedulable, "injected status").WithFailedPlugin("TestPlugin"),
|
||||
want: framework.NewStatus(framework.Unschedulable, injectReason).WithFailedPlugin("TestPlugin"),
|
||||
},
|
||||
{
|
||||
name: "ErrorPermitPlugin",
|
||||
@ -2048,7 +2051,7 @@ func TestPermitPlugins(t *testing.T) {
|
||||
inj: injectedResult{PermitStatus: int(framework.UnschedulableAndUnresolvable)},
|
||||
},
|
||||
},
|
||||
want: framework.NewStatus(framework.UnschedulableAndUnresolvable, "injected status").WithFailedPlugin("TestPlugin"),
|
||||
want: framework.NewStatus(framework.UnschedulableAndUnresolvable, injectReason).WithFailedPlugin("TestPlugin"),
|
||||
},
|
||||
{
|
||||
name: "WaitPermitPlugin",
|
||||
@ -2341,7 +2344,7 @@ func TestRunBindPlugins(t *testing.T) {
|
||||
{
|
||||
name: "invalid status",
|
||||
injects: []framework.Code{framework.Unschedulable},
|
||||
wantStatus: framework.Error,
|
||||
wantStatus: framework.Unschedulable,
|
||||
},
|
||||
{
|
||||
name: "simple error",
|
||||
@ -2356,7 +2359,7 @@ func TestRunBindPlugins(t *testing.T) {
|
||||
{
|
||||
name: "invalid status, returns error",
|
||||
injects: []framework.Code{framework.Skip, framework.UnschedulableAndUnresolvable},
|
||||
wantStatus: framework.Error,
|
||||
wantStatus: framework.UnschedulableAndUnresolvable,
|
||||
},
|
||||
{
|
||||
name: "error after success status, returns success",
|
||||
|
@ -239,9 +239,13 @@ func (sched *Scheduler) bindingCycle(ctx context.Context, state *framework.Cycle
|
||||
// Avoid moving the assumed Pod itself as it's always Unschedulable.
|
||||
// It's intentional to "defer" this operation; otherwise MoveAllToActiveOrBackoffQueue() would
|
||||
// update `q.moveRequest` and thus move the assumed pod to backoffQ anyways.
|
||||
defer sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, func(pod *v1.Pod) bool {
|
||||
return assumedPod.UID != pod.UID
|
||||
})
|
||||
if waitOnPermitStatus.IsUnschedulable() {
|
||||
defer sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, func(pod *v1.Pod) bool {
|
||||
return assumedPod.UID != pod.UID
|
||||
})
|
||||
} else {
|
||||
sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, nil)
|
||||
}
|
||||
}
|
||||
sched.FailureHandler(ctx, fwk, assumedPodInfo, waitOnPermitStatus.AsError(), reason, clearNominatedNode)
|
||||
return
|
||||
@ -250,7 +254,15 @@ func (sched *Scheduler) bindingCycle(ctx context.Context, state *framework.Cycle
|
||||
// Run "prebind" plugins.
|
||||
preBindStatus := fwk.RunPreBindPlugins(ctx, state, assumedPod, scheduleResult.SuggestedHost)
|
||||
if !preBindStatus.IsSuccess() {
|
||||
metrics.PodScheduleError(fwk.ProfileName(), metrics.SinceInSeconds(start))
|
||||
var reason string
|
||||
if preBindStatus.IsUnschedulable() {
|
||||
metrics.PodUnschedulable(fwk.ProfileName(), metrics.SinceInSeconds(start))
|
||||
reason = v1.PodReasonUnschedulable
|
||||
} else {
|
||||
metrics.PodScheduleError(fwk.ProfileName(), metrics.SinceInSeconds(start))
|
||||
reason = v1.PodReasonSchedulerError
|
||||
}
|
||||
|
||||
// trigger un-reserve plugins to clean up state associated with the reserved Pod
|
||||
fwk.RunReservePluginsUnreserve(ctx, state, assumedPod, scheduleResult.SuggestedHost)
|
||||
if forgetErr := sched.Cache.ForgetPod(assumedPod); forgetErr != nil {
|
||||
@ -259,15 +271,29 @@ func (sched *Scheduler) bindingCycle(ctx context.Context, state *framework.Cycle
|
||||
// "Forget"ing an assumed Pod in binding cycle should be treated as a PodDelete event,
|
||||
// as the assumed Pod had occupied a certain amount of resources in scheduler cache.
|
||||
// TODO(#103853): de-duplicate the logic.
|
||||
sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, nil)
|
||||
if preBindStatus.IsUnschedulable() {
|
||||
defer sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, func(pod *v1.Pod) bool {
|
||||
return assumedPod.UID != pod.UID
|
||||
})
|
||||
} else {
|
||||
sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, nil)
|
||||
}
|
||||
}
|
||||
sched.FailureHandler(ctx, fwk, assumedPodInfo, preBindStatus.AsError(), v1.PodReasonSchedulerError, clearNominatedNode)
|
||||
sched.FailureHandler(ctx, fwk, assumedPodInfo, preBindStatus.AsError(), reason, clearNominatedNode)
|
||||
return
|
||||
}
|
||||
|
||||
err := sched.bind(ctx, fwk, assumedPod, scheduleResult.SuggestedHost, state)
|
||||
if err != nil {
|
||||
metrics.PodScheduleError(fwk.ProfileName(), metrics.SinceInSeconds(start))
|
||||
bindStatus := sched.bind(ctx, fwk, assumedPod, scheduleResult.SuggestedHost, state)
|
||||
if !bindStatus.IsSuccess() {
|
||||
var reason string
|
||||
if bindStatus.IsUnschedulable() {
|
||||
metrics.PodUnschedulable(fwk.ProfileName(), metrics.SinceInSeconds(start))
|
||||
reason = v1.PodReasonUnschedulable
|
||||
} else {
|
||||
metrics.PodScheduleError(fwk.ProfileName(), metrics.SinceInSeconds(start))
|
||||
reason = v1.PodReasonSchedulerError
|
||||
}
|
||||
|
||||
// trigger un-reserve plugins to clean up state associated with the reserved Pod
|
||||
fwk.RunReservePluginsUnreserve(ctx, state, assumedPod, scheduleResult.SuggestedHost)
|
||||
if err := sched.Cache.ForgetPod(assumedPod); err != nil {
|
||||
@ -276,9 +302,15 @@ func (sched *Scheduler) bindingCycle(ctx context.Context, state *framework.Cycle
|
||||
// "Forget"ing an assumed Pod in binding cycle should be treated as a PodDelete event,
|
||||
// as the assumed Pod had occupied a certain amount of resources in scheduler cache.
|
||||
// TODO(#103853): de-duplicate the logic.
|
||||
sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, nil)
|
||||
if bindStatus.IsUnschedulable() {
|
||||
defer sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, func(pod *v1.Pod) bool {
|
||||
return assumedPod.UID != pod.UID
|
||||
})
|
||||
} else {
|
||||
sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, nil)
|
||||
}
|
||||
}
|
||||
sched.FailureHandler(ctx, fwk, assumedPodInfo, fmt.Errorf("binding rejected: %w", err), v1.PodReasonSchedulerError, clearNominatedNode)
|
||||
sched.FailureHandler(ctx, fwk, assumedPodInfo, fmt.Errorf("binding rejected: %w", bindStatus.AsError()), reason, clearNominatedNode)
|
||||
return
|
||||
}
|
||||
// Calculating nodeResourceString can be heavy. Avoid it if klog verbosity is below 2.
|
||||
@ -773,23 +805,16 @@ func (sched *Scheduler) assume(assumed *v1.Pod, host string) error {
|
||||
// bind binds a pod to a given node defined in a binding object.
|
||||
// The precedence for binding is: (1) extenders and (2) framework plugins.
|
||||
// We expect this to run asynchronously, so we handle binding metrics internally.
|
||||
func (sched *Scheduler) bind(ctx context.Context, fwk framework.Framework, assumed *v1.Pod, targetNode string, state *framework.CycleState) (err error) {
|
||||
func (sched *Scheduler) bind(ctx context.Context, fwk framework.Framework, assumed *v1.Pod, targetNode string, state *framework.CycleState) (status *framework.Status) {
|
||||
defer func() {
|
||||
sched.finishBinding(fwk, assumed, targetNode, err)
|
||||
sched.finishBinding(fwk, assumed, targetNode, status)
|
||||
}()
|
||||
|
||||
bound, err := sched.extendersBinding(assumed, targetNode)
|
||||
if bound {
|
||||
return err
|
||||
return framework.AsStatus(err)
|
||||
}
|
||||
bindStatus := fwk.RunBindPlugins(ctx, state, assumed, targetNode)
|
||||
if bindStatus.IsSuccess() {
|
||||
return nil
|
||||
}
|
||||
if bindStatus.Code() == framework.Error {
|
||||
return bindStatus.AsError()
|
||||
}
|
||||
return fmt.Errorf("bind status: %s, %v", bindStatus.Code().String(), bindStatus.Message())
|
||||
return fwk.RunBindPlugins(ctx, state, assumed, targetNode)
|
||||
}
|
||||
|
||||
// TODO(#87159): Move this to a Plugin.
|
||||
@ -806,11 +831,11 @@ func (sched *Scheduler) extendersBinding(pod *v1.Pod, node string) (bool, error)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (sched *Scheduler) finishBinding(fwk framework.Framework, assumed *v1.Pod, targetNode string, err error) {
|
||||
func (sched *Scheduler) finishBinding(fwk framework.Framework, assumed *v1.Pod, targetNode string, status *framework.Status) {
|
||||
if finErr := sched.Cache.FinishBinding(assumed); finErr != nil {
|
||||
klog.ErrorS(finErr, "Scheduler cache FinishBinding failed")
|
||||
}
|
||||
if err != nil {
|
||||
if !status.IsSuccess() {
|
||||
klog.V(1).InfoS("Failed to bind pod", "pod", klog.KObj(assumed))
|
||||
return
|
||||
}
|
||||
|
@ -1061,9 +1061,9 @@ func TestSchedulerBinding(t *testing.T) {
|
||||
nodeInfoSnapshot: nil,
|
||||
percentageOfNodesToScore: 0,
|
||||
}
|
||||
err = sched.bind(ctx, fwk, pod, "node", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
status := sched.bind(ctx, fwk, pod, "node", nil)
|
||||
if !status.IsSuccess() {
|
||||
t.Error(status.AsError())
|
||||
}
|
||||
|
||||
// Checking default binding.
|
||||
|
@ -988,12 +988,6 @@ func TestPrebindPlugin(t *testing.T) {
|
||||
reject: false,
|
||||
succeedOnRetry: true,
|
||||
},
|
||||
{
|
||||
name: "reject on 1st try but succeed on retry",
|
||||
fail: false,
|
||||
reject: true,
|
||||
succeedOnRetry: true,
|
||||
},
|
||||
{
|
||||
name: "failure on preBind moves unschedulable pods",
|
||||
fail: true,
|
||||
@ -1022,7 +1016,7 @@ func TestPrebindPlugin(t *testing.T) {
|
||||
t.Errorf("Error while creating a test pod: %v", err)
|
||||
}
|
||||
|
||||
if test.fail || test.reject {
|
||||
if test.fail {
|
||||
if test.succeedOnRetry {
|
||||
if err = testutils.WaitForPodToScheduleWithTimeout(testCtx.ClientSet, pod, 10*time.Second); err != nil {
|
||||
t.Errorf("Expected the pod to be schedulable on retry, but got an error: %v", err)
|
||||
@ -1030,6 +1024,10 @@ func TestPrebindPlugin(t *testing.T) {
|
||||
} else if err = wait.Poll(10*time.Millisecond, 30*time.Second, podSchedulingError(testCtx.ClientSet, pod.Namespace, pod.Name)); err != nil {
|
||||
t.Errorf("Expected a scheduling error, but didn't get it. error: %v", err)
|
||||
}
|
||||
} else if test.reject {
|
||||
if err = testutils.WaitForPodUnschedulable(testCtx.ClientSet, pod); err != nil {
|
||||
t.Errorf("Expected the pod to be unschedulable")
|
||||
}
|
||||
} else if err = testutils.WaitForPodToSchedule(testCtx.ClientSet, pod); err != nil {
|
||||
t.Errorf("Expected the pod to be scheduled. error: %v", err)
|
||||
}
|
||||
@ -1212,27 +1210,27 @@ func TestUnReservePermitPlugins(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
plugin *PermitPlugin
|
||||
fail bool
|
||||
reject bool
|
||||
}{
|
||||
{
|
||||
name: "All Reserve plugins passed, but a Permit plugin was rejected",
|
||||
fail: true,
|
||||
name: "All Reserve plugins passed, but a Permit plugin was rejected",
|
||||
reject: true,
|
||||
plugin: &PermitPlugin{
|
||||
name: "rejectedPermitPlugin",
|
||||
rejectPermit: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "All Reserve plugins passed, but a Permit plugin timeout in waiting",
|
||||
fail: true,
|
||||
name: "All Reserve plugins passed, but a Permit plugin timeout in waiting",
|
||||
reject: true,
|
||||
plugin: &PermitPlugin{
|
||||
name: "timeoutPermitPlugin",
|
||||
timeoutPermit: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "The Permit plugin succeed",
|
||||
fail: false,
|
||||
name: "The Permit plugin succeed",
|
||||
reject: false,
|
||||
plugin: &PermitPlugin{
|
||||
name: "succeedPermitPlugin",
|
||||
},
|
||||
@ -1264,7 +1262,7 @@ func TestUnReservePermitPlugins(t *testing.T) {
|
||||
t.Errorf("Error while creating a test pod: %v", err)
|
||||
}
|
||||
|
||||
if test.fail {
|
||||
if test.reject {
|
||||
if err = waitForPodUnschedulable(testCtx.ClientSet, pod); err != nil {
|
||||
t.Errorf("Didn't expect the pod to be scheduled. error: %v", err)
|
||||
}
|
||||
@ -1296,22 +1294,22 @@ func TestUnReservePermitPlugins(t *testing.T) {
|
||||
// TestUnReservePreBindPlugins tests unreserve of Prebind plugins.
|
||||
func TestUnReservePreBindPlugins(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
plugin *PreBindPlugin
|
||||
fail bool
|
||||
name string
|
||||
plugin *PreBindPlugin
|
||||
wantReject bool
|
||||
}{
|
||||
{
|
||||
name: "All Reserve plugins passed, but a PreBind plugin failed",
|
||||
fail: true,
|
||||
name: "All Reserve plugins passed, but a PreBind plugin failed",
|
||||
wantReject: true,
|
||||
plugin: &PreBindPlugin{
|
||||
podUIDs: make(map[types.UID]struct{}),
|
||||
rejectPreBind: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "All Reserve plugins passed, and PreBind plugin succeed",
|
||||
fail: false,
|
||||
plugin: &PreBindPlugin{podUIDs: make(map[types.UID]struct{})},
|
||||
name: "All Reserve plugins passed, and PreBind plugin succeed",
|
||||
wantReject: false,
|
||||
plugin: &PreBindPlugin{podUIDs: make(map[types.UID]struct{})},
|
||||
},
|
||||
}
|
||||
|
||||
@ -1340,8 +1338,8 @@ func TestUnReservePreBindPlugins(t *testing.T) {
|
||||
t.Errorf("Error while creating a test pod: %v", err)
|
||||
}
|
||||
|
||||
if test.fail {
|
||||
if err = wait.Poll(10*time.Millisecond, 30*time.Second, podSchedulingError(testCtx.ClientSet, pod.Namespace, pod.Name)); err != nil {
|
||||
if test.wantReject {
|
||||
if err = waitForPodUnschedulable(testCtx.ClientSet, pod); err != nil {
|
||||
t.Errorf("Expected a reasons other than Unschedulable, but got: %v", err)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user