mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
Merge pull request #92107 from Huang-Wei/fake-artifacts-refactor
Move scheduler fake artifacts to pkg/scheduler/testing
This commit is contained in:
commit
1c11ff7a26
@ -40,7 +40,6 @@ go_test(
|
|||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/v1/pod:go_default_library",
|
|
||||||
"//pkg/controller/volume/scheduling:go_default_library",
|
"//pkg/controller/volume/scheduling:go_default_library",
|
||||||
"//pkg/scheduler/apis/config:go_default_library",
|
"//pkg/scheduler/apis/config:go_default_library",
|
||||||
"//pkg/scheduler/framework/plugins/defaultbinder:go_default_library",
|
"//pkg/scheduler/framework/plugins/defaultbinder:go_default_library",
|
||||||
|
@ -18,22 +18,17 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
||||||
extenderv1 "k8s.io/kube-scheduler/extender/v1"
|
|
||||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort"
|
||||||
@ -42,340 +37,29 @@ import (
|
|||||||
internalqueue "k8s.io/kubernetes/pkg/scheduler/internal/queue"
|
internalqueue "k8s.io/kubernetes/pkg/scheduler/internal/queue"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/profile"
|
"k8s.io/kubernetes/pkg/scheduler/profile"
|
||||||
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type fitPredicate func(pod *v1.Pod, node *v1.Node) (bool, error)
|
|
||||||
type priorityFunc func(pod *v1.Pod, nodes []*v1.Node) (*framework.NodeScoreList, error)
|
|
||||||
|
|
||||||
type priorityConfig struct {
|
|
||||||
function priorityFunc
|
|
||||||
weight int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorPredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
|
||||||
return false, fmt.Errorf("Some error")
|
|
||||||
}
|
|
||||||
|
|
||||||
func falsePredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func truePredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func machine1PredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
|
||||||
if node.Name == "machine1" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func machine2PredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
|
||||||
if node.Name == "machine2" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorPrioritizerExtender(pod *v1.Pod, nodes []*v1.Node) (*framework.NodeScoreList, error) {
|
|
||||||
return &framework.NodeScoreList{}, fmt.Errorf("Some error")
|
|
||||||
}
|
|
||||||
|
|
||||||
func machine1PrioritizerExtender(pod *v1.Pod, nodes []*v1.Node) (*framework.NodeScoreList, error) {
|
|
||||||
result := framework.NodeScoreList{}
|
|
||||||
for _, node := range nodes {
|
|
||||||
score := 1
|
|
||||||
if node.Name == "machine1" {
|
|
||||||
score = 10
|
|
||||||
}
|
|
||||||
result = append(result, framework.NodeScore{Name: node.Name, Score: int64(score)})
|
|
||||||
}
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func machine2PrioritizerExtender(pod *v1.Pod, nodes []*v1.Node) (*framework.NodeScoreList, error) {
|
|
||||||
result := framework.NodeScoreList{}
|
|
||||||
for _, node := range nodes {
|
|
||||||
score := 1
|
|
||||||
if node.Name == "machine2" {
|
|
||||||
score = 10
|
|
||||||
}
|
|
||||||
result = append(result, framework.NodeScore{Name: node.Name, Score: int64(score)})
|
|
||||||
}
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type machine2PrioritizerPlugin struct{}
|
|
||||||
|
|
||||||
func newMachine2PrioritizerPlugin() framework.PluginFactory {
|
|
||||||
return func(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
|
||||||
return &machine2PrioritizerPlugin{}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *machine2PrioritizerPlugin) Name() string {
|
|
||||||
return "Machine2Prioritizer"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *machine2PrioritizerPlugin) Score(_ context.Context, _ *framework.CycleState, _ *v1.Pod, nodeName string) (int64, *framework.Status) {
|
|
||||||
score := 10
|
|
||||||
if nodeName == "machine2" {
|
|
||||||
score = 100
|
|
||||||
}
|
|
||||||
return int64(score), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *machine2PrioritizerPlugin) ScoreExtensions() framework.ScoreExtensions {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type FakeExtender struct {
|
|
||||||
predicates []fitPredicate
|
|
||||||
prioritizers []priorityConfig
|
|
||||||
weight int64
|
|
||||||
nodeCacheCapable bool
|
|
||||||
filteredNodes []*v1.Node
|
|
||||||
unInterested bool
|
|
||||||
ignorable bool
|
|
||||||
|
|
||||||
// Cached node information for fake extender
|
|
||||||
cachedNodeNameToInfo map[string]*framework.NodeInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExtender) Name() string {
|
|
||||||
return "FakeExtender"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExtender) IsIgnorable() bool {
|
|
||||||
return f.ignorable
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExtender) SupportsPreemption() bool {
|
|
||||||
// Assume preempt verb is always defined.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExtender) ProcessPreemption(
|
|
||||||
pod *v1.Pod,
|
|
||||||
nodeNameToVictims map[string]*extenderv1.Victims,
|
|
||||||
nodeInfos framework.NodeInfoLister,
|
|
||||||
) (map[string]*extenderv1.Victims, error) {
|
|
||||||
nodeNameToVictimsCopy := map[string]*extenderv1.Victims{}
|
|
||||||
// We don't want to change the original nodeNameToVictims
|
|
||||||
for k, v := range nodeNameToVictims {
|
|
||||||
// In real world implementation, extender's user should have their own way to get node object
|
|
||||||
// by name if needed (e.g. query kube-apiserver etc).
|
|
||||||
//
|
|
||||||
// For test purpose, we just use node from parameters directly.
|
|
||||||
nodeNameToVictimsCopy[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
for nodeName, victims := range nodeNameToVictimsCopy {
|
|
||||||
// Try to do preemption on extender side.
|
|
||||||
nodeInfo, _ := nodeInfos.Get(nodeName)
|
|
||||||
extenderVictimPods, extenderPDBViolations, fits, err := f.selectVictimsOnNodeByExtender(pod, nodeInfo.Node())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// If it's unfit after extender's preemption, this node is unresolvable by preemption overall,
|
|
||||||
// let's remove it from potential preemption nodes.
|
|
||||||
if !fits {
|
|
||||||
delete(nodeNameToVictimsCopy, nodeName)
|
|
||||||
} else {
|
|
||||||
// Append new victims to original victims
|
|
||||||
nodeNameToVictimsCopy[nodeName].Pods = append(victims.Pods, extenderVictimPods...)
|
|
||||||
nodeNameToVictimsCopy[nodeName].NumPDBViolations = victims.NumPDBViolations + int64(extenderPDBViolations)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nodeNameToVictimsCopy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// selectVictimsOnNodeByExtender checks the given nodes->pods map with predicates on extender's side.
|
|
||||||
// Returns:
|
|
||||||
// 1. More victim pods (if any) amended by preemption phase of extender.
|
|
||||||
// 2. Number of violating victim (used to calculate PDB).
|
|
||||||
// 3. Fits or not after preemption phase on extender's side.
|
|
||||||
func (f *FakeExtender) selectVictimsOnNodeByExtender(pod *v1.Pod, node *v1.Node) ([]*v1.Pod, int, bool, error) {
|
|
||||||
// If a extender support preemption but have no cached node info, let's run filter to make sure
|
|
||||||
// default scheduler's decision still stand with given pod and node.
|
|
||||||
if !f.nodeCacheCapable {
|
|
||||||
fits, err := f.runPredicate(pod, node)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, false, err
|
|
||||||
}
|
|
||||||
if !fits {
|
|
||||||
return nil, 0, false, nil
|
|
||||||
}
|
|
||||||
return []*v1.Pod{}, 0, true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, as a extender support preemption and have cached node info, we will assume cachedNodeNameToInfo is available
|
|
||||||
// and get cached node info by given node name.
|
|
||||||
nodeInfoCopy := f.cachedNodeNameToInfo[node.GetName()].Clone()
|
|
||||||
|
|
||||||
var potentialVictims []*v1.Pod
|
|
||||||
|
|
||||||
removePod := func(rp *v1.Pod) {
|
|
||||||
nodeInfoCopy.RemovePod(rp)
|
|
||||||
}
|
|
||||||
addPod := func(ap *v1.Pod) {
|
|
||||||
nodeInfoCopy.AddPod(ap)
|
|
||||||
}
|
|
||||||
// As the first step, remove all the lower priority pods from the node and
|
|
||||||
// check if the given pod can be scheduled.
|
|
||||||
podPriority := podutil.GetPodPriority(pod)
|
|
||||||
for _, p := range nodeInfoCopy.Pods {
|
|
||||||
if podutil.GetPodPriority(p.Pod) < podPriority {
|
|
||||||
potentialVictims = append(potentialVictims, p.Pod)
|
|
||||||
removePod(p.Pod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Slice(potentialVictims, func(i, j int) bool { return util.MoreImportantPod(potentialVictims[i], potentialVictims[j]) })
|
|
||||||
|
|
||||||
// If the new pod does not fit after removing all the lower priority pods,
|
|
||||||
// we are almost done and this node is not suitable for preemption.
|
|
||||||
fits, err := f.runPredicate(pod, nodeInfoCopy.Node())
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, false, err
|
|
||||||
}
|
|
||||||
if !fits {
|
|
||||||
return nil, 0, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var victims []*v1.Pod
|
|
||||||
|
|
||||||
// TODO(harry): handle PDBs in the future.
|
|
||||||
numViolatingVictim := 0
|
|
||||||
|
|
||||||
reprievePod := func(p *v1.Pod) bool {
|
|
||||||
addPod(p)
|
|
||||||
fits, _ := f.runPredicate(pod, nodeInfoCopy.Node())
|
|
||||||
if !fits {
|
|
||||||
removePod(p)
|
|
||||||
victims = append(victims, p)
|
|
||||||
}
|
|
||||||
return fits
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, assume all potential victims to be non-violating.
|
|
||||||
// Now we try to reprieve non-violating victims.
|
|
||||||
for _, p := range potentialVictims {
|
|
||||||
reprievePod(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
return victims, numViolatingVictim, true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// runPredicate run predicates of extender one by one for given pod and node.
|
|
||||||
// Returns: fits or not.
|
|
||||||
func (f *FakeExtender) runPredicate(pod *v1.Pod, node *v1.Node) (bool, error) {
|
|
||||||
fits := true
|
|
||||||
var err error
|
|
||||||
for _, predicate := range f.predicates {
|
|
||||||
fits, err = predicate(pod, node)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if !fits {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExtender) Filter(pod *v1.Pod, nodes []*v1.Node) ([]*v1.Node, extenderv1.FailedNodesMap, error) {
|
|
||||||
filtered := []*v1.Node{}
|
|
||||||
failedNodesMap := extenderv1.FailedNodesMap{}
|
|
||||||
for _, node := range nodes {
|
|
||||||
fits, err := f.runPredicate(pod, node)
|
|
||||||
if err != nil {
|
|
||||||
return []*v1.Node{}, extenderv1.FailedNodesMap{}, err
|
|
||||||
}
|
|
||||||
if fits {
|
|
||||||
filtered = append(filtered, node)
|
|
||||||
} else {
|
|
||||||
failedNodesMap[node.Name] = "FakeExtender failed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.filteredNodes = filtered
|
|
||||||
if f.nodeCacheCapable {
|
|
||||||
return filtered, failedNodesMap, nil
|
|
||||||
}
|
|
||||||
return filtered, failedNodesMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExtender) Prioritize(pod *v1.Pod, nodes []*v1.Node) (*extenderv1.HostPriorityList, int64, error) {
|
|
||||||
result := extenderv1.HostPriorityList{}
|
|
||||||
combinedScores := map[string]int64{}
|
|
||||||
for _, prioritizer := range f.prioritizers {
|
|
||||||
weight := prioritizer.weight
|
|
||||||
if weight == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
priorityFunc := prioritizer.function
|
|
||||||
prioritizedList, err := priorityFunc(pod, nodes)
|
|
||||||
if err != nil {
|
|
||||||
return &extenderv1.HostPriorityList{}, 0, err
|
|
||||||
}
|
|
||||||
for _, hostEntry := range *prioritizedList {
|
|
||||||
combinedScores[hostEntry.Name] += hostEntry.Score * weight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for host, score := range combinedScores {
|
|
||||||
result = append(result, extenderv1.HostPriority{Host: host, Score: score})
|
|
||||||
}
|
|
||||||
return &result, f.weight, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExtender) Bind(binding *v1.Binding) error {
|
|
||||||
if len(f.filteredNodes) != 0 {
|
|
||||||
for _, node := range f.filteredNodes {
|
|
||||||
if node.Name == binding.Target.Name {
|
|
||||||
f.filteredNodes = nil
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := fmt.Errorf("Node %v not in filtered nodes %v", binding.Target.Name, f.filteredNodes)
|
|
||||||
f.filteredNodes = nil
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExtender) IsBinder() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeExtender) IsInterested(pod *v1.Pod) bool {
|
|
||||||
return !f.unInterested
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ framework.Extender = &FakeExtender{}
|
|
||||||
|
|
||||||
func TestGenericSchedulerWithExtenders(t *testing.T) {
|
func TestGenericSchedulerWithExtenders(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
registerPlugins []st.RegisterPluginFunc
|
registerPlugins []st.RegisterPluginFunc
|
||||||
extenders []FakeExtender
|
extenders []st.FakeExtender
|
||||||
nodes []string
|
nodes []string
|
||||||
expectedResult ScheduleResult
|
expectedResult ScheduleResult
|
||||||
expectsErr bool
|
expectsErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
extenders: []FakeExtender{
|
extenders: []st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{truePredicateExtender},
|
Predicates: []st.FitPredicate{st.TruePredicateExtender},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{errorPredicateExtender},
|
Predicates: []st.FitPredicate{st.ErrorPredicateExtender},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -384,16 +68,16 @@ func TestGenericSchedulerWithExtenders(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
extenders: []FakeExtender{
|
extenders: []st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{truePredicateExtender},
|
Predicates: []st.FitPredicate{st.TruePredicateExtender},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{falsePredicateExtender},
|
Predicates: []st.FitPredicate{st.FalsePredicateExtender},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -402,16 +86,16 @@ func TestGenericSchedulerWithExtenders(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
extenders: []FakeExtender{
|
extenders: []st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{truePredicateExtender},
|
Predicates: []st.FitPredicate{st.TruePredicateExtender},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{machine1PredicateExtender},
|
Predicates: []st.FitPredicate{st.Machine1PredicateExtender},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -424,16 +108,16 @@ func TestGenericSchedulerWithExtenders(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
extenders: []FakeExtender{
|
extenders: []st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{machine2PredicateExtender},
|
Predicates: []st.FitPredicate{st.Machine2PredicateExtender},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{machine1PredicateExtender},
|
Predicates: []st.FitPredicate{st.Machine1PredicateExtender},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -442,15 +126,15 @@ func TestGenericSchedulerWithExtenders(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
extenders: []FakeExtender{
|
extenders: []st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{truePredicateExtender},
|
Predicates: []st.FitPredicate{st.TruePredicateExtender},
|
||||||
prioritizers: []priorityConfig{{errorPrioritizerExtender, 10}},
|
Prioritizers: []st.PriorityConfig{{Function: st.ErrorPrioritizerExtender, Weight: 10}},
|
||||||
weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1"},
|
nodes: []string{"machine1"},
|
||||||
@ -463,20 +147,20 @@ func TestGenericSchedulerWithExtenders(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
extenders: []FakeExtender{
|
extenders: []st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{truePredicateExtender},
|
Predicates: []st.FitPredicate{st.TruePredicateExtender},
|
||||||
prioritizers: []priorityConfig{{machine1PrioritizerExtender, 10}},
|
Prioritizers: []st.PriorityConfig{{Function: st.Machine1PrioritizerExtender, Weight: 10}},
|
||||||
weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{truePredicateExtender},
|
Predicates: []st.FitPredicate{st.TruePredicateExtender},
|
||||||
prioritizers: []priorityConfig{{machine2PrioritizerExtender, 10}},
|
Prioritizers: []st.PriorityConfig{{Function: st.Machine2PrioritizerExtender, Weight: 10}},
|
||||||
weight: 5,
|
Weight: 5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -489,16 +173,16 @@ func TestGenericSchedulerWithExtenders(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterScorePlugin("Machine2Prioritizer", newMachine2PrioritizerPlugin(), 20),
|
st.RegisterScorePlugin("Machine2Prioritizer", st.NewMachine2PrioritizerPlugin(), 20),
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
extenders: []FakeExtender{
|
extenders: []st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{truePredicateExtender},
|
Predicates: []st.FitPredicate{st.TruePredicateExtender},
|
||||||
prioritizers: []priorityConfig{{machine1PrioritizerExtender, 10}},
|
Prioritizers: []st.PriorityConfig{{Function: st.Machine1PrioritizerExtender, Weight: 10}},
|
||||||
weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -518,16 +202,16 @@ func TestGenericSchedulerWithExtenders(t *testing.T) {
|
|||||||
// because of the errors from errorPredicateExtender and/or
|
// because of the errors from errorPredicateExtender and/or
|
||||||
// errorPrioritizerExtender.
|
// errorPrioritizerExtender.
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterScorePlugin("Machine2Prioritizer", newMachine2PrioritizerPlugin(), 1),
|
st.RegisterScorePlugin("Machine2Prioritizer", st.NewMachine2PrioritizerPlugin(), 1),
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
extenders: []FakeExtender{
|
extenders: []st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{errorPredicateExtender},
|
Predicates: []st.FitPredicate{st.ErrorPredicateExtender},
|
||||||
prioritizers: []priorityConfig{{errorPrioritizerExtender, 10}},
|
Prioritizers: []st.PriorityConfig{{Function: st.ErrorPrioritizerExtender, Weight: 10}},
|
||||||
unInterested: true,
|
UnInterested: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -546,17 +230,17 @@ func TestGenericSchedulerWithExtenders(t *testing.T) {
|
|||||||
// If scheduler did not ignore the extender, the test would fail
|
// If scheduler did not ignore the extender, the test would fail
|
||||||
// because of the errors from errorPredicateExtender.
|
// because of the errors from errorPredicateExtender.
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
extenders: []FakeExtender{
|
extenders: []st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{errorPredicateExtender},
|
Predicates: []st.FitPredicate{st.ErrorPredicateExtender},
|
||||||
ignorable: true,
|
Ignorable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{machine1PredicateExtender},
|
Predicates: []st.FitPredicate{st.Machine1PredicateExtender},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -68,66 +67,6 @@ var (
|
|||||||
errPrioritize = fmt.Errorf("priority map encounters an error")
|
errPrioritize = fmt.Errorf("priority map encounters an error")
|
||||||
)
|
)
|
||||||
|
|
||||||
const ErrReasonFake = "Nodes failed the fake predicate"
|
|
||||||
|
|
||||||
type trueFilterPlugin struct{}
|
|
||||||
|
|
||||||
// Name returns name of the plugin.
|
|
||||||
func (pl *trueFilterPlugin) Name() string {
|
|
||||||
return "TrueFilter"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter invoked at the filter extension point.
|
|
||||||
func (pl *trueFilterPlugin) Filter(_ context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTrueFilterPlugin initializes a trueFilterPlugin and returns it.
|
|
||||||
func NewTrueFilterPlugin(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
|
||||||
return &trueFilterPlugin{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type falseFilterPlugin struct{}
|
|
||||||
|
|
||||||
// Name returns name of the plugin.
|
|
||||||
func (pl *falseFilterPlugin) Name() string {
|
|
||||||
return "FalseFilter"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter invoked at the filter extension point.
|
|
||||||
func (pl *falseFilterPlugin) Filter(_ context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
|
||||||
return framework.NewStatus(framework.Unschedulable, ErrReasonFake)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFalseFilterPlugin initializes a falseFilterPlugin and returns it.
|
|
||||||
func NewFalseFilterPlugin(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
|
||||||
return &falseFilterPlugin{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type matchFilterPlugin struct{}
|
|
||||||
|
|
||||||
// Name returns name of the plugin.
|
|
||||||
func (pl *matchFilterPlugin) Name() string {
|
|
||||||
return "MatchFilter"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter invoked at the filter extension point.
|
|
||||||
func (pl *matchFilterPlugin) Filter(_ context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
|
||||||
node := nodeInfo.Node()
|
|
||||||
if node == nil {
|
|
||||||
return framework.NewStatus(framework.Error, "node not found")
|
|
||||||
}
|
|
||||||
if pod.Name == node.Name {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return framework.NewStatus(framework.Unschedulable, ErrReasonFake)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMatchFilterPlugin initializes a matchFilterPlugin and returns it.
|
|
||||||
func NewMatchFilterPlugin(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
|
||||||
return &matchFilterPlugin{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type noPodsFilterPlugin struct{}
|
type noPodsFilterPlugin struct{}
|
||||||
|
|
||||||
// Name returns name of the plugin.
|
// Name returns name of the plugin.
|
||||||
@ -140,7 +79,7 @@ func (pl *noPodsFilterPlugin) Filter(_ context.Context, _ *framework.CycleState,
|
|||||||
if len(nodeInfo.Pods) == 0 {
|
if len(nodeInfo.Pods) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return framework.NewStatus(framework.Unschedulable, ErrReasonFake)
|
return framework.NewStatus(framework.Unschedulable, st.ErrReasonFake)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNoPodsFilterPlugin initializes a noPodsFilterPlugin and returns it.
|
// NewNoPodsFilterPlugin initializes a noPodsFilterPlugin and returns it.
|
||||||
@ -148,38 +87,6 @@ func NewNoPodsFilterPlugin(_ runtime.Object, _ framework.FrameworkHandle) (frame
|
|||||||
return &noPodsFilterPlugin{}, nil
|
return &noPodsFilterPlugin{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fakeFilterPlugin is a test filter plugin to record how many times its Filter() function have
|
|
||||||
// been called, and it returns different 'Code' depending on its internal 'failedNodeReturnCodeMap'.
|
|
||||||
type fakeFilterPlugin struct {
|
|
||||||
numFilterCalled int32
|
|
||||||
failedNodeReturnCodeMap map[string]framework.Code
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns name of the plugin.
|
|
||||||
func (pl *fakeFilterPlugin) Name() string {
|
|
||||||
return "FakeFilter"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter invoked at the filter extension point.
|
|
||||||
func (pl *fakeFilterPlugin) Filter(_ context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
|
||||||
atomic.AddInt32(&pl.numFilterCalled, 1)
|
|
||||||
|
|
||||||
if returnCode, ok := pl.failedNodeReturnCodeMap[nodeInfo.Node().Name]; ok {
|
|
||||||
return framework.NewStatus(returnCode, fmt.Sprintf("injecting failure for pod %v", pod.Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFakeFilterPlugin initializes a fakeFilterPlugin and returns it.
|
|
||||||
func NewFakeFilterPlugin(failedNodeReturnCodeMap map[string]framework.Code) framework.PluginFactory {
|
|
||||||
return func(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
|
||||||
return &fakeFilterPlugin{
|
|
||||||
failedNodeReturnCodeMap: failedNodeReturnCodeMap,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type numericMapPlugin struct{}
|
type numericMapPlugin struct{}
|
||||||
|
|
||||||
func newNumericMapPlugin() framework.PluginFactory {
|
func newNumericMapPlugin() framework.PluginFactory {
|
||||||
@ -388,7 +295,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("FalseFilter", NewFalseFilterPlugin),
|
st.RegisterFilterPlugin("FalseFilter", st.NewFalseFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -398,15 +305,15 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
||||||
NumAllNodes: 2,
|
NumAllNodes: 2,
|
||||||
FilteredNodesStatuses: framework.NodeToStatusMap{
|
FilteredNodesStatuses: framework.NodeToStatusMap{
|
||||||
"machine1": framework.NewStatus(framework.Unschedulable, ErrReasonFake),
|
"machine1": framework.NewStatus(framework.Unschedulable, st.ErrReasonFake),
|
||||||
"machine2": framework.NewStatus(framework.Unschedulable, ErrReasonFake),
|
"machine2": framework.NewStatus(framework.Unschedulable, st.ErrReasonFake),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -419,7 +326,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
// Fits on a machine where the pod ID matches the machine name
|
// Fits on a machine where the pod ID matches the machine name
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("MatchFilter", NewMatchFilterPlugin),
|
st.RegisterFilterPlugin("MatchFilter", st.NewMatchFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -431,7 +338,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
@ -444,7 +351,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("MatchFilter", NewMatchFilterPlugin),
|
st.RegisterFilterPlugin("MatchFilter", st.NewMatchFilterPlugin),
|
||||||
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
@ -457,7 +364,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
||||||
st.RegisterScorePlugin("ReverseNumericMap", newReverseNumericMapPlugin(), 2),
|
st.RegisterScorePlugin("ReverseNumericMap", newReverseNumericMapPlugin(), 2),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
@ -471,8 +378,8 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterFilterPlugin("FalseFilter", NewFalseFilterPlugin),
|
st.RegisterFilterPlugin("FalseFilter", st.NewFalseFilterPlugin),
|
||||||
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
@ -483,9 +390,9 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
||||||
NumAllNodes: 3,
|
NumAllNodes: 3,
|
||||||
FilteredNodesStatuses: framework.NodeToStatusMap{
|
FilteredNodesStatuses: framework.NodeToStatusMap{
|
||||||
"3": framework.NewStatus(framework.Unschedulable, ErrReasonFake),
|
"3": framework.NewStatus(framework.Unschedulable, st.ErrReasonFake),
|
||||||
"2": framework.NewStatus(framework.Unschedulable, ErrReasonFake),
|
"2": framework.NewStatus(framework.Unschedulable, st.ErrReasonFake),
|
||||||
"1": framework.NewStatus(framework.Unschedulable, ErrReasonFake),
|
"1": framework.NewStatus(framework.Unschedulable, st.ErrReasonFake),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -493,7 +400,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("NoPodsFilter", NewNoPodsFilterPlugin),
|
st.RegisterFilterPlugin("NoPodsFilter", NewNoPodsFilterPlugin),
|
||||||
st.RegisterFilterPlugin("MatchFilter", NewMatchFilterPlugin),
|
st.RegisterFilterPlugin("MatchFilter", st.NewMatchFilterPlugin),
|
||||||
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
@ -515,8 +422,8 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
||||||
NumAllNodes: 2,
|
NumAllNodes: 2,
|
||||||
FilteredNodesStatuses: framework.NodeToStatusMap{
|
FilteredNodesStatuses: framework.NodeToStatusMap{
|
||||||
"1": framework.NewStatus(framework.Unschedulable, ErrReasonFake),
|
"1": framework.NewStatus(framework.Unschedulable, st.ErrReasonFake),
|
||||||
"2": framework.NewStatus(framework.Unschedulable, ErrReasonFake),
|
"2": framework.NewStatus(framework.Unschedulable, st.ErrReasonFake),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -524,7 +431,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
// Pod with existing PVC
|
// Pod with existing PVC
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -551,7 +458,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
// Pod with non existing PVC
|
// Pod with non existing PVC
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -576,7 +483,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
// Pod with deleting PVC
|
// Pod with deleting PVC
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -601,7 +508,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
{
|
{
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterScorePlugin("FalseMap", newFalseMapPlugin(), 1),
|
st.RegisterScorePlugin("FalseMap", newFalseMapPlugin(), 1),
|
||||||
st.RegisterScorePlugin("TrueMap", newTrueMapPlugin(), 2),
|
st.RegisterScorePlugin("TrueMap", newTrueMapPlugin(), 2),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
@ -729,7 +636,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin(
|
st.RegisterFilterPlugin(
|
||||||
"FakeFilter",
|
"FakeFilter",
|
||||||
NewFakeFilterPlugin(map[string]framework.Code{"3": framework.Unschedulable}),
|
st.NewFakeFilterPlugin(map[string]framework.Code{"3": framework.Unschedulable}),
|
||||||
),
|
),
|
||||||
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
@ -751,7 +658,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin(
|
st.RegisterFilterPlugin(
|
||||||
"FakeFilter",
|
"FakeFilter",
|
||||||
NewFakeFilterPlugin(map[string]framework.Code{"3": framework.UnschedulableAndUnresolvable}),
|
st.NewFakeFilterPlugin(map[string]framework.Code{"3": framework.UnschedulableAndUnresolvable}),
|
||||||
),
|
),
|
||||||
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
@ -773,7 +680,7 @@ func TestGenericScheduler(t *testing.T) {
|
|||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin(
|
st.RegisterFilterPlugin(
|
||||||
"FakeFilter",
|
"FakeFilter",
|
||||||
NewFakeFilterPlugin(map[string]framework.Code{"1": framework.Unschedulable}),
|
st.NewFakeFilterPlugin(map[string]framework.Code{"1": framework.Unschedulable}),
|
||||||
),
|
),
|
||||||
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
st.RegisterScorePlugin("NumericMap", newNumericMapPlugin(), 1),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
@ -866,8 +773,8 @@ func TestFindFitAllError(t *testing.T) {
|
|||||||
scheduler := makeScheduler(nodes)
|
scheduler := makeScheduler(nodes)
|
||||||
prof, err := makeProfile(
|
prof, err := makeProfile(
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterFilterPlugin("MatchFilter", NewMatchFilterPlugin),
|
st.RegisterFilterPlugin("MatchFilter", st.NewMatchFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -891,7 +798,7 @@ func TestFindFitAllError(t *testing.T) {
|
|||||||
t.Errorf("failed to find node %v in %v", node.Name, nodeToStatusMap)
|
t.Errorf("failed to find node %v in %v", node.Name, nodeToStatusMap)
|
||||||
}
|
}
|
||||||
reasons := status.Reasons()
|
reasons := status.Reasons()
|
||||||
if len(reasons) != 1 || reasons[0] != ErrReasonFake {
|
if len(reasons) != 1 || reasons[0] != st.ErrReasonFake {
|
||||||
t.Errorf("unexpected failure reasons: %v", reasons)
|
t.Errorf("unexpected failure reasons: %v", reasons)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -903,8 +810,8 @@ func TestFindFitSomeError(t *testing.T) {
|
|||||||
scheduler := makeScheduler(nodes)
|
scheduler := makeScheduler(nodes)
|
||||||
prof, err := makeProfile(
|
prof, err := makeProfile(
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterFilterPlugin("MatchFilter", NewMatchFilterPlugin),
|
st.RegisterFilterPlugin("MatchFilter", st.NewMatchFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -932,7 +839,7 @@ func TestFindFitSomeError(t *testing.T) {
|
|||||||
t.Errorf("failed to find node %v in %v", node.Name, nodeToStatusMap)
|
t.Errorf("failed to find node %v in %v", node.Name, nodeToStatusMap)
|
||||||
}
|
}
|
||||||
reasons := status.Reasons()
|
reasons := status.Reasons()
|
||||||
if len(reasons) != 1 || reasons[0] != ErrReasonFake {
|
if len(reasons) != 1 || reasons[0] != st.ErrReasonFake {
|
||||||
t.Errorf("unexpected failures: %v", reasons)
|
t.Errorf("unexpected failures: %v", reasons)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -960,7 +867,7 @@ func TestFindFitPredicateCallCounts(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
nodes := makeNodeList([]string{"1"})
|
nodes := makeNodeList([]string{"1"})
|
||||||
|
|
||||||
plugin := fakeFilterPlugin{}
|
plugin := st.FakeFilterPlugin{}
|
||||||
registerFakeFilterFunc := st.RegisterFilterPlugin(
|
registerFakeFilterFunc := st.RegisterFilterPlugin(
|
||||||
"FakeFilter",
|
"FakeFilter",
|
||||||
func(_ runtime.Object, fh framework.FrameworkHandle) (framework.Plugin, error) {
|
func(_ runtime.Object, fh framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
@ -988,8 +895,8 @@ func TestFindFitPredicateCallCounts(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if test.expectedCount != plugin.numFilterCalled {
|
if test.expectedCount != plugin.NumFilterCalled {
|
||||||
t.Errorf("predicate was called %d times, expected is %d", plugin.numFilterCalled, test.expectedCount)
|
t.Errorf("predicate was called %d times, expected is %d", plugin.NumFilterCalled, test.expectedCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1288,7 +1195,7 @@ func TestSelectNodesForPreemption(t *testing.T) {
|
|||||||
name: "a pod that does not fit on any machine",
|
name: "a pod that does not fit on any machine",
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("FalseFilter", NewFalseFilterPlugin),
|
st.RegisterFilterPlugin("FalseFilter", st.NewFalseFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -1303,7 +1210,7 @@ func TestSelectNodesForPreemption(t *testing.T) {
|
|||||||
name: "a pod that fits with no preemption",
|
name: "a pod that fits with no preemption",
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -1318,7 +1225,7 @@ func TestSelectNodesForPreemption(t *testing.T) {
|
|||||||
name: "a pod that fits on one machine with no preemption",
|
name: "a pod that fits on one machine with no preemption",
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("MatchFilter", NewMatchFilterPlugin),
|
st.RegisterFilterPlugin("MatchFilter", st.NewMatchFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
},
|
},
|
||||||
nodes: []string{"machine1", "machine2"},
|
nodes: []string{"machine1", "machine2"},
|
||||||
@ -1594,8 +1501,8 @@ func TestSelectNodesForPreemption(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For each test, prepend a FakeFilterPlugin.
|
// For each test, prepend a FakeFilterPlugin.
|
||||||
fakePlugin := fakeFilterPlugin{}
|
fakePlugin := st.FakeFilterPlugin{}
|
||||||
fakePlugin.failedNodeReturnCodeMap = filterFailedNodeReturnCodeMap
|
fakePlugin.FailedNodeReturnCodeMap = filterFailedNodeReturnCodeMap
|
||||||
registerFakeFilterFunc := st.RegisterFilterPlugin(
|
registerFakeFilterFunc := st.RegisterFilterPlugin(
|
||||||
"FakeFilter",
|
"FakeFilter",
|
||||||
func(_ runtime.Object, fh framework.FrameworkHandle) (framework.Plugin, error) {
|
func(_ runtime.Object, fh framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
@ -1639,8 +1546,8 @@ func TestSelectNodesForPreemption(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.expectedNumFilterCalled != fakePlugin.numFilterCalled {
|
if test.expectedNumFilterCalled != fakePlugin.NumFilterCalled {
|
||||||
t.Errorf("expected fakePlugin.numFilterCalled is %d, but got %d", test.expectedNumFilterCalled, fakePlugin.numFilterCalled)
|
t.Errorf("expected fakePlugin.numFilterCalled is %d, but got %d", test.expectedNumFilterCalled, fakePlugin.NumFilterCalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkPreemptionVictims(test.expected, nodeToPods); err != nil {
|
if err := checkPreemptionVictims(test.expected, nodeToPods); err != nil {
|
||||||
@ -2062,7 +1969,7 @@ func TestPreempt(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
pod *v1.Pod
|
pod *v1.Pod
|
||||||
pods []*v1.Pod
|
pods []*v1.Pod
|
||||||
extenders []*FakeExtender
|
extenders []*st.FakeExtender
|
||||||
failedNodeToStatusMap framework.NodeToStatusMap
|
failedNodeToStatusMap framework.NodeToStatusMap
|
||||||
nodeNames []string
|
nodeNames []string
|
||||||
registerPlugins []st.RegisterPluginFunc
|
registerPlugins []st.RegisterPluginFunc
|
||||||
@ -2209,12 +2116,12 @@ func TestPreempt(t *testing.T) {
|
|||||||
|
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
||||||
},
|
},
|
||||||
extenders: []*FakeExtender{
|
extenders: []*st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{truePredicateExtender},
|
Predicates: []st.FitPredicate{st.TruePredicateExtender},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{machine1PredicateExtender},
|
Predicates: []st.FitPredicate{st.Machine1PredicateExtender},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
@ -2238,9 +2145,9 @@ func TestPreempt(t *testing.T) {
|
|||||||
|
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
||||||
},
|
},
|
||||||
extenders: []*FakeExtender{
|
extenders: []*st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{falsePredicateExtender},
|
Predicates: []st.FitPredicate{st.FalsePredicateExtender},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
@ -2264,13 +2171,13 @@ func TestPreempt(t *testing.T) {
|
|||||||
|
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
||||||
},
|
},
|
||||||
extenders: []*FakeExtender{
|
extenders: []*st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{errorPredicateExtender},
|
Predicates: []st.FitPredicate{st.ErrorPredicateExtender},
|
||||||
ignorable: true,
|
Ignorable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{machine1PredicateExtender},
|
Predicates: []st.FitPredicate{st.Machine1PredicateExtender},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
@ -2294,13 +2201,13 @@ func TestPreempt(t *testing.T) {
|
|||||||
|
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
||||||
},
|
},
|
||||||
extenders: []*FakeExtender{
|
extenders: []*st.FakeExtender{
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{machine1PredicateExtender},
|
Predicates: []st.FitPredicate{st.Machine1PredicateExtender},
|
||||||
unInterested: true,
|
UnInterested: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicates: []fitPredicate{truePredicateExtender},
|
Predicates: []st.FitPredicate{st.TruePredicateExtender},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
registerPlugins: []st.RegisterPluginFunc{
|
registerPlugins: []st.RegisterPluginFunc{
|
||||||
@ -2399,7 +2306,7 @@ func TestPreempt(t *testing.T) {
|
|||||||
var extenders []framework.Extender
|
var extenders []framework.Extender
|
||||||
for _, extender := range test.extenders {
|
for _, extender := range test.extenders {
|
||||||
// Set nodeInfoMap as extenders cached node information.
|
// Set nodeInfoMap as extenders cached node information.
|
||||||
extender.cachedNodeNameToInfo = cachedNodeInfoMap
|
extender.CachedNodeNameToInfo = cachedNodeInfoMap
|
||||||
extenders = append(extenders, extender)
|
extenders = append(extenders, extender)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2560,7 +2467,7 @@ func TestFairEvaluationForNodes(t *testing.T) {
|
|||||||
g := makeScheduler(nodes)
|
g := makeScheduler(nodes)
|
||||||
prof, err := makeProfile(
|
prof, err := makeProfile(
|
||||||
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
|
||||||
st.RegisterFilterPlugin("TrueFilter", NewTrueFilterPlugin),
|
st.RegisterFilterPlugin("TrueFilter", st.NewTrueFilterPlugin),
|
||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -5,17 +5,23 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"fake_extender.go",
|
||||||
|
"fake_plugins.go",
|
||||||
"framework_helpers.go",
|
"framework_helpers.go",
|
||||||
"workload_prep.go",
|
"workload_prep.go",
|
||||||
"wrappers.go",
|
"wrappers.go",
|
||||||
],
|
],
|
||||||
importpath = "k8s.io/kubernetes/pkg/scheduler/testing",
|
importpath = "k8s.io/kubernetes/pkg/scheduler/testing",
|
||||||
deps = [
|
deps = [
|
||||||
|
"//pkg/api/v1/pod:go_default_library",
|
||||||
"//pkg/scheduler/apis/config:go_default_library",
|
"//pkg/scheduler/apis/config:go_default_library",
|
||||||
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
||||||
|
"//pkg/scheduler/util:go_default_library",
|
||||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kube-scheduler/extender/v1:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
370
pkg/scheduler/testing/fake_extender.go
Normal file
370
pkg/scheduler/testing/fake_extender.go
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Kubernetes Authors.
|
||||||
|
|
||||||
|
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 testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
extenderv1 "k8s.io/kube-scheduler/extender/v1"
|
||||||
|
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||||
|
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FitPredicate is a function type which is used in fake extender.
|
||||||
|
type FitPredicate func(pod *v1.Pod, node *v1.Node) (bool, error)
|
||||||
|
|
||||||
|
// PriorityFunc is a function type which is used in fake extender.
|
||||||
|
type PriorityFunc func(pod *v1.Pod, nodes []*v1.Node) (*framework.NodeScoreList, error)
|
||||||
|
|
||||||
|
// PriorityConfig is used in fake extender to perform Prioritize function.
|
||||||
|
type PriorityConfig struct {
|
||||||
|
Function PriorityFunc
|
||||||
|
Weight int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorPredicateExtender implements FitPredicate function to always return error.
|
||||||
|
func ErrorPredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
||||||
|
return false, fmt.Errorf("some error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FalsePredicateExtender implements FitPredicate function to always return false.
|
||||||
|
func FalsePredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TruePredicateExtender implements FitPredicate function to always return true.
|
||||||
|
func TruePredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine1PredicateExtender implements FitPredicate function to return true
|
||||||
|
// when the given node's name is "machine1"; otherwise return false.
|
||||||
|
func Machine1PredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
||||||
|
if node.Name == "machine1" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine2PredicateExtender implements FitPredicate function to return true
|
||||||
|
// when the given node's name is "machine2"; otherwise return false.
|
||||||
|
func Machine2PredicateExtender(pod *v1.Pod, node *v1.Node) (bool, error) {
|
||||||
|
if node.Name == "machine2" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorPrioritizerExtender implements PriorityFunc function to always return error.
|
||||||
|
func ErrorPrioritizerExtender(pod *v1.Pod, nodes []*v1.Node) (*framework.NodeScoreList, error) {
|
||||||
|
return &framework.NodeScoreList{}, fmt.Errorf("some error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine1PrioritizerExtender implements PriorityFunc function to give score 10
|
||||||
|
// if the given node's name is "machine1"; otherwise score 1.
|
||||||
|
func Machine1PrioritizerExtender(pod *v1.Pod, nodes []*v1.Node) (*framework.NodeScoreList, error) {
|
||||||
|
result := framework.NodeScoreList{}
|
||||||
|
for _, node := range nodes {
|
||||||
|
score := 1
|
||||||
|
if node.Name == "machine1" {
|
||||||
|
score = 10
|
||||||
|
}
|
||||||
|
result = append(result, framework.NodeScore{Name: node.Name, Score: int64(score)})
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine2PrioritizerExtender implements PriorityFunc function to give score 10
|
||||||
|
// if the given node's name is "machine2"; otherwise score 1.
|
||||||
|
func Machine2PrioritizerExtender(pod *v1.Pod, nodes []*v1.Node) (*framework.NodeScoreList, error) {
|
||||||
|
result := framework.NodeScoreList{}
|
||||||
|
for _, node := range nodes {
|
||||||
|
score := 1
|
||||||
|
if node.Name == "machine2" {
|
||||||
|
score = 10
|
||||||
|
}
|
||||||
|
result = append(result, framework.NodeScore{Name: node.Name, Score: int64(score)})
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type machine2PrioritizerPlugin struct{}
|
||||||
|
|
||||||
|
// NewMachine2PrioritizerPlugin returns a factory function to build machine2PrioritizerPlugin.
|
||||||
|
func NewMachine2PrioritizerPlugin() framework.PluginFactory {
|
||||||
|
return func(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
|
return &machine2PrioritizerPlugin{}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns name of the plugin.
|
||||||
|
func (pl *machine2PrioritizerPlugin) Name() string {
|
||||||
|
return "Machine2Prioritizer"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Score return score 100 if the given nodeName is "machine2"; otherwise return score 10.
|
||||||
|
func (pl *machine2PrioritizerPlugin) Score(_ context.Context, _ *framework.CycleState, _ *v1.Pod, nodeName string) (int64, *framework.Status) {
|
||||||
|
score := 10
|
||||||
|
if nodeName == "machine2" {
|
||||||
|
score = 100
|
||||||
|
}
|
||||||
|
return int64(score), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScoreExtensions returns nil.
|
||||||
|
func (pl *machine2PrioritizerPlugin) ScoreExtensions() framework.ScoreExtensions {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FakeExtender is a data struct which implements the Extender interface.
|
||||||
|
type FakeExtender struct {
|
||||||
|
Predicates []FitPredicate
|
||||||
|
Prioritizers []PriorityConfig
|
||||||
|
Weight int64
|
||||||
|
NodeCacheCapable bool
|
||||||
|
FilteredNodes []*v1.Node
|
||||||
|
UnInterested bool
|
||||||
|
Ignorable bool
|
||||||
|
|
||||||
|
// Cached node information for fake extender
|
||||||
|
CachedNodeNameToInfo map[string]*framework.NodeInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns name of the extender.
|
||||||
|
func (f *FakeExtender) Name() string {
|
||||||
|
return "FakeExtender"
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsIgnorable returns a bool value indicating whether internal errors can be ignored.
|
||||||
|
func (f *FakeExtender) IsIgnorable() bool {
|
||||||
|
return f.Ignorable
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportsPreemption returns true indicating the extender supports preemption.
|
||||||
|
func (f *FakeExtender) SupportsPreemption() bool {
|
||||||
|
// Assume preempt verb is always defined.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessPreemption implements the extender preempt function.
|
||||||
|
func (f *FakeExtender) ProcessPreemption(
|
||||||
|
pod *v1.Pod,
|
||||||
|
nodeNameToVictims map[string]*extenderv1.Victims,
|
||||||
|
nodeInfos framework.NodeInfoLister,
|
||||||
|
) (map[string]*extenderv1.Victims, error) {
|
||||||
|
nodeNameToVictimsCopy := map[string]*extenderv1.Victims{}
|
||||||
|
// We don't want to change the original nodeNameToVictims
|
||||||
|
for k, v := range nodeNameToVictims {
|
||||||
|
// In real world implementation, extender's user should have their own way to get node object
|
||||||
|
// by name if needed (e.g. query kube-apiserver etc).
|
||||||
|
//
|
||||||
|
// For test purpose, we just use node from parameters directly.
|
||||||
|
nodeNameToVictimsCopy[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
for nodeName, victims := range nodeNameToVictimsCopy {
|
||||||
|
// Try to do preemption on extender side.
|
||||||
|
nodeInfo, _ := nodeInfos.Get(nodeName)
|
||||||
|
extenderVictimPods, extenderPDBViolations, fits, err := f.selectVictimsOnNodeByExtender(pod, nodeInfo.Node())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// If it's unfit after extender's preemption, this node is unresolvable by preemption overall,
|
||||||
|
// let's remove it from potential preemption nodes.
|
||||||
|
if !fits {
|
||||||
|
delete(nodeNameToVictimsCopy, nodeName)
|
||||||
|
} else {
|
||||||
|
// Append new victims to original victims
|
||||||
|
nodeNameToVictimsCopy[nodeName].Pods = append(victims.Pods, extenderVictimPods...)
|
||||||
|
nodeNameToVictimsCopy[nodeName].NumPDBViolations = victims.NumPDBViolations + int64(extenderPDBViolations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeNameToVictimsCopy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectVictimsOnNodeByExtender checks the given nodes->pods map with predicates on extender's side.
|
||||||
|
// Returns:
|
||||||
|
// 1. More victim pods (if any) amended by preemption phase of extender.
|
||||||
|
// 2. Number of violating victim (used to calculate PDB).
|
||||||
|
// 3. Fits or not after preemption phase on extender's side.
|
||||||
|
func (f *FakeExtender) selectVictimsOnNodeByExtender(pod *v1.Pod, node *v1.Node) ([]*v1.Pod, int, bool, error) {
|
||||||
|
// If a extender support preemption but have no cached node info, let's run filter to make sure
|
||||||
|
// default scheduler's decision still stand with given pod and node.
|
||||||
|
if !f.NodeCacheCapable {
|
||||||
|
fits, err := f.runPredicate(pod, node)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, false, err
|
||||||
|
}
|
||||||
|
if !fits {
|
||||||
|
return nil, 0, false, nil
|
||||||
|
}
|
||||||
|
return []*v1.Pod{}, 0, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, as a extender support preemption and have cached node info, we will assume cachedNodeNameToInfo is available
|
||||||
|
// and get cached node info by given node name.
|
||||||
|
nodeInfoCopy := f.CachedNodeNameToInfo[node.GetName()].Clone()
|
||||||
|
|
||||||
|
var potentialVictims []*v1.Pod
|
||||||
|
|
||||||
|
removePod := func(rp *v1.Pod) {
|
||||||
|
nodeInfoCopy.RemovePod(rp)
|
||||||
|
}
|
||||||
|
addPod := func(ap *v1.Pod) {
|
||||||
|
nodeInfoCopy.AddPod(ap)
|
||||||
|
}
|
||||||
|
// As the first step, remove all the lower priority pods from the node and
|
||||||
|
// check if the given pod can be scheduled.
|
||||||
|
podPriority := podutil.GetPodPriority(pod)
|
||||||
|
for _, p := range nodeInfoCopy.Pods {
|
||||||
|
if podutil.GetPodPriority(p.Pod) < podPriority {
|
||||||
|
potentialVictims = append(potentialVictims, p.Pod)
|
||||||
|
removePod(p.Pod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(potentialVictims, func(i, j int) bool { return util.MoreImportantPod(potentialVictims[i], potentialVictims[j]) })
|
||||||
|
|
||||||
|
// If the new pod does not fit after removing all the lower priority pods,
|
||||||
|
// we are almost done and this node is not suitable for preemption.
|
||||||
|
fits, err := f.runPredicate(pod, nodeInfoCopy.Node())
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, false, err
|
||||||
|
}
|
||||||
|
if !fits {
|
||||||
|
return nil, 0, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var victims []*v1.Pod
|
||||||
|
|
||||||
|
// TODO(harry): handle PDBs in the future.
|
||||||
|
numViolatingVictim := 0
|
||||||
|
|
||||||
|
reprievePod := func(p *v1.Pod) bool {
|
||||||
|
addPod(p)
|
||||||
|
fits, _ := f.runPredicate(pod, nodeInfoCopy.Node())
|
||||||
|
if !fits {
|
||||||
|
removePod(p)
|
||||||
|
victims = append(victims, p)
|
||||||
|
}
|
||||||
|
return fits
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, assume all potential victims to be non-violating.
|
||||||
|
// Now we try to reprieve non-violating victims.
|
||||||
|
for _, p := range potentialVictims {
|
||||||
|
reprievePod(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return victims, numViolatingVictim, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// runPredicate run predicates of extender one by one for given pod and node.
|
||||||
|
// Returns: fits or not.
|
||||||
|
func (f *FakeExtender) runPredicate(pod *v1.Pod, node *v1.Node) (bool, error) {
|
||||||
|
fits := true
|
||||||
|
var err error
|
||||||
|
for _, predicate := range f.Predicates {
|
||||||
|
fits, err = predicate(pod, node)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !fits {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fits, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter implements the extender Filter function.
|
||||||
|
func (f *FakeExtender) Filter(pod *v1.Pod, nodes []*v1.Node) ([]*v1.Node, extenderv1.FailedNodesMap, error) {
|
||||||
|
var filtered []*v1.Node
|
||||||
|
failedNodesMap := extenderv1.FailedNodesMap{}
|
||||||
|
for _, node := range nodes {
|
||||||
|
fits, err := f.runPredicate(pod, node)
|
||||||
|
if err != nil {
|
||||||
|
return []*v1.Node{}, extenderv1.FailedNodesMap{}, err
|
||||||
|
}
|
||||||
|
if fits {
|
||||||
|
filtered = append(filtered, node)
|
||||||
|
} else {
|
||||||
|
failedNodesMap[node.Name] = "FakeExtender failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.FilteredNodes = filtered
|
||||||
|
if f.NodeCacheCapable {
|
||||||
|
return filtered, failedNodesMap, nil
|
||||||
|
}
|
||||||
|
return filtered, failedNodesMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prioritize implements the extender Prioritize function.
|
||||||
|
func (f *FakeExtender) Prioritize(pod *v1.Pod, nodes []*v1.Node) (*extenderv1.HostPriorityList, int64, error) {
|
||||||
|
result := extenderv1.HostPriorityList{}
|
||||||
|
combinedScores := map[string]int64{}
|
||||||
|
for _, prioritizer := range f.Prioritizers {
|
||||||
|
weight := prioritizer.Weight
|
||||||
|
if weight == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
priorityFunc := prioritizer.Function
|
||||||
|
prioritizedList, err := priorityFunc(pod, nodes)
|
||||||
|
if err != nil {
|
||||||
|
return &extenderv1.HostPriorityList{}, 0, err
|
||||||
|
}
|
||||||
|
for _, hostEntry := range *prioritizedList {
|
||||||
|
combinedScores[hostEntry.Name] += hostEntry.Score * weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for host, score := range combinedScores {
|
||||||
|
result = append(result, extenderv1.HostPriority{Host: host, Score: score})
|
||||||
|
}
|
||||||
|
return &result, f.Weight, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind implements the extender Bind function.
|
||||||
|
func (f *FakeExtender) Bind(binding *v1.Binding) error {
|
||||||
|
if len(f.FilteredNodes) != 0 {
|
||||||
|
for _, node := range f.FilteredNodes {
|
||||||
|
if node.Name == binding.Target.Name {
|
||||||
|
f.FilteredNodes = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := fmt.Errorf("Node %v not in filtered nodes %v", binding.Target.Name, f.FilteredNodes)
|
||||||
|
f.FilteredNodes = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBinder returns true indicating the extender implements the Binder function.
|
||||||
|
func (f *FakeExtender) IsBinder() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInterested returns a bool true indicating whether extender
|
||||||
|
func (f *FakeExtender) IsInterested(pod *v1.Pod) bool {
|
||||||
|
return !f.UnInterested
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ framework.Extender = &FakeExtender{}
|
124
pkg/scheduler/testing/fake_plugins.go
Normal file
124
pkg/scheduler/testing/fake_plugins.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Kubernetes Authors.
|
||||||
|
|
||||||
|
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 testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrReasonFake is a fake error message denotes the filter function errored.
|
||||||
|
const ErrReasonFake = "Nodes failed the fake plugin"
|
||||||
|
|
||||||
|
// FalseFilterPlugin is a filter plugin which always return Unschedulable when Filter function is called.
|
||||||
|
type FalseFilterPlugin struct{}
|
||||||
|
|
||||||
|
// Name returns name of the plugin.
|
||||||
|
func (pl *FalseFilterPlugin) Name() string {
|
||||||
|
return "FalseFilter"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter invoked at the filter extension point.
|
||||||
|
func (pl *FalseFilterPlugin) Filter(_ context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
||||||
|
return framework.NewStatus(framework.Unschedulable, ErrReasonFake)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFalseFilterPlugin initializes a FalseFilterPlugin and returns it.
|
||||||
|
func NewFalseFilterPlugin(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
|
return &FalseFilterPlugin{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrueFilterPlugin is a filter plugin which always return Success when Filter function is called.
|
||||||
|
type TrueFilterPlugin struct{}
|
||||||
|
|
||||||
|
// Name returns name of the plugin.
|
||||||
|
func (pl *TrueFilterPlugin) Name() string {
|
||||||
|
return "TrueFilter"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter invoked at the filter extension point.
|
||||||
|
func (pl *TrueFilterPlugin) Filter(_ context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTrueFilterPlugin initializes a TrueFilterPlugin and returns it.
|
||||||
|
func NewTrueFilterPlugin(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
|
return &TrueFilterPlugin{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FakeFilterPlugin is a test filter plugin to record how many times its Filter() function have
|
||||||
|
// been called, and it returns different 'Code' depending on its internal 'failedNodeReturnCodeMap'.
|
||||||
|
type FakeFilterPlugin struct {
|
||||||
|
NumFilterCalled int32
|
||||||
|
FailedNodeReturnCodeMap map[string]framework.Code
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns name of the plugin.
|
||||||
|
func (pl *FakeFilterPlugin) Name() string {
|
||||||
|
return "FakeFilter"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter invoked at the filter extension point.
|
||||||
|
func (pl *FakeFilterPlugin) Filter(_ context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
||||||
|
atomic.AddInt32(&pl.NumFilterCalled, 1)
|
||||||
|
|
||||||
|
if returnCode, ok := pl.FailedNodeReturnCodeMap[nodeInfo.Node().Name]; ok {
|
||||||
|
return framework.NewStatus(returnCode, fmt.Sprintf("injecting failure for pod %v", pod.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFakeFilterPlugin initializes a fakeFilterPlugin and returns it.
|
||||||
|
func NewFakeFilterPlugin(failedNodeReturnCodeMap map[string]framework.Code) framework.PluginFactory {
|
||||||
|
return func(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
|
return &FakeFilterPlugin{
|
||||||
|
FailedNodeReturnCodeMap: failedNodeReturnCodeMap,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchFilterPlugin is a filter plugin which return Success when the evaluated pod and node
|
||||||
|
// have the same name; otherwise return Unschedulable.
|
||||||
|
type MatchFilterPlugin struct{}
|
||||||
|
|
||||||
|
// Name returns name of the plugin.
|
||||||
|
func (pl *MatchFilterPlugin) Name() string {
|
||||||
|
return "MatchFilter"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter invoked at the filter extension point.
|
||||||
|
func (pl *MatchFilterPlugin) Filter(_ context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
||||||
|
node := nodeInfo.Node()
|
||||||
|
if node == nil {
|
||||||
|
return framework.NewStatus(framework.Error, "node not found")
|
||||||
|
}
|
||||||
|
if pod.Name == node.Name {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return framework.NewStatus(framework.Unschedulable, ErrReasonFake)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMatchFilterPlugin initializes a MatchFilterPlugin and returns it.
|
||||||
|
func NewMatchFilterPlugin(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
|
return &MatchFilterPlugin{}, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user