mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +00:00
Merge pull request #19527 from hongchaodeng/pred
Auto commit by PR queue bot
This commit is contained in:
commit
98b190acf4
40
plugin/pkg/scheduler/algorithm/predicates/error.go
Normal file
40
plugin/pkg/scheduler/algorithm/predicates/error.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package predicates
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrExceededMaxPodNumber = newInsufficientResourceError("PodCount")
|
||||||
|
ErrInsufficientFreeCPU = newInsufficientResourceError("CPU")
|
||||||
|
ErrInsufficientFreeMemory = newInsufficientResourceError("Memory")
|
||||||
|
)
|
||||||
|
|
||||||
|
// InsufficientResourceError is an error type that indicates what kind of resource limit is
|
||||||
|
// hit and caused the unfitting failure.
|
||||||
|
type InsufficientResourceError struct {
|
||||||
|
// ResourceName tells the name of the resource that is insufficient
|
||||||
|
ResourceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInsufficientResourceError(resourceName string) *InsufficientResourceError {
|
||||||
|
return &InsufficientResourceError{resourceName}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InsufficientResourceError) Error() string {
|
||||||
|
return fmt.Sprintf("Node didn't have enough resource: %s", e.ResourceName)
|
||||||
|
}
|
@ -256,8 +256,6 @@ type resourceRequest struct {
|
|||||||
memory int64
|
memory int64
|
||||||
}
|
}
|
||||||
|
|
||||||
var FailedResourceType string
|
|
||||||
|
|
||||||
func getResourceRequest(pod *api.Pod) resourceRequest {
|
func getResourceRequest(pod *api.Pod) resourceRequest {
|
||||||
result := resourceRequest{}
|
result := resourceRequest{}
|
||||||
for _, container := range pod.Spec.Containers {
|
for _, container := range pod.Spec.Containers {
|
||||||
@ -308,8 +306,7 @@ func (r *ResourceFit) PodFitsResources(pod *api.Pod, existingPods []*api.Pod, no
|
|||||||
|
|
||||||
if int64(len(existingPods))+1 > info.Status.Capacity.Pods().Value() {
|
if int64(len(existingPods))+1 > info.Status.Capacity.Pods().Value() {
|
||||||
glog.V(10).Infof("Cannot schedule Pod %+v, because Node %+v is full, running %v out of %v Pods.", podName(pod), node, len(existingPods), info.Status.Capacity.Pods().Value())
|
glog.V(10).Infof("Cannot schedule Pod %+v, because Node %+v is full, running %v out of %v Pods.", podName(pod), node, len(existingPods), info.Status.Capacity.Pods().Value())
|
||||||
FailedResourceType = "PodExceedsMaxPodNumber"
|
return false, ErrExceededMaxPodNumber
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
podRequest := getResourceRequest(pod)
|
podRequest := getResourceRequest(pod)
|
||||||
@ -321,13 +318,11 @@ func (r *ResourceFit) PodFitsResources(pod *api.Pod, existingPods []*api.Pod, no
|
|||||||
_, exceedingCPU, exceedingMemory := CheckPodsExceedingFreeResources(pods, info.Status.Capacity)
|
_, exceedingCPU, exceedingMemory := CheckPodsExceedingFreeResources(pods, info.Status.Capacity)
|
||||||
if len(exceedingCPU) > 0 {
|
if len(exceedingCPU) > 0 {
|
||||||
glog.V(10).Infof("Cannot schedule Pod %+v, because Node %v does not have sufficient CPU", podName(pod), node)
|
glog.V(10).Infof("Cannot schedule Pod %+v, because Node %v does not have sufficient CPU", podName(pod), node)
|
||||||
FailedResourceType = "PodExceedsFreeCPU"
|
return false, ErrInsufficientFreeCPU
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
if len(exceedingMemory) > 0 {
|
if len(exceedingMemory) > 0 {
|
||||||
glog.V(10).Infof("Cannot schedule Pod %+v, because Node %v does not have sufficient Memory", podName(pod), node)
|
glog.V(10).Infof("Cannot schedule Pod %+v, because Node %v does not have sufficient Memory", podName(pod), node)
|
||||||
FailedResourceType = "PodExceedsFreeMemory"
|
return false, ErrInsufficientFreeMemory
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
glog.V(10).Infof("Schedule Pod %+v on Node %+v is allowed, Node is running only %v out of %v Pods.", podName(pod), node, len(pods)-1, info.Status.Capacity.Pods().Value())
|
glog.V(10).Infof("Schedule Pod %+v on Node %+v is allowed, Node is running only %v out of %v Pods.", podName(pod), node, len(pods)-1, info.Status.Capacity.Pods().Value())
|
||||||
return true, nil
|
return true, nil
|
||||||
|
@ -80,6 +80,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
existingPods []*api.Pod
|
existingPods []*api.Pod
|
||||||
fits bool
|
fits bool
|
||||||
test string
|
test string
|
||||||
|
wErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
pod: &api.Pod{},
|
pod: &api.Pod{},
|
||||||
@ -88,6 +89,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
},
|
},
|
||||||
fits: true,
|
fits: true,
|
||||||
test: "no resources requested always fits",
|
test: "no resources requested always fits",
|
||||||
|
wErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: newResourcePod(resourceRequest{milliCPU: 1, memory: 1}),
|
pod: newResourcePod(resourceRequest{milliCPU: 1, memory: 1}),
|
||||||
@ -96,6 +98,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
},
|
},
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "too many resources fails",
|
test: "too many resources fails",
|
||||||
|
wErr: ErrInsufficientFreeCPU,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: newResourcePod(resourceRequest{milliCPU: 1, memory: 1}),
|
pod: newResourcePod(resourceRequest{milliCPU: 1, memory: 1}),
|
||||||
@ -104,6 +107,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
},
|
},
|
||||||
fits: true,
|
fits: true,
|
||||||
test: "both resources fit",
|
test: "both resources fit",
|
||||||
|
wErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: newResourcePod(resourceRequest{milliCPU: 1, memory: 2}),
|
pod: newResourcePod(resourceRequest{milliCPU: 1, memory: 2}),
|
||||||
@ -112,6 +116,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
},
|
},
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "one resources fits",
|
test: "one resources fits",
|
||||||
|
wErr: ErrInsufficientFreeMemory,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: newResourcePod(resourceRequest{milliCPU: 5, memory: 1}),
|
pod: newResourcePod(resourceRequest{milliCPU: 5, memory: 1}),
|
||||||
@ -120,6 +125,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
},
|
},
|
||||||
fits: true,
|
fits: true,
|
||||||
test: "equal edge case",
|
test: "equal edge case",
|
||||||
|
wErr: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,8 +134,8 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
|
|
||||||
fit := ResourceFit{FakeNodeInfo(node)}
|
fit := ResourceFit{FakeNodeInfo(node)}
|
||||||
fits, err := fit.PodFitsResources(test.pod, test.existingPods, "machine")
|
fits, err := fit.PodFitsResources(test.pod, test.existingPods, "machine")
|
||||||
if err != nil {
|
if !reflect.DeepEqual(err, test.wErr) {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("%s: unexpected error: %v, want: %v", test.test, err, test.wErr)
|
||||||
}
|
}
|
||||||
if fits != test.fits {
|
if fits != test.fits {
|
||||||
t.Errorf("%s: expected: %v got %v", test.test, test.fits, fits)
|
t.Errorf("%s: expected: %v got %v", test.test, test.fits, fits)
|
||||||
@ -141,6 +147,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
existingPods []*api.Pod
|
existingPods []*api.Pod
|
||||||
fits bool
|
fits bool
|
||||||
test string
|
test string
|
||||||
|
wErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
pod: &api.Pod{},
|
pod: &api.Pod{},
|
||||||
@ -149,6 +156,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
},
|
},
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "even without specified resources predicate fails when there's no available ips",
|
test: "even without specified resources predicate fails when there's no available ips",
|
||||||
|
wErr: ErrExceededMaxPodNumber,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: newResourcePod(resourceRequest{milliCPU: 1, memory: 1}),
|
pod: newResourcePod(resourceRequest{milliCPU: 1, memory: 1}),
|
||||||
@ -157,6 +165,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
},
|
},
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "even if both resources fit predicate fails when there's no available ips",
|
test: "even if both resources fit predicate fails when there's no available ips",
|
||||||
|
wErr: ErrExceededMaxPodNumber,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: newResourcePod(resourceRequest{milliCPU: 5, memory: 1}),
|
pod: newResourcePod(resourceRequest{milliCPU: 5, memory: 1}),
|
||||||
@ -165,6 +174,7 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
},
|
},
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "even for equal edge case predicate fails when there's no available ips",
|
test: "even for equal edge case predicate fails when there's no available ips",
|
||||||
|
wErr: ErrExceededMaxPodNumber,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range notEnoughPodsTests {
|
for _, test := range notEnoughPodsTests {
|
||||||
@ -172,8 +182,8 @@ func TestPodFitsResources(t *testing.T) {
|
|||||||
|
|
||||||
fit := ResourceFit{FakeNodeInfo(node)}
|
fit := ResourceFit{FakeNodeInfo(node)}
|
||||||
fits, err := fit.PodFitsResources(test.pod, test.existingPods, "machine")
|
fits, err := fit.PodFitsResources(test.pod, test.existingPods, "machine")
|
||||||
if err != nil {
|
if !reflect.DeepEqual(err, test.wErr) {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("%s: unexpected error: %v, want: %v", test.test, err, test.wErr)
|
||||||
}
|
}
|
||||||
if fits != test.fits {
|
if fits != test.fits {
|
||||||
t.Errorf("%s: expected: %v got %v", test.test, test.fits, fits)
|
t.Errorf("%s: expected: %v got %v", test.test, test.fits, fits)
|
||||||
|
@ -127,18 +127,25 @@ func findNodesThatFit(pod *api.Pod, machineToPods map[string][]*api.Pod, predica
|
|||||||
for _, node := range nodes.Items {
|
for _, node := range nodes.Items {
|
||||||
fits := true
|
fits := true
|
||||||
for name, predicate := range predicateFuncs {
|
for name, predicate := range predicateFuncs {
|
||||||
predicates.FailedResourceType = ""
|
|
||||||
fit, err := predicate(pod, machineToPods[node.Name], node.Name)
|
fit, err := predicate(pod, machineToPods[node.Name], node.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
switch e := err.(type) {
|
||||||
|
case *predicates.InsufficientResourceError:
|
||||||
|
if fit {
|
||||||
|
err := fmt.Errorf("got InsufficientResourceError: %v, but also fit='true' which is unexpected", e)
|
||||||
return api.NodeList{}, FailedPredicateMap{}, err
|
return api.NodeList{}, FailedPredicateMap{}, err
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return api.NodeList{}, FailedPredicateMap{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
if !fit {
|
if !fit {
|
||||||
fits = false
|
fits = false
|
||||||
if _, found := failedPredicateMap[node.Name]; !found {
|
if _, found := failedPredicateMap[node.Name]; !found {
|
||||||
failedPredicateMap[node.Name] = sets.String{}
|
failedPredicateMap[node.Name] = sets.String{}
|
||||||
}
|
}
|
||||||
if predicates.FailedResourceType != "" {
|
if re, ok := err.(*predicates.InsufficientResourceError); ok {
|
||||||
failedPredicateMap[node.Name].Insert(predicates.FailedResourceType)
|
failedPredicateMap[node.Name].Insert(re.ResourceName)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
failedPredicateMap[node.Name].Insert(name)
|
failedPredicateMap[node.Name].Insert(name)
|
||||||
|
Loading…
Reference in New Issue
Block a user