New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature(scheduler): won't run Filter if PreFilter returned a Skip status #112637
Conversation
@sanposhiho: This issue is currently awaiting triage. If a SIG or subproject determines this is a relevant issue, they will accept it by applying the The Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/sig scheduling |
2703fdc
to
ec85e91
Compare
27d1069
to
746d8be
Compare
Thanks and apologies for late response. The change LGTM from autoscaling point of view. Since it predates #112660, I guess there's nothing else for me to do here (i.e. my approval won't matter to k8s bot). |
/assign |
// anything but Success. If a non-success status is returned, then the scheduling | ||
// cycle is aborted. | ||
func (f *frameworkImpl) RunPreFilterPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod) (_ *framework.PreFilterResult, status *framework.Status) { | ||
func (f *frameworkImpl) RunPreFilterPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod) (_ *framework.PreFilterResult, _ sets.String, status *framework.Status) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should add a dedicated field in CycleState
to hold the set of SkipFilterPlugins
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, makes sense. I didn't come up with that idea.
Let me change...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed implementation as suggested. 🙏
746d8be
to
35f971d
Compare
@@ -48,6 +50,8 @@ type CycleState struct { | |||
storage sync.Map | |||
// if recordPluginMetrics is true, PluginExecutionDuration will be recorded for this cycle. | |||
recordPluginMetrics bool | |||
// skipFilterPlugin is plugins that are skipped in the Filter extension point. | |||
skipFilterPlugins sets.String |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just export this field instead of adding getters and setters. Or you could have functions like SkipFilterPlugin
to add elements and ShouldSkipFilterPlugin
to check if the plugin is in the set.
Are there scenarios in the codebase where c==nil?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just export this field instead of adding getters and setters.
That seems simpler and better.
I just followed how we handle recordPluginMetrics
, and no big reason to do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there scenarios in the codebase where c==nil?
I checked and seems No.
name: preFilterPluginName, | ||
inj: injectedResult{PreFilterStatus: int(framework.Error)}, | ||
func TestRunPreFilterPlugins(t *testing.T) { | ||
tests := []struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So much better, thanks!
if status == nil && tt.wantStatus != nil || status != nil && tt.wantStatus == nil { | ||
t.Errorf("wrong status. got: %v, want: %v", status, tt.wantStatus) | ||
} else if status == nil && tt.wantStatus == nil { | ||
// do nothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't cmp.Diff
already handle all these cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If status
and/or tt.wantStatus
is nil, *status
and/or *tt.wantStatus
in cmp.Diff
will be nil-pointer panic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use cmp.Diff(status, tt.wantStatus)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cmp.Diff
cannot handle pointer.
↓ is the result by using cmp.Diff(status, tt.wantStatus, cmpopts.IgnoreUnexported(framework.Status{}))
here.
It was actually the same, but cmp.Diff
thought they are different from each other since it's pointer.
(*framework.Status)(
- &⟪0xc00016d780⟫{
- code: 1,
- reasons: []string(⟪ptr:0xc0003d44a0, len:1, cap:1⟫{`running PreFilter plugin "error": injected status`}),
- err: &⟪0xc0003a2060⟫"fmt".wrapError{
- msg: `running PreFilter plugin "error": injected status`,
- err: &⟪0xc0003d4420⟫"errors".errorString{s: "injected status"},
- },
- failedPlugin: "error",
- },
+ &⟪0xc00016d2c0⟫{
+ code: 1,
+ reasons: []string(⟪ptr:0xc0003d52f0, len:1, cap:1⟫{`running PreFilter plugin "error": injected status`}),
+ err: &⟪0xc0003a2580⟫"fmt".wrapError{
+ msg: `running PreFilter plugin "error": injected status`,
+ err: &⟪0xc0003d4c80⟫"errors".errorString{s: "injected status"},
+ },
+ failedPlugin: "error",
+ },
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found ↑ is a lie. Actually, cmp.Diff
can handle pointers.
The reason we cannot just use cmp.Diff
is both errors are created from different error bases.
The status from TestPlugin contains the error created in framework.NewStatus
.
return nil, framework.NewStatus(framework.Code(pl.inj.PreFilterStatus), injectReason) |
But, the status in each test case contains the error
errInjectedStatus
.errInjectedStatus = errors.New(injectReason) |
I fixed here to use cmp.Comparer
and deal with the ↑ problem.
59983cf
to
f6ee006
Compare
Sure, I will do it in this weekend |
df677ef
to
041d0f7
Compare
@alculquicondor @kerthcet Fixed and squashed. 🙏 |
fe9cbef
to
519c9d9
Compare
/retest |
/retest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One nit.
519c9d9
to
f131a03
Compare
if d := cmp.Diff(result, tt.wantPreFilterResult); d != "" { | ||
t.Errorf("wrong status. got: %v, want: %v, diff: %s", result, tt.wantPreFilterResult, d) | ||
} | ||
if d := cmp.Diff(status, tt.wantStatus, cmpopts.EquateErrors(), cmp.Comparer(func(a, b *framework.Status) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there should be no need for EquateErrors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah 🤦, fixed.
f131a03
to
786be73
Compare
@sanposhiho: The following tests failed, say
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
/retest |
/lgtm |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: alculquicondor, sanposhiho The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
remove the release note. |
@sanposhiho can you work on this now? I think this is important for performance reasons too. |
yes, I think i can create a PR hopefully by this weekend |
What type of PR is this?
/kind feature
What this PR does / why we need it:
Change the framework so that it doesn't run plugins's
Filter()
if itsPreFilter()
returned a Skip status.For example, nodeAffinity returns
Skip
in PreFilter if the pod doesn't specify any node selector or affinity.In this PR, I only changed the Framework logic. I'm going to change each plugin's PreFilter in another PR.
Which issue(s) this PR fixes:
Part of #107556
Part of #110643
Special notes for your reviewer:
Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: