2014-09-25 14:56:57 -04:00
/ *
2016-06-02 20:25:58 -04:00
Copyright 2014 The Kubernetes Authors .
2014-09-25 14:56:57 -04: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 .
* /
2015-05-08 07:01:09 -04:00
package predicates
2014-09-25 14:56:57 -04:00
import (
2018-06-05 08:08:23 -04:00
"fmt"
2017-09-01 05:30:24 -04:00
"os"
2014-11-05 00:21:26 -05:00
"reflect"
2017-09-01 05:30:24 -04:00
"strconv"
2017-11-16 18:43:06 -05:00
"strings"
2014-09-25 14:56:57 -04:00
"testing"
2017-06-22 14:24:23 -04:00
"k8s.io/api/core/v1"
2017-11-08 16:09:55 -05:00
storagev1 "k8s.io/api/storage/v1"
2017-01-25 08:13:07 -05:00
"k8s.io/apimachinery/pkg/api/resource"
2016-12-08 10:14:21 -05:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2018-02-08 03:40:56 -05:00
"k8s.io/apimachinery/pkg/util/sets"
2017-11-08 17:34:54 -05:00
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
2018-09-27 22:37:38 -04:00
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
2018-12-07 21:36:11 -05:00
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
2018-01-03 21:12:18 -05:00
schedulertesting "k8s.io/kubernetes/pkg/scheduler/testing"
2014-09-25 14:56:57 -04:00
)
2016-09-26 11:11:31 -04:00
var (
2018-03-28 16:09:23 -04:00
extendedResourceA = v1 . ResourceName ( "example.com/aaa" )
extendedResourceB = v1 . ResourceName ( "example.com/bbb" )
kubernetesIOResourceA = v1 . ResourceName ( "kubernetes.io/something" )
kubernetesIOResourceB = v1 . ResourceName ( "subdomain.kubernetes.io/something" )
hugePageResourceA = v1helper . HugePageResourceName ( resource . MustParse ( "2Mi" ) )
2016-09-26 11:11:31 -04:00
)
2018-03-21 16:56:51 -04:00
func makeResources ( milliCPU , memory , pods , extendedA , storage , hugePageA int64 ) v1 . NodeResources {
2016-11-18 15:52:35 -05:00
return v1 . NodeResources {
Capacity : v1 . ResourceList {
2017-08-16 21:44:15 -04:00
v1 . ResourceCPU : * resource . NewMilliQuantity ( milliCPU , resource . DecimalSI ) ,
v1 . ResourceMemory : * resource . NewQuantity ( memory , resource . BinarySI ) ,
v1 . ResourcePods : * resource . NewQuantity ( pods , resource . DecimalSI ) ,
2017-11-04 03:52:15 -04:00
extendedResourceA : * resource . NewQuantity ( extendedA , resource . DecimalSI ) ,
2017-08-16 21:44:15 -04:00
v1 . ResourceEphemeralStorage : * resource . NewQuantity ( storage , resource . BinarySI ) ,
2017-08-17 14:53:10 -04:00
hugePageResourceA : * resource . NewQuantity ( hugePageA , resource . BinarySI ) ,
2014-09-25 16:55:42 -04:00
} ,
}
}
2018-03-21 16:56:51 -04:00
func makeAllocatableResources ( milliCPU , memory , pods , extendedA , storage , hugePageA int64 ) v1 . ResourceList {
2016-11-18 15:52:35 -05:00
return v1 . ResourceList {
2017-08-16 21:44:15 -04:00
v1 . ResourceCPU : * resource . NewMilliQuantity ( milliCPU , resource . DecimalSI ) ,
v1 . ResourceMemory : * resource . NewQuantity ( memory , resource . BinarySI ) ,
v1 . ResourcePods : * resource . NewQuantity ( pods , resource . DecimalSI ) ,
2017-11-04 03:52:15 -04:00
extendedResourceA : * resource . NewQuantity ( extendedA , resource . DecimalSI ) ,
2017-08-16 21:44:15 -04:00
v1 . ResourceEphemeralStorage : * resource . NewQuantity ( storage , resource . BinarySI ) ,
2017-08-17 14:53:10 -04:00
hugePageResourceA : * resource . NewQuantity ( hugePageA , resource . BinarySI ) ,
2015-12-24 03:29:18 -05:00
}
}
2018-12-07 21:36:11 -05:00
func newResourcePod ( usage ... schedulernodeinfo . Resource ) * v1 . Pod {
2016-11-18 15:52:35 -05:00
containers := [ ] v1 . Container { }
2014-09-25 16:55:42 -04:00
for _ , req := range usage {
2016-11-18 15:52:35 -05:00
containers = append ( containers , v1 . Container {
Resources : v1 . ResourceRequirements { Requests : req . ResourceList ( ) } ,
2014-09-25 16:55:42 -04:00
} )
}
2016-11-18 15:52:35 -05:00
return & v1 . Pod {
Spec : v1 . PodSpec {
2014-11-13 10:52:13 -05:00
Containers : containers ,
2014-09-25 16:55:42 -04:00
} ,
}
}
2018-12-07 21:36:11 -05:00
func newResourceInitPod ( pod * v1 . Pod , usage ... schedulernodeinfo . Resource ) * v1 . Pod {
2016-04-08 11:20:24 -04:00
pod . Spec . InitContainers = newResourcePod ( usage ... ) . Spec . Containers
return pod
}
2018-12-19 07:30:54 -05:00
func GetPredicateMetadata ( p * v1 . Pod , nodeInfo map [ string ] * schedulernodeinfo . NodeInfo ) PredicateMetadata {
2017-02-22 01:31:49 -05:00
pm := PredicateMetadataFactory { schedulertesting . FakePodLister { p } }
2016-10-12 12:03:01 -04:00
return pm . GetMetadata ( p , nodeInfo )
}
2014-09-25 16:55:42 -04:00
func TestPodFitsResources ( t * testing . T ) {
2015-03-17 10:43:49 -04:00
enoughPodsTests := [ ] struct {
2018-02-08 03:40:56 -05:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2018-02-08 03:40:56 -05:00
fits bool
2018-06-05 08:08:23 -04:00
name string
2018-12-19 07:30:54 -05:00
reasons [ ] PredicateFailureReason
2018-02-08 03:40:56 -05:00
ignoredExtendedResources sets . String
2014-09-25 16:55:42 -04:00
} {
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod { } ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 10 , Memory : 20 } ) ) ,
2014-09-25 16:55:42 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "no resources requested always fits" ,
2014-09-25 16:55:42 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 10 , Memory : 20 } ) ) ,
2014-09-25 16:55:42 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "too many resources fails" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason {
2016-11-18 15:52:35 -05:00
NewInsufficientResourceError ( v1 . ResourceCPU , 1 , 10 , 10 ) ,
NewInsufficientResourceError ( v1 . ResourceMemory , 1 , 20 , 20 ) ,
2016-08-09 08:01:46 -04:00
} ,
2014-09-25 16:55:42 -04:00
} ,
2016-04-08 11:20:24 -04:00
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) , schedulernodeinfo . Resource { MilliCPU : 3 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 8 , Memory : 19 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "too many resources fails due to init container cpu" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourceCPU , 3 , 8 , 10 ) } ,
2016-04-08 11:20:24 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) , schedulernodeinfo . Resource { MilliCPU : 3 , Memory : 1 } , schedulernodeinfo . Resource { MilliCPU : 2 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 8 , Memory : 19 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "too many resources fails due to highest init container cpu" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourceCPU , 3 , 8 , 10 ) } ,
2016-04-08 11:20:24 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) , schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 3 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 9 , Memory : 19 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "too many resources fails due to init container memory" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourceMemory , 3 , 19 , 20 ) } ,
2016-04-08 11:20:24 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) , schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 3 } , schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 2 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 9 , Memory : 19 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "too many resources fails due to highest init container memory" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourceMemory , 3 , 19 , 20 ) } ,
2016-04-08 11:20:24 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) , schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 9 , Memory : 19 } ) ) ,
2016-04-08 11:20:24 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "init container fits because it's the max, not sum, of containers and init containers" ,
2016-04-08 11:20:24 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) , schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } , schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 9 , Memory : 19 } ) ) ,
2016-04-08 11:20:24 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "multiple init containers fit because it's the max, not sum, of containers and init containers" ,
2016-04-08 11:20:24 -04:00
} ,
2014-09-25 16:55:42 -04:00
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 5 } ) ) ,
2014-09-25 16:55:42 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "both resources fit" ,
2014-09-25 16:55:42 -04:00
} ,
2016-07-08 03:43:03 -04:00
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 2 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 9 , Memory : 5 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "one resource memory fits" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourceCPU , 2 , 9 , 10 ) } ,
2016-07-08 03:43:03 -04:00
} ,
2014-09-25 16:55:42 -04:00
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 2 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 19 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "one resource cpu fits" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourceMemory , 2 , 19 , 20 ) } ,
2014-09-25 16:55:42 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 19 } ) ) ,
2014-09-25 16:55:42 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "equal edge case" ,
2014-09-25 16:55:42 -04:00
} ,
2016-04-08 11:20:24 -04:00
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 4 , Memory : 1 } ) , schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 19 } ) ) ,
2016-04-08 11:20:24 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "equal edge case for init container" ,
2016-04-08 11:20:24 -04:00
} ,
2016-09-26 11:11:31 -04:00
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 1 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo ( newResourcePod ( schedulernodeinfo . Resource { } ) ) ,
2016-09-26 11:11:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "extended resource fits" ,
2016-09-26 11:11:31 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { } ) , schedulernodeinfo . Resource { ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 1 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo ( newResourcePod ( schedulernodeinfo . Resource { } ) ) ,
2016-09-26 11:11:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "extended resource fits for init container" ,
2016-09-26 11:11:31 -04:00
} ,
{
pod : newResourcePod (
2018-12-07 21:36:11 -05:00
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 10 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 0 } } ) ) ,
2016-09-26 11:11:31 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "extended resource capacity enforced" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( extendedResourceA , 10 , 0 , 5 ) } ,
2016-09-26 11:11:31 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { } ) ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 10 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 0 } } ) ) ,
2016-09-26 11:11:31 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "extended resource capacity enforced for init container" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( extendedResourceA , 10 , 0 , 5 ) } ,
2016-09-26 11:11:31 -04:00
} ,
{
pod : newResourcePod (
2018-12-07 21:36:11 -05:00
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 1 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 5 } } ) ) ,
2016-09-26 11:11:31 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "extended resource allocatable enforced" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( extendedResourceA , 1 , 5 , 5 ) } ,
2016-09-26 11:11:31 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { } ) ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 1 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 5 } } ) ) ,
2016-09-26 11:11:31 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "extended resource allocatable enforced for init container" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( extendedResourceA , 1 , 5 , 5 ) } ,
2016-09-26 11:11:31 -04:00
} ,
{
pod : newResourcePod (
2018-12-07 21:36:11 -05:00
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 3 } } ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 3 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 2 } } ) ) ,
2016-09-26 11:11:31 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "extended resource allocatable enforced for multiple containers" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( extendedResourceA , 6 , 2 , 5 ) } ,
2016-09-26 11:11:31 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { } ) ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 3 } } ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 3 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 2 } } ) ) ,
2016-09-26 11:11:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "extended resource allocatable admits multiple init containers" ,
2016-09-26 11:11:31 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { } ) ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 6 } } ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 3 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceA : 2 } } ) ) ,
2016-09-26 11:11:31 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "extended resource allocatable enforced for multiple init containers" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( extendedResourceA , 6 , 2 , 5 ) } ,
2016-09-26 11:11:31 -04:00
} ,
{
pod : newResourcePod (
2018-12-07 21:36:11 -05:00
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceB : 1 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 } ) ) ,
2016-09-26 11:11:31 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "extended resource allocatable enforced for unknown resource" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( extendedResourceB , 1 , 0 , 0 ) } ,
2016-09-26 11:11:31 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { } ) ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceB : 1 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 } ) ) ,
2016-09-26 11:11:31 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "extended resource allocatable enforced for unknown resource for init container" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( extendedResourceB , 1 , 0 , 0 ) } ,
2016-09-26 11:11:31 -04:00
} ,
2018-03-28 16:09:23 -04:00
{
pod : newResourcePod (
2018-12-07 21:36:11 -05:00
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { kubernetesIOResourceA : 10 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 } ) ) ,
2018-03-28 16:09:23 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "kubernetes.io resource capacity enforced" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( kubernetesIOResourceA , 10 , 0 , 0 ) } ,
2018-03-28 16:09:23 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { } ) ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { kubernetesIOResourceB : 10 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 } ) ) ,
2018-03-28 16:09:23 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "kubernetes.io resource capacity enforced for init container" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( kubernetesIOResourceB , 10 , 0 , 0 ) } ,
2018-03-28 16:09:23 -04:00
} ,
2017-08-17 14:53:10 -04:00
{
pod : newResourcePod (
2018-12-07 21:36:11 -05:00
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { hugePageResourceA : 10 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { hugePageResourceA : 0 } } ) ) ,
2017-08-17 14:53:10 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "hugepages resource capacity enforced" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( hugePageResourceA , 10 , 0 , 5 ) } ,
2017-08-17 14:53:10 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { } ) ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { hugePageResourceA : 10 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { hugePageResourceA : 0 } } ) ) ,
2017-08-17 14:53:10 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "hugepages resource capacity enforced for init container" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( hugePageResourceA , 10 , 0 , 5 ) } ,
2017-08-17 14:53:10 -04:00
} ,
{
pod : newResourcePod (
2018-12-07 21:36:11 -05:00
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { hugePageResourceA : 3 } } ,
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { hugePageResourceA : 3 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 , ScalarResources : map [ v1 . ResourceName ] int64 { hugePageResourceA : 2 } } ) ) ,
2017-08-17 14:53:10 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "hugepages resource allocatable enforced for multiple containers" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( hugePageResourceA , 6 , 2 , 5 ) } ,
2017-08-17 14:53:10 -04:00
} ,
2018-02-08 03:40:56 -05:00
{
pod : newResourcePod (
2018-12-07 21:36:11 -05:00
schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 , ScalarResources : map [ v1 . ResourceName ] int64 { extendedResourceB : 1 } } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 0 , Memory : 0 } ) ) ,
2018-10-05 15:59:38 -04:00
fits : true ,
2018-02-08 03:40:56 -05:00
ignoredExtendedResources : sets . NewString ( string ( extendedResourceB ) ) ,
2018-10-05 15:59:38 -04:00
name : "skip checking ignored extended resource" ,
2018-02-08 03:40:56 -05:00
} ,
2014-09-25 16:55:42 -04:00
}
2015-03-17 10:43:49 -04:00
for _ , test := range enoughPodsTests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
node := v1 . Node { Status : v1 . NodeStatus { Capacity : makeResources ( 10 , 20 , 32 , 5 , 20 , 5 ) . Capacity , Allocatable : makeAllocatableResources ( 10 , 20 , 32 , 5 , 20 , 5 ) } }
test . nodeInfo . SetNode ( & node )
RegisterPredicateMetadataProducerWithExtendedResourceOptions ( test . ignoredExtendedResources )
2018-12-19 07:30:54 -05:00
meta := GetPredicateMetadata ( test . pod , nil )
2018-06-05 08:08:23 -04:00
fits , reasons , err := PodFitsResources ( test . pod , meta , test . nodeInfo )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , test . reasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , test . reasons )
}
if fits != test . fits {
t . Errorf ( "expected: %v got %v" , test . fits , fits )
}
} )
2015-03-17 10:43:49 -04:00
}
notEnoughPodsTests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2016-01-28 15:14:45 -05:00
fits bool
2018-06-05 08:08:23 -04:00
name string
2018-12-19 07:30:54 -05:00
reasons [ ] PredicateFailureReason
2015-03-17 10:43:49 -04:00
} {
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod { } ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 10 , Memory : 20 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "even without specified resources predicate fails when there's no space for additional pod" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourcePods , 1 , 1 , 1 ) } ,
2015-03-17 10:43:49 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 5 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "even if both resources fit predicate fails when there's no space for additional pod" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourcePods , 1 , 1 , 1 ) } ,
2015-03-17 10:43:49 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 19 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "even for equal edge case predicate fails when there's no space for additional pod" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourcePods , 1 , 1 , 1 ) } ,
2015-03-17 10:43:49 -04:00
} ,
2016-04-08 11:20:24 -04:00
{
2018-12-07 21:36:11 -05:00
pod : newResourceInitPod ( newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 1 } ) , schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 19 } ) ) ,
2016-08-09 08:01:46 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "even for equal edge case predicate fails when there's no space for additional pod due to init container" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { NewInsufficientResourceError ( v1 . ResourcePods , 1 , 1 , 1 ) } ,
2016-04-08 11:20:24 -04:00
} ,
2015-03-17 10:43:49 -04:00
}
for _ , test := range notEnoughPodsTests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
node := v1 . Node { Status : v1 . NodeStatus { Capacity : v1 . ResourceList { } , Allocatable : makeAllocatableResources ( 10 , 20 , 1 , 0 , 0 , 0 ) } }
test . nodeInfo . SetNode ( & node )
2018-12-19 07:30:54 -05:00
fits , reasons , err := PodFitsResources ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , test . reasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , test . reasons )
}
if fits != test . fits {
t . Errorf ( "expected: %v got %v" , test . fits , fits )
}
} )
2014-09-25 16:55:42 -04:00
}
2017-05-30 15:41:31 -04:00
storagePodsTests := [ ] struct {
2017-08-16 21:44:15 -04:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2017-08-16 21:44:15 -04:00
fits bool
2018-06-05 08:08:23 -04:00
name string
2018-12-19 07:30:54 -05:00
reasons [ ] PredicateFailureReason
2017-05-30 15:41:31 -04:00
} {
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 10 , Memory : 10 } ) ) ,
2017-05-30 15:41:31 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "due to container scratch disk" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason {
2017-05-30 15:41:31 -04:00
NewInsufficientResourceError ( v1 . ResourceCPU , 1 , 10 , 10 ) ,
} ,
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 1 , Memory : 1 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 2 , Memory : 10 } ) ) ,
2017-05-30 15:41:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "pod fit" ,
2017-05-30 15:41:31 -04:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { EphemeralStorage : 25 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 2 , Memory : 2 } ) ) ,
2017-06-08 09:23:47 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "storage ephemeral local storage request exceeds allocatable" ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason {
2017-08-16 21:44:15 -04:00
NewInsufficientResourceError ( v1 . ResourceEphemeralStorage , 25 , 0 , 20 ) ,
2017-05-30 15:41:31 -04:00
} ,
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { EphemeralStorage : 10 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 2 , Memory : 2 } ) ) ,
2017-06-09 00:32:36 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "pod fits" ,
2017-06-09 00:32:36 -04:00
} ,
2017-05-30 15:41:31 -04:00
}
for _ , test := range storagePodsTests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
node := v1 . Node { Status : v1 . NodeStatus { Capacity : makeResources ( 10 , 20 , 32 , 5 , 20 , 5 ) . Capacity , Allocatable : makeAllocatableResources ( 10 , 20 , 32 , 5 , 20 , 5 ) } }
test . nodeInfo . SetNode ( & node )
2018-12-19 07:30:54 -05:00
fits , reasons , err := PodFitsResources ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , test . reasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , test . reasons )
}
if fits != test . fits {
t . Errorf ( "expected: %v got %v" , test . fits , fits )
}
} )
2017-05-30 15:41:31 -04:00
}
2014-09-25 16:55:42 -04:00
}
2014-12-18 17:12:58 -05:00
func TestPodFitsHost ( t * testing . T ) {
tests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
node * v1 . Node
2014-12-18 17:12:58 -05:00
fits bool
2018-06-05 08:08:23 -04:00
name string
2014-12-18 17:12:58 -05:00
} {
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod { } ,
node : & v1 . Node { } ,
2014-12-18 17:12:58 -05:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "no host specified" ,
2014-12-18 17:12:58 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
Spec : v1 . PodSpec {
2015-05-22 19:40:57 -04:00
NodeName : "foo" ,
2014-12-18 17:12:58 -05:00
} ,
} ,
2016-11-18 15:52:35 -05:00
node : & v1 . Node {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-04-28 10:51:17 -04:00
Name : "foo" ,
} ,
} ,
2014-12-18 17:12:58 -05:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "host matches" ,
2014-12-18 17:12:58 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
Spec : v1 . PodSpec {
2015-05-22 19:40:57 -04:00
NodeName : "bar" ,
2014-12-18 17:12:58 -05:00
} ,
} ,
2016-11-18 15:52:35 -05:00
node : & v1 . Node {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-04-28 10:51:17 -04:00
Name : "foo" ,
} ,
} ,
2014-12-18 17:12:58 -05:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "host doesn't match" ,
2014-12-18 17:12:58 -05:00
} ,
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrPodNotMatchHostName }
2014-12-18 17:12:58 -05:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
2018-12-07 21:36:11 -05:00
nodeInfo := schedulernodeinfo . NewNodeInfo ( )
2018-06-05 08:08:23 -04:00
nodeInfo . SetNode ( test . node )
2018-12-19 07:30:54 -05:00
fits , reasons , err := PodFitsHost ( test . pod , GetPredicateMetadata ( test . pod , nil ) , nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . fits {
t . Errorf ( "unexpected difference: expected: %v got %v" , test . fits , fits )
}
} )
2014-12-18 17:12:58 -05:00
}
}
2017-09-07 05:12:22 -04:00
func newPod ( host string , hostPortInfos ... string ) * v1 . Pod {
2016-11-18 15:52:35 -05:00
networkPorts := [ ] v1 . ContainerPort { }
2017-09-07 05:12:22 -04:00
for _ , portInfo := range hostPortInfos {
2017-11-16 18:43:06 -05:00
splited := strings . Split ( portInfo , "/" )
hostPort , _ := strconv . Atoi ( splited [ 2 ] )
2017-09-07 05:12:22 -04:00
networkPorts = append ( networkPorts , v1 . ContainerPort {
2017-11-16 18:43:06 -05:00
HostIP : splited [ 1 ] ,
2017-09-07 05:12:22 -04:00
HostPort : int32 ( hostPort ) ,
2017-11-16 18:43:06 -05:00
Protocol : v1 . Protocol ( splited [ 0 ] ) ,
2017-09-07 05:12:22 -04:00
} )
2015-05-08 07:01:09 -04:00
}
2016-11-18 15:52:35 -05:00
return & v1 . Pod {
Spec : v1 . PodSpec {
2015-05-22 19:40:57 -04:00
NodeName : host ,
2016-11-18 15:52:35 -05:00
Containers : [ ] v1 . Container {
2015-05-08 07:01:09 -04:00
{
Ports : networkPorts ,
} ,
} ,
} ,
}
}
2015-09-29 05:44:26 -04:00
func TestPodFitsHostPorts ( t * testing . T ) {
2014-09-25 14:56:57 -04:00
tests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2016-01-28 15:14:45 -05:00
fits bool
2018-06-05 08:08:23 -04:00
name string
2014-09-25 14:56:57 -04:00
} {
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod { } ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo ( ) ,
2016-01-28 15:14:45 -05:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "nothing running" ,
2014-09-25 14:56:57 -04:00
} ,
{
2017-09-07 05:12:22 -04:00
pod : newPod ( "m1" , "UDP/127.0.0.1/8080" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "UDP/127.0.0.1/9090" ) ) ,
2014-09-25 14:56:57 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "other port" ,
2014-09-25 14:56:57 -04:00
} ,
{
2017-09-07 05:12:22 -04:00
pod : newPod ( "m1" , "UDP/127.0.0.1/8080" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "UDP/127.0.0.1/8080" ) ) ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "same udp port" ,
2017-09-07 05:12:22 -04:00
} ,
{
pod : newPod ( "m1" , "TCP/127.0.0.1/8080" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "TCP/127.0.0.1/8080" ) ) ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "same tcp port" ,
2017-09-07 05:12:22 -04:00
} ,
{
pod : newPod ( "m1" , "TCP/127.0.0.1/8080" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "TCP/127.0.0.2/8080" ) ) ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "different host ip" ,
2017-09-07 05:12:22 -04:00
} ,
{
pod : newPod ( "m1" , "UDP/127.0.0.1/8080" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "TCP/127.0.0.1/8080" ) ) ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "different protocol" ,
2017-09-07 05:12:22 -04:00
} ,
{
pod : newPod ( "m1" , "UDP/127.0.0.1/8000" , "UDP/127.0.0.1/8080" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "UDP/127.0.0.1/8080" ) ) ,
2014-09-25 14:56:57 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "second udp port conflict" ,
2014-09-25 14:56:57 -04:00
} ,
{
2017-09-07 05:12:22 -04:00
pod : newPod ( "m1" , "TCP/127.0.0.1/8001" , "UDP/127.0.0.1/8080" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "TCP/127.0.0.1/8001" , "UDP/127.0.0.1/8081" ) ) ,
2014-09-25 14:56:57 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "first tcp port conflict" ,
2014-09-25 14:56:57 -04:00
} ,
{
2017-09-07 05:12:22 -04:00
pod : newPod ( "m1" , "TCP/0.0.0.0/8001" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "TCP/127.0.0.1/8001" ) ) ,
2014-09-25 14:56:57 -04:00
fits : false ,
2018-06-05 08:08:23 -04:00
name : "first tcp port conflict due to 0.0.0.0 hostIP" ,
2017-09-07 05:12:22 -04:00
} ,
{
pod : newPod ( "m1" , "TCP/10.0.10.10/8001" , "TCP/0.0.0.0/8001" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "TCP/127.0.0.1/8001" ) ) ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "TCP hostPort conflict due to 0.0.0.0 hostIP" ,
2017-09-07 05:12:22 -04:00
} ,
{
pod : newPod ( "m1" , "TCP/127.0.0.1/8001" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "TCP/0.0.0.0/8001" ) ) ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "second tcp port conflict to 0.0.0.0 hostIP" ,
2017-09-07 05:12:22 -04:00
} ,
{
pod : newPod ( "m1" , "UDP/127.0.0.1/8001" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "TCP/0.0.0.0/8001" ) ) ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "second different protocol" ,
2017-09-07 05:12:22 -04:00
} ,
{
pod : newPod ( "m1" , "UDP/127.0.0.1/8001" ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
2017-09-07 05:12:22 -04:00
newPod ( "m1" , "TCP/0.0.0.0/8001" , "UDP/0.0.0.0/8001" ) ) ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "UDP hostPort conflict due to 0.0.0.0 hostIP" ,
2014-09-25 14:56:57 -04:00
} ,
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrPodNotFitsHostPorts }
2016-08-09 08:01:46 -04:00
2014-09-25 14:56:57 -04:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
2018-12-19 07:30:54 -05:00
fits , reasons , err := PodFitsHostPorts ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if test . fits != fits {
t . Errorf ( "expected %v, saw %v" , test . fits , fits )
}
} )
2014-09-25 14:56:57 -04:00
}
}
2014-10-13 00:34:23 -04:00
2017-10-16 08:05:27 -04:00
func TestGCEDiskConflicts ( t * testing . T ) {
2016-11-18 15:52:35 -05:00
volState := v1 . PodSpec {
Volumes : [ ] v1 . Volume {
2014-11-13 10:52:13 -05:00
{
2016-11-18 15:52:35 -05:00
VolumeSource : v1 . VolumeSource {
GCEPersistentDisk : & v1 . GCEPersistentDiskVolumeSource {
2014-11-13 10:52:13 -05:00
PDName : "foo" ,
2014-10-13 00:34:23 -04:00
} ,
} ,
} ,
} ,
}
2016-11-18 15:52:35 -05:00
volState2 := v1 . PodSpec {
Volumes : [ ] v1 . Volume {
2014-11-13 10:52:13 -05:00
{
2016-11-18 15:52:35 -05:00
VolumeSource : v1 . VolumeSource {
GCEPersistentDisk : & v1 . GCEPersistentDiskVolumeSource {
2014-11-13 10:52:13 -05:00
PDName : "bar" ,
2014-10-13 00:34:23 -04:00
} ,
2015-03-06 09:26:39 -05:00
} ,
} ,
} ,
}
tests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2016-01-28 15:14:45 -05:00
isOk bool
2018-06-05 08:08:23 -04:00
name string
2015-03-06 09:26:39 -05:00
} {
2018-12-07 21:36:11 -05:00
{ & v1 . Pod { } , schedulernodeinfo . NewNodeInfo ( ) , true , "nothing" } ,
{ & v1 . Pod { } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , true , "one state" } ,
{ & v1 . Pod { Spec : volState } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , false , "same state" } ,
{ & v1 . Pod { Spec : volState2 } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , true , "different state" } ,
2015-03-06 09:26:39 -05:00
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrDiskConflict }
2015-03-06 09:26:39 -05:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
2018-12-19 07:30:54 -05:00
ok , reasons , err := NoDiskConflict ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! ok && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if test . isOk && ! ok {
t . Errorf ( "expected ok, got none. %v %s" , test . pod , test . nodeInfo )
}
if ! test . isOk && ok {
t . Errorf ( "expected no ok, got one. %v %s" , test . pod , test . nodeInfo )
}
} )
2015-03-06 09:26:39 -05:00
}
}
func TestAWSDiskConflicts ( t * testing . T ) {
2016-11-18 15:52:35 -05:00
volState := v1 . PodSpec {
Volumes : [ ] v1 . Volume {
2015-03-06 09:26:39 -05:00
{
2016-11-18 15:52:35 -05:00
VolumeSource : v1 . VolumeSource {
AWSElasticBlockStore : & v1 . AWSElasticBlockStoreVolumeSource {
2015-04-09 09:34:16 -04:00
VolumeID : "foo" ,
2015-03-06 09:26:39 -05:00
} ,
} ,
} ,
} ,
}
2016-11-18 15:52:35 -05:00
volState2 := v1 . PodSpec {
Volumes : [ ] v1 . Volume {
2015-03-06 09:26:39 -05:00
{
2016-11-18 15:52:35 -05:00
VolumeSource : v1 . VolumeSource {
AWSElasticBlockStore : & v1 . AWSElasticBlockStoreVolumeSource {
2015-04-09 09:34:16 -04:00
VolumeID : "bar" ,
2015-03-06 09:26:39 -05:00
} ,
2014-10-13 00:34:23 -04:00
} ,
} ,
} ,
}
tests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2016-01-28 15:14:45 -05:00
isOk bool
2018-06-05 08:08:23 -04:00
name string
2015-10-20 13:24:23 -04:00
} {
2018-12-07 21:36:11 -05:00
{ & v1 . Pod { } , schedulernodeinfo . NewNodeInfo ( ) , true , "nothing" } ,
{ & v1 . Pod { } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , true , "one state" } ,
{ & v1 . Pod { Spec : volState } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , false , "same state" } ,
{ & v1 . Pod { Spec : volState2 } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , true , "different state" } ,
2015-10-20 13:24:23 -04:00
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrDiskConflict }
2015-10-20 13:24:23 -04:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
2018-12-19 07:30:54 -05:00
ok , reasons , err := NoDiskConflict ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! ok && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if test . isOk && ! ok {
t . Errorf ( "expected ok, got none. %v %s" , test . pod , test . nodeInfo )
}
if ! test . isOk && ok {
t . Errorf ( "expected no ok, got one. %v %s" , test . pod , test . nodeInfo )
}
} )
2015-10-20 13:24:23 -04:00
}
}
func TestRBDDiskConflicts ( t * testing . T ) {
2016-11-18 15:52:35 -05:00
volState := v1 . PodSpec {
Volumes : [ ] v1 . Volume {
2015-10-20 13:24:23 -04:00
{
2016-11-18 15:52:35 -05:00
VolumeSource : v1 . VolumeSource {
RBD : & v1 . RBDVolumeSource {
2015-10-20 13:24:23 -04:00
CephMonitors : [ ] string { "a" , "b" } ,
RBDPool : "foo" ,
RBDImage : "bar" ,
FSType : "ext4" ,
} ,
} ,
} ,
} ,
}
2016-11-18 15:52:35 -05:00
volState2 := v1 . PodSpec {
Volumes : [ ] v1 . Volume {
2015-10-20 13:24:23 -04:00
{
2016-11-18 15:52:35 -05:00
VolumeSource : v1 . VolumeSource {
RBD : & v1 . RBDVolumeSource {
2015-10-20 13:24:23 -04:00
CephMonitors : [ ] string { "c" , "d" } ,
RBDPool : "foo" ,
RBDImage : "bar" ,
FSType : "ext4" ,
} ,
} ,
} ,
} ,
}
tests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2016-01-28 15:14:45 -05:00
isOk bool
2018-06-05 08:08:23 -04:00
name string
2014-10-13 00:34:23 -04:00
} {
2018-12-07 21:36:11 -05:00
{ & v1 . Pod { } , schedulernodeinfo . NewNodeInfo ( ) , true , "nothing" } ,
{ & v1 . Pod { } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , true , "one state" } ,
{ & v1 . Pod { Spec : volState } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , false , "same state" } ,
{ & v1 . Pod { Spec : volState2 } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , true , "different state" } ,
2016-12-09 11:17:13 -05:00
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrDiskConflict }
2016-12-09 11:17:13 -05:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
2018-12-19 07:30:54 -05:00
ok , reasons , err := NoDiskConflict ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! ok && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if test . isOk && ! ok {
t . Errorf ( "expected ok, got none. %v %s" , test . pod , test . nodeInfo )
}
if ! test . isOk && ok {
t . Errorf ( "expected no ok, got one. %v %s" , test . pod , test . nodeInfo )
}
} )
2016-12-09 11:17:13 -05:00
}
}
func TestISCSIDiskConflicts ( t * testing . T ) {
volState := v1 . PodSpec {
Volumes : [ ] v1 . Volume {
{
VolumeSource : v1 . VolumeSource {
ISCSI : & v1 . ISCSIVolumeSource {
TargetPortal : "127.0.0.1:3260" ,
2017-02-15 00:45:22 -05:00
IQN : "iqn.2016-12.server:storage.target01" ,
2016-12-09 11:17:13 -05:00
FSType : "ext4" ,
Lun : 0 ,
} ,
} ,
} ,
} ,
}
volState2 := v1 . PodSpec {
Volumes : [ ] v1 . Volume {
{
VolumeSource : v1 . VolumeSource {
ISCSI : & v1 . ISCSIVolumeSource {
2017-02-15 00:45:22 -05:00
TargetPortal : "127.0.0.1:3260" ,
IQN : "iqn.2017-12.server:storage.target01" ,
2016-12-09 11:17:13 -05:00
FSType : "ext4" ,
2017-02-15 00:45:22 -05:00
Lun : 0 ,
2016-12-09 11:17:13 -05:00
} ,
} ,
} ,
} ,
}
tests := [ ] struct {
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2016-12-09 11:17:13 -05:00
isOk bool
2018-06-05 08:08:23 -04:00
name string
2016-12-09 11:17:13 -05:00
} {
2018-12-07 21:36:11 -05:00
{ & v1 . Pod { } , schedulernodeinfo . NewNodeInfo ( ) , true , "nothing" } ,
{ & v1 . Pod { } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , true , "one state" } ,
{ & v1 . Pod { Spec : volState } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , false , "same state" } ,
{ & v1 . Pod { Spec : volState2 } , schedulernodeinfo . NewNodeInfo ( & v1 . Pod { Spec : volState } ) , true , "different state" } ,
2014-10-13 00:34:23 -04:00
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrDiskConflict }
2014-10-13 00:34:23 -04:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
2018-12-19 07:30:54 -05:00
ok , reasons , err := NoDiskConflict ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! ok && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if test . isOk && ! ok {
t . Errorf ( "expected ok, got none. %v %s" , test . pod , test . nodeInfo )
}
if ! test . isOk && ok {
t . Errorf ( "expected no ok, got one. %v %s" , test . pod , test . nodeInfo )
}
} )
2014-10-13 00:34:23 -04:00
}
}
2014-10-21 20:13:52 -04:00
2017-07-18 07:26:41 -04:00
// TODO: Add test case for RequiredDuringSchedulingRequiredDuringExecution after it's implemented.
2014-10-21 20:13:52 -04:00
func TestPodFitsSelector ( t * testing . T ) {
tests := [ ] struct {
2018-04-24 02:01:23 -04:00
pod * v1 . Pod
labels map [ string ] string
nodeName string
fits bool
2018-06-05 08:08:23 -04:00
name string
2014-10-21 20:13:52 -04:00
} {
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod { } ,
2014-10-21 20:13:52 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "no selector" ,
2014-10-21 20:13:52 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
Spec : v1 . PodSpec {
2014-11-13 10:52:13 -05:00
NodeSelector : map [ string ] string {
"foo" : "bar" ,
} ,
2014-10-21 20:13:52 -04:00
} ,
} ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "missing labels" ,
2014-10-21 20:13:52 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
Spec : v1 . PodSpec {
2014-11-13 10:52:13 -05:00
NodeSelector : map [ string ] string {
"foo" : "bar" ,
} ,
2014-10-21 20:13:52 -04:00
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "same labels" ,
2014-10-21 20:13:52 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
Spec : v1 . PodSpec {
2014-11-13 10:52:13 -05:00
NodeSelector : map [ string ] string {
"foo" : "bar" ,
} ,
2014-10-21 20:13:52 -04:00
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
"baz" : "blah" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "node labels are superset" ,
2014-10-21 20:13:52 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
Spec : v1 . PodSpec {
2014-11-13 10:52:13 -05:00
NodeSelector : map [ string ] string {
"foo" : "bar" ,
"baz" : "blah" ,
} ,
2014-10-21 20:13:52 -04:00
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "node labels are subset" ,
2014-10-21 20:13:52 -04:00
} ,
2016-01-26 18:03:18 -05:00
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "bar" , "value2" } ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with matchExpressions using In operator that matches the existing node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "kernel-version" ,
Operator : v1 . NodeSelectorOpGt ,
Values : [ ] string { "0204" } ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
2016-09-01 05:21:17 -04:00
// We use two digit to denote major version and two digit for minor version.
2016-07-04 19:02:42 -04:00
"kernel-version" : "0206" ,
2016-01-26 18:03:18 -05:00
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with matchExpressions using Gt operator that matches the existing node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "mem-type" ,
Operator : v1 . NodeSelectorOpNotIn ,
Values : [ ] string { "DDR" , "DDR2" } ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"mem-type" : "DDR3" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with matchExpressions using NotIn operator that matches the existing node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "GPU" ,
Operator : v1 . NodeSelectorOpExists ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"GPU" : "NVIDIA-GRID-K1" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with matchExpressions using Exists operator that matches the existing node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "value1" , "value2" } ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with affinity that don't match node's labels won't schedule onto the node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : nil ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with a nil []NodeSelectorTerm in affinity, can't match the node's labels and won't schedule onto the node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm { } ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with an empty []NodeSelectorTerm in affinity, can't match the node's labels and won't schedule onto the node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement { } ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with empty MatchExpressions is not a valid value will match no objects and won't schedule onto the node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-30 11:51:12 -05:00
pod : & v1 . Pod { } ,
2016-01-26 18:03:18 -05:00
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with no Affinity will schedule onto a node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : nil ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with Affinity but nil NodeSelector will schedule onto a node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "GPU" ,
Operator : v1 . NodeSelectorOpExists ,
} , {
Key : "GPU" ,
Operator : v1 . NodeSelectorOpNotIn ,
Values : [ ] string { "AMD" , "INTER" } ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"GPU" : "NVIDIA-GRID-K1" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with multiple matchExpressions ANDed that matches the existing node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "GPU" ,
Operator : v1 . NodeSelectorOpExists ,
} , {
Key : "GPU" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "AMD" , "INTER" } ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"GPU" : "NVIDIA-GRID-K1" ,
} ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with multiple matchExpressions ANDed that doesn't match the existing node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-11-30 11:51:12 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "bar" , "value2" } ,
} ,
} ,
} ,
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "diffkey" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "wrong" , "value2" } ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
2016-11-30 11:51:12 -05:00
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with multiple NodeSelectorTerms ORed in affinity, matches the node's labels and will schedule onto the node" ,
2016-01-26 18:03:18 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
Spec : v1 . PodSpec {
2016-01-26 18:03:18 -05:00
NodeSelector : map [ string ] string {
"foo" : "bar" ,
} ,
2016-11-30 11:51:12 -05:00
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpExists ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with an Affinity and a PodSpec.NodeSelector(the old thing that we are deprecating) " +
2016-01-26 18:03:18 -05:00
"both are satisfied, will schedule onto the node" ,
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
Spec : v1 . PodSpec {
2016-01-26 18:03:18 -05:00
NodeSelector : map [ string ] string {
"foo" : "bar" ,
} ,
2016-11-30 11:51:12 -05:00
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpExists ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-01-26 18:03:18 -05:00
} ,
} ,
labels : map [ string ] string {
"foo" : "barrrrrr" ,
} ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with an Affinity matches node's labels but the PodSpec.NodeSelector(the old thing that we are deprecating) " +
2016-01-26 18:03:18 -05:00
"is not satisfied, won't schedule onto the node" ,
} ,
2018-04-24 23:14:24 -04:00
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpNotIn ,
Values : [ ] string { "invalid value: ___@#$%^" } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
labels : map [ string ] string {
"foo" : "bar" ,
} ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with an invalid value in Affinity term won't be scheduled onto the node" ,
2018-04-24 23:14:24 -04:00
} ,
2018-04-24 02:01:23 -04:00
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchFields : [ ] v1 . NodeSelectorRequirement {
{
2018-09-27 22:37:38 -04:00
Key : schedulerapi . NodeFieldSelectorKeyNodeName ,
2018-04-24 02:01:23 -04:00
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "node_1" } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
nodeName : "node_1" ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with matchFields using In operator that matches the existing node" ,
2018-04-24 02:01:23 -04:00
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchFields : [ ] v1 . NodeSelectorRequirement {
{
2018-09-27 22:37:38 -04:00
Key : schedulerapi . NodeFieldSelectorKeyNodeName ,
2018-04-24 02:01:23 -04:00
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "node_1" } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
nodeName : "node_2" ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with matchFields using In operator that does not match the existing node" ,
2018-04-24 02:01:23 -04:00
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchFields : [ ] v1 . NodeSelectorRequirement {
{
2018-09-27 22:37:38 -04:00
Key : schedulerapi . NodeFieldSelectorKeyNodeName ,
2018-04-24 02:01:23 -04:00
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "node_1" } ,
} ,
} ,
} ,
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "bar" } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
nodeName : "node_2" ,
labels : map [ string ] string { "foo" : "bar" } ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with two terms: matchFields does not match, but matchExpressions matches" ,
2018-04-24 02:01:23 -04:00
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchFields : [ ] v1 . NodeSelectorRequirement {
{
2018-09-27 22:37:38 -04:00
Key : schedulerapi . NodeFieldSelectorKeyNodeName ,
2018-04-24 02:01:23 -04:00
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "node_1" } ,
} ,
} ,
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "bar" } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
nodeName : "node_2" ,
labels : map [ string ] string { "foo" : "bar" } ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with one term: matchFields does not match, but matchExpressions matches" ,
2018-04-24 02:01:23 -04:00
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchFields : [ ] v1 . NodeSelectorRequirement {
{
2018-09-27 22:37:38 -04:00
Key : schedulerapi . NodeFieldSelectorKeyNodeName ,
2018-04-24 02:01:23 -04:00
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "node_1" } ,
} ,
} ,
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "bar" } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
nodeName : "node_1" ,
labels : map [ string ] string { "foo" : "bar" } ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "Pod with one term: both matchFields and matchExpressions match" ,
2018-04-24 02:01:23 -04:00
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchFields : [ ] v1 . NodeSelectorRequirement {
{
2018-09-27 22:37:38 -04:00
Key : schedulerapi . NodeFieldSelectorKeyNodeName ,
2018-04-24 02:01:23 -04:00
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "node_1" } ,
} ,
} ,
} ,
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "foo" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "not-match-to-bar" } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
nodeName : "node_2" ,
labels : map [ string ] string { "foo" : "bar" } ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Pod with two terms: both matchFields and matchExpressions do not match" ,
2018-04-24 02:01:23 -04:00
} ,
2014-10-21 20:13:52 -04:00
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrNodeSelectorNotMatch }
2016-01-26 18:03:18 -05:00
2014-10-21 20:13:52 -04:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
node := v1 . Node { ObjectMeta : metav1 . ObjectMeta {
Name : test . nodeName ,
Labels : test . labels ,
} }
2018-12-07 21:36:11 -05:00
nodeInfo := schedulernodeinfo . NewNodeInfo ( )
2018-06-05 08:08:23 -04:00
nodeInfo . SetNode ( & node )
2018-12-19 07:30:54 -05:00
fits , reasons , err := PodMatchNodeSelector ( test . pod , GetPredicateMetadata ( test . pod , nil ) , nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . fits {
t . Errorf ( "expected: %v got %v" , test . fits , fits )
}
} )
2014-10-21 20:13:52 -04:00
}
}
2014-12-22 16:54:41 -05:00
func TestNodeLabelPresence ( t * testing . T ) {
label := map [ string ] string { "foo" : "bar" , "bar" : "foo" }
tests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
2016-01-28 15:14:45 -05:00
labels [ ] string
presence bool
fits bool
2018-06-05 08:08:23 -04:00
name string
2014-12-22 16:54:41 -05:00
} {
{
labels : [ ] string { "baz" } ,
presence : true ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "label does not match, presence true" ,
2014-12-22 16:54:41 -05:00
} ,
{
labels : [ ] string { "baz" } ,
presence : false ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "label does not match, presence false" ,
2014-12-22 16:54:41 -05:00
} ,
{
labels : [ ] string { "foo" , "baz" } ,
presence : true ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "one label matches, presence true" ,
2014-12-22 16:54:41 -05:00
} ,
{
labels : [ ] string { "foo" , "baz" } ,
presence : false ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "one label matches, presence false" ,
2014-12-22 16:54:41 -05:00
} ,
{
labels : [ ] string { "foo" , "bar" } ,
presence : true ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "all labels match, presence true" ,
2014-12-22 16:54:41 -05:00
} ,
{
labels : [ ] string { "foo" , "bar" } ,
presence : false ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "all labels match, presence false" ,
2014-12-22 16:54:41 -05:00
} ,
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrNodeLabelPresenceViolated }
2016-08-09 08:01:46 -04:00
2014-12-22 16:54:41 -05:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
node := v1 . Node { ObjectMeta : metav1 . ObjectMeta { Labels : label } }
2018-12-07 21:36:11 -05:00
nodeInfo := schedulernodeinfo . NewNodeInfo ( )
2018-06-05 08:08:23 -04:00
nodeInfo . SetNode ( & node )
labelChecker := NodeLabelChecker { test . labels , test . presence }
2018-12-19 07:30:54 -05:00
fits , reasons , err := labelChecker . CheckNodeLabelPresence ( test . pod , GetPredicateMetadata ( test . pod , nil ) , nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . fits {
t . Errorf ( "expected: %v got %v" , test . fits , fits )
}
} )
2014-12-22 16:54:41 -05:00
}
}
2014-12-22 18:55:31 -05:00
func TestServiceAffinity ( t * testing . T ) {
selector := map [ string ] string { "foo" : "bar" }
labels1 := map [ string ] string {
"region" : "r1" ,
"zone" : "z11" ,
}
labels2 := map [ string ] string {
"region" : "r1" ,
"zone" : "z12" ,
}
labels3 := map [ string ] string {
"region" : "r2" ,
"zone" : "z21" ,
}
labels4 := map [ string ] string {
"region" : "r2" ,
"zone" : "z22" ,
}
2017-01-16 22:38:19 -05:00
node1 := v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , Labels : labels1 } }
node2 := v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "machine2" , Labels : labels2 } }
node3 := v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "machine3" , Labels : labels3 } }
node4 := v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "machine4" , Labels : labels4 } }
node5 := v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "machine5" , Labels : labels4 } }
2014-12-22 18:55:31 -05:00
tests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
pods [ ] * v1 . Pod
services [ ] * v1 . Service
node * v1 . Node
2014-12-22 18:55:31 -05:00
labels [ ] string
fits bool
2018-06-05 08:08:23 -04:00
name string
2014-12-22 18:55:31 -05:00
} {
{
2016-11-18 15:52:35 -05:00
pod : new ( v1 . Pod ) ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2014-12-22 18:55:31 -05:00
fits : true ,
labels : [ ] string { "region" } ,
2018-06-05 08:08:23 -04:00
name : "nothing scheduled" ,
2014-12-22 18:55:31 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod { Spec : v1 . PodSpec { NodeSelector : map [ string ] string { "region" : "r1" } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2014-12-22 18:55:31 -05:00
fits : true ,
labels : [ ] string { "region" } ,
2018-06-05 08:08:23 -04:00
name : "pod with region label match" ,
2014-12-22 18:55:31 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod { Spec : v1 . PodSpec { NodeSelector : map [ string ] string { "region" : "r2" } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2014-12-22 18:55:31 -05:00
fits : false ,
labels : [ ] string { "region" } ,
2018-06-05 08:08:23 -04:00
name : "pod with region label mismatch" ,
2014-12-22 18:55:31 -05:00
} ,
{
2017-01-16 22:38:19 -05:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Labels : selector } } ,
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Labels : selector } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-11-18 15:52:35 -05:00
services : [ ] * v1 . Service { { Spec : v1 . ServiceSpec { Selector : selector } } } ,
2014-12-22 18:55:31 -05:00
fits : true ,
labels : [ ] string { "region" } ,
2018-06-05 08:08:23 -04:00
name : "service pod on same node" ,
2014-12-22 18:55:31 -05:00
} ,
{
2017-01-16 22:38:19 -05:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Labels : selector } } ,
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine2" } , ObjectMeta : metav1 . ObjectMeta { Labels : selector } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-11-18 15:52:35 -05:00
services : [ ] * v1 . Service { { Spec : v1 . ServiceSpec { Selector : selector } } } ,
2014-12-22 18:55:31 -05:00
fits : true ,
labels : [ ] string { "region" } ,
2018-06-05 08:08:23 -04:00
name : "service pod on different node, region match" ,
2014-12-22 18:55:31 -05:00
} ,
{
2017-01-16 22:38:19 -05:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Labels : selector } } ,
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine3" } , ObjectMeta : metav1 . ObjectMeta { Labels : selector } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-11-18 15:52:35 -05:00
services : [ ] * v1 . Service { { Spec : v1 . ServiceSpec { Selector : selector } } } ,
2014-12-22 18:55:31 -05:00
fits : false ,
labels : [ ] string { "region" } ,
2018-06-05 08:08:23 -04:00
name : "service pod on different node, region mismatch" ,
2014-12-22 18:55:31 -05:00
} ,
2015-03-06 19:30:16 -05:00
{
2017-01-16 22:38:19 -05:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Labels : selector , Namespace : "ns1" } } ,
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine3" } , ObjectMeta : metav1 . ObjectMeta { Labels : selector , Namespace : "ns1" } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2017-01-16 22:38:19 -05:00
services : [ ] * v1 . Service { { Spec : v1 . ServiceSpec { Selector : selector } , ObjectMeta : metav1 . ObjectMeta { Namespace : "ns2" } } } ,
2015-03-06 19:30:16 -05:00
fits : true ,
labels : [ ] string { "region" } ,
2018-06-05 08:08:23 -04:00
name : "service in different namespace, region mismatch" ,
2015-03-06 19:30:16 -05:00
} ,
{
2017-01-16 22:38:19 -05:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Labels : selector , Namespace : "ns1" } } ,
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine3" } , ObjectMeta : metav1 . ObjectMeta { Labels : selector , Namespace : "ns2" } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2017-01-16 22:38:19 -05:00
services : [ ] * v1 . Service { { Spec : v1 . ServiceSpec { Selector : selector } , ObjectMeta : metav1 . ObjectMeta { Namespace : "ns1" } } } ,
2015-03-06 19:30:16 -05:00
fits : true ,
labels : [ ] string { "region" } ,
2018-06-05 08:08:23 -04:00
name : "pod in different namespace, region mismatch" ,
2015-03-06 19:30:16 -05:00
} ,
{
2017-01-16 22:38:19 -05:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Labels : selector , Namespace : "ns1" } } ,
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine3" } , ObjectMeta : metav1 . ObjectMeta { Labels : selector , Namespace : "ns1" } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2017-01-16 22:38:19 -05:00
services : [ ] * v1 . Service { { Spec : v1 . ServiceSpec { Selector : selector } , ObjectMeta : metav1 . ObjectMeta { Namespace : "ns1" } } } ,
2015-03-06 19:30:16 -05:00
fits : false ,
labels : [ ] string { "region" } ,
2018-06-05 08:08:23 -04:00
name : "service and pod in same namespace, region mismatch" ,
2015-03-06 19:30:16 -05:00
} ,
2014-12-22 18:55:31 -05:00
{
2017-01-16 22:38:19 -05:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Labels : selector } } ,
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine2" } , ObjectMeta : metav1 . ObjectMeta { Labels : selector } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-11-18 15:52:35 -05:00
services : [ ] * v1 . Service { { Spec : v1 . ServiceSpec { Selector : selector } } } ,
2014-12-22 18:55:31 -05:00
fits : false ,
labels : [ ] string { "region" , "zone" } ,
2018-06-05 08:08:23 -04:00
name : "service pod on different node, multiple labels, not all match" ,
2014-12-22 18:55:31 -05:00
} ,
{
2017-01-16 22:38:19 -05:00
pod : & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Labels : selector } } ,
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine5" } , ObjectMeta : metav1 . ObjectMeta { Labels : selector } } } ,
2016-04-28 10:51:17 -04:00
node : & node4 ,
2016-11-18 15:52:35 -05:00
services : [ ] * v1 . Service { { Spec : v1 . ServiceSpec { Selector : selector } } } ,
2014-12-22 18:55:31 -05:00
fits : true ,
labels : [ ] string { "region" , "zone" } ,
2018-06-05 08:08:23 -04:00
name : "service pod on different node, multiple labels, all match" ,
2014-12-22 18:55:31 -05:00
} ,
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrServiceAffinityViolated }
2014-12-22 18:55:31 -05:00
for _ , test := range tests {
2016-10-12 12:03:01 -04:00
testIt := func ( skipPrecompute bool ) {
2018-06-05 08:08:23 -04:00
t . Run ( fmt . Sprintf ( "%v/skipPrecompute/%v" , test . name , skipPrecompute ) , func ( t * testing . T ) {
nodes := [ ] v1 . Node { node1 , node2 , node3 , node4 , node5 }
2018-12-07 21:36:11 -05:00
nodeInfo := schedulernodeinfo . NewNodeInfo ( )
2018-06-05 08:08:23 -04:00
nodeInfo . SetNode ( test . node )
2018-12-07 21:36:11 -05:00
nodeInfoMap := map [ string ] * schedulernodeinfo . NodeInfo { test . node . Name : nodeInfo }
2018-06-05 08:08:23 -04:00
// Reimplementing the logic that the scheduler implements: Any time it makes a predicate, it registers any precomputations.
predicate , precompute := NewServiceAffinityPredicate ( schedulertesting . FakePodLister ( test . pods ) , schedulertesting . FakeServiceLister ( test . services ) , FakeNodeListInfo ( nodes ) , test . labels )
// Register a precomputation or Rewrite the precomputation to a no-op, depending on the state we want to test.
RegisterPredicateMetadataProducer ( "ServiceAffinityMetaProducer" , func ( pm * predicateMetadata ) {
if ! skipPrecompute {
precompute ( pm )
}
} )
2018-12-19 07:30:54 -05:00
if pmeta , ok := ( GetPredicateMetadata ( test . pod , nodeInfoMap ) ) . ( * predicateMetadata ) ; ok {
2018-06-05 08:08:23 -04:00
fits , reasons , err := predicate ( test . pod , pmeta , nodeInfo )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . fits {
t . Errorf ( "expected: %v got %v" , test . fits , fits )
}
} else {
t . Errorf ( "Error casting." )
2016-10-12 12:03:01 -04:00
}
} )
2014-12-22 18:55:31 -05:00
}
2016-10-12 12:03:01 -04:00
testIt ( false ) // Confirm that the predicate works without precomputed data (resilience)
testIt ( true ) // Confirm that the predicate works with the precomputed data (better performance)
2014-12-22 18:55:31 -05:00
}
}
2016-01-14 15:45:08 -05:00
2016-11-18 15:52:35 -05:00
func newPodWithPort ( hostPorts ... int ) * v1 . Pod {
networkPorts := [ ] v1 . ContainerPort { }
2016-01-05 20:10:59 -05:00
for _ , port := range hostPorts {
2016-11-18 15:52:35 -05:00
networkPorts = append ( networkPorts , v1 . ContainerPort { HostPort : int32 ( port ) } )
2016-01-05 20:10:59 -05:00
}
2016-11-18 15:52:35 -05:00
return & v1 . Pod {
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-01-05 20:10:59 -05:00
{
Ports : networkPorts ,
} ,
} ,
} ,
}
}
func TestRunGeneralPredicates ( t * testing . T ) {
resourceTests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2016-11-18 15:52:35 -05:00
node * v1 . Node
2016-01-05 20:10:59 -05:00
fits bool
2018-06-05 08:08:23 -04:00
name string
2016-01-05 20:10:59 -05:00
wErr error
2018-12-19 07:30:54 -05:00
reasons [ ] PredicateFailureReason
2016-01-05 20:10:59 -05:00
} {
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod { } ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 9 , Memory : 19 } ) ) ,
2016-11-18 15:52:35 -05:00
node : & v1 . Node {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "machine1" } ,
2018-03-21 16:56:51 -04:00
Status : v1 . NodeStatus { Capacity : makeResources ( 10 , 20 , 32 , 0 , 0 , 0 ) . Capacity , Allocatable : makeAllocatableResources ( 10 , 20 , 32 , 0 , 0 , 0 ) } ,
2016-04-28 10:51:17 -04:00
} ,
2016-01-05 20:10:59 -05:00
fits : true ,
wErr : nil ,
2018-06-05 08:08:23 -04:00
name : "no resources/port/host requested always fits" ,
2016-01-05 20:10:59 -05:00
} ,
{
2018-12-07 21:36:11 -05:00
pod : newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 8 , Memory : 10 } ) ,
nodeInfo : schedulernodeinfo . NewNodeInfo (
newResourcePod ( schedulernodeinfo . Resource { MilliCPU : 5 , Memory : 19 } ) ) ,
2016-11-18 15:52:35 -05:00
node : & v1 . Node {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "machine1" } ,
2018-03-21 16:56:51 -04:00
Status : v1 . NodeStatus { Capacity : makeResources ( 10 , 20 , 32 , 0 , 0 , 0 ) . Capacity , Allocatable : makeAllocatableResources ( 10 , 20 , 32 , 0 , 0 , 0 ) } ,
2016-04-28 10:51:17 -04:00
} ,
2016-01-05 20:10:59 -05:00
fits : false ,
2016-08-09 08:01:46 -04:00
wErr : nil ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason {
2016-11-18 15:52:35 -05:00
NewInsufficientResourceError ( v1 . ResourceCPU , 8 , 5 , 10 ) ,
NewInsufficientResourceError ( v1 . ResourceMemory , 10 , 19 , 20 ) ,
2016-08-09 08:01:46 -04:00
} ,
2018-06-05 08:08:23 -04:00
name : "not enough cpu and memory resource" ,
2016-01-05 20:10:59 -05:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
Spec : v1 . PodSpec {
2016-01-05 20:10:59 -05:00
NodeName : "machine2" ,
} ,
} ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo ( ) ,
2016-11-18 15:52:35 -05:00
node : & v1 . Node {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "machine1" } ,
2018-03-21 16:56:51 -04:00
Status : v1 . NodeStatus { Capacity : makeResources ( 10 , 20 , 32 , 0 , 0 , 0 ) . Capacity , Allocatable : makeAllocatableResources ( 10 , 20 , 32 , 0 , 0 , 0 ) } ,
2016-04-28 10:51:17 -04:00
} ,
2016-08-09 08:01:46 -04:00
fits : false ,
wErr : nil ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { ErrPodNotMatchHostName } ,
2018-06-05 08:08:23 -04:00
name : "host not match" ,
2016-01-05 20:10:59 -05:00
} ,
{
pod : newPodWithPort ( 123 ) ,
2018-12-07 21:36:11 -05:00
nodeInfo : schedulernodeinfo . NewNodeInfo ( newPodWithPort ( 123 ) ) ,
2016-11-18 15:52:35 -05:00
node : & v1 . Node {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "machine1" } ,
2018-03-21 16:56:51 -04:00
Status : v1 . NodeStatus { Capacity : makeResources ( 10 , 20 , 32 , 0 , 0 , 0 ) . Capacity , Allocatable : makeAllocatableResources ( 10 , 20 , 32 , 0 , 0 , 0 ) } ,
2016-04-28 10:51:17 -04:00
} ,
2016-08-09 08:01:46 -04:00
fits : false ,
wErr : nil ,
2018-12-19 07:30:54 -05:00
reasons : [ ] PredicateFailureReason { ErrPodNotFitsHostPorts } ,
2018-06-05 08:08:23 -04:00
name : "hostport conflict" ,
2016-01-05 20:10:59 -05:00
} ,
}
for _ , test := range resourceTests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
test . nodeInfo . SetNode ( test . node )
2018-12-19 07:30:54 -05:00
fits , reasons , err := GeneralPredicates ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , test . reasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , test . reasons )
}
if fits != test . fits {
t . Errorf ( "expected: %v got %v" , test . fits , fits )
}
} )
2016-01-05 20:10:59 -05:00
}
}
2016-05-04 02:50:31 -04:00
2017-07-18 07:26:41 -04:00
// TODO: Add test case for RequiredDuringSchedulingRequiredDuringExecution after it's implemented.
2016-05-04 02:50:31 -04:00
func TestInterPodAffinity ( t * testing . T ) {
podLabel := map [ string ] string { "service" : "securityscan" }
labels1 := map [ string ] string {
"region" : "r1" ,
"zone" : "z11" ,
}
podLabel2 := map [ string ] string { "security" : "S1" }
2017-01-16 22:38:19 -05:00
node1 := v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , Labels : labels1 } }
2016-05-04 02:50:31 -04:00
tests := [ ] struct {
2017-09-13 11:47:58 -04:00
pod * v1 . Pod
pods [ ] * v1 . Pod
node * v1 . Node
fits bool
2018-06-05 08:08:23 -04:00
name string
2018-12-19 07:30:54 -05:00
expectFailureReasons [ ] PredicateFailureReason
2016-05-04 02:50:31 -04:00
} {
{
2016-11-18 15:52:35 -05:00
pod : new ( v1 . Pod ) ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-05-04 02:50:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "A pod that has no required pod affinity scheduling rules can schedule onto a node with no existing pods" ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel2 ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
TopologyKey : "region" ,
} ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2017-01-16 22:38:19 -05:00
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-05-04 02:50:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "satisfies with requiredDuringSchedulingIgnoredDuringExecution in PodAffinity using In operator that matches the existing pod" ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel2 ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpNotIn ,
Values : [ ] string { "securityscan3" , "value3" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2017-01-16 22:38:19 -05:00
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-05-04 02:50:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "satisfies the pod with requiredDuringSchedulingIgnoredDuringExecution in PodAffinity using not in operator in labelSelector that matches the existing pod" ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel2 ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
Namespaces : [ ] string { "DiffNameSpace" } ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2017-09-13 11:47:58 -04:00
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Labels : podLabel , Namespace : "ns" } } } ,
node : & node1 ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Does not satisfy the PodAffinity with labelSelector because of diff Namespace" ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrPodAffinityRulesNotMatch } ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "antivirusscan" , "value2" } ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2017-09-13 11:47:58 -04:00
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } } } ,
node : & node1 ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "Doesn't satisfy the PodAffinity because of unmatching labelSelector with the existing pod" ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrPodAffinityRulesNotMatch } ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel2 ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
2016-05-04 02:50:31 -04:00
{
2016-12-08 10:14:21 -05:00
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpExists ,
} , {
Key : "wrongkey" ,
Operator : metav1 . LabelSelectorOpDoesNotExist ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
TopologyKey : "region" ,
2016-05-04 02:50:31 -04:00
} , {
2016-12-08 10:14:21 -05:00
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" } ,
} , {
Key : "service" ,
Operator : metav1 . LabelSelectorOpNotIn ,
Values : [ ] string { "WrongValue" } ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
TopologyKey : "region" ,
} ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2017-01-16 22:38:19 -05:00
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-05-04 02:50:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "satisfies the PodAffinity with different label Operators in multiple RequiredDuringSchedulingIgnoredDuringExecution " ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel2 ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
2016-05-04 02:50:31 -04:00
{
2016-12-08 10:14:21 -05:00
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpExists ,
} , {
Key : "wrongkey" ,
Operator : metav1 . LabelSelectorOpDoesNotExist ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
TopologyKey : "region" ,
2016-05-04 02:50:31 -04:00
} , {
2016-12-08 10:14:21 -05:00
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan2" } ,
} , {
Key : "service" ,
Operator : metav1 . LabelSelectorOpNotIn ,
Values : [ ] string { "WrongValue" } ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
TopologyKey : "region" ,
} ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2017-09-13 11:47:58 -04:00
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } } } ,
node : & node1 ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "The labelSelector requirements(items of matchExpressions) are ANDed, the pod cannot schedule onto the node because one of the matchExpression item don't match." ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrPodAffinityRulesNotMatch } ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel2 ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "antivirusscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "node" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2017-01-16 22:38:19 -05:00
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } } } ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-05-04 02:50:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "satisfies the PodAffinity and PodAntiAffinity with the existing pod" ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel2 ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "antivirusscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "node" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2016-12-08 10:14:21 -05:00
pods : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec {
NodeName : "machine1" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "antivirusscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "node" ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
} ,
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-04-28 10:51:17 -04:00
node : & node1 ,
2016-05-04 02:50:31 -04:00
fits : true ,
2018-06-05 08:08:23 -04:00
name : "satisfies the PodAffinity and PodAntiAffinity and PodAntiAffinity symmetry with the existing pod" ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel2 ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "zone" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2017-09-13 11:47:58 -04:00
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } } } ,
node : & node1 ,
fits : false ,
2018-10-25 21:59:40 -04:00
name : "satisfies the PodAffinity but doesn't satisfy the PodAntiAffinity with the existing pod" ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "antivirusscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "node" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2016-12-08 10:14:21 -05:00
pods : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec {
NodeName : "machine1" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
} ,
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2017-09-13 11:47:58 -04:00
node : & node1 ,
fits : false ,
2018-10-25 21:59:40 -04:00
name : "satisfies the PodAffinity and PodAntiAffinity but doesn't satisfy PodAntiAffinity symmetry with the existing pod" ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-05-04 02:50:31 -04:00
Labels : podLabel ,
2016-12-08 10:14:21 -05:00
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpNotIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2017-09-13 11:47:58 -04:00
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "machine2" } , ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } } } ,
node : & node1 ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "pod matches its own Label in PodAffinity and that matches the existing pod Labels" ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrPodAffinityRulesNotMatch } ,
2016-05-04 02:50:31 -04:00
} ,
2016-07-12 23:47:50 -04:00
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-07-12 23:47:50 -04:00
Labels : podLabel ,
} ,
} ,
2016-12-08 10:14:21 -05:00
pods : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec { NodeName : "machine1" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
2016-07-12 23:47:50 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
} ,
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2017-09-13 11:47:58 -04:00
node : & node1 ,
fits : false ,
2018-06-05 08:08:23 -04:00
name : "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. doesn't satisfy PodAntiAffinity symmetry with the existing pod" ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
2016-07-12 23:47:50 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-07-12 23:47:50 -04:00
Labels : podLabel ,
} ,
} ,
2016-12-08 10:14:21 -05:00
pods : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec { NodeName : "machine1" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpNotIn ,
Values : [ ] string { "securityscan" , "value2" } ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-07-12 23:47:50 -04:00
node : & node1 ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. satisfy PodAntiAffinity symmetry with the existing pod" ,
2016-07-12 23:47:50 -04:00
} ,
2018-09-04 02:10:17 -04:00
{
pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Labels : podLabel ,
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "security" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{
ObjectMeta : metav1 . ObjectMeta { Labels : podLabel2 } ,
Spec : v1 . PodSpec { NodeName : "machine1" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "security" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
node : & node1 ,
fits : false ,
name : "satisfies the PodAntiAffinity with existing pod but doesn't satisfy PodAntiAffinity symmetry with incoming pod" ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
2018-09-04 02:10:17 -04:00
} ,
{
pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "security" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{
ObjectMeta : metav1 . ObjectMeta { Labels : podLabel2 } ,
Spec : v1 . PodSpec {
NodeName : "machine1" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "security" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
node : & node1 ,
fits : false ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
2018-09-04 02:10:17 -04:00
name : "PodAntiAffinity symmetry check a1: incoming pod and existing pod partially match each other on AffinityTerms" ,
} ,
{
pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Labels : podLabel2 } ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "security" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{
ObjectMeta : metav1 . ObjectMeta { Labels : podLabel } ,
Spec : v1 . PodSpec {
NodeName : "machine1" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "security" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
node : & node1 ,
fits : false ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
2018-09-04 02:10:17 -04:00
name : "PodAntiAffinity symmetry check a2: incoming pod and existing pod partially match each other on AffinityTerms" ,
} ,
{
pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "abc" : "" , "xyz" : "" } } ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "abc" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "def" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "def" : "" , "xyz" : "" } } ,
Spec : v1 . PodSpec {
NodeName : "machine1" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "abc" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "def" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
node : & node1 ,
fits : false ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
2018-09-04 02:10:17 -04:00
name : "PodAntiAffinity symmetry check b1: incoming pod and existing pod partially match each other on AffinityTerms" ,
} ,
{
pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "def" : "" , "xyz" : "" } } ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "abc" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "def" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "abc" : "" , "xyz" : "" } } ,
Spec : v1 . PodSpec {
NodeName : "machine1" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "abc" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "def" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
node : & node1 ,
fits : false ,
2018-12-19 07:30:54 -05:00
expectFailureReasons : [ ] PredicateFailureReason { ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
2018-09-04 02:10:17 -04:00
name : "PodAntiAffinity symmetry check b2: incoming pod and existing pod partially match each other on AffinityTerms" ,
} ,
2016-05-04 02:50:31 -04:00
}
2016-08-09 08:01:46 -04:00
2016-05-04 02:50:31 -04:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
node := test . node
var podsOnNode [ ] * v1 . Pod
for _ , pod := range test . pods {
if pod . Spec . NodeName == node . Name {
podsOnNode = append ( podsOnNode , pod )
}
2016-05-04 02:50:31 -04:00
}
2018-06-05 08:08:23 -04:00
fit := PodAffinityChecker {
info : FakeNodeInfo ( * node ) ,
podLister : schedulertesting . FakePodLister ( test . pods ) ,
}
2018-12-07 21:36:11 -05:00
nodeInfo := schedulernodeinfo . NewNodeInfo ( podsOnNode ... )
2018-06-05 08:08:23 -04:00
nodeInfo . SetNode ( test . node )
2018-12-07 21:36:11 -05:00
nodeInfoMap := map [ string ] * schedulernodeinfo . NodeInfo { test . node . Name : nodeInfo }
2018-12-19 07:30:54 -05:00
fits , reasons , _ := fit . InterPodAffinityMatches ( test . pod , GetPredicateMetadata ( test . pod , nodeInfoMap ) , nodeInfo )
2018-06-05 08:08:23 -04:00
if ! fits && ! reflect . DeepEqual ( reasons , test . expectFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , test . expectFailureReasons )
}
if fits != test . fits {
t . Errorf ( "expected %v got %v" , test . fits , fits )
}
} )
2016-05-04 02:50:31 -04:00
}
}
func TestInterPodAffinityWithMultipleNodes ( t * testing . T ) {
podLabelA := map [ string ] string {
"foo" : "bar" ,
}
labelRgChina := map [ string ] string {
"region" : "China" ,
}
labelRgChinaAzAz1 := map [ string ] string {
"region" : "China" ,
"az" : "az1" ,
}
labelRgIndia := map [ string ] string {
"region" : "India" ,
}
2017-01-17 00:28:54 -05:00
labelRgUS := map [ string ] string {
"region" : "US" ,
}
2016-05-04 02:50:31 -04:00
tests := [ ] struct {
2017-09-13 11:47:58 -04:00
pod * v1 . Pod
pods [ ] * v1 . Pod
nodes [ ] v1 . Node
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons [ ] [ ] PredicateFailureReason
2017-09-13 11:47:58 -04:00
fits map [ string ] bool
2018-06-05 08:08:23 -04:00
name string
2017-09-13 11:47:58 -04:00
nometa bool
2016-05-04 02:50:31 -04:00
} {
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2016-12-08 10:14:21 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
2018-09-04 02:10:17 -04:00
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "bar" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{ Spec : v1 . PodSpec { NodeName : "machine1" } , ObjectMeta : metav1 . ObjectMeta { Name : "p1" , Labels : podLabelA } } ,
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "machine1" , Labels : labelRgChina } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "machine2" , Labels : labelRgChinaAzAz1 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "machine3" , Labels : labelRgIndia } } ,
} ,
fits : map [ string ] bool {
"machine1" : true ,
"machine2" : true ,
"machine3" : false ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason { nil , nil , { ErrPodAffinityNotMatch , ErrPodAffinityRulesNotMatch } } ,
2018-10-25 21:59:40 -04:00
name : "A pod can be scheduled onto all the nodes that have the same topology key & label value with one of them has an existing pod that matches the affinity rules" ,
2018-09-04 02:10:17 -04:00
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "hostname" ,
Operator : v1 . NodeSelectorOpNotIn ,
Values : [ ] string { "h1" } ,
} ,
} ,
} ,
} ,
} ,
} ,
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "abc" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{ Spec : v1 . PodSpec { NodeName : "nodeA" } , ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "abc" } } } ,
{ Spec : v1 . PodSpec { NodeName : "nodeB" } , ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "def" } } } ,
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "hostname" : "h1" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "hostname" : "h2" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason { nil , nil } ,
2018-09-04 02:10:17 -04:00
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : true ,
} ,
2018-10-25 21:59:40 -04:00
name : "NodeA and nodeB have same topologyKey and label value. NodeA does not satisfy node affinity rule, but has an existing pod that matches the inter pod affinity rule. The pod can be scheduled onto nodeB." ,
2018-09-04 02:10:17 -04:00
} ,
{
pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Labels : map [ string ] string {
"foo" : "bar" ,
"service" : "securityscan" ,
} ,
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "bar" } ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" } ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod { { Spec : v1 . PodSpec { NodeName : "nodeA" } , ObjectMeta : metav1 . ObjectMeta { Name : "p1" , Labels : map [ string ] string { "foo" : "bar" } } } } ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "zone" : "az1" , "hostname" : "h1" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "zone" : "az2" , "hostname" : "h2" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason { nil , nil } ,
2018-09-04 02:10:17 -04:00
fits : map [ string ] bool {
"nodeA" : true ,
"nodeB" : true ,
} ,
name : "The affinity rule is to schedule all of the pods of this collection to the same zone. The first pod of the collection " +
2018-10-25 21:59:40 -04:00
"should not be blocked from being scheduled onto any node, even there's no existing pod that matches the rule anywhere." ,
2018-09-04 02:10:17 -04:00
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "abc" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{ Spec : v1 . PodSpec { NodeName : "nodeA" } , ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "abc" } } } ,
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason { { ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } , { ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } } ,
2018-09-04 02:10:17 -04:00
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : false ,
} ,
2018-10-25 21:59:40 -04:00
name : "NodeA and nodeB have same topologyKey and label value. NodeA has an existing pod that matches the inter pod affinity rule. The pod can not be scheduled onto nodeA and nodeB." ,
2018-09-04 02:10:17 -04:00
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "abc" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "service" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "securityscan" } ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{ Spec : v1 . PodSpec { NodeName : "nodeA" } , ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "abc" , "service" : "securityscan" } } } ,
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z2" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
} ,
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : false ,
} ,
name : "This test ensures that anti-affinity matches a pod when any term of the anti-affinity rule matches a pod." ,
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "abc" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{ Spec : v1 . PodSpec { NodeName : "nodeA" } , ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "abc" } } } ,
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : labelRgChina } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : labelRgChinaAzAz1 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeC" , Labels : labelRgIndia } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason { { ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } , { ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } , nil } ,
2018-09-04 02:10:17 -04:00
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : false ,
"nodeC" : true ,
} ,
2018-10-25 21:59:40 -04:00
name : "NodeA and nodeB have same topologyKey and label value. NodeA has an existing pod that matches the inter pod affinity rule. The pod can not be scheduled onto nodeA and nodeB but can be scheduled onto nodeC" ,
2018-09-04 02:10:17 -04:00
} ,
{
pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "123" } } ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "bar" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{ Spec : v1 . PodSpec { NodeName : "nodeA" } , ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "bar" } } } ,
{
Spec : v1 . PodSpec {
NodeName : "nodeC" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "123" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : labelRgChina } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : labelRgChinaAzAz1 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeC" , Labels : labelRgIndia } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeD" , Labels : labelRgUS } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
{ ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
nil ,
} ,
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : false ,
"nodeC" : false ,
"nodeD" : true ,
} ,
2018-10-25 21:59:40 -04:00
name : "NodeA and nodeB have same topologyKey and label value. NodeA has an existing pod that matches the inter pod affinity rule. NodeC has an existing pod that match the inter pod affinity rule. The pod can not be scheduled onto nodeA, nodeB and nodeC but can be schedulerd onto nodeD" ,
2018-09-04 02:10:17 -04:00
nometa : true ,
} ,
{
pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Labels : map [ string ] string { "foo" : "123" } ,
Namespace : "NS1" ,
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
2016-12-08 10:14:21 -05:00
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "bar" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2016-11-18 15:52:35 -05:00
pods : [ ] * v1 . Pod {
2018-09-04 02:10:17 -04:00
{
ObjectMeta : metav1 . ObjectMeta {
Labels : map [ string ] string { "foo" : "bar" } ,
Namespace : "NS1" ,
} ,
Spec : v1 . PodSpec { NodeName : "nodeA" } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Namespace : "NS2" } ,
Spec : v1 . PodSpec {
NodeName : "nodeC" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpIn ,
Values : [ ] string { "123" } ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-11-18 15:52:35 -05:00
nodes : [ ] v1 . Node {
2018-09-04 02:10:17 -04:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : labelRgChina } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : labelRgChinaAzAz1 } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeC" , Labels : labelRgIndia } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
nil ,
2016-05-04 02:50:31 -04:00
} ,
fits : map [ string ] bool {
2018-09-04 02:10:17 -04:00
"nodeA" : false ,
"nodeB" : false ,
"nodeC" : true ,
2016-05-04 02:50:31 -04:00
} ,
2018-10-25 21:59:40 -04:00
name : "NodeA and nodeB have same topologyKey and label value. NodeA has an existing pod that matches the inter pod affinity rule. The pod can not be scheduled onto nodeA, nodeB, but can be scheduled onto nodeC (NodeC has an existing pod that match the inter pod affinity rule but in different namespace)" ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2018-09-04 02:10:17 -04:00
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "" } } ,
} ,
pods : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
2016-11-30 11:51:12 -05:00
{
2018-09-04 02:10:17 -04:00
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
2016-11-30 11:51:12 -05:00
} ,
} ,
2018-09-04 02:10:17 -04:00
TopologyKey : "invalid-node-label" ,
2016-11-30 11:51:12 -05:00
} ,
} ,
} ,
} ,
2018-09-04 02:10:17 -04:00
} ,
} ,
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason { } ,
2018-09-04 02:10:17 -04:00
fits : map [ string ] bool {
"nodeA" : true ,
"nodeB" : true ,
} ,
name : "Test existing pod's anti-affinity: if an existing pod has a term with invalid topologyKey, labelSelector of the term is firstly checked, and then topologyKey of the term is also checked" ,
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
2016-12-08 10:14:21 -05:00
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
2018-09-04 02:10:17 -04:00
Operator : metav1 . LabelSelectorOpExists ,
2016-12-08 10:14:21 -05:00
} ,
} ,
} ,
2018-09-04 02:10:17 -04:00
TopologyKey : "invalid-node-label" ,
2016-12-08 10:14:21 -05:00
} ,
} ,
} ,
2016-11-30 11:51:12 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-11-18 15:52:35 -05:00
pods : [ ] * v1 . Pod {
2018-09-04 02:10:17 -04:00
{
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "" } } ,
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-11-18 15:52:35 -05:00
nodes : [ ] v1 . Node {
2018-09-04 02:10:17 -04:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeB" } } } ,
2016-05-04 02:50:31 -04:00
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason { } ,
2016-05-04 02:50:31 -04:00
fits : map [ string ] bool {
2018-09-04 02:10:17 -04:00
"nodeA" : true ,
2016-05-04 02:50:31 -04:00
"nodeB" : true ,
} ,
2018-12-13 00:24:04 -05:00
name : "Test incoming pod's anti-affinity: even if labelSelector matches, we still check if topologyKey matches" ,
2016-05-04 02:50:31 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2018-09-04 02:10:17 -04:00
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "" , "bar" : "" } } ,
} ,
pods : [ ] * v1 . Pod {
{
ObjectMeta : metav1 . ObjectMeta { Name : "pod1" } ,
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "pod2" } ,
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "bar" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
} ,
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
2018-09-04 02:10:17 -04:00
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z2" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
{ ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
} ,
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : false ,
} ,
name : "Test existing pod's anti-affinity: incoming pod wouldn't considered as a fit as it violates each existingPod's terms on all nodes" ,
} ,
{
pod : & v1 . Pod {
2016-12-08 10:14:21 -05:00
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
2018-09-04 02:10:17 -04:00
PodAntiAffinity : & v1 . PodAntiAffinity {
2016-12-08 10:14:21 -05:00
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
2018-09-04 02:10:17 -04:00
Operator : metav1 . LabelSelectorOpExists ,
2016-12-08 10:14:21 -05:00
} ,
} ,
} ,
TopologyKey : "zone" ,
2016-05-04 02:50:31 -04:00
} ,
2018-04-06 20:43:51 -04:00
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
2018-09-04 02:10:17 -04:00
Key : "bar" ,
Operator : metav1 . LabelSelectorOpExists ,
2018-04-06 20:43:51 -04:00
} ,
} ,
} ,
2018-09-04 02:10:17 -04:00
TopologyKey : "region" ,
2018-04-06 20:43:51 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2016-05-04 02:50:31 -04:00
} ,
} ,
} ,
2018-09-04 02:10:17 -04:00
pods : [ ] * v1 . Pod {
{
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "" } } ,
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
} ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "bar" : "" } } ,
Spec : v1 . PodSpec {
NodeName : "nodeB" ,
} ,
} ,
} ,
2016-11-18 15:52:35 -05:00
nodes : [ ] v1 . Node {
2018-09-04 02:10:17 -04:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z2" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
2016-05-04 02:50:31 -04:00
} ,
fits : map [ string ] bool {
2018-09-04 02:10:17 -04:00
"nodeA" : false ,
"nodeB" : false ,
2016-05-04 02:50:31 -04:00
} ,
2018-09-04 02:10:17 -04:00
name : "Test incoming pod's anti-affinity: incoming pod wouldn't considered as a fit as it at least violates one anti-affinity rule of existingPod" ,
2016-05-04 02:50:31 -04:00
} ,
2016-10-13 05:01:58 -04:00
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2018-09-04 02:10:17 -04:00
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "" , "bar" : "" } } ,
} ,
pods : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2018-09-04 02:10:17 -04:00
TopologyKey : "invalid-node-label" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "bar" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
2016-10-13 05:01:58 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
} ,
2016-10-13 05:01:58 -04:00
} ,
} ,
} ,
2016-11-18 15:52:35 -05:00
nodes : [ ] v1 . Node {
2018-09-04 02:10:17 -04:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z2" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
2016-10-13 05:01:58 -04:00
} ,
fits : map [ string ] bool {
"nodeA" : false ,
2018-09-04 02:10:17 -04:00
"nodeB" : true ,
2016-10-13 05:01:58 -04:00
} ,
2018-10-25 21:59:40 -04:00
name : "Test existing pod's anti-affinity: only when labelSelector and topologyKey both match, it's counted as a single term match - case when one term has invalid topologyKey" ,
2016-10-13 05:01:58 -04:00
} ,
2018-04-14 22:32:58 -04:00
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
2018-09-04 02:10:17 -04:00
Operator : metav1 . LabelSelectorOpExists ,
2018-04-14 22:32:58 -04:00
} ,
} ,
} ,
2018-09-04 02:10:17 -04:00
TopologyKey : "invalid-node-label" ,
2018-04-14 22:32:58 -04:00
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
2018-09-04 02:10:17 -04:00
Key : "bar" ,
Operator : metav1 . LabelSelectorOpExists ,
2018-04-14 22:32:58 -04:00
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
2018-09-04 02:10:17 -04:00
{
ObjectMeta : metav1 . ObjectMeta { Name : "podA" , Labels : map [ string ] string { "foo" : "" , "bar" : "" } } ,
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
} ,
} ,
2018-04-14 22:32:58 -04:00
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z2" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
} ,
2018-04-14 22:32:58 -04:00
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : true ,
} ,
2018-10-25 21:59:40 -04:00
name : "Test incoming pod's anti-affinity: only when labelSelector and topologyKey both match, it's counted as a single term match - case when one term has invalid topologyKey" ,
2018-04-14 22:32:58 -04:00
} ,
2016-10-13 05:01:58 -04:00
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2018-09-04 02:10:17 -04:00
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "" , "bar" : "" } } ,
} ,
pods : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
2018-09-04 02:10:17 -04:00
TopologyKey : "region" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "bar" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
2016-10-13 05:01:58 -04:00
} ,
2016-12-08 10:14:21 -05:00
} ,
} ,
} ,
2016-10-13 05:01:58 -04:00
} ,
} ,
} ,
2016-11-18 15:52:35 -05:00
nodes : [ ] v1 . Node {
2018-09-04 02:10:17 -04:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z2" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
{ ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
2016-10-13 05:01:58 -04:00
} ,
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : false ,
} ,
2018-10-25 21:59:40 -04:00
name : "Test existing pod's anti-affinity: only when labelSelector and topologyKey both match, it's counted as a single term match - case when all terms have valid topologyKey" ,
2016-10-13 05:01:58 -04:00
} ,
2017-01-17 00:28:54 -05:00
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
2018-09-04 02:10:17 -04:00
Operator : metav1 . LabelSelectorOpExists ,
2017-01-17 00:28:54 -05:00
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
2018-09-04 02:10:17 -04:00
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "bar" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
2017-01-17 00:28:54 -05:00
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{
2018-09-04 02:10:17 -04:00
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "" , "bar" : "" } } ,
2017-01-17 00:28:54 -05:00
Spec : v1 . PodSpec {
2018-09-04 02:10:17 -04:00
NodeName : "nodeA" ,
} ,
} ,
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z2" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
{ ErrPodAffinityNotMatch , ErrPodAntiAffinityRulesNotMatch } ,
} ,
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : false ,
} ,
2018-10-25 21:59:40 -04:00
name : "Test incoming pod's anti-affinity: only when labelSelector and topologyKey both match, it's counted as a single term match - case when all terms have valid topologyKey" ,
2018-09-04 02:10:17 -04:00
} ,
{
pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Labels : map [ string ] string { "foo" : "" , "bar" : "" } } ,
} ,
pods : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
2017-01-17 00:28:54 -05:00
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
2018-09-04 02:10:17 -04:00
Operator : metav1 . LabelSelectorOpExists ,
2017-01-17 00:28:54 -05:00
} ,
} ,
} ,
2018-09-04 02:10:17 -04:00
TopologyKey : "zone" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "labelA" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
} ,
} ,
} ,
} ,
} ,
{
Spec : v1 . PodSpec {
NodeName : "nodeB" ,
Affinity : & v1 . Affinity {
PodAntiAffinity : & v1 . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "bar" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "labelB" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
2017-01-17 00:28:54 -05:00
} ,
} ,
} ,
} ,
} ,
} ,
} ,
nodes : [ ] v1 . Node {
2018-09-04 02:10:17 -04:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z2" , "hostname" : "nodeB" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeC" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z3" , "hostname" : "nodeC" } } } ,
2017-01-17 00:28:54 -05:00
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2017-09-13 11:47:58 -04:00
{ ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrExistingPodsAntiAffinityRulesNotMatch } ,
2017-09-13 11:47:58 -04:00
} ,
2017-01-17 00:28:54 -05:00
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : false ,
2018-09-04 02:10:17 -04:00
"nodeC" : true ,
2017-01-17 00:28:54 -05:00
} ,
2018-09-04 02:10:17 -04:00
name : "Test existing pod's anti-affinity: existingPod on nodeA and nodeB has at least one anti-affinity term matches incoming pod, so incoming pod can only be scheduled to nodeC" ,
2017-01-17 00:28:54 -05:00
} ,
2017-04-30 00:18:03 -04:00
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
2018-09-04 02:10:17 -04:00
PodAffinity : & v1 . PodAffinity {
2017-04-30 00:18:03 -04:00
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
2018-09-04 02:10:17 -04:00
Operator : metav1 . LabelSelectorOpExists ,
2017-04-30 00:18:03 -04:00
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
2018-09-04 02:10:17 -04:00
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "bar" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "zone" ,
} ,
2017-04-30 00:18:03 -04:00
} ,
} ,
} ,
} ,
} ,
pods : [ ] * v1 . Pod {
{
2018-09-04 02:10:17 -04:00
ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , Labels : map [ string ] string { "foo" : "" , "bar" : "" } } ,
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
2017-04-30 00:18:03 -04:00
} ,
} ,
2018-09-04 02:10:17 -04:00
} ,
nodes : [ ] v1 . Node {
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeB" } } } ,
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ } ,
{ ErrPodAffinityNotMatch , ErrPodAffinityRulesNotMatch } ,
} ,
fits : map [ string ] bool {
"nodeA" : true ,
"nodeB" : true ,
} ,
2018-10-25 21:59:40 -04:00
name : "Test incoming pod's affinity: firstly check if all affinityTerms match, and then check if all topologyKeys match" ,
2018-09-04 02:10:17 -04:00
} ,
{
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
PodAffinity : & v1 . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] v1 . PodAffinityTerm {
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "foo" ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
} ,
} ,
TopologyKey : "region" ,
} ,
{
LabelSelector : & metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : "bar" ,
Operator : metav1 . LabelSelectorOpExists ,
2017-04-30 00:18:03 -04:00
} ,
} ,
} ,
2018-09-04 02:10:17 -04:00
TopologyKey : "zone" ,
2017-04-30 00:18:03 -04:00
} ,
} ,
} ,
} ,
} ,
} ,
2018-09-04 02:10:17 -04:00
pods : [ ] * v1 . Pod {
{
ObjectMeta : metav1 . ObjectMeta { Name : "pod1" , Labels : map [ string ] string { "foo" : "" } } ,
Spec : v1 . PodSpec {
NodeName : "nodeA" ,
} ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "pod2" , Labels : map [ string ] string { "bar" : "" } } ,
Spec : v1 . PodSpec {
NodeName : "nodeB" ,
} ,
} ,
} ,
2017-04-30 00:18:03 -04:00
nodes : [ ] v1 . Node {
2018-09-04 02:10:17 -04:00
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeA" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z1" , "hostname" : "nodeA" } } } ,
{ ObjectMeta : metav1 . ObjectMeta { Name : "nodeB" , Labels : map [ string ] string { "region" : "r1" , "zone" : "z2" , "hostname" : "nodeB" } } } ,
2017-04-30 00:18:03 -04:00
} ,
2018-12-19 07:30:54 -05:00
nodesExpectAffinityFailureReasons : [ ] [ ] PredicateFailureReason {
2018-09-04 02:10:17 -04:00
{ ErrPodAffinityNotMatch , ErrPodAffinityRulesNotMatch } ,
{ ErrPodAffinityNotMatch , ErrPodAffinityRulesNotMatch } ,
2017-09-13 11:47:58 -04:00
} ,
2017-04-30 00:18:03 -04:00
fits : map [ string ] bool {
"nodeA" : false ,
"nodeB" : false ,
} ,
2018-10-25 21:59:40 -04:00
name : "Test incoming pod's affinity: firstly check if all affinityTerms match, and then check if all topologyKeys match, and the match logic should be satified on the same pod" ,
2017-04-30 00:18:03 -04:00
} ,
2016-05-04 02:50:31 -04:00
}
2017-09-13 11:47:58 -04:00
2018-12-19 07:30:54 -05:00
selectorExpectedFailureReasons := [ ] PredicateFailureReason { ErrNodeSelectorNotMatch }
2016-08-09 08:01:46 -04:00
2017-09-13 11:47:58 -04:00
for indexTest , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
nodeListInfo := FakeNodeListInfo ( test . nodes )
2018-12-07 21:36:11 -05:00
nodeInfoMap := make ( map [ string ] * schedulernodeinfo . NodeInfo )
2018-06-05 08:08:23 -04:00
for i , node := range test . nodes {
var podsOnNode [ ] * v1 . Pod
for _ , pod := range test . pods {
if pod . Spec . NodeName == node . Name {
podsOnNode = append ( podsOnNode , pod )
}
2016-05-04 02:50:31 -04:00
}
2018-04-04 20:49:59 -04:00
2018-12-07 21:36:11 -05:00
nodeInfo := schedulernodeinfo . NewNodeInfo ( podsOnNode ... )
2018-06-05 08:08:23 -04:00
nodeInfo . SetNode ( & test . nodes [ i ] )
nodeInfoMap [ node . Name ] = nodeInfo
2016-05-04 02:50:31 -04:00
}
2017-01-17 00:28:54 -05:00
2018-06-05 08:08:23 -04:00
for indexNode , node := range test . nodes {
testFit := PodAffinityChecker {
info : nodeListInfo ,
podLister : schedulertesting . FakePodLister ( test . pods ) ,
}
2017-01-17 00:28:54 -05:00
2018-12-19 07:30:54 -05:00
var meta PredicateMetadata
2018-06-05 08:08:23 -04:00
if ! test . nometa {
2018-12-19 07:30:54 -05:00
meta = GetPredicateMetadata ( test . pod , nodeInfoMap )
2016-08-09 08:01:46 -04:00
}
2018-06-05 08:08:23 -04:00
fits , reasons , _ := testFit . InterPodAffinityMatches ( test . pod , meta , nodeInfoMap [ node . Name ] )
if ! fits && ! reflect . DeepEqual ( reasons , test . nodesExpectAffinityFailureReasons [ indexNode ] ) {
t . Errorf ( "index: %d unexpected failure reasons: %v expect: %v" , indexTest , reasons , test . nodesExpectAffinityFailureReasons [ indexNode ] )
}
affinity := test . pod . Spec . Affinity
if affinity != nil && affinity . NodeAffinity != nil {
2018-12-07 21:36:11 -05:00
nodeInfo := schedulernodeinfo . NewNodeInfo ( )
2018-06-05 08:08:23 -04:00
nodeInfo . SetNode ( & node )
2018-12-07 21:36:11 -05:00
nodeInfoMap := map [ string ] * schedulernodeinfo . NodeInfo { node . Name : nodeInfo }
2018-12-19 07:30:54 -05:00
fits2 , reasons , err := PodMatchNodeSelector ( test . pod , GetPredicateMetadata ( test . pod , nodeInfoMap ) , nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits2 && ! reflect . DeepEqual ( reasons , selectorExpectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , selectorExpectedFailureReasons )
}
fits = fits && fits2
2016-05-04 02:50:31 -04:00
}
2018-06-05 08:08:23 -04:00
if fits != test . fits [ node . Name ] {
t . Errorf ( "expected %v for %s got %v" , test . fits [ node . Name ] , node . Name , fits )
}
2016-05-04 02:50:31 -04:00
}
2018-06-05 08:08:23 -04:00
} )
2016-05-04 02:50:31 -04:00
}
}
2016-03-30 23:42:57 -04:00
func TestPodToleratesTaints ( t * testing . T ) {
podTolerateTaintsTests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
node v1 . Node
2016-03-30 23:42:57 -04:00
fits bool
2018-06-05 08:08:23 -04:00
name string
2016-03-30 23:42:57 -04:00
} {
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-03-30 23:42:57 -04:00
Name : "pod0" ,
} ,
} ,
2016-11-18 15:52:35 -05:00
node : v1 . Node {
2017-02-07 09:08:45 -05:00
Spec : v1 . NodeSpec {
Taints : [ ] v1 . Taint { { Key : "dedicated" , Value : "user1" , Effect : "NoSchedule" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
fits : false ,
2018-10-25 21:59:40 -04:00
name : "A pod having no tolerations can't be scheduled onto a node with nonempty taints" ,
2016-03-30 23:42:57 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-03-30 23:42:57 -04:00
Name : "pod1" ,
} ,
2016-11-18 15:52:35 -05:00
Spec : v1 . PodSpec {
2017-02-07 09:08:45 -05:00
Containers : [ ] v1 . Container { { Image : "pod1:V1" } } ,
Tolerations : [ ] v1 . Toleration { { Key : "dedicated" , Value : "user1" , Effect : "NoSchedule" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
2016-11-18 15:52:35 -05:00
node : v1 . Node {
2017-02-07 09:08:45 -05:00
Spec : v1 . NodeSpec {
Taints : [ ] v1 . Taint { { Key : "dedicated" , Value : "user1" , Effect : "NoSchedule" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
fits : true ,
2018-10-25 21:59:40 -04:00
name : "A pod which can be scheduled on a dedicated node assigned to user1 with effect NoSchedule" ,
2016-03-30 23:42:57 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-03-30 23:42:57 -04:00
Name : "pod2" ,
} ,
2016-11-18 15:52:35 -05:00
Spec : v1 . PodSpec {
2017-02-07 09:08:45 -05:00
Containers : [ ] v1 . Container { { Image : "pod2:V1" } } ,
Tolerations : [ ] v1 . Toleration { { Key : "dedicated" , Operator : "Equal" , Value : "user2" , Effect : "NoSchedule" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
2016-11-18 15:52:35 -05:00
node : v1 . Node {
2017-02-07 09:08:45 -05:00
Spec : v1 . NodeSpec {
Taints : [ ] v1 . Taint { { Key : "dedicated" , Value : "user1" , Effect : "NoSchedule" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
fits : false ,
2018-10-25 21:59:40 -04:00
name : "A pod which can't be scheduled on a dedicated node assigned to user2 with effect NoSchedule" ,
2016-03-30 23:42:57 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-03-30 23:42:57 -04:00
Name : "pod2" ,
} ,
2016-11-18 15:52:35 -05:00
Spec : v1 . PodSpec {
2017-02-07 09:08:45 -05:00
Containers : [ ] v1 . Container { { Image : "pod2:V1" } } ,
Tolerations : [ ] v1 . Toleration { { Key : "foo" , Operator : "Exists" , Effect : "NoSchedule" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
2016-11-18 15:52:35 -05:00
node : v1 . Node {
2017-02-07 09:08:45 -05:00
Spec : v1 . NodeSpec {
Taints : [ ] v1 . Taint { { Key : "foo" , Value : "bar" , Effect : "NoSchedule" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
fits : true ,
2018-10-25 21:59:40 -04:00
name : "A pod can be scheduled onto the node, with a toleration uses operator Exists that tolerates the taints on the node" ,
2016-03-30 23:42:57 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-03-30 23:42:57 -04:00
Name : "pod2" ,
} ,
2016-11-18 15:52:35 -05:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container { { Image : "pod2:V1" } } ,
2017-02-07 09:08:45 -05:00
Tolerations : [ ] v1 . Toleration {
{ Key : "dedicated" , Operator : "Equal" , Value : "user2" , Effect : "NoSchedule" } ,
{ Key : "foo" , Operator : "Exists" , Effect : "NoSchedule" } ,
} ,
2016-03-30 23:42:57 -04:00
} ,
} ,
2016-11-18 15:52:35 -05:00
node : v1 . Node {
2017-02-07 09:08:45 -05:00
Spec : v1 . NodeSpec {
Taints : [ ] v1 . Taint {
{ Key : "dedicated" , Value : "user2" , Effect : "NoSchedule" } ,
{ Key : "foo" , Value : "bar" , Effect : "NoSchedule" } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
} ,
fits : true ,
2018-10-25 21:59:40 -04:00
name : "A pod has multiple tolerations, node has multiple taints, all the taints are tolerated, pod can be scheduled onto the node" ,
2016-03-30 23:42:57 -04:00
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-03-30 23:42:57 -04:00
Name : "pod2" ,
} ,
2016-11-18 15:52:35 -05:00
Spec : v1 . PodSpec {
2017-02-07 09:08:45 -05:00
Containers : [ ] v1 . Container { { Image : "pod2:V1" } } ,
Tolerations : [ ] v1 . Toleration { { Key : "foo" , Operator : "Equal" , Value : "bar" , Effect : "PreferNoSchedule" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
2016-11-18 15:52:35 -05:00
node : v1 . Node {
2017-02-07 09:08:45 -05:00
Spec : v1 . NodeSpec {
Taints : [ ] v1 . Taint {
{ Key : "foo" , Value : "bar" , Effect : "NoSchedule" } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
} ,
fits : false ,
2018-10-25 21:59:40 -04:00
name : "A pod has a toleration that keys and values match the taint on the node, but (non-empty) effect doesn't match, " +
2016-03-30 23:42:57 -04:00
"can't be scheduled onto the node" ,
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-03-30 23:42:57 -04:00
Name : "pod2" ,
} ,
2016-11-18 15:52:35 -05:00
Spec : v1 . PodSpec {
2017-02-07 09:08:45 -05:00
Containers : [ ] v1 . Container { { Image : "pod2:V1" } } ,
Tolerations : [ ] v1 . Toleration { { Key : "foo" , Operator : "Equal" , Value : "bar" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
2016-11-18 15:52:35 -05:00
node : v1 . Node {
2017-02-07 09:08:45 -05:00
Spec : v1 . NodeSpec {
Taints : [ ] v1 . Taint {
{ Key : "foo" , Value : "bar" , Effect : "NoSchedule" } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "The pod has a toleration that keys and values match the taint on the node, the effect of toleration is empty, " +
2016-03-30 23:42:57 -04:00
"and the effect of taint is NoSchedule. Pod can be scheduled onto the node" ,
} ,
{
2016-11-18 15:52:35 -05:00
pod : & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-03-30 23:42:57 -04:00
Name : "pod2" ,
} ,
2016-11-18 15:52:35 -05:00
Spec : v1 . PodSpec {
2017-02-07 09:08:45 -05:00
Containers : [ ] v1 . Container { { Image : "pod2:V1" } } ,
Tolerations : [ ] v1 . Toleration { { Key : "dedicated" , Operator : "Equal" , Value : "user2" , Effect : "NoSchedule" } } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
2016-11-18 15:52:35 -05:00
node : v1 . Node {
2017-02-07 09:08:45 -05:00
Spec : v1 . NodeSpec {
Taints : [ ] v1 . Taint {
{ Key : "dedicated" , Value : "user1" , Effect : "PreferNoSchedule" } ,
2016-03-30 23:42:57 -04:00
} ,
} ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "The pod has a toleration that key and value don't match the taint on the node, " +
2016-09-01 05:21:17 -04:00
"but the effect of taint on node is PreferNochedule. Pod can be scheduled onto the node" ,
2016-03-30 23:42:57 -04:00
} ,
2017-01-09 05:16:43 -05:00
{
pod : & v1 . Pod {
2017-01-14 01:55:53 -05:00
ObjectMeta : metav1 . ObjectMeta {
2017-01-09 05:16:43 -05:00
Name : "pod2" ,
} ,
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container { { Image : "pod2:V1" } } ,
} ,
} ,
node : v1 . Node {
2017-02-07 09:08:45 -05:00
Spec : v1 . NodeSpec {
Taints : [ ] v1 . Taint {
{ Key : "dedicated" , Value : "user1" , Effect : "PreferNoSchedule" } ,
2017-01-09 05:16:43 -05:00
} ,
} ,
} ,
fits : true ,
2018-06-05 08:08:23 -04:00
name : "The pod has no toleration, " +
2017-01-09 05:16:43 -05:00
"but the effect of taint on node is PreferNochedule. Pod can be scheduled onto the node" ,
} ,
2016-03-30 23:42:57 -04:00
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrTaintsTolerationsNotMatch }
2016-03-30 23:42:57 -04:00
for _ , test := range podTolerateTaintsTests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
2018-12-07 21:36:11 -05:00
nodeInfo := schedulernodeinfo . NewNodeInfo ( )
2018-06-05 08:08:23 -04:00
nodeInfo . SetNode ( & test . node )
2018-12-19 07:30:54 -05:00
fits , reasons , err := PodToleratesNodeTaints ( test . pod , GetPredicateMetadata ( test . pod , nil ) , nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reason: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . fits {
t . Errorf ( "expected: %v got %v" , test . fits , fits )
}
} )
2016-03-30 23:42:57 -04:00
}
}
2016-05-12 08:01:33 -04:00
2018-12-07 21:36:11 -05:00
func makeEmptyNodeInfo ( node * v1 . Node ) * schedulernodeinfo . NodeInfo {
nodeInfo := schedulernodeinfo . NewNodeInfo ( )
2016-05-12 08:01:33 -04:00
nodeInfo . SetNode ( node )
return nodeInfo
}
func TestPodSchedulesOnNodeWithMemoryPressureCondition ( t * testing . T ) {
// specify best-effort pod
2016-11-18 15:52:35 -05:00
bestEffortPod := & v1 . Pod {
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-05-12 08:01:33 -04:00
{
Name : "container" ,
Image : "image" ,
ImagePullPolicy : "Always" ,
// no requirements -> best effort pod
2016-11-18 15:52:35 -05:00
Resources : v1 . ResourceRequirements { } ,
2016-05-12 08:01:33 -04:00
} ,
} ,
} ,
}
// specify non-best-effort pod
2016-11-18 15:52:35 -05:00
nonBestEffortPod := & v1 . Pod {
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-05-12 08:01:33 -04:00
{
Name : "container" ,
Image : "image" ,
ImagePullPolicy : "Always" ,
// at least one requirement -> burstable pod
2016-11-18 15:52:35 -05:00
Resources : v1 . ResourceRequirements {
2018-03-21 16:56:51 -04:00
Requests : makeAllocatableResources ( 100 , 100 , 100 , 0 , 0 , 0 ) ,
2016-05-12 08:01:33 -04:00
} ,
} ,
} ,
} ,
}
// specify a node with no memory pressure condition on
2016-11-18 15:52:35 -05:00
noMemoryPressureNode := & v1 . Node {
Status : v1 . NodeStatus {
Conditions : [ ] v1 . NodeCondition {
2016-05-12 08:01:33 -04:00
{
Type : "Ready" ,
Status : "True" ,
} ,
} ,
} ,
}
// specify a node with memory pressure condition on
2016-11-18 15:52:35 -05:00
memoryPressureNode := & v1 . Node {
Status : v1 . NodeStatus {
Conditions : [ ] v1 . NodeCondition {
2016-05-12 08:01:33 -04:00
{
Type : "MemoryPressure" ,
Status : "True" ,
} ,
} ,
} ,
}
tests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2016-05-12 08:01:33 -04:00
fits bool
name string
} {
{
pod : bestEffortPod ,
nodeInfo : makeEmptyNodeInfo ( noMemoryPressureNode ) ,
fits : true ,
name : "best-effort pod schedulable on node without memory pressure condition on" ,
} ,
{
pod : bestEffortPod ,
nodeInfo : makeEmptyNodeInfo ( memoryPressureNode ) ,
fits : false ,
name : "best-effort pod not schedulable on node with memory pressure condition on" ,
} ,
{
pod : nonBestEffortPod ,
nodeInfo : makeEmptyNodeInfo ( memoryPressureNode ) ,
fits : true ,
name : "non best-effort pod schedulable on node with memory pressure condition on" ,
} ,
{
pod : nonBestEffortPod ,
nodeInfo : makeEmptyNodeInfo ( noMemoryPressureNode ) ,
fits : true ,
name : "non best-effort pod schedulable on node without memory pressure condition on" ,
} ,
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrNodeUnderMemoryPressure }
2016-05-12 08:01:33 -04:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
2018-12-19 07:30:54 -05:00
fits , reasons , err := CheckNodeMemoryPressurePredicate ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . fits {
t . Errorf ( "expected %v got %v" , test . fits , fits )
}
} )
2016-05-12 08:01:33 -04:00
}
}
2016-07-22 15:23:34 -04:00
func TestPodSchedulesOnNodeWithDiskPressureCondition ( t * testing . T ) {
2016-11-18 15:52:35 -05:00
pod := & v1 . Pod {
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-07-22 15:23:34 -04:00
{
Name : "container" ,
Image : "image" ,
ImagePullPolicy : "Always" ,
} ,
} ,
} ,
}
// specify a node with no disk pressure condition on
2016-11-18 15:52:35 -05:00
noPressureNode := & v1 . Node {
Status : v1 . NodeStatus {
Conditions : [ ] v1 . NodeCondition {
2016-07-22 15:23:34 -04:00
{
Type : "Ready" ,
Status : "True" ,
} ,
} ,
} ,
}
// specify a node with pressure condition on
2016-11-18 15:52:35 -05:00
pressureNode := & v1 . Node {
Status : v1 . NodeStatus {
Conditions : [ ] v1 . NodeCondition {
2016-07-22 15:23:34 -04:00
{
Type : "DiskPressure" ,
Status : "True" ,
} ,
} ,
} ,
}
tests := [ ] struct {
2016-11-18 15:52:35 -05:00
pod * v1 . Pod
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2016-07-22 15:23:34 -04:00
fits bool
name string
} {
{
pod : pod ,
nodeInfo : makeEmptyNodeInfo ( noPressureNode ) ,
fits : true ,
name : "pod schedulable on node without pressure condition on" ,
} ,
{
pod : pod ,
nodeInfo : makeEmptyNodeInfo ( pressureNode ) ,
fits : false ,
name : "pod not schedulable on node with pressure condition on" ,
} ,
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrNodeUnderDiskPressure }
2016-07-22 15:23:34 -04:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
2018-12-19 07:30:54 -05:00
fits , reasons , err := CheckNodeDiskPressurePredicate ( test . pod , GetPredicateMetadata ( test . pod , nil ) , test . nodeInfo )
2018-06-05 08:08:23 -04:00
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . fits {
t . Errorf ( "expected %v got %v" , test . fits , fits )
}
} )
2016-07-22 15:23:34 -04:00
}
}
2017-01-17 00:38:45 -05:00
2018-08-26 22:57:04 -04:00
func TestPodSchedulesOnNodeWithPIDPressureCondition ( t * testing . T ) {
// specify a node with no pid pressure condition on
noPressureNode := & v1 . Node {
Status : v1 . NodeStatus {
Conditions : [ ] v1 . NodeCondition {
{
Type : v1 . NodeReady ,
Status : v1 . ConditionTrue ,
} ,
} ,
} ,
}
// specify a node with pressure condition on
pressureNode := & v1 . Node {
Status : v1 . NodeStatus {
Conditions : [ ] v1 . NodeCondition {
{
Type : v1 . NodePIDPressure ,
Status : v1 . ConditionTrue ,
} ,
} ,
} ,
}
tests := [ ] struct {
2018-12-07 21:36:11 -05:00
nodeInfo * schedulernodeinfo . NodeInfo
2018-08-26 22:57:04 -04:00
fits bool
name string
} {
{
nodeInfo : makeEmptyNodeInfo ( noPressureNode ) ,
fits : true ,
name : "pod schedulable on node without pressure condition on" ,
} ,
{
nodeInfo : makeEmptyNodeInfo ( pressureNode ) ,
fits : false ,
name : "pod not schedulable on node with pressure condition on" ,
} ,
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrNodeUnderPIDPressure }
2018-08-26 22:57:04 -04:00
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
2018-12-19 07:30:54 -05:00
fits , reasons , err := CheckNodePIDPressurePredicate ( & v1 . Pod { } , GetPredicateMetadata ( & v1 . Pod { } , nil ) , test . nodeInfo )
2018-08-26 22:57:04 -04:00
if err != nil {
t . Fatalf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . fits {
t . Errorf ( "expected %v got %v" , test . fits , fits )
}
} )
}
}
2017-08-22 23:00:42 -04:00
func TestNodeConditionPredicate ( t * testing . T ) {
tests := [ ] struct {
2018-06-05 08:08:23 -04:00
name string
2017-08-22 23:00:42 -04:00
node * v1 . Node
schedulable bool
} {
{
2018-06-05 08:08:23 -04:00
name : "node1 considered" ,
2017-08-22 23:00:42 -04:00
node : & v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "node1" } , Status : v1 . NodeStatus { Conditions : [ ] v1 . NodeCondition { { Type : v1 . NodeReady , Status : v1 . ConditionTrue } } } } ,
schedulable : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "node2 ignored - node not Ready" ,
2017-08-22 23:00:42 -04:00
node : & v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "node2" } , Status : v1 . NodeStatus { Conditions : [ ] v1 . NodeCondition { { Type : v1 . NodeReady , Status : v1 . ConditionFalse } } } } ,
schedulable : false ,
} ,
{
2018-12-13 03:31:46 -05:00
name : "node3 ignored - node unschedulable" ,
2017-08-22 23:00:42 -04:00
node : & v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "node9" } , Spec : v1 . NodeSpec { Unschedulable : true } } ,
schedulable : false ,
} ,
{
2018-12-13 03:31:46 -05:00
name : "node4 considered" ,
2017-08-22 23:00:42 -04:00
node : & v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "node10" } , Spec : v1 . NodeSpec { Unschedulable : false } } ,
schedulable : true ,
} ,
{
2018-12-13 03:31:46 -05:00
name : "node5 considered" ,
2017-08-22 23:00:42 -04:00
node : & v1 . Node { ObjectMeta : metav1 . ObjectMeta { Name : "node11" } } ,
schedulable : true ,
} ,
}
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
nodeInfo := makeEmptyNodeInfo ( test . node )
if fit , reasons , err := CheckNodeConditionPredicate ( nil , nil , nodeInfo ) ; fit != test . schedulable {
t . Errorf ( "%s: expected: %t, got %t; %+v, %v" ,
test . node . Name , test . schedulable , fit , reasons , err )
}
} )
2017-08-22 23:00:42 -04:00
}
}
2017-01-17 00:38:45 -05:00
func createPodWithVolume ( pod , pv , pvc string ) * v1 . Pod {
return & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Name : pod , Namespace : "default" } ,
Spec : v1 . PodSpec {
Volumes : [ ] v1 . Volume {
{
Name : pv ,
VolumeSource : v1 . VolumeSource {
PersistentVolumeClaim : & v1 . PersistentVolumeClaimVolumeSource {
ClaimName : pvc ,
} ,
} ,
} ,
} ,
} ,
}
}
func TestVolumeZonePredicate ( t * testing . T ) {
pvInfo := FakePersistentVolumeInfo {
{
2019-01-31 21:43:49 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "Vol_1" , Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-a" } } ,
2017-01-17 00:38:45 -05:00
} ,
{
2019-01-31 21:43:49 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "Vol_2" , Labels : map [ string ] string { v1 . LabelZoneRegion : "us-west1-b" , "uselessLabel" : "none" } } ,
2017-01-17 00:38:45 -05:00
} ,
{
2019-01-31 21:43:49 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "Vol_3" , Labels : map [ string ] string { v1 . LabelZoneRegion : "us-west1-c" } } ,
2017-01-17 00:38:45 -05:00
} ,
}
pvcInfo := FakePersistentVolumeClaimInfo {
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_1" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { VolumeName : "Vol_1" } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_2" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { VolumeName : "Vol_2" } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_3" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { VolumeName : "Vol_3" } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_4" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { VolumeName : "Vol_not_exist" } ,
} ,
}
tests := [ ] struct {
2018-06-05 08:08:23 -04:00
name string
2017-01-17 00:38:45 -05:00
Pod * v1 . Pod
Fits bool
Node * v1 . Node
} {
{
2018-06-05 08:08:23 -04:00
name : "pod without volume" ,
2017-01-17 00:38:45 -05:00
Pod : & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Name : "pod_1" , Namespace : "default" } ,
} ,
Node : & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
2019-01-31 21:43:49 -05:00
Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-a" } ,
2017-01-17 00:38:45 -05:00
} ,
} ,
Fits : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "node without labels" ,
2017-01-17 00:38:45 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_1" ) ,
Node : & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
} ,
} ,
Fits : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "label zone failure domain matched" ,
2017-01-17 00:38:45 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_1" ) ,
Node : & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
2019-01-31 21:43:49 -05:00
Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-a" , "uselessLabel" : "none" } ,
2017-01-17 00:38:45 -05:00
} ,
} ,
Fits : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "label zone region matched" ,
2017-01-17 00:38:45 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_2" ) ,
Node : & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
2019-01-31 21:43:49 -05:00
Labels : map [ string ] string { v1 . LabelZoneRegion : "us-west1-b" , "uselessLabel" : "none" } ,
2017-01-17 00:38:45 -05:00
} ,
} ,
Fits : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "label zone region failed match" ,
2017-01-17 00:38:45 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_2" ) ,
Node : & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
2019-01-31 21:43:49 -05:00
Labels : map [ string ] string { v1 . LabelZoneRegion : "no_us-west1-b" , "uselessLabel" : "none" } ,
2017-01-17 00:38:45 -05:00
} ,
} ,
Fits : false ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "label zone failure domain failed match" ,
2017-01-17 00:38:45 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_1" ) ,
Node : & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
2019-01-31 21:43:49 -05:00
Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "no_us-west1-a" , "uselessLabel" : "none" } ,
2017-08-30 21:59:41 -04:00
} ,
} ,
Fits : false ,
} ,
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrVolumeZoneConflict }
2017-08-30 21:59:41 -04:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
fit := NewVolumeZonePredicate ( pvInfo , pvcInfo , nil )
2018-12-07 21:36:11 -05:00
node := & schedulernodeinfo . NodeInfo { }
2018-06-05 08:08:23 -04:00
node . SetNode ( test . Node )
fits , reasons , err := fit ( test . Pod , nil , node )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . Fits {
t . Errorf ( "expected %v got %v" , test . Fits , fits )
}
} )
2017-08-30 21:59:41 -04:00
}
}
func TestVolumeZonePredicateMultiZone ( t * testing . T ) {
pvInfo := FakePersistentVolumeInfo {
{
2019-01-31 21:43:49 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "Vol_1" , Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-a" } } ,
2017-08-30 21:59:41 -04:00
} ,
{
2019-01-31 21:43:49 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "Vol_2" , Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-b" , "uselessLabel" : "none" } } ,
2017-08-30 21:59:41 -04:00
} ,
{
2019-01-31 21:43:49 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "Vol_3" , Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-c__us-west1-a" } } ,
2017-08-30 21:59:41 -04:00
} ,
}
pvcInfo := FakePersistentVolumeClaimInfo {
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_1" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { VolumeName : "Vol_1" } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_2" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { VolumeName : "Vol_2" } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_3" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { VolumeName : "Vol_3" } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_4" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { VolumeName : "Vol_not_exist" } ,
} ,
}
tests := [ ] struct {
2018-06-05 08:08:23 -04:00
name string
2017-08-30 21:59:41 -04:00
Pod * v1 . Pod
Fits bool
Node * v1 . Node
} {
{
2018-06-05 08:08:23 -04:00
name : "node without labels" ,
2017-08-30 21:59:41 -04:00
Pod : createPodWithVolume ( "pod_1" , "Vol_3" , "PVC_3" ) ,
Node : & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
} ,
} ,
Fits : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "label zone failure domain matched" ,
2017-08-30 21:59:41 -04:00
Pod : createPodWithVolume ( "pod_1" , "Vol_3" , "PVC_3" ) ,
Node : & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
2019-01-31 21:43:49 -05:00
Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-a" , "uselessLabel" : "none" } ,
2017-08-30 21:59:41 -04:00
} ,
} ,
Fits : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "label zone failure domain failed match" ,
2017-08-30 21:59:41 -04:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_1" ) ,
Node : & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
2019-01-31 21:43:49 -05:00
Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-b" , "uselessLabel" : "none" } ,
2017-01-17 00:38:45 -05:00
} ,
} ,
Fits : false ,
} ,
}
2018-12-19 07:30:54 -05:00
expectedFailureReasons := [ ] PredicateFailureReason { ErrVolumeZoneConflict }
2017-01-17 00:38:45 -05:00
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
fit := NewVolumeZonePredicate ( pvInfo , pvcInfo , nil )
2018-12-07 21:36:11 -05:00
node := & schedulernodeinfo . NodeInfo { }
2018-06-05 08:08:23 -04:00
node . SetNode ( test . Node )
fits , reasons , err := fit ( test . Pod , nil , node )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if ! fits && ! reflect . DeepEqual ( reasons , expectedFailureReasons ) {
t . Errorf ( "unexpected failure reasons: %v, want: %v" , reasons , expectedFailureReasons )
}
if fits != test . Fits {
t . Errorf ( "expected %v got %v" , test . Fits , fits )
}
} )
2017-01-17 00:38:45 -05:00
}
}
2017-09-01 05:30:24 -04:00
2017-11-08 16:09:55 -05:00
func TestVolumeZonePredicateWithVolumeBinding ( t * testing . T ) {
var (
modeWait = storagev1 . VolumeBindingWaitForFirstConsumer
class0 = "Class_0"
classWait = "Class_Wait"
classImmediate = "Class_Immediate"
)
classInfo := FakeStorageClassInfo {
{
ObjectMeta : metav1 . ObjectMeta { Name : classImmediate } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : classWait } ,
VolumeBindingMode : & modeWait ,
} ,
}
pvInfo := FakePersistentVolumeInfo {
{
2019-01-31 21:43:49 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : "Vol_1" , Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-a" } } ,
2017-11-08 16:09:55 -05:00
} ,
}
pvcInfo := FakePersistentVolumeClaimInfo {
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_1" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { VolumeName : "Vol_1" } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_NoSC" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { StorageClassName : & class0 } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_EmptySC" , Namespace : "default" } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_WaitSC" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { StorageClassName : & classWait } ,
} ,
{
ObjectMeta : metav1 . ObjectMeta { Name : "PVC_ImmediateSC" , Namespace : "default" } ,
Spec : v1 . PersistentVolumeClaimSpec { StorageClassName : & classImmediate } ,
} ,
}
testNode := & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "host1" ,
2019-01-31 21:43:49 -05:00
Labels : map [ string ] string { v1 . LabelZoneFailureDomain : "us-west1-a" , "uselessLabel" : "none" } ,
2017-11-08 16:09:55 -05:00
} ,
}
tests := [ ] struct {
2018-06-05 08:08:23 -04:00
name string
2017-11-08 16:09:55 -05:00
Pod * v1 . Pod
Fits bool
Node * v1 . Node
ExpectFailure bool
} {
{
2018-06-05 08:08:23 -04:00
name : "label zone failure domain matched" ,
2017-11-08 16:09:55 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_1" ) ,
Node : testNode ,
Fits : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "unbound volume empty storage class" ,
2017-11-08 16:09:55 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_EmptySC" ) ,
Node : testNode ,
Fits : false ,
ExpectFailure : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "unbound volume no storage class" ,
2017-11-08 16:09:55 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_NoSC" ) ,
Node : testNode ,
Fits : false ,
ExpectFailure : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "unbound volume immediate binding mode" ,
2017-11-08 16:09:55 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_ImmediateSC" ) ,
Node : testNode ,
Fits : false ,
ExpectFailure : true ,
} ,
{
2018-06-05 08:08:23 -04:00
name : "unbound volume wait binding mode" ,
2017-11-08 16:09:55 -05:00
Pod : createPodWithVolume ( "pod_1" , "vol_1" , "PVC_WaitSC" ) ,
Node : testNode ,
Fits : true ,
} ,
}
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
fit := NewVolumeZonePredicate ( pvInfo , pvcInfo , classInfo )
2018-12-07 21:36:11 -05:00
node := & schedulernodeinfo . NodeInfo { }
2018-06-05 08:08:23 -04:00
node . SetNode ( test . Node )
fits , _ , err := fit ( test . Pod , nil , node )
if ! test . ExpectFailure && err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
if test . ExpectFailure && err == nil {
t . Errorf ( "expected error, got success" )
}
if fits != test . Fits {
t . Errorf ( "expected %v got %v" , test . Fits , fits )
}
} )
2017-11-08 16:09:55 -05:00
}
}
2017-09-01 05:30:24 -04:00
func TestGetMaxVols ( t * testing . T ) {
previousValue := os . Getenv ( KubeMaxPDVols )
tests := [ ] struct {
rawMaxVols string
expected int
2018-06-05 08:08:23 -04:00
name string
2017-09-01 05:30:24 -04:00
} {
{
rawMaxVols : "invalid" ,
2018-07-19 15:05:58 -04:00
expected : - 1 ,
2018-06-05 08:08:23 -04:00
name : "Unable to parse maximum PD volumes value, using default value" ,
2017-09-01 05:30:24 -04:00
} ,
{
rawMaxVols : "-2" ,
2018-07-19 15:05:58 -04:00
expected : - 1 ,
2018-06-05 08:08:23 -04:00
name : "Maximum PD volumes must be a positive value, using default value" ,
2017-09-01 05:30:24 -04:00
} ,
{
rawMaxVols : "40" ,
expected : 40 ,
2018-06-05 08:08:23 -04:00
name : "Parse maximum PD volumes value from env" ,
2017-09-01 05:30:24 -04:00
} ,
}
for _ , test := range tests {
2018-06-05 08:08:23 -04:00
t . Run ( test . name , func ( t * testing . T ) {
os . Setenv ( KubeMaxPDVols , test . rawMaxVols )
2018-07-19 15:05:58 -04:00
result := getMaxVolLimitFromEnv ( )
2018-06-05 08:08:23 -04:00
if result != test . expected {
t . Errorf ( "expected %v got %v" , test . expected , result )
}
} )
2017-09-01 05:30:24 -04:00
}
os . Unsetenv ( KubeMaxPDVols )
if previousValue != "" {
os . Setenv ( KubeMaxPDVols , previousValue )
}
}
2018-09-22 21:47:45 -04:00
func TestCheckNodeUnschedulablePredicate ( t * testing . T ) {
testCases := [ ] struct {
name string
pod * v1 . Pod
node * v1 . Node
fit bool
} {
{
name : "Does not schedule pod to unschedulable node (node.Spec.Unschedulable==true)" ,
pod : & v1 . Pod { } ,
node : & v1 . Node {
Spec : v1 . NodeSpec {
Unschedulable : true ,
} ,
} ,
fit : false ,
} ,
{
name : "Schedule pod to normal node" ,
pod : & v1 . Pod { } ,
node : & v1 . Node {
Spec : v1 . NodeSpec {
Unschedulable : false ,
} ,
} ,
fit : true ,
} ,
{
name : "Schedule pod with toleration to unschedulable node (node.Spec.Unschedulable==true)" ,
pod : & v1 . Pod {
Spec : v1 . PodSpec {
Tolerations : [ ] v1 . Toleration {
{
2018-09-27 22:37:38 -04:00
Key : schedulerapi . TaintNodeUnschedulable ,
2018-09-22 21:47:45 -04:00
Effect : v1 . TaintEffectNoSchedule ,
} ,
} ,
} ,
} ,
node : & v1 . Node {
Spec : v1 . NodeSpec {
Unschedulable : true ,
} ,
} ,
fit : true ,
} ,
}
for _ , test := range testCases {
2018-12-07 21:36:11 -05:00
nodeInfo := schedulernodeinfo . NewNodeInfo ( )
2018-09-22 21:47:45 -04:00
nodeInfo . SetNode ( test . node )
fit , _ , err := CheckNodeUnschedulablePredicate ( test . pod , nil , nodeInfo )
if err != nil {
t . Fatalf ( "Failed to check node unschedulable: %v" , err )
}
if fit != test . fit {
t . Errorf ( "Unexpected fit: expected %v, got %v" , test . fit , fit )
}
}
}