mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 18:24:07 +00:00
Merge pull request #119778 from sanposhiho/bugfix-unschedulableandunresolvable
fix: when PreFilter returns UnschedulableAndUnresolvable, copy the state in all nodes in statusmap
This commit is contained in:
commit
719d1a84f7
@ -313,32 +313,45 @@ const (
|
|||||||
// Error returns detailed information of why the pod failed to fit on each node.
|
// Error returns detailed information of why the pod failed to fit on each node.
|
||||||
// A message format is "0/X nodes are available: <PreFilterMsg>. <FilterMsg>. <PostFilterMsg>."
|
// A message format is "0/X nodes are available: <PreFilterMsg>. <FilterMsg>. <PostFilterMsg>."
|
||||||
func (f *FitError) Error() string {
|
func (f *FitError) Error() string {
|
||||||
reasons := make(map[string]int)
|
reasonMsg := fmt.Sprintf(NoNodeAvailableMsg+":", f.NumAllNodes)
|
||||||
for _, status := range f.Diagnosis.NodeToStatusMap {
|
preFilterMsg := f.Diagnosis.PreFilterMsg
|
||||||
for _, reason := range status.Reasons() {
|
if preFilterMsg != "" {
|
||||||
reasons[reason]++
|
// PreFilter plugin returns unschedulable.
|
||||||
|
// Add the messages from PreFilter plugins to reasonMsg.
|
||||||
|
reasonMsg += fmt.Sprintf(SeparatorFormat, preFilterMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if preFilterMsg == "" {
|
||||||
|
// the scheduling cycle went through PreFilter extension point successfully.
|
||||||
|
//
|
||||||
|
// When the prefilter plugin returns unschedulable,
|
||||||
|
// the scheduling framework inserts the same unschedulable status to all nodes in NodeToStatusMap.
|
||||||
|
// So, we shouldn't add the message from NodeToStatusMap when the PreFilter failed.
|
||||||
|
// Otherwise, we will have duplicated reasons in the error message.
|
||||||
|
reasons := make(map[string]int)
|
||||||
|
for _, status := range f.Diagnosis.NodeToStatusMap {
|
||||||
|
for _, reason := range status.Reasons() {
|
||||||
|
reasons[reason]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortReasonsHistogram := func() []string {
|
||||||
|
var reasonStrings []string
|
||||||
|
for k, v := range reasons {
|
||||||
|
reasonStrings = append(reasonStrings, fmt.Sprintf("%v %v", v, k))
|
||||||
|
}
|
||||||
|
sort.Strings(reasonStrings)
|
||||||
|
return reasonStrings
|
||||||
|
}
|
||||||
|
sortedFilterMsg := sortReasonsHistogram()
|
||||||
|
if len(sortedFilterMsg) != 0 {
|
||||||
|
reasonMsg += fmt.Sprintf(SeparatorFormat, strings.Join(sortedFilterMsg, ", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reasonMsg := fmt.Sprintf(NoNodeAvailableMsg+":", f.NumAllNodes)
|
|
||||||
// Add the messages from PreFilter plugins to reasonMsg.
|
|
||||||
preFilterMsg := f.Diagnosis.PreFilterMsg
|
|
||||||
if preFilterMsg != "" {
|
|
||||||
reasonMsg += fmt.Sprintf(SeparatorFormat, preFilterMsg)
|
|
||||||
}
|
|
||||||
sortReasonsHistogram := func() []string {
|
|
||||||
var reasonStrings []string
|
|
||||||
for k, v := range reasons {
|
|
||||||
reasonStrings = append(reasonStrings, fmt.Sprintf("%v %v", v, k))
|
|
||||||
}
|
|
||||||
sort.Strings(reasonStrings)
|
|
||||||
return reasonStrings
|
|
||||||
}
|
|
||||||
sortedFilterMsg := sortReasonsHistogram()
|
|
||||||
if len(sortedFilterMsg) != 0 {
|
|
||||||
reasonMsg += fmt.Sprintf(SeparatorFormat, strings.Join(sortedFilterMsg, ", "))
|
|
||||||
}
|
|
||||||
// Add the messages from PostFilter plugins to reasonMsg.
|
// Add the messages from PostFilter plugins to reasonMsg.
|
||||||
|
// We can add this message regardless of whether the scheduling cycle fails at PreFilter or Filter
|
||||||
|
// since we may run PostFilter (if enabled) in both cases.
|
||||||
postFilterMsg := f.Diagnosis.PostFilterMsg
|
postFilterMsg := f.Diagnosis.PostFilterMsg
|
||||||
if postFilterMsg != "" {
|
if postFilterMsg != "" {
|
||||||
reasonMsg += fmt.Sprintf(SeparatorFormat, postFilterMsg)
|
reasonMsg += fmt.Sprintf(SeparatorFormat, postFilterMsg)
|
||||||
|
@ -1390,9 +1390,33 @@ func TestFitError_Error(t *testing.T) {
|
|||||||
numAllNodes: 3,
|
numAllNodes: 3,
|
||||||
diagnosis: Diagnosis{
|
diagnosis: Diagnosis{
|
||||||
PreFilterMsg: "Node(s) failed PreFilter plugin FalsePreFilter",
|
PreFilterMsg: "Node(s) failed PreFilter plugin FalsePreFilter",
|
||||||
|
NodeToStatusMap: NodeToStatusMap{
|
||||||
|
// They're inserted by the framework.
|
||||||
|
// We don't include them in the reason message because they'd be just duplicates.
|
||||||
|
"node1": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
|
||||||
|
"node2": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
|
||||||
|
"node3": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
wantReasonMsg: "0/3 nodes are available: Node(s) failed PreFilter plugin FalsePreFilter.",
|
wantReasonMsg: "0/3 nodes are available: Node(s) failed PreFilter plugin FalsePreFilter.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "nodes failed Prefilter plugin and the preemption also failed",
|
||||||
|
numAllNodes: 3,
|
||||||
|
diagnosis: Diagnosis{
|
||||||
|
PreFilterMsg: "Node(s) failed PreFilter plugin FalsePreFilter",
|
||||||
|
NodeToStatusMap: NodeToStatusMap{
|
||||||
|
// They're inserted by the framework.
|
||||||
|
// We don't include them in the reason message because they'd be just duplicates.
|
||||||
|
"node1": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
|
||||||
|
"node2": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
|
||||||
|
"node3": NewStatus(Unschedulable, "Node(s) failed PreFilter plugin FalsePreFilter"),
|
||||||
|
},
|
||||||
|
// PostFilterMsg will be included.
|
||||||
|
PostFilterMsg: "Error running PostFilter plugin FailedPostFilter",
|
||||||
|
},
|
||||||
|
wantReasonMsg: "0/3 nodes are available: Node(s) failed PreFilter plugin FalsePreFilter. Error running PostFilter plugin FailedPostFilter.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "nodes failed one Filter plugin with an empty PostFilterMsg",
|
name: "nodes failed one Filter plugin with an empty PostFilterMsg",
|
||||||
numAllNodes: 3,
|
numAllNodes: 3,
|
||||||
|
@ -438,6 +438,12 @@ func (sched *Scheduler) findNodesThatFitPod(ctx context.Context, fwk framework.F
|
|||||||
if !s.IsUnschedulable() {
|
if !s.IsUnschedulable() {
|
||||||
return nil, diagnosis, s.AsError()
|
return nil, diagnosis, s.AsError()
|
||||||
}
|
}
|
||||||
|
// All nodes in NodeToStatusMap will have the same status so that they can be handled in the preemption.
|
||||||
|
// Some non trivial refactoring is needed to avoid this copy.
|
||||||
|
for _, n := range allNodes {
|
||||||
|
diagnosis.NodeToStatusMap[n.Node().Name] = s
|
||||||
|
}
|
||||||
|
|
||||||
// Record the messages from PreFilter in Diagnosis.PreFilterMsg.
|
// Record the messages from PreFilter in Diagnosis.PreFilterMsg.
|
||||||
msg := s.Message()
|
msg := s.Message()
|
||||||
diagnosis.PreFilterMsg = msg
|
diagnosis.PreFilterMsg = msg
|
||||||
|
@ -1948,7 +1948,10 @@ func TestSchedulerSchedulePod(t *testing.T) {
|
|||||||
Pod: st.MakePod().Name("ignore").UID("ignore").PVC("unknownPVC").Obj(),
|
Pod: st.MakePod().Name("ignore").UID("ignore").PVC("unknownPVC").Obj(),
|
||||||
NumAllNodes: 2,
|
NumAllNodes: 2,
|
||||||
Diagnosis: framework.Diagnosis{
|
Diagnosis: framework.Diagnosis{
|
||||||
NodeToStatusMap: framework.NodeToStatusMap{},
|
NodeToStatusMap: framework.NodeToStatusMap{
|
||||||
|
"node1": framework.NewStatus(framework.UnschedulableAndUnresolvable, `persistentvolumeclaim "unknownPVC" not found`).WithFailedPlugin("VolumeBinding"),
|
||||||
|
"node2": framework.NewStatus(framework.UnschedulableAndUnresolvable, `persistentvolumeclaim "unknownPVC" not found`).WithFailedPlugin("VolumeBinding"),
|
||||||
|
},
|
||||||
PreFilterMsg: `persistentvolumeclaim "unknownPVC" not found`,
|
PreFilterMsg: `persistentvolumeclaim "unknownPVC" not found`,
|
||||||
UnschedulablePlugins: sets.New(volumebinding.Name),
|
UnschedulablePlugins: sets.New(volumebinding.Name),
|
||||||
},
|
},
|
||||||
@ -1970,7 +1973,10 @@ func TestSchedulerSchedulePod(t *testing.T) {
|
|||||||
Pod: st.MakePod().Name("ignore").UID("ignore").Namespace(v1.NamespaceDefault).PVC("existingPVC").Obj(),
|
Pod: st.MakePod().Name("ignore").UID("ignore").Namespace(v1.NamespaceDefault).PVC("existingPVC").Obj(),
|
||||||
NumAllNodes: 2,
|
NumAllNodes: 2,
|
||||||
Diagnosis: framework.Diagnosis{
|
Diagnosis: framework.Diagnosis{
|
||||||
NodeToStatusMap: framework.NodeToStatusMap{},
|
NodeToStatusMap: framework.NodeToStatusMap{
|
||||||
|
"node1": framework.NewStatus(framework.UnschedulableAndUnresolvable, `persistentvolumeclaim "existingPVC" is being deleted`).WithFailedPlugin("VolumeBinding"),
|
||||||
|
"node2": framework.NewStatus(framework.UnschedulableAndUnresolvable, `persistentvolumeclaim "existingPVC" is being deleted`).WithFailedPlugin("VolumeBinding"),
|
||||||
|
},
|
||||||
PreFilterMsg: `persistentvolumeclaim "existingPVC" is being deleted`,
|
PreFilterMsg: `persistentvolumeclaim "existingPVC" is being deleted`,
|
||||||
UnschedulablePlugins: sets.New(volumebinding.Name),
|
UnschedulablePlugins: sets.New(volumebinding.Name),
|
||||||
},
|
},
|
||||||
@ -2128,7 +2134,10 @@ func TestSchedulerSchedulePod(t *testing.T) {
|
|||||||
Pod: st.MakePod().Name("test-prefilter").UID("test-prefilter").Obj(),
|
Pod: st.MakePod().Name("test-prefilter").UID("test-prefilter").Obj(),
|
||||||
NumAllNodes: 2,
|
NumAllNodes: 2,
|
||||||
Diagnosis: framework.Diagnosis{
|
Diagnosis: framework.Diagnosis{
|
||||||
NodeToStatusMap: framework.NodeToStatusMap{},
|
NodeToStatusMap: framework.NodeToStatusMap{
|
||||||
|
"1": framework.NewStatus(framework.UnschedulableAndUnresolvable, "injected unschedulable status").WithFailedPlugin("FakePreFilter"),
|
||||||
|
"2": framework.NewStatus(framework.UnschedulableAndUnresolvable, "injected unschedulable status").WithFailedPlugin("FakePreFilter"),
|
||||||
|
},
|
||||||
PreFilterMsg: "injected unschedulable status",
|
PreFilterMsg: "injected unschedulable status",
|
||||||
UnschedulablePlugins: sets.New("FakePreFilter"),
|
UnschedulablePlugins: sets.New("FakePreFilter"),
|
||||||
},
|
},
|
||||||
@ -2196,7 +2205,11 @@ func TestSchedulerSchedulePod(t *testing.T) {
|
|||||||
Pod: st.MakePod().Name("test-prefilter").UID("test-prefilter").Obj(),
|
Pod: st.MakePod().Name("test-prefilter").UID("test-prefilter").Obj(),
|
||||||
NumAllNodes: 3,
|
NumAllNodes: 3,
|
||||||
Diagnosis: framework.Diagnosis{
|
Diagnosis: framework.Diagnosis{
|
||||||
NodeToStatusMap: framework.NodeToStatusMap{},
|
NodeToStatusMap: framework.NodeToStatusMap{
|
||||||
|
"node1": framework.NewStatus(framework.Unschedulable, "node(s) didn't satisfy plugin(s) [FakePreFilter2 FakePreFilter3] simultaneously"),
|
||||||
|
"node2": framework.NewStatus(framework.Unschedulable, "node(s) didn't satisfy plugin(s) [FakePreFilter2 FakePreFilter3] simultaneously"),
|
||||||
|
"node3": framework.NewStatus(framework.Unschedulable, "node(s) didn't satisfy plugin(s) [FakePreFilter2 FakePreFilter3] simultaneously"),
|
||||||
|
},
|
||||||
UnschedulablePlugins: sets.Set[string]{},
|
UnschedulablePlugins: sets.Set[string]{},
|
||||||
PreFilterMsg: "node(s) didn't satisfy plugin(s) [FakePreFilter2 FakePreFilter3] simultaneously",
|
PreFilterMsg: "node(s) didn't satisfy plugin(s) [FakePreFilter2 FakePreFilter3] simultaneously",
|
||||||
},
|
},
|
||||||
@ -2222,7 +2235,9 @@ func TestSchedulerSchedulePod(t *testing.T) {
|
|||||||
Pod: st.MakePod().Name("test-prefilter").UID("test-prefilter").Obj(),
|
Pod: st.MakePod().Name("test-prefilter").UID("test-prefilter").Obj(),
|
||||||
NumAllNodes: 1,
|
NumAllNodes: 1,
|
||||||
Diagnosis: framework.Diagnosis{
|
Diagnosis: framework.Diagnosis{
|
||||||
NodeToStatusMap: framework.NodeToStatusMap{},
|
NodeToStatusMap: framework.NodeToStatusMap{
|
||||||
|
"node1": framework.NewStatus(framework.Unschedulable, "node(s) didn't satisfy plugin FakePreFilter2"),
|
||||||
|
},
|
||||||
UnschedulablePlugins: sets.Set[string]{},
|
UnschedulablePlugins: sets.Set[string]{},
|
||||||
PreFilterMsg: "node(s) didn't satisfy plugin FakePreFilter2",
|
PreFilterMsg: "node(s) didn't satisfy plugin FakePreFilter2",
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user