2015-04-17 10:00:03 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2015-04-17 10:00:03 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2016-06-08 18:44:10 +00:00
package scheduler
2015-04-17 10:00:03 +00:00
// This file tests the scheduler.
import (
2015-05-02 00:00:37 +00:00
"fmt"
2015-04-17 10:00:03 +00:00
"testing"
"time"
2017-01-13 17:48:50 +00:00
"k8s.io/apimachinery/pkg/api/errors"
2017-01-25 13:13:07 +00:00
"k8s.io/apimachinery/pkg/api/resource"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
2017-01-30 18:39:54 +00:00
clientv1core "k8s.io/client-go/kubernetes/typed/core/v1"
clientv1 "k8s.io/client-go/pkg/api/v1"
2017-01-19 18:27:59 +00:00
restclient "k8s.io/client-go/rest"
2017-01-24 14:11:51 +00:00
"k8s.io/client-go/tools/cache"
2017-01-30 18:39:54 +00:00
"k8s.io/client-go/tools/record"
2017-01-12 18:17:43 +00:00
"k8s.io/kubernetes/pkg/api"
2016-11-18 20:55:32 +00:00
"k8s.io/kubernetes/pkg/api/v1"
2017-01-10 08:49:34 +00:00
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
2017-02-21 20:00:57 +00:00
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/externalversions"
corelisters "k8s.io/kubernetes/pkg/client/listers/core/v1"
2017-03-23 00:26:39 +00:00
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app"
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/options"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/plugin/pkg/scheduler"
2017-04-05 23:59:24 +00:00
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
2015-08-05 22:03:47 +00:00
_ "k8s.io/kubernetes/plugin/pkg/scheduler/algorithmprovider"
2017-04-05 23:59:24 +00:00
schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/plugin/pkg/scheduler/factory"
2017-04-05 23:59:24 +00:00
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
2016-05-26 16:16:43 +00:00
e2e "k8s.io/kubernetes/test/e2e/framework"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/test/integration/framework"
2015-04-17 10:00:03 +00:00
)
2017-02-21 20:00:57 +00:00
type nodeMutationFunc func ( t * testing . T , n * v1 . Node , nodeLister corelisters . NodeLister , c clientset . Interface )
2015-05-02 00:00:37 +00:00
type nodeStateManager struct {
makeSchedulable nodeMutationFunc
makeUnSchedulable nodeMutationFunc
}
2017-04-05 23:59:24 +00:00
func PredicateOne ( pod * v1 . Pod , meta interface { } , nodeInfo * schedulercache . NodeInfo ) ( bool , [ ] algorithm . PredicateFailureReason , error ) {
return true , nil , nil
}
func PredicateTwo ( pod * v1 . Pod , meta interface { } , nodeInfo * schedulercache . NodeInfo ) ( bool , [ ] algorithm . PredicateFailureReason , error ) {
return true , nil , nil
}
func PriorityOne ( pod * v1 . Pod , nodeNameToInfo map [ string ] * schedulercache . NodeInfo , nodes [ ] * v1 . Node ) ( schedulerapi . HostPriorityList , error ) {
return [ ] schedulerapi . HostPriority { } , nil
}
func PriorityTwo ( pod * v1 . Pod , nodeNameToInfo map [ string ] * schedulercache . NodeInfo , nodes [ ] * v1 . Node ) ( schedulerapi . HostPriorityList , error ) {
return [ ] schedulerapi . HostPriority { } , nil
}
2017-03-23 00:26:39 +00:00
// TestSchedulerCreationFromConfigMap verifies that scheduler can be created
2017-04-05 23:59:24 +00:00
// from configurations provided by a ConfigMap object and then verifies that the
// configuration is applied correctly.
2017-03-23 00:26:39 +00:00
func TestSchedulerCreationFromConfigMap ( t * testing . T ) {
_ , s := framework . RunAMaster ( nil )
defer s . Close ( )
ns := framework . CreateTestingNamespace ( "configmap" , s , t )
defer framework . DeleteTestingNamespace ( ns , s , t )
clientSet := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL , ContentConfig : restclient . ContentConfig { GroupVersion : & api . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion } } )
2017-04-05 23:59:24 +00:00
defer clientSet . Core ( ) . Nodes ( ) . DeleteCollection ( nil , metav1 . ListOptions { } )
2017-03-23 00:26:39 +00:00
informerFactory := informers . NewSharedInformerFactory ( clientSet , 0 )
2017-04-05 23:59:24 +00:00
// Pre-register some predicate and priority functions
factory . RegisterFitPredicate ( "PredicateOne" , PredicateOne )
factory . RegisterFitPredicate ( "PredicateTwo" , PredicateTwo )
factory . RegisterPriorityFunction ( "PriorityOne" , PriorityOne , 1 )
factory . RegisterPriorityFunction ( "PriorityTwo" , PriorityTwo , 1 )
2017-03-23 00:26:39 +00:00
// Add a ConfigMap object.
configPolicyName := "scheduler-custom-policy-config"
policyConfigMap := v1 . ConfigMap {
ObjectMeta : metav1 . ObjectMeta { Namespace : metav1 . NamespaceSystem , Name : configPolicyName } ,
Data : map [ string ] string {
2017-04-12 20:10:04 +00:00
options . SchedulerPolicyConfigMapKey : ` {
2017-03-23 00:26:39 +00:00
"kind" : "Policy" ,
"apiVersion" : "v1" ,
"predicates" : [
2017-04-05 23:59:24 +00:00
{ "name" : "PredicateOne" } ,
{ "name" : "PredicateTwo" }
2017-03-23 00:26:39 +00:00
] ,
"priorities" : [
2017-04-05 23:59:24 +00:00
{ "name" : "PriorityOne" , "weight" : 1 } ,
{ "name" : "PriorityTwo" , "weight" : 5 }
2017-03-23 00:26:39 +00:00
]
} ` ,
} ,
}
2017-04-05 23:59:24 +00:00
2017-03-23 00:26:39 +00:00
policyConfigMap . APIVersion = api . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion . String ( )
clientSet . Core ( ) . ConfigMaps ( metav1 . NamespaceSystem ) . Create ( & policyConfigMap )
eventBroadcaster := record . NewBroadcaster ( )
eventBroadcaster . StartRecordingToSink ( & clientv1core . EventSinkImpl { Interface : clientv1core . New ( clientSet . Core ( ) . RESTClient ( ) ) . Events ( "" ) } )
ss := options . NewSchedulerServer ( )
ss . HardPodAffinitySymmetricWeight = v1 . DefaultHardPodAffinitySymmetricWeight
ss . PolicyConfigMapName = configPolicyName
sched , err := app . CreateScheduler ( ss , clientSet ,
informerFactory . Core ( ) . V1 ( ) . Nodes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumeClaims ( ) ,
informerFactory . Core ( ) . V1 ( ) . ReplicationControllers ( ) ,
informerFactory . Extensions ( ) . V1beta1 ( ) . ReplicaSets ( ) ,
informerFactory . Apps ( ) . V1beta1 ( ) . StatefulSets ( ) ,
informerFactory . Core ( ) . V1 ( ) . Services ( ) ,
eventBroadcaster . NewRecorder ( api . Scheme , clientv1 . EventSource { Component : v1 . DefaultSchedulerName } ) ,
)
if err != nil {
t . Fatalf ( "Error creating scheduler: %v" , err )
}
2017-04-05 23:59:24 +00:00
// Verify that the config is applied correctly.
schedPredicates := sched . Config ( ) . Algorithm . Predicates ( )
schedPrioritizers := sched . Config ( ) . Algorithm . Prioritizers ( )
if len ( schedPredicates ) != 2 || len ( schedPrioritizers ) != 2 {
t . Errorf ( "Unexpected number of predicates or priority functions. Number of predicates: %v, number of prioritizers: %v" , len ( schedPredicates ) , len ( schedPrioritizers ) )
}
// Check a predicate and a priority function.
if schedPredicates [ "PredicateTwo" ] == nil {
t . Errorf ( "Expected to have a PodFitsHostPorts predicate." )
}
if schedPrioritizers [ 1 ] . Function == nil || schedPrioritizers [ 1 ] . Weight != 5 {
t . Errorf ( "Unexpected prioritizer: func: %v, weight: %v" , schedPrioritizers [ 1 ] . Function , schedPrioritizers [ 1 ] . Weight )
}
2017-03-23 00:26:39 +00:00
2017-04-05 23:59:24 +00:00
defer close ( sched . Config ( ) . StopEverything )
2017-03-23 00:26:39 +00:00
}
// TestSchedulerCreationFromNonExistentConfigMap ensures that creation of the
// scheduler from a non-existent ConfigMap fails.
func TestSchedulerCreationFromNonExistentConfigMap ( t * testing . T ) {
_ , s := framework . RunAMaster ( nil )
defer s . Close ( )
ns := framework . CreateTestingNamespace ( "configmap" , s , t )
defer framework . DeleteTestingNamespace ( ns , s , t )
clientSet := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL , ContentConfig : restclient . ContentConfig { GroupVersion : & api . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion } } )
defer clientSet . Core ( ) . Nodes ( ) . DeleteCollection ( nil , metav1 . ListOptions { } )
informerFactory := informers . NewSharedInformerFactory ( clientSet , 0 )
eventBroadcaster := record . NewBroadcaster ( )
eventBroadcaster . StartRecordingToSink ( & clientv1core . EventSinkImpl { Interface : clientv1core . New ( clientSet . Core ( ) . RESTClient ( ) ) . Events ( "" ) } )
ss := options . NewSchedulerServer ( )
ss . PolicyConfigMapName = "non-existent-config"
_ , err := app . CreateScheduler ( ss , clientSet ,
informerFactory . Core ( ) . V1 ( ) . Nodes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumeClaims ( ) ,
informerFactory . Core ( ) . V1 ( ) . ReplicationControllers ( ) ,
informerFactory . Extensions ( ) . V1beta1 ( ) . ReplicaSets ( ) ,
informerFactory . Apps ( ) . V1beta1 ( ) . StatefulSets ( ) ,
informerFactory . Core ( ) . V1 ( ) . Services ( ) ,
eventBroadcaster . NewRecorder ( api . Scheme , clientv1 . EventSource { Component : v1 . DefaultSchedulerName } ) ,
)
if err == nil {
t . Fatalf ( "Creation of scheduler didn't fail while the policy ConfigMap didn't exist." )
}
}
// TestSchedulerCreationInLegacyMode ensures that creation of the scheduler
// works fine when legacy mode is enabled.
func TestSchedulerCreationInLegacyMode ( t * testing . T ) {
_ , s := framework . RunAMaster ( nil )
defer s . Close ( )
ns := framework . CreateTestingNamespace ( "configmap" , s , t )
defer framework . DeleteTestingNamespace ( ns , s , t )
clientSet := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL , ContentConfig : restclient . ContentConfig { GroupVersion : & api . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion } } )
defer clientSet . Core ( ) . Nodes ( ) . DeleteCollection ( nil , metav1 . ListOptions { } )
informerFactory := informers . NewSharedInformerFactory ( clientSet , 0 )
eventBroadcaster := record . NewBroadcaster ( )
eventBroadcaster . StartRecordingToSink ( & clientv1core . EventSinkImpl { Interface : clientv1core . New ( clientSet . Core ( ) . RESTClient ( ) ) . Events ( "" ) } )
ss := options . NewSchedulerServer ( )
ss . HardPodAffinitySymmetricWeight = v1 . DefaultHardPodAffinitySymmetricWeight
ss . PolicyConfigMapName = "non-existent-configmap"
ss . UseLegacyPolicyConfig = true
sched , err := app . CreateScheduler ( ss , clientSet ,
informerFactory . Core ( ) . V1 ( ) . Nodes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumeClaims ( ) ,
informerFactory . Core ( ) . V1 ( ) . ReplicationControllers ( ) ,
informerFactory . Extensions ( ) . V1beta1 ( ) . ReplicaSets ( ) ,
informerFactory . Apps ( ) . V1beta1 ( ) . StatefulSets ( ) ,
informerFactory . Core ( ) . V1 ( ) . Services ( ) ,
eventBroadcaster . NewRecorder ( api . Scheme , clientv1 . EventSource { Component : v1 . DefaultSchedulerName } ) ,
)
if err != nil {
t . Fatalf ( "Creation of scheduler in legacy mode failed: %v" , err )
}
2017-04-05 23:59:24 +00:00
informerFactory . Start ( sched . Config ( ) . StopEverything )
defer close ( sched . Config ( ) . StopEverything )
2017-03-23 00:26:39 +00:00
sched . Run ( )
2017-04-05 23:59:24 +00:00
DoTestUnschedulableNodes ( t , clientSet , ns , informerFactory . Core ( ) . V1 ( ) . Nodes ( ) . Lister ( ) )
2017-03-23 00:26:39 +00:00
}
2015-04-17 10:00:03 +00:00
func TestUnschedulableNodes ( t * testing . T ) {
2016-07-04 13:16:13 +00:00
_ , s := framework . RunAMaster ( nil )
2016-04-21 11:50:55 +00:00
defer s . Close ( )
2015-04-17 10:00:03 +00:00
2016-07-05 08:22:13 +00:00
ns := framework . CreateTestingNamespace ( "unschedulable-nodes" , s , t )
defer framework . DeleteTestingNamespace ( ns , s , t )
2017-01-12 18:17:43 +00:00
clientSet := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL , ContentConfig : restclient . ContentConfig { GroupVersion : & api . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion } } )
2017-02-21 20:00:57 +00:00
informerFactory := informers . NewSharedInformerFactory ( clientSet , 0 )
schedulerConfigFactory := factory . NewConfigFactory (
v1 . DefaultSchedulerName ,
clientSet ,
informerFactory . Core ( ) . V1 ( ) . Nodes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumeClaims ( ) ,
informerFactory . Core ( ) . V1 ( ) . ReplicationControllers ( ) ,
informerFactory . Extensions ( ) . V1beta1 ( ) . ReplicaSets ( ) ,
2017-02-19 07:28:09 +00:00
informerFactory . Apps ( ) . V1beta1 ( ) . StatefulSets ( ) ,
2017-02-21 20:00:57 +00:00
informerFactory . Core ( ) . V1 ( ) . Services ( ) ,
v1 . DefaultHardPodAffinitySymmetricWeight ,
)
2015-04-17 10:00:03 +00:00
schedulerConfig , err := schedulerConfigFactory . Create ( )
if err != nil {
t . Fatalf ( "Couldn't create scheduler config: %v" , err )
}
eventBroadcaster := record . NewBroadcaster ( )
2017-01-30 18:39:54 +00:00
schedulerConfig . Recorder = eventBroadcaster . NewRecorder ( api . Scheme , clientv1 . EventSource { Component : v1 . DefaultSchedulerName } )
eventBroadcaster . StartRecordingToSink ( & clientv1core . EventSinkImpl { Interface : clientv1core . New ( clientSet . Core ( ) . RESTClient ( ) ) . Events ( "" ) } )
2017-02-21 20:00:57 +00:00
informerFactory . Start ( schedulerConfig . StopEverything )
2017-05-08 07:10:25 +00:00
sched , _ := scheduler . NewFromConfigurator ( & scheduler . FakeConfigurator { Config : schedulerConfig } , nil ... )
sched . Run ( )
2015-04-17 10:00:03 +00:00
defer close ( schedulerConfig . StopEverything )
2017-02-21 20:00:57 +00:00
DoTestUnschedulableNodes ( t , clientSet , ns , schedulerConfigFactory . GetNodeLister ( ) )
2015-04-17 10:00:03 +00:00
}
2016-10-18 13:00:38 +00:00
func podScheduled ( c clientset . Interface , podNamespace , podName string ) wait . ConditionFunc {
2015-04-17 10:00:03 +00:00
return func ( ) ( bool , error ) {
2016-12-07 14:40:26 +00:00
pod , err := c . Core ( ) . Pods ( podNamespace ) . Get ( podName , metav1 . GetOptions { } )
2015-04-17 10:00:03 +00:00
if errors . IsNotFound ( err ) {
return false , nil
}
if err != nil {
// This could be a connection error so we want to retry.
return false , nil
}
2015-05-22 23:40:57 +00:00
if pod . Spec . NodeName == "" {
2015-04-17 10:00:03 +00:00
return false , nil
}
return true , nil
}
}
2015-05-02 00:00:37 +00:00
// Wait till the passFunc confirms that the object it expects to see is in the store.
// Used to observe reflected events.
2017-02-21 20:00:57 +00:00
func waitForReflection ( t * testing . T , nodeLister corelisters . NodeLister , key string , passFunc func ( n interface { } ) bool ) error {
2016-11-18 20:55:32 +00:00
nodes := [ ] * v1 . Node { }
2016-06-08 13:00:08 +00:00
err := wait . Poll ( time . Millisecond * 100 , wait . ForeverTestTimeout , func ( ) ( bool , error ) {
2017-02-21 20:00:57 +00:00
n , err := nodeLister . Get ( key )
switch {
case err == nil && passFunc ( n ) :
2015-05-02 00:00:37 +00:00
return true , nil
2017-02-21 20:00:57 +00:00
case errors . IsNotFound ( err ) :
nodes = append ( nodes , nil )
case err != nil :
t . Errorf ( "Unexpected error: %v" , err )
default :
nodes = append ( nodes , n )
2015-05-02 00:00:37 +00:00
}
2017-02-21 20:00:57 +00:00
return false , nil
2015-05-02 00:00:37 +00:00
} )
2016-06-08 13:00:08 +00:00
if err != nil {
t . Logf ( "Logging consecutive node versions received from store:" )
for i , n := range nodes {
t . Logf ( "%d: %#v" , i , n )
}
}
return err
2015-05-02 00:00:37 +00:00
}
2017-02-21 20:00:57 +00:00
func DoTestUnschedulableNodes ( t * testing . T , cs clientset . Interface , ns * v1 . Namespace , nodeLister corelisters . NodeLister ) {
2016-07-05 08:22:13 +00:00
// NOTE: This test cannot run in parallel, because it is creating and deleting
// non-namespaced objects (Nodes).
2017-01-22 03:36:02 +00:00
defer cs . Core ( ) . Nodes ( ) . DeleteCollection ( nil , metav1 . ListOptions { } )
2016-07-05 08:22:13 +00:00
2016-11-18 20:55:32 +00:00
goodCondition := v1 . NodeCondition {
Type : v1 . NodeReady ,
Status : v1 . ConditionTrue ,
2015-05-02 00:00:37 +00:00
Reason : fmt . Sprintf ( "schedulable condition" ) ,
2017-04-27 16:58:00 +00:00
LastHeartbeatTime : metav1 . Time { Time : time . Now ( ) } ,
2015-04-17 10:00:03 +00:00
}
2016-11-18 20:55:32 +00:00
badCondition := v1 . NodeCondition {
Type : v1 . NodeReady ,
Status : v1 . ConditionUnknown ,
2015-05-02 00:00:37 +00:00
Reason : fmt . Sprintf ( "unschedulable condition" ) ,
2017-04-27 16:58:00 +00:00
LastHeartbeatTime : metav1 . Time { Time : time . Now ( ) } ,
2015-04-17 10:00:03 +00:00
}
2015-05-02 00:00:37 +00:00
// Create a new schedulable node, since we're first going to apply
// the unschedulable condition and verify that pods aren't scheduled.
2016-11-18 20:55:32 +00:00
node := & v1 . Node {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "node-scheduling-test-node" } ,
2016-11-18 20:55:32 +00:00
Spec : v1 . NodeSpec { Unschedulable : false } ,
Status : v1 . NodeStatus {
Capacity : v1 . ResourceList {
v1 . ResourcePods : * resource . NewQuantity ( 32 , resource . DecimalSI ) ,
2015-03-17 14:43:49 +00:00
} ,
2016-11-18 20:55:32 +00:00
Conditions : [ ] v1 . NodeCondition { goodCondition } ,
2015-04-17 10:00:03 +00:00
} ,
}
2015-05-02 00:00:37 +00:00
nodeKey , err := cache . MetaNamespaceKeyFunc ( node )
2015-04-17 10:00:03 +00:00
if err != nil {
2015-05-02 00:00:37 +00:00
t . Fatalf ( "Couldn't retrieve key for node %v" , node . Name )
2015-04-17 10:00:03 +00:00
}
2015-05-02 00:00:37 +00:00
// The test does the following for each nodeStateManager in this list:
// 1. Create a new node
// 2. Apply the makeUnSchedulable function
// 3. Create a new pod
// 4. Check that the pod doesn't get assigned to the node
// 5. Apply the schedulable function
// 6. Check that the pod *does* get assigned to the node
// 7. Delete the pod and node.
nodeModifications := [ ] nodeStateManager {
// Test node.Spec.Unschedulable=true/false
{
2017-02-21 20:00:57 +00:00
makeUnSchedulable : func ( t * testing . T , n * v1 . Node , nodeLister corelisters . NodeLister , c clientset . Interface ) {
2015-05-02 00:00:37 +00:00
n . Spec . Unschedulable = true
2016-10-18 13:00:38 +00:00
if _ , err := c . Core ( ) . Nodes ( ) . Update ( n ) ; err != nil {
2015-05-02 00:00:37 +00:00
t . Fatalf ( "Failed to update node with unschedulable=true: %v" , err )
}
2017-02-21 20:00:57 +00:00
err = waitForReflection ( t , nodeLister , nodeKey , func ( node interface { } ) bool {
2016-06-08 19:07:12 +00:00
// An unschedulable node should still be present in the store
// Nodes that are unschedulable or that are not ready or
2016-12-14 14:03:00 +00:00
// have their disk full (Node.Spec.Conditions) are excluded
2016-06-08 19:07:12 +00:00
// based on NodeConditionPredicate, a separate check
2016-11-18 20:55:32 +00:00
return node != nil && node . ( * v1 . Node ) . Spec . Unschedulable == true
2015-05-02 00:00:37 +00:00
} )
if err != nil {
t . Fatalf ( "Failed to observe reflected update for setting unschedulable=true: %v" , err )
}
} ,
2017-02-21 20:00:57 +00:00
makeSchedulable : func ( t * testing . T , n * v1 . Node , nodeLister corelisters . NodeLister , c clientset . Interface ) {
2015-05-02 00:00:37 +00:00
n . Spec . Unschedulable = false
2016-10-18 13:00:38 +00:00
if _ , err := c . Core ( ) . Nodes ( ) . Update ( n ) ; err != nil {
2015-05-02 00:00:37 +00:00
t . Fatalf ( "Failed to update node with unschedulable=false: %v" , err )
}
2017-02-21 20:00:57 +00:00
err = waitForReflection ( t , nodeLister , nodeKey , func ( node interface { } ) bool {
2016-11-18 20:55:32 +00:00
return node != nil && node . ( * v1 . Node ) . Spec . Unschedulable == false
2015-05-02 00:00:37 +00:00
} )
if err != nil {
t . Fatalf ( "Failed to observe reflected update for setting unschedulable=false: %v" , err )
}
} ,
} ,
// Test node.Status.Conditions=ConditionTrue/Unknown
{
2017-02-21 20:00:57 +00:00
makeUnSchedulable : func ( t * testing . T , n * v1 . Node , nodeLister corelisters . NodeLister , c clientset . Interface ) {
2016-11-18 20:55:32 +00:00
n . Status = v1 . NodeStatus {
Capacity : v1 . ResourceList {
v1 . ResourcePods : * resource . NewQuantity ( 32 , resource . DecimalSI ) ,
2015-03-17 14:43:49 +00:00
} ,
2016-11-18 20:55:32 +00:00
Conditions : [ ] v1 . NodeCondition { badCondition } ,
2015-05-02 00:00:37 +00:00
}
2016-10-18 13:00:38 +00:00
if _ , err = c . Core ( ) . Nodes ( ) . UpdateStatus ( n ) ; err != nil {
2015-05-02 00:00:37 +00:00
t . Fatalf ( "Failed to update node with bad status condition: %v" , err )
}
2017-02-21 20:00:57 +00:00
err = waitForReflection ( t , nodeLister , nodeKey , func ( node interface { } ) bool {
2016-11-18 20:55:32 +00:00
return node != nil && node . ( * v1 . Node ) . Status . Conditions [ 0 ] . Status == v1 . ConditionUnknown
2015-05-02 00:00:37 +00:00
} )
if err != nil {
t . Fatalf ( "Failed to observe reflected update for status condition update: %v" , err )
}
} ,
2017-02-21 20:00:57 +00:00
makeSchedulable : func ( t * testing . T , n * v1 . Node , nodeLister corelisters . NodeLister , c clientset . Interface ) {
2016-11-18 20:55:32 +00:00
n . Status = v1 . NodeStatus {
Capacity : v1 . ResourceList {
v1 . ResourcePods : * resource . NewQuantity ( 32 , resource . DecimalSI ) ,
2015-03-17 14:43:49 +00:00
} ,
2016-11-18 20:55:32 +00:00
Conditions : [ ] v1 . NodeCondition { goodCondition } ,
2015-05-02 00:00:37 +00:00
}
2016-10-18 13:00:38 +00:00
if _ , err = c . Core ( ) . Nodes ( ) . UpdateStatus ( n ) ; err != nil {
2015-05-02 00:00:37 +00:00
t . Fatalf ( "Failed to update node with healthy status condition: %v" , err )
}
2017-02-21 20:00:57 +00:00
err = waitForReflection ( t , nodeLister , nodeKey , func ( node interface { } ) bool {
2016-11-18 20:55:32 +00:00
return node != nil && node . ( * v1 . Node ) . Status . Conditions [ 0 ] . Status == v1 . ConditionTrue
2015-05-02 00:00:37 +00:00
} )
if err != nil {
t . Fatalf ( "Failed to observe reflected update for status condition update: %v" , err )
}
} ,
} ,
2015-04-17 10:00:03 +00:00
}
2015-05-02 00:00:37 +00:00
for i , mod := range nodeModifications {
2016-10-18 13:00:38 +00:00
unSchedNode , err := cs . Core ( ) . Nodes ( ) . Create ( node )
2015-05-02 00:00:37 +00:00
if err != nil {
t . Fatalf ( "Failed to create node: %v" , err )
}
// Apply the unschedulable modification to the node, and wait for the reflection
2017-02-21 20:00:57 +00:00
mod . makeUnSchedulable ( t , unSchedNode , nodeLister , cs )
2015-05-02 00:00:37 +00:00
// Create the new pod, note that this needs to happen post unschedulable
// modification or we have a race in the test.
2016-11-18 20:55:32 +00:00
pod := & v1 . Pod {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "node-scheduling-test-pod" } ,
2016-11-18 20:55:32 +00:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container { { Name : "container" , Image : e2e . GetPauseImageName ( cs ) } } ,
2015-05-02 00:00:37 +00:00
} ,
}
2016-10-18 13:00:38 +00:00
myPod , err := cs . Core ( ) . Pods ( ns . Name ) . Create ( pod )
2015-05-02 00:00:37 +00:00
if err != nil {
t . Fatalf ( "Failed to create pod: %v" , err )
}
// There are no schedulable nodes - the pod shouldn't be scheduled.
2016-10-18 13:00:38 +00:00
err = wait . Poll ( time . Second , wait . ForeverTestTimeout , podScheduled ( cs , myPod . Namespace , myPod . Name ) )
2015-05-02 00:00:37 +00:00
if err == nil {
t . Errorf ( "Pod scheduled successfully on unschedulable nodes" )
}
if err != wait . ErrWaitTimeout {
2015-05-10 04:25:14 +00:00
t . Errorf ( "Test %d: failed while trying to confirm the pod does not get scheduled on the node: %v" , i , err )
2015-05-02 00:00:37 +00:00
} else {
t . Logf ( "Test %d: Pod did not get scheduled on an unschedulable node" , i )
}
// Apply the schedulable modification to the node, and wait for the reflection
2016-12-07 14:40:26 +00:00
schedNode , err := cs . Core ( ) . Nodes ( ) . Get ( unSchedNode . Name , metav1 . GetOptions { } )
2015-05-02 00:00:37 +00:00
if err != nil {
t . Fatalf ( "Failed to get node: %v" , err )
}
2017-02-21 20:00:57 +00:00
mod . makeSchedulable ( t , schedNode , nodeLister , cs )
2015-05-02 00:00:37 +00:00
// Wait until the pod is scheduled.
2016-10-18 13:00:38 +00:00
err = wait . Poll ( time . Second , wait . ForeverTestTimeout , podScheduled ( cs , myPod . Namespace , myPod . Name ) )
2015-05-02 00:00:37 +00:00
if err != nil {
2015-05-10 04:25:14 +00:00
t . Errorf ( "Test %d: failed to schedule a pod: %v" , i , err )
2015-05-02 00:00:37 +00:00
} else {
t . Logf ( "Test %d: Pod got scheduled on a schedulable node" , i )
}
2017-01-24 15:38:21 +00:00
err = cs . Core ( ) . Pods ( ns . Name ) . Delete ( myPod . Name , metav1 . NewDeleteOptions ( 0 ) )
2015-05-02 00:00:37 +00:00
if err != nil {
t . Errorf ( "Failed to delete pod: %v" , err )
}
2016-10-18 13:00:38 +00:00
err = cs . Core ( ) . Nodes ( ) . Delete ( schedNode . Name , nil )
2015-05-02 00:00:37 +00:00
if err != nil {
t . Errorf ( "Failed to delete node: %v" , err )
}
2015-04-17 10:00:03 +00:00
}
}
2015-11-27 09:07:17 +00:00
func TestMultiScheduler ( t * testing . T ) {
2016-07-04 13:16:13 +00:00
_ , s := framework . RunAMaster ( nil )
2016-01-10 22:39:32 +00:00
// TODO: Uncomment when fix #19254
2016-06-23 12:53:41 +00:00
// This seems to be a different issue - it still doesn't work.
2016-01-10 22:39:32 +00:00
// defer s.Close()
2015-11-27 09:07:17 +00:00
2016-07-05 08:22:13 +00:00
ns := framework . CreateTestingNamespace ( "multi-scheduler" , s , t )
defer framework . DeleteTestingNamespace ( ns , s , t )
2015-11-27 09:07:17 +00:00
/ *
This integration tests the multi - scheduler feature in the following way :
1. create a default scheduler
2. create a node
3. create 3 pods : testPodNoAnnotation , testPodWithAnnotationFitsDefault and testPodWithAnnotationFitsFoo
- note : the first two should be picked and scheduled by default scheduler while the last one should be
picked by scheduler of name "foo-scheduler" which does not exist yet .
4. * * check point - 1 * * :
- testPodNoAnnotation , testPodWithAnnotationFitsDefault should be scheduled
- testPodWithAnnotationFitsFoo should NOT be scheduled
5. create a scheduler with name "foo-scheduler"
6. * * check point - 2 * * :
- testPodWithAnnotationFitsFoo should be scheduled
7. stop default scheduler
8. create 2 pods : testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2
- note : these two pods belong to default scheduler which no longer exists
9. * * check point - 3 * * :
2016-12-14 14:03:00 +00:00
- testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 should NOT be scheduled
2015-11-27 09:07:17 +00:00
* /
// 1. create and start default-scheduler
2017-01-12 18:17:43 +00:00
clientSet := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL , ContentConfig : restclient . ContentConfig { GroupVersion : & api . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion } } )
2015-11-27 09:07:17 +00:00
2016-07-05 08:22:13 +00:00
// NOTE: This test cannot run in parallel, because it is creating and deleting
// non-namespaced objects (Nodes).
2017-01-22 03:36:02 +00:00
defer clientSet . Core ( ) . Nodes ( ) . DeleteCollection ( nil , metav1 . ListOptions { } )
2016-07-05 08:22:13 +00:00
2017-02-21 20:00:57 +00:00
informerFactory := informers . NewSharedInformerFactory ( clientSet , 0 )
schedulerConfigFactory := factory . NewConfigFactory (
v1 . DefaultSchedulerName ,
clientSet ,
informerFactory . Core ( ) . V1 ( ) . Nodes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumeClaims ( ) ,
informerFactory . Core ( ) . V1 ( ) . ReplicationControllers ( ) ,
informerFactory . Extensions ( ) . V1beta1 ( ) . ReplicaSets ( ) ,
2017-02-19 07:28:09 +00:00
informerFactory . Apps ( ) . V1beta1 ( ) . StatefulSets ( ) ,
2017-02-21 20:00:57 +00:00
informerFactory . Core ( ) . V1 ( ) . Services ( ) ,
v1 . DefaultHardPodAffinitySymmetricWeight ,
)
2015-11-27 09:07:17 +00:00
schedulerConfig , err := schedulerConfigFactory . Create ( )
if err != nil {
t . Fatalf ( "Couldn't create scheduler config: %v" , err )
}
eventBroadcaster := record . NewBroadcaster ( )
2017-01-30 18:39:54 +00:00
schedulerConfig . Recorder = eventBroadcaster . NewRecorder ( api . Scheme , clientv1 . EventSource { Component : v1 . DefaultSchedulerName } )
eventBroadcaster . StartRecordingToSink ( & clientv1core . EventSinkImpl { Interface : clientv1core . New ( clientSet . Core ( ) . RESTClient ( ) ) . Events ( "" ) } )
2017-02-21 20:00:57 +00:00
informerFactory . Start ( schedulerConfig . StopEverything )
2017-05-08 07:10:25 +00:00
sched , _ := scheduler . NewFromConfigurator ( & scheduler . FakeConfigurator { Config : schedulerConfig } , nil ... )
sched . Run ( )
2015-11-27 09:07:17 +00:00
// default-scheduler will be stopped later
// 2. create a node
2016-11-18 20:55:32 +00:00
node := & v1 . Node {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "node-multi-scheduler-test-node" } ,
2016-11-18 20:55:32 +00:00
Spec : v1 . NodeSpec { Unschedulable : false } ,
Status : v1 . NodeStatus {
Capacity : v1 . ResourceList {
v1 . ResourcePods : * resource . NewQuantity ( 32 , resource . DecimalSI ) ,
2015-11-27 09:07:17 +00:00
} ,
} ,
}
2016-10-18 13:00:38 +00:00
clientSet . Core ( ) . Nodes ( ) . Create ( node )
2015-11-27 09:07:17 +00:00
// 3. create 3 pods for testing
2017-01-05 23:47:54 +00:00
podWithoutSchedulerName := createPod ( clientSet , "pod-without-scheduler-name" , "" )
testPod , err := clientSet . Core ( ) . Pods ( ns . Name ) . Create ( podWithoutSchedulerName )
2015-11-27 09:07:17 +00:00
if err != nil {
t . Fatalf ( "Failed to create pod: %v" , err )
}
2017-01-05 23:47:54 +00:00
schedulerFitsDefault := "default-scheduler"
podFitsDefault := createPod ( clientSet , "pod-fits-default" , schedulerFitsDefault )
testPodFitsDefault , err := clientSet . Core ( ) . Pods ( ns . Name ) . Create ( podFitsDefault )
2015-11-27 09:07:17 +00:00
if err != nil {
t . Fatalf ( "Failed to create pod: %v" , err )
}
2017-01-05 23:47:54 +00:00
schedulerFitsFoo := "foo-scheduler"
podFitsFoo := createPod ( clientSet , "pod-fits-foo" , schedulerFitsFoo )
testPodFitsFoo , err := clientSet . Core ( ) . Pods ( ns . Name ) . Create ( podFitsFoo )
2015-11-27 09:07:17 +00:00
if err != nil {
t . Fatalf ( "Failed to create pod: %v" , err )
}
// 4. **check point-1**:
2017-01-05 23:47:54 +00:00
// - testPod, testPodFitsDefault should be scheduled
// - testPodFitsFoo should NOT be scheduled
err = wait . Poll ( time . Second , time . Second * 5 , podScheduled ( clientSet , testPod . Namespace , testPod . Name ) )
2015-11-27 09:07:17 +00:00
if err != nil {
2017-01-05 23:47:54 +00:00
t . Errorf ( "Test MultiScheduler: %s Pod not scheduled: %v" , testPod . Name , err )
2015-11-27 09:07:17 +00:00
} else {
2017-01-05 23:47:54 +00:00
t . Logf ( "Test MultiScheduler: %s Pod scheduled" , testPod . Name )
2015-11-27 09:07:17 +00:00
}
2017-01-05 23:47:54 +00:00
err = wait . Poll ( time . Second , time . Second * 5 , podScheduled ( clientSet , testPodFitsDefault . Namespace , testPodFitsDefault . Name ) )
2015-11-27 09:07:17 +00:00
if err != nil {
2017-01-05 23:47:54 +00:00
t . Errorf ( "Test MultiScheduler: %s Pod not scheduled: %v" , testPodFitsDefault . Name , err )
2015-11-27 09:07:17 +00:00
} else {
2017-01-05 23:47:54 +00:00
t . Logf ( "Test MultiScheduler: %s Pod scheduled" , testPodFitsDefault . Name )
2015-11-27 09:07:17 +00:00
}
2017-01-05 23:47:54 +00:00
err = wait . Poll ( time . Second , time . Second * 5 , podScheduled ( clientSet , testPodFitsFoo . Namespace , testPodFitsFoo . Name ) )
2015-11-27 09:07:17 +00:00
if err == nil {
2017-01-05 23:47:54 +00:00
t . Errorf ( "Test MultiScheduler: %s Pod got scheduled, %v" , testPodFitsFoo . Name , err )
2015-11-27 09:07:17 +00:00
} else {
2017-01-05 23:47:54 +00:00
t . Logf ( "Test MultiScheduler: %s Pod not scheduled" , testPodFitsFoo . Name )
2015-11-27 09:07:17 +00:00
}
// 5. create and start a scheduler with name "foo-scheduler"
2017-01-12 18:17:43 +00:00
clientSet2 := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL , ContentConfig : restclient . ContentConfig { GroupVersion : & api . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion } } )
2017-02-21 20:00:57 +00:00
informerFactory2 := informers . NewSharedInformerFactory ( clientSet , 0 )
schedulerConfigFactory2 := factory . NewConfigFactory (
"foo-scheduler" ,
clientSet2 ,
informerFactory . Core ( ) . V1 ( ) . Nodes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumeClaims ( ) ,
informerFactory . Core ( ) . V1 ( ) . ReplicationControllers ( ) ,
informerFactory . Extensions ( ) . V1beta1 ( ) . ReplicaSets ( ) ,
2017-02-19 07:28:09 +00:00
informerFactory . Apps ( ) . V1beta1 ( ) . StatefulSets ( ) ,
2017-02-21 20:00:57 +00:00
informerFactory . Core ( ) . V1 ( ) . Services ( ) ,
v1 . DefaultHardPodAffinitySymmetricWeight ,
)
2015-11-27 09:07:17 +00:00
schedulerConfig2 , err := schedulerConfigFactory2 . Create ( )
if err != nil {
t . Errorf ( "Couldn't create scheduler config: %v" , err )
}
eventBroadcaster2 := record . NewBroadcaster ( )
2017-01-30 18:39:54 +00:00
schedulerConfig2 . Recorder = eventBroadcaster2 . NewRecorder ( api . Scheme , clientv1 . EventSource { Component : "foo-scheduler" } )
eventBroadcaster . StartRecordingToSink ( & clientv1core . EventSinkImpl { Interface : clientv1core . New ( clientSet2 . Core ( ) . RESTClient ( ) ) . Events ( "" ) } )
2017-02-21 20:00:57 +00:00
informerFactory2 . Start ( schedulerConfig2 . StopEverything )
2015-11-27 09:07:17 +00:00
2017-05-08 07:10:25 +00:00
sched2 , _ := scheduler . NewFromConfigurator ( & scheduler . FakeConfigurator { Config : schedulerConfig2 } , nil ... )
sched2 . Run ( )
2015-11-27 09:07:17 +00:00
defer close ( schedulerConfig2 . StopEverything )
// 6. **check point-2**:
// - testPodWithAnnotationFitsFoo should be scheduled
2017-01-05 23:47:54 +00:00
err = wait . Poll ( time . Second , time . Second * 5 , podScheduled ( clientSet , testPodFitsFoo . Namespace , testPodFitsFoo . Name ) )
2015-11-27 09:07:17 +00:00
if err != nil {
2017-01-05 23:47:54 +00:00
t . Errorf ( "Test MultiScheduler: %s Pod not scheduled, %v" , testPodFitsFoo . Name , err )
2015-11-27 09:07:17 +00:00
} else {
2017-01-05 23:47:54 +00:00
t . Logf ( "Test MultiScheduler: %s Pod scheduled" , testPodFitsFoo . Name )
2015-11-27 09:07:17 +00:00
}
// 7. delete the pods that were scheduled by the default scheduler, and stop the default scheduler
2017-01-24 15:38:21 +00:00
err = clientSet . Core ( ) . Pods ( ns . Name ) . Delete ( testPod . Name , metav1 . NewDeleteOptions ( 0 ) )
2015-11-27 09:07:17 +00:00
if err != nil {
t . Errorf ( "Failed to delete pod: %v" , err )
}
2017-01-24 15:38:21 +00:00
err = clientSet . Core ( ) . Pods ( ns . Name ) . Delete ( testPodFitsDefault . Name , metav1 . NewDeleteOptions ( 0 ) )
2015-11-27 09:07:17 +00:00
if err != nil {
t . Errorf ( "Failed to delete pod: %v" , err )
}
2016-03-31 23:56:10 +00:00
// The rest of this test assumes that closing StopEverything will cause the
// scheduler thread to stop immediately. It won't, and in fact it will often
// schedule 1 more pod before finally exiting. Comment out until we fix that.
//
// See https://github.com/kubernetes/kubernetes/issues/23715 for more details.
2015-11-27 09:07:17 +00:00
2016-03-31 23:56:10 +00:00
/ *
close ( schedulerConfig . StopEverything )
// 8. create 2 pods: testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2
// - note: these two pods belong to default scheduler which no longer exists
podWithNoAnnotation2 := createPod ( "pod-with-no-annotation2" , nil )
podWithAnnotationFitsDefault2 := createPod ( "pod-with-annotation-fits-default2" , schedulerAnnotationFitsDefault )
2016-10-18 13:00:38 +00:00
testPodNoAnnotation2 , err := clientSet . Core ( ) . Pods ( ns . Name ) . Create ( podWithNoAnnotation2 )
2016-03-31 23:56:10 +00:00
if err != nil {
t . Fatalf ( "Failed to create pod: %v" , err )
}
2016-10-18 13:00:38 +00:00
testPodWithAnnotationFitsDefault2 , err := clientSet . Core ( ) . Pods ( ns . Name ) . Create ( podWithAnnotationFitsDefault2 )
2016-03-31 23:56:10 +00:00
if err != nil {
t . Fatalf ( "Failed to create pod: %v" , err )
}
// 9. **check point-3**:
2016-12-14 14:03:00 +00:00
// - testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 should NOT be scheduled
2016-10-18 13:00:38 +00:00
err = wait . Poll ( time . Second , time . Second * 5 , podScheduled ( clientSet , testPodNoAnnotation2 . Namespace , testPodNoAnnotation2 . Name ) )
2016-03-31 23:56:10 +00:00
if err == nil {
t . Errorf ( "Test MultiScheduler: %s Pod got scheduled, %v" , testPodNoAnnotation2 . Name , err )
} else {
t . Logf ( "Test MultiScheduler: %s Pod not scheduled" , testPodNoAnnotation2 . Name )
}
2016-10-18 13:00:38 +00:00
err = wait . Poll ( time . Second , time . Second * 5 , podScheduled ( clientSet , testPodWithAnnotationFitsDefault2 . Namespace , testPodWithAnnotationFitsDefault2 . Name ) )
2016-03-31 23:56:10 +00:00
if err == nil {
t . Errorf ( "Test MultiScheduler: %s Pod got scheduled, %v" , testPodWithAnnotationFitsDefault2 . Name , err )
} else {
t . Logf ( "Test MultiScheduler: %s Pod scheduled" , testPodWithAnnotationFitsDefault2 . Name )
}
* /
2015-11-27 09:07:17 +00:00
}
2017-01-05 23:47:54 +00:00
func createPod ( client clientset . Interface , name string , scheduler string ) * v1 . Pod {
2016-11-18 20:55:32 +00:00
return & v1 . Pod {
2017-01-05 23:47:54 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : name } ,
2016-11-18 20:55:32 +00:00
Spec : v1 . PodSpec {
2017-01-05 23:47:54 +00:00
Containers : [ ] v1 . Container { { Name : "container" , Image : e2e . GetPauseImageName ( client ) } } ,
SchedulerName : scheduler ,
2015-11-27 09:07:17 +00:00
} ,
}
}
2016-01-13 16:29:31 +00:00
// This test will verify scheduler can work well regardless of whether kubelet is allocatable aware or not.
func TestAllocatable ( t * testing . T ) {
2016-07-04 13:16:13 +00:00
_ , s := framework . RunAMaster ( nil )
2016-01-13 16:29:31 +00:00
defer s . Close ( )
2016-07-05 08:22:13 +00:00
ns := framework . CreateTestingNamespace ( "allocatable" , s , t )
defer framework . DeleteTestingNamespace ( ns , s , t )
2016-01-13 16:29:31 +00:00
// 1. create and start default-scheduler
2017-01-12 18:17:43 +00:00
clientSet := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL , ContentConfig : restclient . ContentConfig { GroupVersion : & api . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion } } )
2017-02-21 20:00:57 +00:00
informerFactory := informers . NewSharedInformerFactory ( clientSet , 0 )
2016-01-13 16:29:31 +00:00
2016-07-05 08:22:13 +00:00
// NOTE: This test cannot run in parallel, because it is creating and deleting
// non-namespaced objects (Nodes).
2017-01-22 03:36:02 +00:00
defer clientSet . Core ( ) . Nodes ( ) . DeleteCollection ( nil , metav1 . ListOptions { } )
2016-07-05 08:22:13 +00:00
2017-02-21 20:00:57 +00:00
schedulerConfigFactory := factory . NewConfigFactory (
v1 . DefaultSchedulerName ,
clientSet ,
informerFactory . Core ( ) . V1 ( ) . Nodes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumes ( ) ,
informerFactory . Core ( ) . V1 ( ) . PersistentVolumeClaims ( ) ,
informerFactory . Core ( ) . V1 ( ) . ReplicationControllers ( ) ,
informerFactory . Extensions ( ) . V1beta1 ( ) . ReplicaSets ( ) ,
2017-02-19 07:28:09 +00:00
informerFactory . Apps ( ) . V1beta1 ( ) . StatefulSets ( ) ,
2017-02-21 20:00:57 +00:00
informerFactory . Core ( ) . V1 ( ) . Services ( ) ,
v1 . DefaultHardPodAffinitySymmetricWeight ,
)
2016-01-13 16:29:31 +00:00
schedulerConfig , err := schedulerConfigFactory . Create ( )
if err != nil {
t . Fatalf ( "Couldn't create scheduler config: %v" , err )
}
eventBroadcaster := record . NewBroadcaster ( )
2017-01-30 18:39:54 +00:00
schedulerConfig . Recorder = eventBroadcaster . NewRecorder ( api . Scheme , clientv1 . EventSource { Component : v1 . DefaultSchedulerName } )
eventBroadcaster . StartRecordingToSink ( & clientv1core . EventSinkImpl { Interface : clientv1core . New ( clientSet . Core ( ) . RESTClient ( ) ) . Events ( "" ) } )
2017-02-21 20:00:57 +00:00
informerFactory . Start ( schedulerConfig . StopEverything )
2017-05-08 07:10:25 +00:00
sched , _ := scheduler . NewFromConfigurator ( & scheduler . FakeConfigurator { Config : schedulerConfig } , nil ... )
sched . Run ( )
2016-01-13 16:29:31 +00:00
// default-scheduler will be stopped later
defer close ( schedulerConfig . StopEverything )
// 2. create a node without allocatable awareness
2016-11-18 20:55:32 +00:00
node := & v1 . Node {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "node-allocatable-scheduler-test-node" } ,
2016-11-18 20:55:32 +00:00
Spec : v1 . NodeSpec { Unschedulable : false } ,
Status : v1 . NodeStatus {
Capacity : v1 . ResourceList {
v1 . ResourcePods : * resource . NewQuantity ( 32 , resource . DecimalSI ) ,
v1 . ResourceCPU : * resource . NewMilliQuantity ( 30 , resource . DecimalSI ) ,
v1 . ResourceMemory : * resource . NewQuantity ( 30 , resource . BinarySI ) ,
2016-01-13 16:29:31 +00:00
} ,
} ,
}
2016-10-18 13:00:38 +00:00
allocNode , err := clientSet . Core ( ) . Nodes ( ) . Create ( node )
2016-01-13 16:29:31 +00:00
if err != nil {
t . Fatalf ( "Failed to create node: %v" , err )
}
// 3. create resource pod which requires less than Capacity
2016-11-18 20:55:32 +00:00
podResource := & v1 . Pod {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "pod-test-allocatable" } ,
2016-11-18 20:55:32 +00:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-01-13 16:29:31 +00:00
{
Name : "container" ,
2016-10-18 13:00:38 +00:00
Image : e2e . GetPauseImageName ( clientSet ) ,
2016-11-18 20:55:32 +00:00
Resources : v1 . ResourceRequirements {
Requests : v1 . ResourceList {
v1 . ResourceCPU : * resource . NewMilliQuantity ( 20 , resource . DecimalSI ) ,
v1 . ResourceMemory : * resource . NewQuantity ( 20 , resource . BinarySI ) ,
2016-01-13 16:29:31 +00:00
} ,
} ,
} ,
} ,
} ,
}
2016-10-18 13:00:38 +00:00
testAllocPod , err := clientSet . Core ( ) . Pods ( ns . Name ) . Create ( podResource )
2016-01-13 16:29:31 +00:00
if err != nil {
t . Fatalf ( "Test allocatable unawareness failed to create pod: %v" , err )
}
// 4. Test: this test pod should be scheduled since api-server will use Capacity as Allocatable
2016-10-18 13:00:38 +00:00
err = wait . Poll ( time . Second , time . Second * 5 , podScheduled ( clientSet , testAllocPod . Namespace , testAllocPod . Name ) )
2016-01-13 16:29:31 +00:00
if err != nil {
t . Errorf ( "Test allocatable unawareness: %s Pod not scheduled: %v" , testAllocPod . Name , err )
} else {
t . Logf ( "Test allocatable unawareness: %s Pod scheduled" , testAllocPod . Name )
}
// 5. Change the node status to allocatable aware, note that Allocatable is less than Pod's requirement
2016-11-18 20:55:32 +00:00
allocNode . Status = v1 . NodeStatus {
Capacity : v1 . ResourceList {
v1 . ResourcePods : * resource . NewQuantity ( 32 , resource . DecimalSI ) ,
v1 . ResourceCPU : * resource . NewMilliQuantity ( 30 , resource . DecimalSI ) ,
v1 . ResourceMemory : * resource . NewQuantity ( 30 , resource . BinarySI ) ,
2016-01-13 16:29:31 +00:00
} ,
2016-11-18 20:55:32 +00:00
Allocatable : v1 . ResourceList {
v1 . ResourcePods : * resource . NewQuantity ( 32 , resource . DecimalSI ) ,
v1 . ResourceCPU : * resource . NewMilliQuantity ( 10 , resource . DecimalSI ) ,
v1 . ResourceMemory : * resource . NewQuantity ( 10 , resource . BinarySI ) ,
2016-01-13 16:29:31 +00:00
} ,
}
2016-10-18 13:00:38 +00:00
if _ , err := clientSet . Core ( ) . Nodes ( ) . UpdateStatus ( allocNode ) ; err != nil {
2016-01-13 16:29:31 +00:00
t . Fatalf ( "Failed to update node with Status.Allocatable: %v" , err )
}
2017-01-24 15:38:21 +00:00
if err := clientSet . Core ( ) . Pods ( ns . Name ) . Delete ( podResource . Name , & metav1 . DeleteOptions { } ) ; err != nil {
2016-01-13 16:29:31 +00:00
t . Fatalf ( "Failed to remove first resource pod: %v" , err )
}
// 6. Make another pod with different name, same resource request
podResource . ObjectMeta . Name = "pod-test-allocatable2"
2016-10-18 13:00:38 +00:00
testAllocPod2 , err := clientSet . Core ( ) . Pods ( ns . Name ) . Create ( podResource )
2016-01-13 16:29:31 +00:00
if err != nil {
t . Fatalf ( "Test allocatable awareness failed to create pod: %v" , err )
}
// 7. Test: this test pod should not be scheduled since it request more than Allocatable
2016-10-18 13:00:38 +00:00
err = wait . Poll ( time . Second , time . Second * 5 , podScheduled ( clientSet , testAllocPod2 . Namespace , testAllocPod2 . Name ) )
2016-01-13 16:29:31 +00:00
if err == nil {
2016-12-14 14:03:00 +00:00
t . Errorf ( "Test allocatable awareness: %s Pod got scheduled unexpectedly, %v" , testAllocPod2 . Name , err )
2016-01-13 16:29:31 +00:00
} else {
t . Logf ( "Test allocatable awareness: %s Pod not scheduled as expected" , testAllocPod2 . Name )
}
}