2014-09-24 16:32:36 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2014-09-24 16:32:36 +00:00
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 .
* /
2017-01-31 16:03:46 +00:00
package core
2014-09-24 16:32:36 +00:00
import (
"fmt"
2014-11-26 02:10:25 +00:00
"math"
2016-01-06 01:10:59 +00:00
"reflect"
2014-09-24 16:32:36 +00:00
"strconv"
2017-01-05 21:23:23 +00:00
"strings"
2014-09-24 16:32:36 +00:00
"testing"
2016-04-28 14:51:17 +00:00
"time"
2014-09-24 16:32:36 +00:00
2018-07-26 07:38:26 +00:00
apps "k8s.io/api/apps/v1"
2017-06-22 18:24:23 +00:00
"k8s.io/api/core/v1"
2017-01-25 13:13:07 +00:00
"k8s.io/apimachinery/pkg/api/resource"
2017-01-17 03:38:19 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2018-03-12 22:41:25 +00:00
"k8s.io/apimachinery/pkg/types"
2018-09-26 12:16:05 +00:00
"k8s.io/apimachinery/pkg/util/errors"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
2018-01-04 02:12:18 +00:00
"k8s.io/kubernetes/pkg/scheduler/algorithm"
algorithmpredicates "k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
2019-01-08 21:09:11 +00:00
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
2018-01-04 02:12:18 +00:00
priorityutil "k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/util"
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
2019-05-04 10:29:30 +00:00
schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
2019-03-21 00:07:25 +00:00
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
2019-03-22 01:12:33 +00:00
internalcache "k8s.io/kubernetes/pkg/scheduler/internal/cache"
2018-09-21 23:18:48 +00:00
internalqueue "k8s.io/kubernetes/pkg/scheduler/internal/queue"
2018-12-08 02:36:11 +00:00
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
2018-01-04 02:12:18 +00:00
schedulertesting "k8s.io/kubernetes/pkg/scheduler/testing"
2014-09-24 16:32:36 +00:00
)
2017-12-14 00:57:23 +00:00
var (
2018-09-26 12:16:05 +00:00
errPrioritize = fmt . Errorf ( "priority map encounters an error" )
order = [ ] string { "false" , "true" , "matches" , "nopods" , algorithmpredicates . MatchInterPodAffinityPred }
2017-12-14 00:57:23 +00:00
)
2018-12-19 12:30:54 +00:00
func falsePredicate ( pod * v1 . Pod , meta algorithmpredicates . PredicateMetadata , nodeInfo * schedulernodeinfo . NodeInfo ) ( bool , [ ] algorithmpredicates . PredicateFailureReason , error ) {
return false , [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } , nil
2014-09-25 18:56:57 +00:00
}
2018-12-19 12:30:54 +00:00
func truePredicate ( pod * v1 . Pod , meta algorithmpredicates . PredicateMetadata , nodeInfo * schedulernodeinfo . NodeInfo ) ( bool , [ ] algorithmpredicates . PredicateFailureReason , error ) {
2016-08-09 12:01:46 +00:00
return true , nil , nil
2014-09-25 18:56:57 +00:00
}
2018-12-19 12:30:54 +00:00
func matchesPredicate ( pod * v1 . Pod , meta algorithmpredicates . PredicateMetadata , nodeInfo * schedulernodeinfo . NodeInfo ) ( bool , [ ] algorithmpredicates . PredicateFailureReason , error ) {
2016-04-28 14:51:17 +00:00
node := nodeInfo . Node ( )
if node == nil {
2016-08-09 12:01:46 +00:00
return false , nil , fmt . Errorf ( "node not found" )
2016-04-28 14:51:17 +00:00
}
if pod . Name == node . Name {
2016-08-09 12:01:46 +00:00
return true , nil , nil
2016-01-06 01:10:59 +00:00
}
2018-12-19 12:30:54 +00:00
return false , [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } , nil
2014-09-24 16:32:36 +00:00
}
2018-12-19 12:30:54 +00:00
func hasNoPodsPredicate ( pod * v1 . Pod , meta algorithmpredicates . PredicateMetadata , nodeInfo * schedulernodeinfo . NodeInfo ) ( bool , [ ] algorithmpredicates . PredicateFailureReason , error ) {
2016-01-06 01:10:59 +00:00
if len ( nodeInfo . Pods ( ) ) == 0 {
2016-08-09 12:01:46 +00:00
return true , nil , nil
2016-01-06 01:10:59 +00:00
}
2018-12-19 12:30:54 +00:00
return false , [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } , nil
2015-06-10 21:35:59 +00:00
}
2018-12-08 02:36:11 +00:00
func numericPriority ( pod * v1 . Pod , nodeNameToInfo map [ string ] * schedulernodeinfo . NodeInfo , nodes [ ] * v1 . Node ) ( schedulerapi . HostPriorityList , error ) {
2015-09-04 06:50:14 +00:00
result := [ ] schedulerapi . HostPriority { }
2016-07-11 14:55:10 +00:00
for _ , node := range nodes {
2015-09-10 08:40:22 +00:00
score , err := strconv . Atoi ( node . Name )
2014-09-24 16:32:36 +00:00
if err != nil {
return nil , err
}
2015-09-04 06:50:14 +00:00
result = append ( result , schedulerapi . HostPriority {
2015-09-10 08:40:22 +00:00
Host : node . Name ,
2015-05-08 11:01:09 +00:00
Score : score ,
2014-09-24 16:32:36 +00:00
} )
}
return result , nil
}
2018-12-08 02:36:11 +00:00
func reverseNumericPriority ( pod * v1 . Pod , nodeNameToInfo map [ string ] * schedulernodeinfo . NodeInfo , nodes [ ] * v1 . Node ) ( schedulerapi . HostPriorityList , error ) {
2014-11-26 02:10:25 +00:00
var maxScore float64
minScore := math . MaxFloat64
2015-09-04 06:50:14 +00:00
reverseResult := [ ] schedulerapi . HostPriority { }
2016-07-19 12:35:43 +00:00
result , err := numericPriority ( pod , nodeNameToInfo , nodes )
2014-11-26 02:10:25 +00:00
if err != nil {
return nil , err
}
for _ , hostPriority := range result {
2015-05-08 11:01:09 +00:00
maxScore = math . Max ( maxScore , float64 ( hostPriority . Score ) )
minScore = math . Min ( minScore , float64 ( hostPriority . Score ) )
2014-11-26 02:10:25 +00:00
}
for _ , hostPriority := range result {
2015-09-04 06:50:14 +00:00
reverseResult = append ( reverseResult , schedulerapi . HostPriority {
2015-05-08 11:01:09 +00:00
Host : hostPriority . Host ,
Score : int ( maxScore + minScore - float64 ( hostPriority . Score ) ) ,
2014-11-26 02:10:25 +00:00
} )
}
return reverseResult , nil
}
2018-12-08 02:36:11 +00:00
func trueMapPriority ( pod * v1 . Pod , meta interface { } , nodeInfo * schedulernodeinfo . NodeInfo ) ( schedulerapi . HostPriority , error ) {
2018-09-26 12:16:05 +00:00
return schedulerapi . HostPriority {
Host : nodeInfo . Node ( ) . Name ,
Score : 1 ,
} , nil
}
2018-12-08 02:36:11 +00:00
func falseMapPriority ( pod * v1 . Pod , meta interface { } , nodeInfo * schedulernodeinfo . NodeInfo ) ( schedulerapi . HostPriority , error ) {
2018-09-26 12:16:05 +00:00
return schedulerapi . HostPriority { } , errPrioritize
}
2018-12-08 02:36:11 +00:00
func getNodeReducePriority ( pod * v1 . Pod , meta interface { } , nodeNameToInfo map [ string ] * schedulernodeinfo . NodeInfo , result schedulerapi . HostPriorityList ) error {
2018-09-26 12:16:05 +00:00
for _ , host := range result {
if host . Host == "" {
return fmt . Errorf ( "unexpected empty host name" )
}
}
return nil
}
2019-03-21 00:07:25 +00:00
// EmptyPluginRegistry is a test plugin set used by the default scheduler.
var EmptyPluginRegistry = framework . Registry { }
2019-05-04 10:29:30 +00:00
var emptyFramework , _ = framework . NewFramework ( EmptyPluginRegistry , nil , [ ] schedulerconfig . PluginConfig { } )
2018-11-09 02:08:38 +00:00
2016-11-18 20:52:35 +00:00
func makeNodeList ( nodeNames [ ] string ) [ ] * v1 . Node {
result := make ( [ ] * v1 . Node , 0 , len ( nodeNames ) )
2016-07-11 14:55:10 +00:00
for _ , nodeName := range nodeNames {
2017-01-17 03:38:19 +00:00
result = append ( result , & v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : nodeName } } )
2014-10-06 22:58:18 +00:00
}
return result
}
2014-11-06 05:48:42 +00:00
func TestSelectHost ( t * testing . T ) {
2016-05-21 18:36:53 +00:00
scheduler := genericScheduler { }
2014-11-06 05:48:42 +00:00
tests := [ ] struct {
2018-06-01 14:16:50 +00:00
name string
2015-09-04 06:50:14 +00:00
list schedulerapi . HostPriorityList
2015-09-09 17:45:01 +00:00
possibleHosts sets . String
2014-11-07 05:38:41 +00:00
expectsErr bool
2014-11-06 05:48:42 +00:00
} {
{
2018-06-01 14:16:50 +00:00
name : "unique properly ordered scores" ,
2015-09-04 06:50:14 +00:00
list : [ ] schedulerapi . HostPriority {
2015-05-08 11:01:09 +00:00
{ Host : "machine1.1" , Score : 1 } ,
{ Host : "machine2.1" , Score : 2 } ,
2014-11-06 05:48:42 +00:00
} ,
2015-09-09 17:45:01 +00:00
possibleHosts : sets . NewString ( "machine2.1" ) ,
2014-11-07 05:38:41 +00:00
expectsErr : false ,
2014-11-06 05:48:42 +00:00
} ,
{
2018-06-01 14:16:50 +00:00
name : "equal scores" ,
2015-09-04 06:50:14 +00:00
list : [ ] schedulerapi . HostPriority {
2015-05-08 11:01:09 +00:00
{ Host : "machine1.1" , Score : 1 } ,
{ Host : "machine1.2" , Score : 2 } ,
{ Host : "machine1.3" , Score : 2 } ,
{ Host : "machine2.1" , Score : 2 } ,
2014-11-06 05:48:42 +00:00
} ,
2015-09-09 17:45:01 +00:00
possibleHosts : sets . NewString ( "machine1.2" , "machine1.3" , "machine2.1" ) ,
2014-11-07 05:38:41 +00:00
expectsErr : false ,
2014-11-06 05:48:42 +00:00
} ,
{
2018-06-01 14:16:50 +00:00
name : "out of order scores" ,
2015-09-04 06:50:14 +00:00
list : [ ] schedulerapi . HostPriority {
2015-05-08 11:01:09 +00:00
{ Host : "machine1.1" , Score : 3 } ,
{ Host : "machine1.2" , Score : 3 } ,
{ Host : "machine2.1" , Score : 2 } ,
{ Host : "machine3.1" , Score : 1 } ,
{ Host : "machine1.3" , Score : 3 } ,
2014-11-06 05:48:42 +00:00
} ,
2015-09-09 17:45:01 +00:00
possibleHosts : sets . NewString ( "machine1.1" , "machine1.2" , "machine1.3" ) ,
2014-11-07 05:38:41 +00:00
expectsErr : false ,
} ,
{
2018-06-01 14:16:50 +00:00
name : "empty priority list" ,
2015-09-04 06:50:14 +00:00
list : [ ] schedulerapi . HostPriority { } ,
2015-09-09 17:45:01 +00:00
possibleHosts : sets . NewString ( ) ,
2014-11-07 05:38:41 +00:00
expectsErr : true ,
2014-11-06 05:48:42 +00:00
} ,
}
for _ , test := range tests {
2018-06-01 14:16:50 +00:00
t . Run ( test . name , func ( t * testing . T ) {
// increase the randomness
for i := 0 ; i < 10 ; i ++ {
got , err := scheduler . selectHost ( test . list )
if test . expectsErr {
if err == nil {
t . Error ( "Unexpected non-error" )
}
} else {
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if ! test . possibleHosts . Has ( got ) {
t . Errorf ( "got %s is not in the possible map %v" , got , test . possibleHosts )
}
2014-11-07 05:38:41 +00:00
}
2014-11-06 05:48:42 +00:00
}
2018-06-01 14:16:50 +00:00
} )
2014-11-06 05:48:42 +00:00
}
}
2014-09-24 16:32:36 +00:00
func TestGenericScheduler ( t * testing . T ) {
2019-05-09 01:03:58 +00:00
defer algorithmpredicates . SetPredicatesOrderingDuringTest ( order ) ( )
2014-09-24 16:32:36 +00:00
tests := [ ] struct {
2017-12-21 15:03:46 +00:00
name string
2018-12-19 12:30:54 +00:00
predicates map [ string ] algorithmpredicates . FitPredicate
2019-01-08 21:09:11 +00:00
prioritizers [ ] priorities . PriorityConfig
2017-12-21 15:03:46 +00:00
alwaysCheckAllPredicates bool
nodes [ ] string
pvcs [ ] * v1 . PersistentVolumeClaim
pod * v1 . Pod
pods [ ] * v1 . Pod
expectedHosts sets . String
expectsErr bool
wErr error
2014-09-24 16:32:36 +00:00
} {
{
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "false" : falsePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Map : EqualPriorityMap , Weight : 1 } } ,
2014-11-20 22:42:31 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
expectsErr : true ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2014-11-26 02:10:25 +00:00
name : "test 1" ,
2016-07-20 12:46:50 +00:00
wErr : & FitError {
2018-03-12 22:41:25 +00:00
Pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2017-10-06 13:58:59 +00:00
NumAllNodes : 2 ,
2016-07-20 12:46:50 +00:00
FailedPredicates : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } ,
2016-07-20 12:46:50 +00:00
} } ,
2014-09-24 16:32:36 +00:00
} ,
{
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Map : EqualPriorityMap , Weight : 1 } } ,
2016-01-21 02:39:59 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "ignore" , UID : types . UID ( "ignore" ) } } ,
2016-01-21 02:39:59 +00:00
expectedHosts : sets . NewString ( "machine1" , "machine2" ) ,
name : "test 2" ,
2016-01-06 01:10:59 +00:00
wErr : nil ,
2014-09-24 16:32:36 +00:00
} ,
{
2014-09-24 21:18:31 +00:00
// Fits on a machine where the pod ID matches the machine name
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : matchesPredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Map : EqualPriorityMap , Weight : 1 } } ,
2016-01-21 02:39:59 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine2" , UID : types . UID ( "machine2" ) } } ,
2016-01-21 02:39:59 +00:00
expectedHosts : sets . NewString ( "machine2" ) ,
name : "test 3" ,
2016-01-06 01:10:59 +00:00
wErr : nil ,
2014-09-24 16:32:36 +00:00
} ,
{
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Function : numericPriority , Weight : 1 } } ,
2016-01-21 02:39:59 +00:00
nodes : [ ] string { "3" , "2" , "1" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "ignore" , UID : types . UID ( "ignore" ) } } ,
2016-01-21 02:39:59 +00:00
expectedHosts : sets . NewString ( "3" ) ,
name : "test 4" ,
2016-01-06 01:10:59 +00:00
wErr : nil ,
2014-09-24 16:32:36 +00:00
} ,
{
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : matchesPredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Function : numericPriority , Weight : 1 } } ,
2016-01-21 02:39:59 +00:00
nodes : [ ] string { "3" , "2" , "1" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2016-01-21 02:39:59 +00:00
expectedHosts : sets . NewString ( "2" ) ,
name : "test 5" ,
2016-01-06 01:10:59 +00:00
wErr : nil ,
2014-11-26 02:10:25 +00:00
} ,
{
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Function : numericPriority , Weight : 1 } , { Function : reverseNumericPriority , Weight : 2 } } ,
2016-01-21 02:39:59 +00:00
nodes : [ ] string { "3" , "2" , "1" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2016-01-21 02:39:59 +00:00
expectedHosts : sets . NewString ( "1" ) ,
name : "test 6" ,
2016-01-06 01:10:59 +00:00
wErr : nil ,
2014-09-24 16:32:36 +00:00
} ,
{
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate , "false" : falsePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Function : numericPriority , Weight : 1 } } ,
2014-11-20 22:42:31 +00:00
nodes : [ ] string { "3" , "2" , "1" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2014-11-20 22:42:31 +00:00
expectsErr : true ,
2014-11-26 02:10:25 +00:00
name : "test 7" ,
2016-07-20 12:46:50 +00:00
wErr : & FitError {
2018-03-12 22:41:25 +00:00
Pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2017-10-06 13:58:59 +00:00
NumAllNodes : 3 ,
2016-07-20 12:46:50 +00:00
FailedPredicates : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"3" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } ,
"2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } ,
"1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } ,
2016-07-20 12:46:50 +00:00
} ,
} ,
2014-09-24 16:32:36 +00:00
} ,
2015-06-10 21:35:59 +00:00
{
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate {
2015-06-10 21:35:59 +00:00
"nopods" : hasNoPodsPredicate ,
"matches" : matchesPredicate ,
} ,
2016-11-18 20:52:35 +00:00
pods : [ ] * v1 . Pod {
2015-06-10 21:35:59 +00:00
{
2018-03-12 22:41:25 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } ,
2016-11-18 20:52:35 +00:00
Spec : v1 . PodSpec {
2015-06-10 21:35:59 +00:00
NodeName : "2" ,
} ,
2016-11-18 20:52:35 +00:00
Status : v1 . PodStatus {
Phase : v1 . PodRunning ,
2015-06-10 21:35:59 +00:00
} ,
} ,
} ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Function : numericPriority , Weight : 1 } } ,
2015-06-10 21:35:59 +00:00
nodes : [ ] string { "1" , "2" } ,
expectsErr : true ,
name : "test 8" ,
2016-07-20 12:46:50 +00:00
wErr : & FitError {
2018-03-12 22:41:25 +00:00
Pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2017-10-06 13:58:59 +00:00
NumAllNodes : 2 ,
2016-07-20 12:46:50 +00:00
FailedPredicates : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } ,
"2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate } ,
2016-07-20 12:46:50 +00:00
} ,
} ,
2015-06-10 21:35:59 +00:00
} ,
2017-11-23 09:01:23 +00:00
{
// Pod with existing PVC
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Map : EqualPriorityMap , Weight : 1 } } ,
2017-11-23 09:01:23 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
pvcs : [ ] * v1 . PersistentVolumeClaim { { ObjectMeta : metav1 . ObjectMeta { Name : "existingPVC" } } } ,
pod : & v1 . Pod {
2018-03-12 22:41:25 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "ignore" , UID : types . UID ( "ignore" ) } ,
2017-11-23 09:01:23 +00:00
Spec : v1 . PodSpec {
Volumes : [ ] v1 . Volume {
{
VolumeSource : v1 . VolumeSource {
PersistentVolumeClaim : & v1 . PersistentVolumeClaimVolumeSource {
ClaimName : "existingPVC" ,
} ,
} ,
} ,
} ,
} ,
} ,
expectedHosts : sets . NewString ( "machine1" , "machine2" ) ,
name : "existing PVC" ,
wErr : nil ,
} ,
{
// Pod with non existing PVC
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Map : EqualPriorityMap , Weight : 1 } } ,
2017-11-23 09:01:23 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
pod : & v1 . Pod {
2018-03-12 22:41:25 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "ignore" , UID : types . UID ( "ignore" ) } ,
2017-11-23 09:01:23 +00:00
Spec : v1 . PodSpec {
Volumes : [ ] v1 . Volume {
{
VolumeSource : v1 . VolumeSource {
PersistentVolumeClaim : & v1 . PersistentVolumeClaimVolumeSource {
ClaimName : "unknownPVC" ,
} ,
} ,
} ,
} ,
} ,
} ,
name : "unknown PVC" ,
expectsErr : true ,
wErr : fmt . Errorf ( "persistentvolumeclaim \"unknownPVC\" not found" ) ,
} ,
{
// Pod with deleting PVC
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Map : EqualPriorityMap , Weight : 1 } } ,
2017-11-23 09:01:23 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
pvcs : [ ] * v1 . PersistentVolumeClaim { { ObjectMeta : metav1 . ObjectMeta { Name : "existingPVC" , DeletionTimestamp : & metav1 . Time { } } } } ,
pod : & v1 . Pod {
2018-03-12 22:41:25 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "ignore" , UID : types . UID ( "ignore" ) } ,
2017-11-23 09:01:23 +00:00
Spec : v1 . PodSpec {
Volumes : [ ] v1 . Volume {
{
VolumeSource : v1 . VolumeSource {
PersistentVolumeClaim : & v1 . PersistentVolumeClaimVolumeSource {
ClaimName : "existingPVC" ,
} ,
} ,
} ,
} ,
} ,
} ,
name : "deleted PVC" ,
expectsErr : true ,
wErr : fmt . Errorf ( "persistentvolumeclaim \"existingPVC\" is being deleted" ) ,
} ,
2017-12-21 15:03:46 +00:00
{
// alwaysCheckAllPredicates is true
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate , "matches" : matchesPredicate , "false" : falsePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Map : EqualPriorityMap , Weight : 1 } } ,
2017-12-21 15:03:46 +00:00
alwaysCheckAllPredicates : true ,
2019-05-30 22:28:21 +00:00
nodes : [ ] string { "1" } ,
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
name : "test alwaysCheckAllPredicates is true" ,
2017-12-21 15:03:46 +00:00
wErr : & FitError {
2018-03-12 22:41:25 +00:00
Pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2017-12-21 15:03:46 +00:00
NumAllNodes : 1 ,
FailedPredicates : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrFakePredicate , algorithmpredicates . ErrFakePredicate } ,
2017-12-21 15:03:46 +00:00
} ,
} ,
} ,
2018-09-26 12:16:05 +00:00
{
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate } ,
2019-01-08 21:09:11 +00:00
prioritizers : [ ] priorities . PriorityConfig { { Map : falseMapPriority , Weight : 1 } , { Map : trueMapPriority , Reduce : getNodeReducePriority , Weight : 2 } } ,
2018-09-26 12:16:05 +00:00
nodes : [ ] string { "2" , "1" } ,
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" } } ,
name : "test error with priority map" ,
wErr : errors . NewAggregate ( [ ] error { errPrioritize , errPrioritize } ) ,
} ,
2014-09-24 16:32:36 +00:00
}
for _ , test := range tests {
2018-06-01 14:16:50 +00:00
t . Run ( test . name , func ( t * testing . T ) {
2019-03-22 01:12:33 +00:00
cache := internalcache . New ( time . Duration ( 0 ) , wait . NeverStop )
2018-06-01 14:16:50 +00:00
for _ , pod := range test . pods {
cache . AddPod ( pod )
}
for _ , name := range test . nodes {
cache . AddNode ( & v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : name } } )
}
pvcs := [ ] * v1 . PersistentVolumeClaim { }
pvcs = append ( pvcs , test . pvcs ... )
pvcLister := schedulertesting . FakePersistentVolumeClaimLister ( pvcs )
scheduler := NewGenericScheduler (
cache ,
2019-05-07 01:03:00 +00:00
internalqueue . NewSchedulingQueue ( nil , nil ) ,
2018-06-01 14:16:50 +00:00
test . predicates ,
2018-12-19 12:30:54 +00:00
algorithmpredicates . EmptyPredicateMetadataProducer ,
2018-06-01 14:16:50 +00:00
test . prioritizers ,
2019-01-08 21:09:11 +00:00
priorities . EmptyPriorityMetadataProducer ,
2019-05-04 10:29:30 +00:00
emptyFramework ,
2018-06-01 14:16:50 +00:00
[ ] algorithm . SchedulerExtender { } ,
nil ,
pvcLister ,
2018-09-19 00:05:48 +00:00
schedulertesting . FakePDBLister { } ,
2018-06-01 14:16:50 +00:00
test . alwaysCheckAllPredicates ,
2018-07-28 00:17:09 +00:00
false ,
2019-05-30 22:28:21 +00:00
schedulerapi . DefaultPercentageOfNodesToScore ,
false )
2018-12-07 03:40:45 +00:00
result , err := scheduler . Schedule ( test . pod , schedulertesting . FakeNodeLister ( makeNodeList ( test . nodes ) ) )
2018-06-01 14:16:50 +00:00
if ! reflect . DeepEqual ( err , test . wErr ) {
t . Errorf ( "Unexpected error: %v, expected: %v" , err , test . wErr )
}
2018-12-07 03:40:45 +00:00
if test . expectedHosts != nil && ! test . expectedHosts . Has ( result . SuggestedHost ) {
t . Errorf ( "Expected: %s, got: %s" , test . expectedHosts , result . SuggestedHost )
2018-06-01 14:16:50 +00:00
}
} )
2014-09-24 16:32:36 +00:00
}
}
2015-02-24 04:36:22 +00:00
2018-04-23 21:24:00 +00:00
// makeScheduler makes a simple genericScheduler for testing.
2018-12-19 12:30:54 +00:00
func makeScheduler ( predicates map [ string ] algorithmpredicates . FitPredicate , nodes [ ] * v1 . Node ) * genericScheduler {
2019-03-22 01:12:33 +00:00
cache := internalcache . New ( time . Duration ( 0 ) , wait . NeverStop )
2018-04-23 21:24:00 +00:00
for _ , n := range nodes {
cache . AddNode ( n )
2015-12-10 19:30:30 +00:00
}
2019-01-08 21:09:11 +00:00
prioritizers := [ ] priorities . PriorityConfig { { Map : EqualPriorityMap , Weight : 1 } }
2018-04-23 21:24:00 +00:00
s := NewGenericScheduler (
cache ,
2019-05-07 01:03:00 +00:00
internalqueue . NewSchedulingQueue ( nil , nil ) ,
2018-04-23 21:24:00 +00:00
predicates ,
2018-12-19 12:30:54 +00:00
algorithmpredicates . EmptyPredicateMetadataProducer ,
2018-04-23 21:24:00 +00:00
prioritizers ,
2019-01-08 21:09:11 +00:00
priorities . EmptyPriorityMetadataProducer ,
2019-05-04 10:29:30 +00:00
emptyFramework ,
2019-05-30 22:28:21 +00:00
nil , nil , nil , nil , false , false ,
schedulerapi . DefaultPercentageOfNodesToScore , false )
2019-03-21 00:07:25 +00:00
cache . UpdateNodeInfoSnapshot ( s . ( * genericScheduler ) . nodeInfoSnapshot )
2018-04-23 21:24:00 +00:00
return s . ( * genericScheduler )
}
func TestFindFitAllError ( t * testing . T ) {
2019-05-09 01:03:58 +00:00
defer algorithmpredicates . SetPredicatesOrderingDuringTest ( order ) ( )
2018-12-19 12:30:54 +00:00
predicates := map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate , "matches" : matchesPredicate }
2018-04-23 21:24:00 +00:00
nodes := makeNodeList ( [ ] string { "3" , "2" , "1" } )
scheduler := makeScheduler ( predicates , nodes )
_ , predicateMap , err := scheduler . findNodesThatFit ( & v1 . Pod { } , nodes )
2015-02-24 04:36:22 +00:00
if err != nil {
2015-03-31 22:32:02 +00:00
t . Errorf ( "unexpected error: %v" , err )
2015-02-24 04:36:22 +00:00
}
if len ( predicateMap ) != len ( nodes ) {
t . Errorf ( "unexpected failed predicate map: %v" , predicateMap )
}
for _ , node := range nodes {
2018-06-01 14:16:50 +00:00
t . Run ( node . Name , func ( t * testing . T ) {
failures , found := predicateMap [ node . Name ]
if ! found {
t . Errorf ( "failed to find node in %v" , predicateMap )
}
if len ( failures ) != 1 || failures [ 0 ] != algorithmpredicates . ErrFakePredicate {
t . Errorf ( "unexpected failures: %v" , failures )
}
} )
2015-02-24 04:36:22 +00:00
}
}
func TestFindFitSomeError ( t * testing . T ) {
2019-05-09 01:03:58 +00:00
defer algorithmpredicates . SetPredicatesOrderingDuringTest ( order ) ( )
2018-12-19 12:30:54 +00:00
predicates := map [ string ] algorithmpredicates . FitPredicate { "true" : truePredicate , "matches" : matchesPredicate }
2018-04-23 21:24:00 +00:00
nodes := makeNodeList ( [ ] string { "3" , "2" , "1" } )
scheduler := makeScheduler ( predicates , nodes )
2018-03-12 22:41:25 +00:00
pod := & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "1" , UID : types . UID ( "1" ) } }
2018-04-23 21:24:00 +00:00
_ , predicateMap , err := scheduler . findNodesThatFit ( pod , nodes )
2015-02-24 04:36:22 +00:00
2016-08-09 12:01:46 +00:00
if err != nil {
2015-03-31 22:32:02 +00:00
t . Errorf ( "unexpected error: %v" , err )
2015-02-24 04:36:22 +00:00
}
if len ( predicateMap ) != ( len ( nodes ) - 1 ) {
t . Errorf ( "unexpected failed predicate map: %v" , predicateMap )
}
for _ , node := range nodes {
2018-04-23 21:24:00 +00:00
if node . Name == pod . Name {
2015-02-24 04:36:22 +00:00
continue
}
2018-06-01 14:16:50 +00:00
t . Run ( node . Name , func ( t * testing . T ) {
failures , found := predicateMap [ node . Name ]
if ! found {
t . Errorf ( "failed to find node in %v" , predicateMap )
}
if len ( failures ) != 1 || failures [ 0 ] != algorithmpredicates . ErrFakePredicate {
t . Errorf ( "unexpected failures: %v" , failures )
}
} )
2015-02-24 04:36:22 +00:00
}
}
2016-08-26 14:08:40 +00:00
2016-11-18 20:52:35 +00:00
func makeNode ( node string , milliCPU , memory int64 ) * v1 . Node {
return & v1 . Node {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : node } ,
2016-11-18 20:52:35 +00:00
Status : v1 . NodeStatus {
Capacity : v1 . ResourceList {
2017-08-15 07:56:18 +00:00
v1 . ResourceCPU : * resource . NewMilliQuantity ( milliCPU , resource . DecimalSI ) ,
v1 . ResourceMemory : * resource . NewQuantity ( memory , resource . BinarySI ) ,
2017-08-03 01:20:45 +00:00
"pods" : * resource . NewQuantity ( 100 , resource . DecimalSI ) ,
2016-08-26 14:08:40 +00:00
} ,
2016-11-18 20:52:35 +00:00
Allocatable : v1 . ResourceList {
2017-08-03 01:20:45 +00:00
2017-08-15 07:56:18 +00:00
v1 . ResourceCPU : * resource . NewMilliQuantity ( milliCPU , resource . DecimalSI ) ,
v1 . ResourceMemory : * resource . NewQuantity ( memory , resource . BinarySI ) ,
2017-08-03 01:20:45 +00:00
"pods" : * resource . NewQuantity ( 100 , resource . DecimalSI ) ,
2016-08-26 14:08:40 +00:00
} ,
} ,
}
}
2017-01-05 21:23:23 +00:00
func TestHumanReadableFitError ( t * testing . T ) {
2017-06-13 07:32:30 +00:00
err := & FitError {
2018-03-12 22:41:25 +00:00
Pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "2" , UID : types . UID ( "2" ) } } ,
2017-10-06 13:58:59 +00:00
NumAllNodes : 3 ,
2017-01-05 21:23:23 +00:00
FailedPredicates : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeUnderMemoryPressure } ,
"2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeUnderDiskPressure } ,
"3" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeUnderDiskPressure } ,
2017-01-05 21:23:23 +00:00
} ,
}
2017-10-06 13:58:59 +00:00
if strings . Contains ( err . Error ( ) , "0/3 nodes are available" ) {
2018-01-30 01:04:58 +00:00
if strings . Contains ( err . Error ( ) , "2 node(s) had disk pressure" ) && strings . Contains ( err . Error ( ) , "1 node(s) had memory pressure" ) {
2017-01-05 21:23:23 +00:00
return
}
}
2017-06-13 07:32:30 +00:00
t . Errorf ( "Error message doesn't have all the information content: [" + err . Error ( ) + "]" )
2017-01-05 21:23:23 +00:00
}
2016-08-26 14:08:40 +00:00
// The point of this test is to show that you:
// - get the same priority for a zero-request pod as for a pod with the defaults requests,
// both when the zero-request pod is already on the machine and when the zero-request pod
// is the one being scheduled.
// - don't get the same score no matter what we schedule.
func TestZeroRequest ( t * testing . T ) {
// A pod with no resources. We expect spreading to count it as having the default resources.
2016-11-18 20:52:35 +00:00
noResources := v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-08-26 14:08:40 +00:00
{ } ,
} ,
}
noResources1 := noResources
noResources1 . NodeName = "machine1"
// A pod with the same resources as a 0-request pod gets by default as its resources (for spreading).
2016-11-18 20:52:35 +00:00
small := v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-08-26 14:08:40 +00:00
{
2016-11-18 20:52:35 +00:00
Resources : v1 . ResourceRequirements {
Requests : v1 . ResourceList {
2017-08-15 07:56:18 +00:00
v1 . ResourceCPU : resource . MustParse (
2018-02-08 06:42:19 +00:00
strconv . FormatInt ( priorityutil . DefaultMilliCPURequest , 10 ) + "m" ) ,
2017-08-15 07:56:18 +00:00
v1 . ResourceMemory : resource . MustParse (
2016-08-26 14:08:40 +00:00
strconv . FormatInt ( priorityutil . DefaultMemoryRequest , 10 ) ) ,
} ,
} ,
} ,
} ,
}
small2 := small
small2 . NodeName = "machine2"
// A larger pod.
2016-11-18 20:52:35 +00:00
large := v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-08-26 14:08:40 +00:00
{
2016-11-18 20:52:35 +00:00
Resources : v1 . ResourceRequirements {
Requests : v1 . ResourceList {
2017-08-15 07:56:18 +00:00
v1 . ResourceCPU : resource . MustParse (
2018-02-08 06:42:19 +00:00
strconv . FormatInt ( priorityutil . DefaultMilliCPURequest * 3 , 10 ) + "m" ) ,
2017-08-15 07:56:18 +00:00
v1 . ResourceMemory : resource . MustParse (
2016-08-26 14:08:40 +00:00
strconv . FormatInt ( priorityutil . DefaultMemoryRequest * 3 , 10 ) ) ,
} ,
} ,
} ,
} ,
}
large1 := large
large1 . NodeName = "machine1"
large2 := large
large2 . NodeName = "machine2"
tests := [ ] struct {
2018-07-21 15:51:33 +00:00
pod * v1 . Pod
pods [ ] * v1 . Pod
nodes [ ] * v1 . Node
name string
expectedScore int
2016-08-26 14:08:40 +00:00
} {
// The point of these next two tests is to show you get the same priority for a zero-request pod
// as for a pod with the defaults requests, both when the zero-request pod is already on the machine
// and when the zero-request pod is the one being scheduled.
{
2016-11-18 20:52:35 +00:00
pod : & v1 . Pod { Spec : noResources } ,
nodes : [ ] * v1 . Node { makeNode ( "machine1" , 1000 , priorityutil . DefaultMemoryRequest * 10 ) , makeNode ( "machine2" , 1000 , priorityutil . DefaultMemoryRequest * 10 ) } ,
2018-06-01 14:16:50 +00:00
name : "test priority of zero-request pod with machine with zero-request pod" ,
2016-11-18 20:52:35 +00:00
pods : [ ] * v1 . Pod {
2016-08-26 14:08:40 +00:00
{ Spec : large1 } , { Spec : noResources1 } ,
{ Spec : large2 } , { Spec : small2 } ,
} ,
2018-07-21 15:51:33 +00:00
expectedScore : 25 ,
2016-08-26 14:08:40 +00:00
} ,
{
2016-11-18 20:52:35 +00:00
pod : & v1 . Pod { Spec : small } ,
nodes : [ ] * v1 . Node { makeNode ( "machine1" , 1000 , priorityutil . DefaultMemoryRequest * 10 ) , makeNode ( "machine2" , 1000 , priorityutil . DefaultMemoryRequest * 10 ) } ,
2018-06-01 14:16:50 +00:00
name : "test priority of nonzero-request pod with machine with zero-request pod" ,
2016-11-18 20:52:35 +00:00
pods : [ ] * v1 . Pod {
2016-08-26 14:08:40 +00:00
{ Spec : large1 } , { Spec : noResources1 } ,
{ Spec : large2 } , { Spec : small2 } ,
} ,
2018-07-21 15:51:33 +00:00
expectedScore : 25 ,
2016-08-26 14:08:40 +00:00
} ,
// The point of this test is to verify that we're not just getting the same score no matter what we schedule.
{
2016-11-18 20:52:35 +00:00
pod : & v1 . Pod { Spec : large } ,
nodes : [ ] * v1 . Node { makeNode ( "machine1" , 1000 , priorityutil . DefaultMemoryRequest * 10 ) , makeNode ( "machine2" , 1000 , priorityutil . DefaultMemoryRequest * 10 ) } ,
2018-06-01 14:16:50 +00:00
name : "test priority of larger pod with machine with zero-request pod" ,
2016-11-18 20:52:35 +00:00
pods : [ ] * v1 . Pod {
2016-08-26 14:08:40 +00:00
{ Spec : large1 } , { Spec : noResources1 } ,
{ Spec : large2 } , { Spec : small2 } ,
} ,
2018-07-21 15:51:33 +00:00
expectedScore : 23 ,
2016-08-26 14:08:40 +00:00
} ,
}
for _ , test := range tests {
2018-06-01 14:16:50 +00:00
t . Run ( test . name , func ( t * testing . T ) {
// This should match the configuration in defaultPriorities() in
// pkg/scheduler/algorithmprovider/defaults/defaults.go if you want
// to test what's actually in production.
2019-01-08 21:09:11 +00:00
priorityConfigs := [ ] priorities . PriorityConfig {
{ Map : priorities . LeastRequestedPriorityMap , Weight : 1 } ,
{ Map : priorities . BalancedResourceAllocationMap , Weight : 1 } ,
2018-06-01 14:16:50 +00:00
}
2019-01-08 21:09:11 +00:00
selectorSpreadPriorityMap , selectorSpreadPriorityReduce := priorities . NewSelectorSpreadPriority (
2018-06-01 14:16:50 +00:00
schedulertesting . FakeServiceLister ( [ ] * v1 . Service { } ) ,
schedulertesting . FakeControllerLister ( [ ] * v1 . ReplicationController { } ) ,
2018-07-26 07:38:26 +00:00
schedulertesting . FakeReplicaSetLister ( [ ] * apps . ReplicaSet { } ) ,
2018-06-01 14:16:50 +00:00
schedulertesting . FakeStatefulSetLister ( [ ] * apps . StatefulSet { } ) )
2019-01-08 21:09:11 +00:00
pc := priorities . PriorityConfig { Map : selectorSpreadPriorityMap , Reduce : selectorSpreadPriorityReduce , Weight : 1 }
2018-06-01 14:16:50 +00:00
priorityConfigs = append ( priorityConfigs , pc )
2018-12-08 02:36:11 +00:00
nodeNameToInfo := schedulernodeinfo . CreateNodeNameToInfoMap ( test . pods , test . nodes )
2018-06-01 14:16:50 +00:00
2019-01-08 21:09:11 +00:00
metaDataProducer := priorities . NewPriorityMetadataFactory (
2018-06-01 14:16:50 +00:00
schedulertesting . FakeServiceLister ( [ ] * v1 . Service { } ) ,
schedulertesting . FakeControllerLister ( [ ] * v1 . ReplicationController { } ) ,
2018-07-26 07:38:26 +00:00
schedulertesting . FakeReplicaSetLister ( [ ] * apps . ReplicaSet { } ) ,
2018-06-01 14:16:50 +00:00
schedulertesting . FakeStatefulSetLister ( [ ] * apps . StatefulSet { } ) )
2018-11-02 04:08:49 +00:00
metaData := metaDataProducer ( test . pod , nodeNameToInfo )
2018-06-01 14:16:50 +00:00
list , err := PrioritizeNodes (
2018-11-02 04:08:49 +00:00
test . pod , nodeNameToInfo , metaData , priorityConfigs ,
2018-06-01 14:16:50 +00:00
schedulertesting . FakeNodeLister ( test . nodes ) , [ ] algorithm . SchedulerExtender { } )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
for _ , hp := range list {
2018-07-21 15:51:33 +00:00
if hp . Score != test . expectedScore {
t . Errorf ( "expected %d for all priorities, got list %#v" , test . expectedScore , list )
2016-08-26 14:08:40 +00:00
}
}
2018-06-01 14:16:50 +00:00
} )
2016-08-26 14:08:40 +00:00
}
}
2017-08-03 01:20:45 +00:00
2017-11-17 02:21:03 +00:00
func printNodeToVictims ( nodeToVictims map [ * v1 . Node ] * schedulerapi . Victims ) string {
2017-08-10 01:15:40 +00:00
var output string
2017-11-21 21:29:16 +00:00
for node , victims := range nodeToVictims {
2017-08-10 01:15:40 +00:00
output += node . Name + ": ["
2017-11-17 02:21:03 +00:00
for _ , pod := range victims . Pods {
2017-08-10 01:15:40 +00:00
output += pod . Name + ", "
}
output += "]"
}
return output
}
2018-06-01 14:16:50 +00:00
func checkPreemptionVictims ( expected map [ string ] map [ string ] bool , nodeToPods map [ * v1 . Node ] * schedulerapi . Victims ) error {
2017-08-03 01:20:45 +00:00
if len ( expected ) == len ( nodeToPods ) {
2017-11-21 21:29:16 +00:00
for k , victims := range nodeToPods {
2017-08-10 01:15:40 +00:00
if expPods , ok := expected [ k . Name ] ; ok {
2017-11-17 02:21:03 +00:00
if len ( victims . Pods ) != len ( expPods ) {
2018-06-01 14:16:50 +00:00
return fmt . Errorf ( "unexpected number of pods. expected: %v, got: %v" , expected , printNodeToVictims ( nodeToPods ) )
2017-08-03 01:20:45 +00:00
}
prevPriority := int32 ( math . MaxInt32 )
2017-11-17 02:21:03 +00:00
for _ , p := range victims . Pods {
2017-08-03 01:20:45 +00:00
// Check that pods are sorted by their priority.
if * p . Spec . Priority > prevPriority {
2018-06-01 14:16:50 +00:00
return fmt . Errorf ( "pod %v of node %v was not sorted by priority" , p . Name , k )
2017-08-03 01:20:45 +00:00
}
prevPriority = * p . Spec . Priority
if _ , ok := expPods [ p . Name ] ; ! ok {
2018-06-01 14:16:50 +00:00
return fmt . Errorf ( "pod %v was not expected. Expected: %v" , p . Name , expPods )
2017-08-03 01:20:45 +00:00
}
}
} else {
2018-06-01 14:16:50 +00:00
return fmt . Errorf ( "unexpected machines. expected: %v, got: %v" , expected , printNodeToVictims ( nodeToPods ) )
2017-08-03 01:20:45 +00:00
}
}
} else {
2018-06-01 14:16:50 +00:00
return fmt . Errorf ( "unexpected number of machines. expected: %v, got: %v" , expected , printNodeToVictims ( nodeToPods ) )
2017-08-03 01:20:45 +00:00
}
return nil
}
type FakeNodeInfo v1 . Node
func ( n FakeNodeInfo ) GetNodeInfo ( nodeName string ) ( * v1 . Node , error ) {
node := v1 . Node ( n )
return & node , nil
}
2018-12-19 12:30:54 +00:00
func PredicateMetadata ( p * v1 . Pod , nodeInfo map [ string ] * schedulernodeinfo . NodeInfo ) algorithmpredicates . PredicateMetadata {
2017-08-03 01:20:45 +00:00
return algorithmpredicates . NewPredicateMetadataFactory ( schedulertesting . FakePodLister { p } ) ( p , nodeInfo )
}
2017-08-09 18:36:35 +00:00
var smallContainers = [ ] v1 . Container {
{
Resources : v1 . ResourceRequirements {
Requests : v1 . ResourceList {
"cpu" : resource . MustParse (
2018-02-08 06:42:19 +00:00
strconv . FormatInt ( priorityutil . DefaultMilliCPURequest , 10 ) + "m" ) ,
2017-08-09 18:36:35 +00:00
"memory" : resource . MustParse (
strconv . FormatInt ( priorityutil . DefaultMemoryRequest , 10 ) ) ,
2017-08-03 01:20:45 +00:00
} ,
} ,
2017-08-09 18:36:35 +00:00
} ,
}
var mediumContainers = [ ] v1 . Container {
{
Resources : v1 . ResourceRequirements {
Requests : v1 . ResourceList {
"cpu" : resource . MustParse (
2018-02-08 06:42:19 +00:00
strconv . FormatInt ( priorityutil . DefaultMilliCPURequest * 2 , 10 ) + "m" ) ,
2017-08-09 18:36:35 +00:00
"memory" : resource . MustParse (
strconv . FormatInt ( priorityutil . DefaultMemoryRequest * 2 , 10 ) ) ,
2017-08-03 01:20:45 +00:00
} ,
} ,
2017-08-09 18:36:35 +00:00
} ,
}
var largeContainers = [ ] v1 . Container {
{
Resources : v1 . ResourceRequirements {
Requests : v1 . ResourceList {
"cpu" : resource . MustParse (
2018-02-08 06:42:19 +00:00
strconv . FormatInt ( priorityutil . DefaultMilliCPURequest * 3 , 10 ) + "m" ) ,
2017-08-09 18:36:35 +00:00
"memory" : resource . MustParse (
strconv . FormatInt ( priorityutil . DefaultMemoryRequest * 3 , 10 ) ) ,
2017-08-03 01:20:45 +00:00
} ,
} ,
2017-08-09 18:36:35 +00:00
} ,
}
var veryLargeContainers = [ ] v1 . Container {
{
Resources : v1 . ResourceRequirements {
Requests : v1 . ResourceList {
"cpu" : resource . MustParse (
2018-02-08 06:42:19 +00:00
strconv . FormatInt ( priorityutil . DefaultMilliCPURequest * 5 , 10 ) + "m" ) ,
2017-08-09 18:36:35 +00:00
"memory" : resource . MustParse (
strconv . FormatInt ( priorityutil . DefaultMemoryRequest * 5 , 10 ) ) ,
} ,
} ,
} ,
}
var negPriority , lowPriority , midPriority , highPriority , veryHighPriority = int32 ( - 100 ) , int32 ( 0 ) , int32 ( 100 ) , int32 ( 1000 ) , int32 ( 10000 )
2019-03-12 04:30:15 +00:00
var startTime = metav1 . Date ( 2019 , 1 , 1 , 1 , 1 , 1 , 0 , time . UTC )
var startTime20190102 = metav1 . Date ( 2019 , 1 , 2 , 1 , 1 , 1 , 0 , time . UTC )
var startTime20190103 = metav1 . Date ( 2019 , 1 , 3 , 1 , 1 , 1 , 0 , time . UTC )
var startTime20190104 = metav1 . Date ( 2019 , 1 , 4 , 1 , 1 , 1 , 0 , time . UTC )
var startTime20190105 = metav1 . Date ( 2019 , 1 , 5 , 1 , 1 , 1 , 0 , time . UTC )
var startTime20190106 = metav1 . Date ( 2019 , 1 , 6 , 1 , 1 , 1 , 0 , time . UTC )
var startTime20190107 = metav1 . Date ( 2019 , 1 , 7 , 1 , 1 , 1 , 0 , time . UTC )
2017-08-09 18:36:35 +00:00
// TestSelectNodesForPreemption tests selectNodesForPreemption. This test assumes
// that podsFitsOnNode works correctly and is tested separately.
func TestSelectNodesForPreemption ( t * testing . T ) {
2019-05-09 01:03:58 +00:00
defer algorithmpredicates . SetPredicatesOrderingDuringTest ( order ) ( )
2017-08-03 01:20:45 +00:00
tests := [ ] struct {
name string
2018-12-19 12:30:54 +00:00
predicates map [ string ] algorithmpredicates . FitPredicate
2017-08-03 01:20:45 +00:00
nodes [ ] string
pod * v1 . Pod
pods [ ] * v1 . Pod
expected map [ string ] map [ string ] bool // Map from node name to a list of pods names which should be preempted.
addAffinityPredicate bool
} {
{
name : "a pod that does not fit on any machine" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : falsePredicate } ,
2017-08-03 01:20:45 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "new" , UID : types . UID ( "new" ) } , Spec : v1 . PodSpec { Priority : & highPriority } } ,
2017-08-03 01:20:45 +00:00
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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" } } } ,
2017-08-03 01:20:45 +00:00
expected : map [ string ] map [ string ] bool { } ,
} ,
{
name : "a pod that fits with no preemption" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : truePredicate } ,
2017-08-03 01:20:45 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "new" , UID : types . UID ( "new" ) } , Spec : v1 . PodSpec { Priority : & highPriority } } ,
2017-08-03 01:20:45 +00:00
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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" } } } ,
2017-08-09 18:36:35 +00:00
expected : map [ string ] map [ string ] bool { "machine1" : { } , "machine2" : { } } ,
2017-08-03 01:20:45 +00:00
} ,
{
name : "a pod that fits on one machine with no preemption" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : matchesPredicate } ,
2017-08-03 01:20:45 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Priority : & highPriority } } ,
2017-08-03 01:20:45 +00:00
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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" } } } ,
2017-08-09 18:36:35 +00:00
expected : map [ string ] map [ string ] bool { "machine1" : { } } ,
2017-08-03 01:20:45 +00:00
} ,
{
name : "a pod that fits on both machines when lower priority pods are preempted" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-03 01:20:45 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & highPriority } } ,
2017-08-03 01:20:45 +00:00
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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" } } } ,
2017-08-03 01:20:45 +00:00
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" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-03 01:20:45 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & lowPriority } } ,
2017-08-03 01:20:45 +00:00
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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" } } } ,
2017-08-03 01:20:45 +00:00
expected : map [ string ] map [ string ] bool { } ,
} ,
{
name : "medium priority pod is preempted, but lower priority one stays as it is small" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-03 01:20:45 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & highPriority } } ,
2017-08-03 01:20:45 +00:00
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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" } } } ,
2017-08-03 01:20:45 +00:00
expected : map [ string ] map [ string ] bool { "machine1" : { "b" : true } , "machine2" : { "c" : true } } ,
} ,
{
name : "mixed priority pods are preempted" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-03 01:20:45 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & highPriority } } ,
2017-08-03 01:20:45 +00:00
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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" } } } ,
2017-08-03 01:20:45 +00:00
expected : map [ string ] map [ string ] bool { "machine1" : { "b" : true , "c" : true } } ,
} ,
2019-03-20 13:11:26 +00:00
{
name : "mixed priority pods are preempted, pick later StartTime one when priorities are equal" ,
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
nodes : [ ] string { "machine1" , "machine2" } ,
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" , UID : types . UID ( "a" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & lowPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190107 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "b" , UID : types . UID ( "b" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & lowPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190106 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "c" , UID : types . UID ( "c" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190105 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "d" , UID : types . UID ( "d" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & highPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190104 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "e" , UID : types . UID ( "e" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & highPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime20190103 } } } ,
expected : map [ string ] map [ string ] bool { "machine1" : { "a" : true , "c" : true } } ,
} ,
2017-08-03 01:20:45 +00:00
{
2017-08-10 01:15:40 +00:00
name : "pod with anti-affinity is preempted" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-03 01:20:45 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2017-08-10 01:15:40 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta {
Name : "machine1" ,
Labels : map [ string ] string { "pod" : "preemptor" } } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & highPriority } } ,
2017-08-03 01:20:45 +00:00
pods : [ ] * v1 . Pod {
2018-07-23 01:28:03 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "a" , UID : types . UID ( "a" ) , Labels : map [ string ] string { "service" : "securityscan" } } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & lowPriority , NodeName : "machine1" , Affinity : & v1 . Affinity {
2017-08-10 01:15:40 +00:00
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "pod" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "preemptor" , "value2" } ,
} ,
2017-08-03 01:20:45 +00:00
} ,
} ,
2017-08-10 01:15:40 +00:00
TopologyKey : "hostname" ,
2017-08-03 01:20:45 +00:00
} ,
} ,
2017-08-10 01:15:40 +00:00
} } } } ,
2018-03-12 22:41:25 +00:00
{ 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" } } } ,
2017-08-10 01:15:40 +00:00
expected : map [ string ] map [ string ] bool { "machine1" : { "a" : true } , "machine2" : { } } ,
2017-08-03 01:20:45 +00:00
addAffinityPredicate : true ,
} ,
}
for _ , test := range tests {
2018-06-01 14:16:50 +00:00
t . Run ( test . name , func ( t * testing . T ) {
nodes := [ ] * v1 . Node { }
for _ , n := range test . nodes {
node := makeNode ( n , 1000 * 5 , priorityutil . DefaultMemoryRequest * 5 )
node . ObjectMeta . Labels = map [ string ] string { "hostname" : node . Name }
nodes = append ( nodes , node )
}
if test . addAffinityPredicate {
test . predicates [ algorithmpredicates . MatchInterPodAffinityPred ] = algorithmpredicates . NewPodAffinityPredicate ( FakeNodeInfo ( * nodes [ 0 ] ) , schedulertesting . FakePodLister ( test . pods ) )
}
2018-12-08 02:36:11 +00:00
nodeNameToInfo := schedulernodeinfo . CreateNodeNameToInfoMap ( test . pods , nodes )
2018-11-16 20:07:28 +00:00
// newnode simulate a case that a new node is added to the cluster, but nodeNameToInfo
// doesn't have it yet.
newnode := makeNode ( "newnode" , 1000 * 5 , priorityutil . DefaultMemoryRequest * 5 )
newnode . ObjectMeta . Labels = map [ string ] string { "hostname" : "newnode" }
nodes = append ( nodes , newnode )
2018-06-01 14:16:50 +00:00
nodeToPods , err := selectNodesForPreemption ( test . pod , nodeNameToInfo , nodes , test . predicates , PredicateMetadata , nil , nil )
if err != nil {
t . Error ( err )
}
if err := checkPreemptionVictims ( test . expected , nodeToPods ) ; err != nil {
t . Error ( err )
}
} )
2017-08-03 01:20:45 +00:00
}
}
2017-08-09 18:36:35 +00:00
// TestPickOneNodeForPreemption tests pickOneNodeForPreemption.
func TestPickOneNodeForPreemption ( t * testing . T ) {
2019-05-09 01:03:58 +00:00
defer algorithmpredicates . SetPredicatesOrderingDuringTest ( order ) ( )
2017-08-09 18:36:35 +00:00
tests := [ ] struct {
name string
2018-12-19 12:30:54 +00:00
predicates map [ string ] algorithmpredicates . FitPredicate
2017-08-09 18:36:35 +00:00
nodes [ ] string
pod * v1 . Pod
pods [ ] * v1 . Pod
expected [ ] string // any of the items is valid
} {
{
name : "No node needs preemption" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-09 18:36:35 +00:00
nodes : [ ] string { "machine1" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & highPriority } } ,
2017-08-09 18:36:35 +00:00
pods : [ ] * v1 . Pod {
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.1" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } } ,
2017-08-09 18:36:35 +00:00
expected : [ ] string { "machine1" } ,
} ,
{
name : "a pod that fits on both machines when lower priority pods are preempted" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-09 18:36:35 +00:00
nodes : [ ] string { "machine1" , "machine2" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & highPriority } } ,
2017-08-09 18:36:35 +00:00
pods : [ ] * v1 . Pod {
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.1" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } } ,
2017-08-09 18:36:35 +00:00
expected : [ ] string { "machine1" , "machine2" } ,
} ,
{
name : "a pod that fits on a machine with no preemption" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-09 18:36:35 +00:00
nodes : [ ] string { "machine1" , "machine2" , "machine3" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & highPriority } } ,
2017-08-09 18:36:35 +00:00
pods : [ ] * v1 . Pod {
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.1" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } } ,
2017-08-09 18:36:35 +00:00
expected : [ ] string { "machine3" } ,
} ,
{
name : "machine with min highest priority pod is picked" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-09 18:36:35 +00:00
nodes : [ ] string { "machine1" , "machine2" , "machine3" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : veryLargeContainers , Priority : & highPriority } } ,
2017-08-09 18:36:35 +00:00
pods : [ ] * v1 . Pod {
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.1" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.2" , UID : types . UID ( "m1.2" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.2" , UID : types . UID ( "m2.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & lowPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.1" , UID : types . UID ( "m3.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & lowPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.2" , UID : types . UID ( "m3.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & lowPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
} ,
expected : [ ] string { "machine3" } ,
} ,
{
name : "when highest priorities are the same, minimum sum of priorities is picked" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-09 18:36:35 +00:00
nodes : [ ] string { "machine1" , "machine2" , "machine3" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : veryLargeContainers , Priority : & highPriority } } ,
2017-08-09 18:36:35 +00:00
pods : [ ] * v1 . Pod {
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.1" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.2" , UID : types . UID ( "m1.2" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.2" , UID : types . UID ( "m2.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & lowPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.1" , UID : types . UID ( "m3.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.2" , UID : types . UID ( "m3.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
} ,
expected : [ ] string { "machine2" } ,
} ,
{
name : "when highest priority and sum are the same, minimum number of pods is picked" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-09 18:36:35 +00:00
nodes : [ ] string { "machine1" , "machine2" , "machine3" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : veryLargeContainers , Priority : & highPriority } } ,
2017-08-09 18:36:35 +00:00
pods : [ ] * v1 . Pod {
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.1" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.2" , UID : types . UID ( "m1.2" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & negPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.3" , UID : types . UID ( "m1.3" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.4" , UID : types . UID ( "m1.4" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & negPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.2" , UID : types . UID ( "m2.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & negPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.1" , UID : types . UID ( "m3.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.2" , UID : types . UID ( "m3.2" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & negPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.3" , UID : types . UID ( "m3.3" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & lowPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
} ,
expected : [ ] string { "machine2" } ,
} ,
{
// pickOneNodeForPreemption adjusts pod priorities when finding the sum of the victims. This
// test ensures that the logic works correctly.
name : "sum of adjusted priorities is considered" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-09 18:36:35 +00:00
nodes : [ ] string { "machine1" , "machine2" , "machine3" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , UID : types . UID ( "machine1" ) } , Spec : v1 . PodSpec { Containers : veryLargeContainers , Priority : & highPriority } } ,
2017-08-09 18:36:35 +00:00
pods : [ ] * v1 . Pod {
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.1" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.2" , UID : types . UID ( "m1.2" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & negPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.3" , UID : types . UID ( "m1.3" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & negPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.2" , UID : types . UID ( "m2.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & negPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.1" , UID : types . UID ( "m3.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.2" , UID : types . UID ( "m3.2" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & negPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.3" , UID : types . UID ( "m3.3" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & lowPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
} ,
expected : [ ] string { "machine2" } ,
} ,
{
name : "non-overlapping lowest high priority, sum priorities, and number of pods" ,
2018-12-19 12:30:54 +00:00
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
2017-08-09 18:36:35 +00:00
nodes : [ ] string { "machine1" , "machine2" , "machine3" , "machine4" } ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , UID : types . UID ( "pod1" ) } , Spec : v1 . PodSpec { Containers : veryLargeContainers , Priority : & veryHighPriority } } ,
2017-08-09 18:36:35 +00:00
pods : [ ] * v1 . Pod {
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.1" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.2" , UID : types . UID ( "m1.2" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & lowPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.3" , UID : types . UID ( "m1.3" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & lowPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & highPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.1" , UID : types . UID ( "m3.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.2" , UID : types . UID ( "m3.2" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & lowPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.3" , UID : types . UID ( "m3.3" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & lowPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.4" , UID : types . UID ( "m3.4" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & lowPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
2019-03-12 04:30:15 +00:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "m4.1" , UID : types . UID ( "m4.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine4" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m4.2" , UID : types . UID ( "m4.2" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & midPriority , NodeName : "machine4" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m4.3" , UID : types . UID ( "m4.3" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & midPriority , NodeName : "machine4" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m4.4" , UID : types . UID ( "m4.4" ) } , Spec : v1 . PodSpec { Containers : smallContainers , Priority : & negPriority , NodeName : "machine4" } , Status : v1 . PodStatus { StartTime : & startTime } } ,
2017-08-09 18:36:35 +00:00
} ,
expected : [ ] string { "machine1" } ,
} ,
2019-03-12 04:30:15 +00:00
{
name : "same priority, same number of victims, different start time for each machine's pod" ,
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
nodes : [ ] string { "machine1" , "machine2" , "machine3" } ,
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" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190103 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.2" , UID : types . UID ( "m1.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190103 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime20190104 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.2" , UID : types . UID ( "m2.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime20190104 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.1" , UID : types . UID ( "m3.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime20190102 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.2" , UID : types . UID ( "m3.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime20190102 } } ,
} ,
expected : [ ] string { "machine2" } ,
} ,
{
name : "same priority, same number of victims, different start time for all pods" ,
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
nodes : [ ] string { "machine1" , "machine2" , "machine3" } ,
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" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190105 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.2" , UID : types . UID ( "m1.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190103 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime20190106 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.2" , UID : types . UID ( "m2.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime20190102 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.1" , UID : types . UID ( "m3.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime20190104 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.2" , UID : types . UID ( "m3.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime20190107 } } ,
} ,
expected : [ ] string { "machine3" } ,
} ,
{
name : "different priority, same number of victims, different start time for all pods" ,
predicates : map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
nodes : [ ] string { "machine1" , "machine2" , "machine3" } ,
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" , UID : types . UID ( "m1.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & lowPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190105 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m1.2" , UID : types . UID ( "m1.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine1" } , Status : v1 . PodStatus { StartTime : & startTime20190103 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.1" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime20190107 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m2.2" , UID : types . UID ( "m2.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & lowPriority , NodeName : "machine2" } , Status : v1 . PodStatus { StartTime : & startTime20190102 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.1" , UID : types . UID ( "m3.1" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & lowPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime20190104 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "m3.2" , UID : types . UID ( "m3.2" ) } , Spec : v1 . PodSpec { Containers : mediumContainers , Priority : & midPriority , NodeName : "machine3" } , Status : v1 . PodStatus { StartTime : & startTime20190106 } } ,
} ,
expected : [ ] string { "machine2" } ,
} ,
2017-08-09 18:36:35 +00:00
}
for _ , test := range tests {
2018-06-01 14:16:50 +00:00
t . Run ( test . name , func ( t * testing . T ) {
nodes := [ ] * v1 . Node { }
for _ , n := range test . nodes {
nodes = append ( nodes , makeNode ( n , priorityutil . DefaultMilliCPURequest * 5 , priorityutil . DefaultMemoryRequest * 5 ) )
2017-08-09 18:36:35 +00:00
}
2018-12-08 02:36:11 +00:00
nodeNameToInfo := schedulernodeinfo . CreateNodeNameToInfoMap ( test . pods , nodes )
2018-06-01 14:16:50 +00:00
candidateNodes , _ := selectNodesForPreemption ( test . pod , nodeNameToInfo , nodes , test . predicates , PredicateMetadata , nil , nil )
node := pickOneNodeForPreemption ( candidateNodes )
found := false
for _ , nodeName := range test . expected {
if node . Name == nodeName {
found = true
break
}
}
if ! found {
t . Errorf ( "unexpected node: %v" , node )
}
} )
2017-08-09 18:36:35 +00:00
}
}
2017-08-10 01:15:40 +00:00
func TestNodesWherePreemptionMightHelp ( t * testing . T ) {
// Prepare 4 node names.
nodeNames := [ ] string { }
for i := 1 ; i < 5 ; i ++ {
nodeNames = append ( nodeNames , fmt . Sprintf ( "machine%d" , i ) )
}
tests := [ ] struct {
name string
failedPredMap FailedPredicateMap
expected map [ string ] bool // set of expected node names. Value is ignored.
} {
{
name : "No node should be attempted" ,
failedPredMap : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeSelectorNotMatch } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrPodNotMatchHostName } ,
"machine3" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrTaintsTolerationsNotMatch } ,
"machine4" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeLabelPresenceViolated } ,
2017-08-10 01:15:40 +00:00
} ,
expected : map [ string ] bool { } ,
} ,
{
2018-06-11 23:39:39 +00:00
name : "ErrPodAffinityNotMatch should be tried as it indicates that the pod is unschedulable due to inter-pod affinity or anti-affinity" ,
2017-08-10 01:15:40 +00:00
failedPredMap : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrPodAffinityNotMatch } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrPodNotMatchHostName } ,
"machine3" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeUnschedulable } ,
2017-08-10 01:15:40 +00:00
} ,
expected : map [ string ] bool { "machine1" : true , "machine4" : true } ,
} ,
{
name : "pod with both pod affinity and anti-affinity should be tried" ,
failedPredMap : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrPodAffinityNotMatch } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrPodNotMatchHostName } ,
2017-08-10 01:15:40 +00:00
} ,
expected : map [ string ] bool { "machine1" : true , "machine3" : true , "machine4" : true } ,
} ,
2018-06-11 23:39:39 +00:00
{
name : "ErrPodAffinityRulesNotMatch should not be tried as it indicates that the pod is unschedulable due to inter-pod affinity, but ErrPodAffinityNotMatch should be tried as it indicates that the pod is unschedulable due to inter-pod affinity or anti-affinity" ,
failedPredMap : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrPodAffinityRulesNotMatch } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrPodAffinityNotMatch } ,
2018-06-11 23:39:39 +00:00
} ,
expected : map [ string ] bool { "machine2" : true , "machine3" : true , "machine4" : true } ,
} ,
2017-08-10 01:15:40 +00:00
{
name : "Mix of failed predicates works fine" ,
failedPredMap : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeSelectorNotMatch , algorithmpredicates . ErrNodeUnderDiskPressure , algorithmpredicates . NewInsufficientResourceError ( v1 . ResourceMemory , 1000 , 500 , 300 ) } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrPodNotMatchHostName , algorithmpredicates . ErrDiskConflict } ,
"machine3" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . NewInsufficientResourceError ( v1 . ResourceMemory , 1000 , 600 , 400 ) } ,
"machine4" : [ ] algorithmpredicates . PredicateFailureReason { } ,
2017-08-10 01:15:40 +00:00
} ,
expected : map [ string ] bool { "machine3" : true , "machine4" : true } ,
} ,
2018-06-11 23:39:39 +00:00
{
name : "Node condition errors should be considered unresolvable" ,
failedPredMap : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeUnderDiskPressure } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeUnderPIDPressure } ,
"machine3" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeUnderMemoryPressure } ,
2018-06-11 23:39:39 +00:00
} ,
2018-12-13 08:31:46 +00:00
expected : map [ string ] bool { "machine4" : true } ,
2018-06-11 23:39:39 +00:00
} ,
2018-08-23 10:54:23 +00:00
{
name : "Node condition errors and ErrNodeUnknownCondition should be considered unresolvable" ,
failedPredMap : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeNotReady } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeNetworkUnavailable } ,
"machine3" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrNodeUnknownCondition } ,
2018-08-23 10:54:23 +00:00
} ,
expected : map [ string ] bool { "machine4" : true } ,
} ,
{
name : "ErrVolume... errors should not be tried as it indicates that the pod is unschedulable due to no matching volumes for pod on node" ,
failedPredMap : FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrVolumeZoneConflict } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrVolumeNodeConflict } ,
"machine3" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrVolumeBindConflict } ,
2018-08-23 10:54:23 +00:00
} ,
expected : map [ string ] bool { "machine4" : true } ,
} ,
2017-08-10 01:15:40 +00:00
}
for _ , test := range tests {
2018-06-01 14:16:50 +00:00
t . Run ( test . name , func ( t * testing . T ) {
nodes := nodesWherePreemptionMightHelp ( makeNodeList ( nodeNames ) , test . failedPredMap )
if len ( test . expected ) != len ( nodes ) {
t . Errorf ( "number of nodes is not the same as expected. exptectd: %d, got: %d. Nodes: %v" , len ( test . expected ) , len ( nodes ) , nodes )
2017-08-10 01:15:40 +00:00
}
2018-06-01 14:16:50 +00:00
for _ , node := range nodes {
if _ , found := test . expected [ node . Name ] ; ! found {
t . Errorf ( "node %v is not expected." , node . Name )
}
}
} )
2017-08-10 01:15:40 +00:00
}
}
func TestPreempt ( t * testing . T ) {
2019-05-09 01:03:58 +00:00
defer algorithmpredicates . SetPredicatesOrderingDuringTest ( order ) ( )
2017-08-10 01:15:40 +00:00
failedPredMap := FailedPredicateMap {
2018-12-19 12:30:54 +00:00
"machine1" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . NewInsufficientResourceError ( v1 . ResourceMemory , 1000 , 500 , 300 ) } ,
"machine2" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . ErrDiskConflict } ,
"machine3" : [ ] algorithmpredicates . PredicateFailureReason { algorithmpredicates . NewInsufficientResourceError ( v1 . ResourceMemory , 1000 , 600 , 400 ) } ,
2017-08-10 01:15:40 +00:00
}
// Prepare 3 node names.
nodeNames := [ ] string { }
for i := 1 ; i < 4 ; i ++ {
nodeNames = append ( nodeNames , fmt . Sprintf ( "machine%d" , i ) )
}
2019-05-30 22:28:21 +00:00
var (
preemptLowerPriority = v1 . PreemptLowerPriority
preemptNever = v1 . PreemptNever
)
2017-08-10 01:15:40 +00:00
tests := [ ] struct {
name string
pod * v1 . Pod
pods [ ] * v1 . Pod
extenders [ ] * FakeExtender
expectedNode string
expectedPods [ ] string // list of preempted pods
} {
{
name : "basic preemption logic" ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , UID : types . UID ( "pod1" ) } , Spec : v1 . PodSpec {
2019-05-30 22:28:21 +00:00
Containers : veryLargeContainers ,
Priority : & highPriority ,
PreemptionPolicy : & preemptLowerPriority } ,
2017-08-10 01:15:40 +00:00
} ,
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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 } } ,
2017-08-10 01:15:40 +00:00
} ,
expectedNode : "machine1" ,
expectedPods : [ ] string { "m1.1" , "m1.2" } ,
} ,
{
name : "One node doesn't need any preemption" ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , UID : types . UID ( "pod1" ) } , Spec : v1 . PodSpec {
2019-05-30 22:28:21 +00:00
Containers : veryLargeContainers ,
Priority : & highPriority ,
PreemptionPolicy : & preemptLowerPriority } ,
2017-08-10 01:15:40 +00:00
} ,
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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 } } ,
2017-08-10 01:15:40 +00:00
2018-03-12 22:41:25 +00:00
{ 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 } } ,
2017-08-10 01:15:40 +00:00
} ,
expectedNode : "machine3" ,
expectedPods : [ ] string { } ,
} ,
{
name : "Scheduler extenders allow only machine1, otherwise machine3 would have been chosen" ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , UID : types . UID ( "pod1" ) } , Spec : v1 . PodSpec {
2019-05-30 22:28:21 +00:00
Containers : veryLargeContainers ,
Priority : & highPriority ,
PreemptionPolicy : & preemptLowerPriority } ,
2017-08-10 01:15:40 +00:00
} ,
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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 } } ,
2017-08-10 01:15:40 +00:00
2018-03-12 22:41:25 +00:00
{ 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 } } ,
2017-08-10 01:15:40 +00:00
} ,
extenders : [ ] * FakeExtender {
{
predicates : [ ] fitPredicate { truePredicateExtender } ,
} ,
{
predicates : [ ] fitPredicate { machine1PredicateExtender } ,
} ,
} ,
expectedNode : "machine1" ,
expectedPods : [ ] string { "m1.1" , "m1.2" } ,
} ,
{
name : "Scheduler extenders do not allow any preemption" ,
2018-03-12 22:41:25 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , UID : types . UID ( "pod1" ) } , Spec : v1 . PodSpec {
2019-05-30 22:28:21 +00:00
Containers : veryLargeContainers ,
Priority : & highPriority ,
PreemptionPolicy : & preemptLowerPriority } ,
2017-08-10 01:15:40 +00:00
} ,
pods : [ ] * v1 . Pod {
2018-03-12 22:41:25 +00:00
{ 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 } } ,
2017-08-10 01:15:40 +00:00
2018-03-12 22:41:25 +00:00
{ 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 } } ,
2017-08-10 01:15:40 +00:00
} ,
extenders : [ ] * FakeExtender {
{
predicates : [ ] fitPredicate { falsePredicateExtender } ,
} ,
} ,
expectedNode : "" ,
expectedPods : [ ] string { } ,
} ,
2018-03-30 21:01:09 +00:00
{
name : "One scheduler extender allows only machine1, the other returns error but ignorable. Only machine1 would be chosen" ,
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , UID : types . UID ( "pod1" ) } , Spec : v1 . PodSpec {
2019-05-30 22:28:21 +00:00
Containers : veryLargeContainers ,
Priority : & highPriority ,
PreemptionPolicy : & preemptLowerPriority } ,
2018-03-30 21:01:09 +00:00
} ,
pods : [ ] * v1 . Pod {
{ 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" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { Phase : v1 . PodRunning } } ,
} ,
extenders : [ ] * FakeExtender {
{
predicates : [ ] fitPredicate { errorPredicateExtender } ,
ignorable : true ,
} ,
{
predicates : [ ] fitPredicate { machine1PredicateExtender } ,
} ,
} ,
expectedNode : "machine1" ,
expectedPods : [ ] string { "m1.1" , "m1.2" } ,
} ,
2018-07-17 12:09:45 +00:00
{
name : "One scheduler extender allows only machine1, but it is not interested in given pod, otherwise machine1 would have been chosen" ,
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , UID : types . UID ( "pod1" ) } , Spec : v1 . PodSpec {
2019-05-30 22:28:21 +00:00
Containers : veryLargeContainers ,
Priority : & highPriority ,
PreemptionPolicy : & preemptLowerPriority } ,
2018-07-17 12:09:45 +00:00
} ,
pods : [ ] * v1 . Pod {
{ 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" , UID : types . UID ( "m2.1" ) } , Spec : v1 . PodSpec { Containers : largeContainers , Priority : & midPriority , NodeName : "machine2" } , Status : v1 . PodStatus { Phase : v1 . PodRunning } } ,
} ,
extenders : [ ] * FakeExtender {
{
predicates : [ ] fitPredicate { machine1PredicateExtender } ,
unInterested : true ,
} ,
{
predicates : [ ] fitPredicate { truePredicateExtender } ,
} ,
} ,
expectedNode : "machine3" ,
expectedPods : [ ] string { } ,
} ,
2019-05-30 22:28:21 +00:00
{
name : "no preempting in pod" ,
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , UID : types . UID ( "pod1" ) } , Spec : v1 . PodSpec {
Containers : veryLargeContainers ,
Priority : & highPriority ,
PreemptionPolicy : & preemptNever } ,
} ,
pods : [ ] * v1 . Pod {
{ 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 : "" ,
expectedPods : nil ,
} ,
{
name : "PreemptionPolicy is nil" ,
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , UID : types . UID ( "pod1" ) } , Spec : v1 . PodSpec {
Containers : veryLargeContainers ,
Priority : & highPriority ,
PreemptionPolicy : nil } ,
} ,
pods : [ ] * v1 . Pod {
{ 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" } ,
} ,
2017-08-10 01:15:40 +00:00
}
for _ , test := range tests {
2018-06-01 14:16:50 +00:00
t . Run ( test . name , func ( t * testing . T ) {
2019-01-14 22:27:16 +00:00
t . Logf ( "===== Running test %v" , t . Name ( ) )
2018-06-01 14:16:50 +00:00
stop := make ( chan struct { } )
2019-03-22 01:12:33 +00:00
cache := internalcache . New ( time . Duration ( 0 ) , stop )
2018-06-01 14:16:50 +00:00
for _ , pod := range test . pods {
cache . AddPod ( pod )
}
2018-12-08 02:36:11 +00:00
cachedNodeInfoMap := map [ string ] * schedulernodeinfo . NodeInfo { }
2018-06-01 14:16:50 +00:00
for _ , name := range nodeNames {
node := makeNode ( name , 1000 * 5 , priorityutil . DefaultMemoryRequest * 5 )
cache . AddNode ( node )
// Set nodeInfo to extenders to mock extenders' cache for preemption.
2018-12-08 02:36:11 +00:00
cachedNodeInfo := schedulernodeinfo . NewNodeInfo ( )
2018-06-01 14:16:50 +00:00
cachedNodeInfo . SetNode ( node )
cachedNodeInfoMap [ name ] = cachedNodeInfo
}
extenders := [ ] algorithm . SchedulerExtender { }
for _ , extender := range test . extenders {
// Set nodeInfoMap as extenders cached node information.
extender . cachedNodeNameToInfo = cachedNodeInfoMap
extenders = append ( extenders , extender )
}
scheduler := NewGenericScheduler (
cache ,
2019-05-07 01:03:00 +00:00
internalqueue . NewSchedulingQueue ( nil , nil ) ,
2018-12-19 12:30:54 +00:00
map [ string ] algorithmpredicates . FitPredicate { "matches" : algorithmpredicates . PodFitsResources } ,
algorithmpredicates . EmptyPredicateMetadataProducer ,
2019-01-08 21:09:11 +00:00
[ ] priorities . PriorityConfig { { Function : numericPriority , Weight : 1 } } ,
priorities . EmptyPriorityMetadataProducer ,
2019-05-04 10:29:30 +00:00
emptyFramework ,
2018-06-01 14:16:50 +00:00
extenders ,
nil ,
schedulertesting . FakePersistentVolumeClaimLister { } ,
2018-09-19 00:05:48 +00:00
schedulertesting . FakePDBLister { } ,
2018-06-01 14:16:50 +00:00
false ,
2018-07-28 00:17:09 +00:00
false ,
2019-05-30 22:28:21 +00:00
schedulerapi . DefaultPercentageOfNodesToScore ,
true )
2019-01-14 22:27:16 +00:00
scheduler . ( * genericScheduler ) . snapshot ( )
2018-06-01 14:16:50 +00:00
// Call Preempt and check the expected results.
node , victims , _ , err := scheduler . Preempt ( test . pod , schedulertesting . FakeNodeLister ( makeNodeList ( nodeNames ) ) , error ( & FitError { Pod : test . pod , FailedPredicates : failedPredMap } ) )
if err != nil {
t . Errorf ( "unexpected error in preemption: %v" , err )
}
2019-01-14 22:27:16 +00:00
if node != nil && node . Name != test . expectedNode {
2018-07-17 12:09:45 +00:00
t . Errorf ( "expected node: %v, got: %v" , test . expectedNode , node . GetName ( ) )
2018-06-01 14:16:50 +00:00
}
2019-01-14 22:27:16 +00:00
if node == nil && len ( test . expectedNode ) != 0 {
t . Errorf ( "expected node: %v, got: nothing" , test . expectedNode )
}
2018-06-01 14:16:50 +00:00
if len ( victims ) != len ( test . expectedPods ) {
t . Errorf ( "expected %v pods, got %v." , len ( test . expectedPods ) , len ( victims ) )
}
for _ , victim := range victims {
found := false
for _ , expPod := range test . expectedPods {
if expPod == victim . Name {
found = true
break
}
2017-08-10 01:15:40 +00:00
}
2018-06-01 14:16:50 +00:00
if ! found {
t . Errorf ( "pod %v is not expected to be a victim." , victim . Name )
}
// Mark the victims for deletion and record the preemptor's nominated node name.
now := metav1 . Now ( )
victim . DeletionTimestamp = & now
test . pod . Status . NominatedNodeName = node . Name
2017-08-10 01:15:40 +00:00
}
2018-06-01 14:16:50 +00:00
// Call preempt again and make sure it doesn't preempt any more pods.
node , victims , _ , err = scheduler . Preempt ( test . pod , schedulertesting . FakeNodeLister ( makeNodeList ( nodeNames ) ) , error ( & FitError { Pod : test . pod , FailedPredicates : failedPredMap } ) )
if err != nil {
t . Errorf ( "unexpected error in preemption: %v" , err )
2017-08-10 01:15:40 +00:00
}
2018-06-01 14:16:50 +00:00
if node != nil && len ( victims ) > 0 {
t . Errorf ( "didn't expect any more preemption. Node %v is selected for preemption." , node )
}
close ( stop )
} )
2017-08-10 01:15:40 +00:00
}
}
2018-12-18 03:17:40 +00:00
func TestNumFeasibleNodesToFind ( t * testing . T ) {
tests := [ ] struct {
name string
percentageOfNodesToScore int32
numAllNodes int32
wantNumNodes int32
} {
{
name : "not set percentageOfNodesToScore and nodes number not more than 50" ,
numAllNodes : 10 ,
wantNumNodes : 10 ,
} ,
{
2019-05-30 22:28:21 +00:00
name : "set percentageOfNodesToScore and nodes number not more than 50" ,
2018-12-18 03:17:40 +00:00
percentageOfNodesToScore : 40 ,
numAllNodes : 10 ,
wantNumNodes : 10 ,
} ,
{
name : "not set percentageOfNodesToScore and nodes number more than 50" ,
numAllNodes : 1000 ,
wantNumNodes : 420 ,
} ,
{
2019-05-30 22:28:21 +00:00
name : "set percentageOfNodesToScore and nodes number more than 50" ,
2018-12-18 03:17:40 +00:00
percentageOfNodesToScore : 40 ,
numAllNodes : 1000 ,
wantNumNodes : 400 ,
} ,
{
name : "not set percentageOfNodesToScore and nodes number more than 50*125" ,
numAllNodes : 6000 ,
wantNumNodes : 300 ,
} ,
{
2019-05-30 22:28:21 +00:00
name : "set percentageOfNodesToScore and nodes number more than 50*125" ,
2018-12-18 03:17:40 +00:00
percentageOfNodesToScore : 40 ,
numAllNodes : 6000 ,
wantNumNodes : 2400 ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
g := & genericScheduler {
percentageOfNodesToScore : tt . percentageOfNodesToScore ,
}
if gotNumNodes := g . numFeasibleNodesToFind ( tt . numAllNodes ) ; gotNumNodes != tt . wantNumNodes {
t . Errorf ( "genericScheduler.numFeasibleNodesToFind() = %v, want %v" , gotNumNodes , tt . wantNumNodes )
}
} )
}
}