|
|
|
@ -30,6 +30,7 @@ import (
|
|
|
|
|
extensions "k8s.io/api/extensions/v1beta1"
|
|
|
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
|
"k8s.io/apimachinery/pkg/types"
|
|
|
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
|
|
|
|
"k8s.io/kubernetes/pkg/scheduler/algorithm"
|
|
|
|
@ -203,10 +204,10 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Map: EqualPriorityMap, Weight: 1}},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
expectsErr: true,
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
name: "test 1",
|
|
|
|
|
wErr: &FitError{
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
NumAllNodes: 2,
|
|
|
|
|
FailedPredicates: FailedPredicateMap{
|
|
|
|
|
"machine1": []algorithm.PredicateFailureReason{algorithmpredicates.ErrFakePredicate},
|
|
|
|
@ -217,7 +218,7 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Map: EqualPriorityMap, Weight: 1}},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "ignore"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "ignore", UID: types.UID("ignore")}},
|
|
|
|
|
expectedHosts: sets.NewString("machine1", "machine2"),
|
|
|
|
|
name: "test 2",
|
|
|
|
|
wErr: nil,
|
|
|
|
@ -227,7 +228,7 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": matchesPredicate},
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Map: EqualPriorityMap, Weight: 1}},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine2"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine2", UID: types.UID("machine2")}},
|
|
|
|
|
expectedHosts: sets.NewString("machine2"),
|
|
|
|
|
name: "test 3",
|
|
|
|
|
wErr: nil,
|
|
|
|
@ -236,7 +237,7 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Function: numericPriority, Weight: 1}},
|
|
|
|
|
nodes: []string{"3", "2", "1"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "ignore"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "ignore", UID: types.UID("ignore")}},
|
|
|
|
|
expectedHosts: sets.NewString("3"),
|
|
|
|
|
name: "test 4",
|
|
|
|
|
wErr: nil,
|
|
|
|
@ -245,7 +246,7 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": matchesPredicate},
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Function: numericPriority, Weight: 1}},
|
|
|
|
|
nodes: []string{"3", "2", "1"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
expectedHosts: sets.NewString("2"),
|
|
|
|
|
name: "test 5",
|
|
|
|
|
wErr: nil,
|
|
|
|
@ -254,7 +255,7 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Function: numericPriority, Weight: 1}, {Function: reverseNumericPriority, Weight: 2}},
|
|
|
|
|
nodes: []string{"3", "2", "1"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
expectedHosts: sets.NewString("1"),
|
|
|
|
|
name: "test 6",
|
|
|
|
|
wErr: nil,
|
|
|
|
@ -263,11 +264,11 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"true": truePredicate, "false": falsePredicate},
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Function: numericPriority, Weight: 1}},
|
|
|
|
|
nodes: []string{"3", "2", "1"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
expectsErr: true,
|
|
|
|
|
name: "test 7",
|
|
|
|
|
wErr: &FitError{
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
NumAllNodes: 3,
|
|
|
|
|
FailedPredicates: FailedPredicateMap{
|
|
|
|
|
"3": []algorithm.PredicateFailureReason{algorithmpredicates.ErrFakePredicate},
|
|
|
|
@ -283,7 +284,7 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "2"},
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")},
|
|
|
|
|
Spec: v1.PodSpec{
|
|
|
|
|
NodeName: "2",
|
|
|
|
|
},
|
|
|
|
@ -292,13 +293,13 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Function: numericPriority, Weight: 1}},
|
|
|
|
|
nodes: []string{"1", "2"},
|
|
|
|
|
expectsErr: true,
|
|
|
|
|
name: "test 8",
|
|
|
|
|
wErr: &FitError{
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
NumAllNodes: 2,
|
|
|
|
|
FailedPredicates: FailedPredicateMap{
|
|
|
|
|
"1": []algorithm.PredicateFailureReason{algorithmpredicates.ErrFakePredicate},
|
|
|
|
@ -313,7 +314,7 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pvcs: []*v1.PersistentVolumeClaim{{ObjectMeta: metav1.ObjectMeta{Name: "existingPVC"}}},
|
|
|
|
|
pod: &v1.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "ignore"},
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "ignore", UID: types.UID("ignore")},
|
|
|
|
|
Spec: v1.PodSpec{
|
|
|
|
|
Volumes: []v1.Volume{
|
|
|
|
|
{
|
|
|
|
@ -336,7 +337,7 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Map: EqualPriorityMap, Weight: 1}},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "ignore"},
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "ignore", UID: types.UID("ignore")},
|
|
|
|
|
Spec: v1.PodSpec{
|
|
|
|
|
Volumes: []v1.Volume{
|
|
|
|
|
{
|
|
|
|
@ -360,7 +361,7 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pvcs: []*v1.PersistentVolumeClaim{{ObjectMeta: metav1.ObjectMeta{Name: "existingPVC", DeletionTimestamp: &metav1.Time{}}}},
|
|
|
|
|
pod: &v1.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "ignore"},
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "ignore", UID: types.UID("ignore")},
|
|
|
|
|
Spec: v1.PodSpec{
|
|
|
|
|
Volumes: []v1.Volume{
|
|
|
|
|
{
|
|
|
|
@ -383,10 +384,10 @@ func TestGenericScheduler(t *testing.T) {
|
|
|
|
|
prioritizers: []algorithm.PriorityConfig{{Map: EqualPriorityMap, Weight: 1}},
|
|
|
|
|
alwaysCheckAllPredicates: true,
|
|
|
|
|
nodes: []string{"1"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
name: "test alwaysCheckAllPredicates is true",
|
|
|
|
|
wErr: &FitError{
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
NumAllNodes: 1,
|
|
|
|
|
FailedPredicates: FailedPredicateMap{
|
|
|
|
|
"1": []algorithm.PredicateFailureReason{algorithmpredicates.ErrFakePredicate, algorithmpredicates.ErrFakePredicate},
|
|
|
|
@ -455,7 +456,7 @@ func TestFindFitSomeError(t *testing.T) {
|
|
|
|
|
algorithmpredicates.SetPredicatesOrdering(order)
|
|
|
|
|
nodes := []string{"3", "2", "1"}
|
|
|
|
|
predicates := map[string]algorithm.FitPredicate{"true": truePredicate, "matches": matchesPredicate}
|
|
|
|
|
pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "1"}}
|
|
|
|
|
pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "1", UID: types.UID("1")}}
|
|
|
|
|
nodeNameToInfo := map[string]*schedulercache.NodeInfo{
|
|
|
|
|
"3": schedulercache.NewNodeInfo(),
|
|
|
|
|
"2": schedulercache.NewNodeInfo(),
|
|
|
|
@ -509,7 +510,7 @@ func makeNode(node string, milliCPU, memory int64) *v1.Node {
|
|
|
|
|
|
|
|
|
|
func TestHumanReadableFitError(t *testing.T) {
|
|
|
|
|
err := &FitError{
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}},
|
|
|
|
|
Pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2", UID: types.UID("2")}},
|
|
|
|
|
NumAllNodes: 3,
|
|
|
|
|
FailedPredicates: FailedPredicateMap{
|
|
|
|
|
"1": []algorithm.PredicateFailureReason{algorithmpredicates.ErrNodeUnderMemoryPressure},
|
|
|
|
@ -778,74 +779,74 @@ func TestSelectNodesForPreemption(t *testing.T) {
|
|
|
|
|
name: "a pod that does not fit on any machine",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": falsePredicate},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "new"}, Spec: v1.PodSpec{Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "new", UID: types.UID("new")}, Spec: v1.PodSpec{Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a"}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b"}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a", UID: types.UID("a")}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b", UID: types.UID("b")}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: map[string]map[string]bool{},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "a pod that fits with no preemption",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": truePredicate},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "new"}, Spec: v1.PodSpec{Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "new", UID: types.UID("new")}, Spec: v1.PodSpec{Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a"}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b"}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a", UID: types.UID("a")}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b", UID: types.UID("b")}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: map[string]map[string]bool{"machine1": {}, "machine2": {}},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "a pod that fits on one machine with no preemption",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": matchesPredicate},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a"}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b"}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a", UID: types.UID("a")}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b", UID: types.UID("b")}, Spec: v1.PodSpec{Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: map[string]map[string]bool{"machine1": {}},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "a pod that fits on both machines when lower priority pods are preempted",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a", UID: types.UID("a")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b", UID: types.UID("b")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: map[string]map[string]bool{"machine1": {"a": true}, "machine2": {"b": true}},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "a pod that would fit on the machines, but other pods running are higher priority",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &lowPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &lowPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a", UID: types.UID("a")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b", UID: types.UID("b")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: map[string]map[string]bool{},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "medium priority pod is preempted, but lower priority one stays as it is small",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "c"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a", UID: types.UID("a")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b", UID: types.UID("b")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "c", UID: types.UID("c")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: map[string]map[string]bool{"machine1": {"b": true}, "machine2": {"c": true}},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "mixed priority pods are preempted",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "c"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "d"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &highPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "e"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "a", UID: types.UID("a")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b", UID: types.UID("b")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "c", UID: types.UID("c")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "d", UID: types.UID("d")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &highPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "e", UID: types.UID("e")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: map[string]map[string]bool{"machine1": {"b": true, "c": true}},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -873,9 +874,9 @@ func TestSelectNodesForPreemption(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "d"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &highPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "e"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "b", UID: types.UID("b")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "d", UID: types.UID("d")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &highPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "e", UID: types.UID("e")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: map[string]map[string]bool{"machine1": {"a": true}, "machine2": {}},
|
|
|
|
|
addAffinityPredicate: true,
|
|
|
|
|
},
|
|
|
|
@ -916,47 +917,47 @@ func TestPickOneNodeForPreemption(t *testing.T) {
|
|
|
|
|
name: "No node needs preemption",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}}},
|
|
|
|
|
expected: []string{"machine1"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "a pod that fits on both machines when lower priority pods are preempted",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: []string{"machine1", "machine2"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "a pod that fits on a machine with no preemption",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2", "machine3"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}}},
|
|
|
|
|
expected: []string{"machine3"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "machine with min highest priority pod is picked",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2", "machine3"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2", UID: types.UID("m1.2")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.2"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.2", UID: types.UID("m2.2")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine2"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1", UID: types.UID("m3.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2", UID: types.UID("m3.2")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
},
|
|
|
|
|
expected: []string{"machine3"},
|
|
|
|
|
},
|
|
|
|
@ -964,16 +965,16 @@ func TestPickOneNodeForPreemption(t *testing.T) {
|
|
|
|
|
name: "when highest priorities are the same, minimum sum of priorities is picked",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2", "machine3"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2", UID: types.UID("m1.2")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.2"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.2", UID: types.UID("m2.2")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine2"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1", UID: types.UID("m3.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2", UID: types.UID("m3.2")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
},
|
|
|
|
|
expected: []string{"machine2"},
|
|
|
|
|
},
|
|
|
|
@ -981,19 +982,19 @@ func TestPickOneNodeForPreemption(t *testing.T) {
|
|
|
|
|
name: "when highest priority and sum are the same, minimum number of pods is picked",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2", "machine3"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.3"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.4"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2", UID: types.UID("m1.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.3", UID: types.UID("m1.3")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.4", UID: types.UID("m1.4")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine1"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.2"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &negPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.2", UID: types.UID("m2.2")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &negPriority, NodeName: "machine2"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.3"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1", UID: types.UID("m3.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2", UID: types.UID("m3.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.3", UID: types.UID("m3.3")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
},
|
|
|
|
|
expected: []string{"machine2"},
|
|
|
|
|
},
|
|
|
|
@ -1003,18 +1004,18 @@ func TestPickOneNodeForPreemption(t *testing.T) {
|
|
|
|
|
name: "sum of adjusted priorities is considered",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2", "machine3"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &highPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &highPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.3"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2", UID: types.UID("m1.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.3", UID: types.UID("m1.3")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine1"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.2"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &negPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &midPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.2", UID: types.UID("m2.2")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &negPriority, NodeName: "machine2"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.3"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1", UID: types.UID("m3.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2", UID: types.UID("m3.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.3", UID: types.UID("m3.3")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
},
|
|
|
|
|
expected: []string{"machine2"},
|
|
|
|
|
},
|
|
|
|
@ -1022,23 +1023,23 @@ func TestPickOneNodeForPreemption(t *testing.T) {
|
|
|
|
|
name: "non-overlapping lowest high priority, sum priorities, and number of pods",
|
|
|
|
|
predicates: map[string]algorithm.FitPredicate{"matches": algorithmpredicates.PodFitsResources},
|
|
|
|
|
nodes: []string{"machine1", "machine2", "machine3", "machine4"},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &veryHighPriority}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", UID: types.UID("pod1")}, Spec: v1.PodSpec{Containers: veryLargeContainers, Priority: &veryHighPriority}},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.3"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2", UID: types.UID("m1.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.3", UID: types.UID("m1.3")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority, NodeName: "machine2"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority, NodeName: "machine2"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.3"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.4"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1", UID: types.UID("m3.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.2", UID: types.UID("m3.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.3", UID: types.UID("m3.3")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.4", UID: types.UID("m3.4")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &lowPriority, NodeName: "machine3"}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m4.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine4"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m4.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine4"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m4.3"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine4"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m4.4"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine4"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m4.1", UID: types.UID("m4.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine4"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m4.2", UID: types.UID("m4.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine4"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m4.3", UID: types.UID("m4.3")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine4"}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m4.4", UID: types.UID("m4.4")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &negPriority, NodeName: "machine4"}},
|
|
|
|
|
},
|
|
|
|
|
expected: []string{"machine1"},
|
|
|
|
|
},
|
|
|
|
@ -1085,7 +1086,7 @@ func TestNodesWherePreemptionMightHelp(t *testing.T) {
|
|
|
|
|
"machine3": []algorithm.PredicateFailureReason{algorithmpredicates.ErrTaintsTolerationsNotMatch},
|
|
|
|
|
"machine4": []algorithm.PredicateFailureReason{algorithmpredicates.ErrNodeLabelPresenceViolated},
|
|
|
|
|
},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", UID: types.UID("pod1")}},
|
|
|
|
|
expected: map[string]bool{},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -1095,7 +1096,7 @@ func TestNodesWherePreemptionMightHelp(t *testing.T) {
|
|
|
|
|
"machine2": []algorithm.PredicateFailureReason{algorithmpredicates.ErrPodNotMatchHostName},
|
|
|
|
|
"machine3": []algorithm.PredicateFailureReason{algorithmpredicates.ErrNodeUnschedulable},
|
|
|
|
|
},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}, Spec: v1.PodSpec{Affinity: &v1.Affinity{
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", UID: types.UID("pod1")}, Spec: v1.PodSpec{Affinity: &v1.Affinity{
|
|
|
|
|
PodAffinity: &v1.PodAffinity{
|
|
|
|
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
|
|
|
|
{
|
|
|
|
@ -1120,7 +1121,7 @@ func TestNodesWherePreemptionMightHelp(t *testing.T) {
|
|
|
|
|
"machine1": []algorithm.PredicateFailureReason{algorithmpredicates.ErrPodAffinityNotMatch},
|
|
|
|
|
"machine2": []algorithm.PredicateFailureReason{algorithmpredicates.ErrPodNotMatchHostName},
|
|
|
|
|
},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}, Spec: v1.PodSpec{Affinity: &v1.Affinity{
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", UID: types.UID("pod1")}, Spec: v1.PodSpec{Affinity: &v1.Affinity{
|
|
|
|
|
PodAffinity: &v1.PodAffinity{
|
|
|
|
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
|
|
|
|
{
|
|
|
|
@ -1164,7 +1165,7 @@ func TestNodesWherePreemptionMightHelp(t *testing.T) {
|
|
|
|
|
"machine3": []algorithm.PredicateFailureReason{algorithmpredicates.NewInsufficientResourceError(v1.ResourceMemory, 1000, 600, 400)},
|
|
|
|
|
"machine4": []algorithm.PredicateFailureReason{},
|
|
|
|
|
},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}},
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", UID: types.UID("pod1")}},
|
|
|
|
|
expected: map[string]bool{"machine3": true, "machine4": true},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -1203,47 +1204,45 @@ func TestPreempt(t *testing.T) {
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "basic preemption logic",
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}, Spec: v1.PodSpec{
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", UID: types.UID("pod1")}, Spec: v1.PodSpec{
|
|
|
|
|
Containers: veryLargeContainers,
|
|
|
|
|
Priority: &highPriority},
|
|
|
|
|
},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1"}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2", UID: types.UID("m1.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1", UID: types.UID("m2.1")}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m3.1", UID: types.UID("m3.1")}, Spec: v1.PodSpec{Containers: mediumContainers, Priority: &midPriority, NodeName: "machine3"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
},
|
|
|
|
|
expectedNode: "machine1",
|
|
|
|
|
expectedPods: []string{"m1.1", "m1.2"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "One node doesn't need any preemption",
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}, Spec: v1.PodSpec{
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", UID: types.UID("pod1")}, Spec: v1.PodSpec{
|
|
|
|
|
Containers: veryLargeContainers,
|
|
|
|
|
Priority: &highPriority},
|
|
|
|
|
},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2", UID: types.UID("m1.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m2.1"}, Spec: v1.PodSpec{Containers: largeContainers, Priority: &highPriority, 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: &highPriority, NodeName: "machine2"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
},
|
|
|
|
|
expectedNode: "machine3",
|
|
|
|
|
expectedPods: []string{},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "Scheduler extenders allow only machine1, otherwise machine3 would have been chosen",
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}, Spec: v1.PodSpec{
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", UID: types.UID("pod1")}, Spec: v1.PodSpec{
|
|
|
|
|
Containers: veryLargeContainers,
|
|
|
|
|
Priority: &highPriority},
|
|
|
|
|
},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2", UID: types.UID("m1.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "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{
|
|
|
|
|
{
|
|
|
|
@ -1258,15 +1257,15 @@ func TestPreempt(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "Scheduler extenders do not allow any preemption",
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}, Spec: v1.PodSpec{
|
|
|
|
|
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", UID: types.UID("pod1")}, Spec: v1.PodSpec{
|
|
|
|
|
Containers: veryLargeContainers,
|
|
|
|
|
Priority: &highPriority},
|
|
|
|
|
},
|
|
|
|
|
pods: []*v1.Pod{
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2"}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.1", UID: types.UID("m1.1")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &midPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "m1.2", UID: types.UID("m1.2")}, Spec: v1.PodSpec{Containers: smallContainers, Priority: &lowPriority, NodeName: "machine1"}, Status: v1.PodStatus{Phase: v1.PodRunning}},
|
|
|
|
|
|
|
|
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "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{
|
|
|
|
|
{
|
|
|
|
|