run all PreFilter when the preemption will happen later in the same scheduling cycle

This commit is contained in:
Kensei Nakada 2023-08-06 01:39:18 +00:00
parent 3be9a8cc73
commit 5ab2317947
2 changed files with 83 additions and 18 deletions

View File

@ -670,6 +670,7 @@ func (f *frameworkImpl) RunPreFilterPlugins(ctx context.Context, state *framewor
if verboseLogs {
logger = klog.LoggerWithName(logger, "PreFilter")
}
var returnStatus *framework.Status
for _, pl := range f.preFilterPlugins {
ctx := ctx
if verboseLogs {
@ -684,7 +685,16 @@ func (f *frameworkImpl) RunPreFilterPlugins(ctx context.Context, state *framewor
if !s.IsSuccess() {
s.SetPlugin(pl.Name())
if s.IsRejected() {
return nil, s
if s.Code() == framework.UnschedulableAndUnresolvable {
// In this case, the preemption shouldn't happen in this scheduling cycle.
// So, no need to execute all PreFilter.
return nil, s
}
// In this case, the preemption should happen later in this scheduling cycle.
// So we need to execute all PreFilter.
// https://github.com/kubernetes/kubernetes/issues/119770
returnStatus = s
continue
}
return nil, framework.AsStatus(fmt.Errorf("running PreFilter plugin %q: %w", pl.Name(), s.AsError())).WithPlugin(pl.Name())
}
@ -697,10 +707,14 @@ func (f *frameworkImpl) RunPreFilterPlugins(ctx context.Context, state *framewor
if len(pluginsWithNodes) == 1 {
msg = fmt.Sprintf("node(s) didn't satisfy plugin %v", pluginsWithNodes[0])
}
return nil, framework.NewStatus(framework.Unschedulable, msg)
// In this case, the preemption should happen later in this scheduling cycle.
// So we need to execute all PreFilter.
// https://github.com/kubernetes/kubernetes/issues/119770
returnStatus = framework.NewStatus(framework.Unschedulable, msg)
continue
}
}
return result, nil
return result, returnStatus
}
func (f *frameworkImpl) runPreFilterPlugin(ctx context.Context, pl framework.PreFilterPlugin, state *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) {

View File

@ -197,7 +197,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), injectReason)
return pl.inj.PreFilterResult, framework.NewStatus(framework.Code(pl.inj.PreFilterStatus), injectReason)
}
func (pl *TestPlugin) PreFilterExtensions() framework.PreFilterExtensions {
@ -1622,6 +1622,56 @@ func TestRunPreFilterPlugins(t *testing.T) {
wantSkippedPlugins: sets.New("skip1", "skip2"),
wantStatusCode: framework.Success,
},
{
name: "one PreFilter plugin returned Unschedulable, but another PreFilter plugin should be executed",
plugins: []*TestPlugin{
{
name: "unschedulable",
inj: injectedResult{PreFilterStatus: int(framework.Unschedulable)},
},
{
// to make sure this plugin is executed, this plugin return Skip and we confirm it via wantSkippedPlugins.
name: "skip",
inj: injectedResult{PreFilterStatus: int(framework.Skip)},
},
},
wantPreFilterResult: nil,
wantSkippedPlugins: sets.New("skip"),
wantStatusCode: framework.Unschedulable,
},
{
name: "one PreFilter plugin returned UnschedulableAndUnresolvable, and all other plugins aren't executed",
plugins: []*TestPlugin{
{
name: "unresolvable",
inj: injectedResult{PreFilterStatus: int(framework.UnschedulableAndUnresolvable)},
},
{
// to make sure this plugin is not executed, this plugin return Skip and we confirm it via wantSkippedPlugins.
name: "skip",
inj: injectedResult{PreFilterStatus: int(framework.Skip)},
},
},
wantPreFilterResult: nil,
wantStatusCode: framework.UnschedulableAndUnresolvable,
},
{
name: "all nodes are filtered out by prefilter result, but all other plugins are executed",
plugins: []*TestPlugin{
{
name: "reject-all-nodes",
inj: injectedResult{PreFilterResult: &framework.PreFilterResult{NodeNames: sets.New[string]()}},
},
{
// to make sure this plugin is not executed, this plugin return Skip and we confirm it via wantSkippedPlugins.
name: "skip",
inj: injectedResult{PreFilterStatus: int(framework.Skip)},
},
},
wantPreFilterResult: &framework.PreFilterResult{NodeNames: sets.New[string]()},
wantSkippedPlugins: sets.New("skip"),
wantStatusCode: framework.Unschedulable,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -3224,20 +3274,21 @@ func buildScoreConfigWithWeights(weights map[string]int32, ps ...string) *config
}
type injectedResult struct {
ScoreRes int64 `json:"scoreRes,omitempty"`
NormalizeRes int64 `json:"normalizeRes,omitempty"`
ScoreStatus int `json:"scoreStatus,omitempty"`
NormalizeStatus int `json:"normalizeStatus,omitempty"`
PreFilterStatus int `json:"preFilterStatus,omitempty"`
PreFilterAddPodStatus int `json:"preFilterAddPodStatus,omitempty"`
PreFilterRemovePodStatus int `json:"preFilterRemovePodStatus,omitempty"`
FilterStatus int `json:"filterStatus,omitempty"`
PostFilterStatus int `json:"postFilterStatus,omitempty"`
PreScoreStatus int `json:"preScoreStatus,omitempty"`
ReserveStatus int `json:"reserveStatus,omitempty"`
PreBindStatus int `json:"preBindStatus,omitempty"`
BindStatus int `json:"bindStatus,omitempty"`
PermitStatus int `json:"permitStatus,omitempty"`
ScoreRes int64 `json:"scoreRes,omitempty"`
NormalizeRes int64 `json:"normalizeRes,omitempty"`
ScoreStatus int `json:"scoreStatus,omitempty"`
NormalizeStatus int `json:"normalizeStatus,omitempty"`
PreFilterResult *framework.PreFilterResult `json:"preFilterResult,omitempty"`
PreFilterStatus int `json:"preFilterStatus,omitempty"`
PreFilterAddPodStatus int `json:"preFilterAddPodStatus,omitempty"`
PreFilterRemovePodStatus int `json:"preFilterRemovePodStatus,omitempty"`
FilterStatus int `json:"filterStatus,omitempty"`
PostFilterStatus int `json:"postFilterStatus,omitempty"`
PreScoreStatus int `json:"preScoreStatus,omitempty"`
ReserveStatus int `json:"reserveStatus,omitempty"`
PreBindStatus int `json:"preBindStatus,omitempty"`
BindStatus int `json:"bindStatus,omitempty"`
PermitStatus int `json:"permitStatus,omitempty"`
}
func setScoreRes(inj injectedResult) (int64, *framework.Status) {