2015-09-08 18:50:39 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2015-09-08 18:50:39 +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 .
* /
package daemon
import (
"fmt"
2017-02-26 01:34:14 +00:00
"reflect"
"sort"
"strconv"
2017-02-16 10:18:16 +00:00
"sync"
2015-09-08 18:50:39 +00:00
"testing"
2018-08-15 14:03:39 +00:00
"time"
2015-09-08 18:50:39 +00:00
2018-02-14 18:35:38 +00:00
apps "k8s.io/api/apps/v1"
2017-06-22 18:24:23 +00:00
"k8s.io/api/core/v1"
2017-01-25 13:13:07 +00:00
"k8s.io/apimachinery/pkg/api/resource"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
2018-08-15 14:03:39 +00:00
"k8s.io/apimachinery/pkg/util/clock"
2017-05-20 00:34:04 +00:00
"k8s.io/apimachinery/pkg/util/intstr"
2017-02-26 00:22:54 +00:00
"k8s.io/apimachinery/pkg/util/uuid"
2017-01-14 06:55:53 +00:00
"k8s.io/apiserver/pkg/storage/names"
2017-02-24 01:14:46 +00:00
utilfeature "k8s.io/apiserver/pkg/util/feature"
2018-11-16 02:58:34 +00:00
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
2017-06-23 20:56:37 +00:00
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
2017-01-25 20:07:10 +00:00
core "k8s.io/client-go/testing"
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"
2018-08-15 14:03:39 +00:00
"k8s.io/client-go/util/flowcontrol"
2017-02-26 01:34:14 +00:00
"k8s.io/client-go/util/workqueue"
2017-10-16 11:41:50 +00:00
"k8s.io/kubernetes/pkg/api/legacyscheme"
2017-04-17 17:56:40 +00:00
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
2017-11-08 22:34:54 +00:00
api "k8s.io/kubernetes/pkg/apis/core"
2015-09-08 18:50:39 +00:00
"k8s.io/kubernetes/pkg/controller"
2018-03-08 02:09:54 +00:00
"k8s.io/kubernetes/pkg/features"
2017-02-24 01:14:46 +00:00
kubelettypes "k8s.io/kubernetes/pkg/kubelet/types"
2018-09-28 02:37:38 +00:00
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
2015-09-08 18:50:39 +00:00
"k8s.io/kubernetes/pkg/securitycontext"
2017-05-17 23:53:46 +00:00
labelsutil "k8s.io/kubernetes/pkg/util/labels"
2015-09-08 18:50:39 +00:00
)
2018-09-11 17:58:33 +00:00
// IMPORTANT NOTE: Some tests in file need to pass irrespective of ScheduleDaemonSetPods feature is enabled. For rest
// of the tests, an explicit comment is mentioned whether we are testing codepath specific to ScheduleDaemonSetPods or
// without that feature.
2015-09-08 18:50:39 +00:00
var (
simpleDaemonSetLabel = map [ string ] string { "name" : "simple-daemon" , "type" : "production" }
simpleDaemonSetLabel2 = map [ string ] string { "name" : "simple-daemon" , "type" : "test" }
simpleNodeLabel = map [ string ] string { "color" : "blue" , "speed" : "fast" }
simpleNodeLabel2 = map [ string ] string { "color" : "red" , "speed" : "fast" }
2015-10-03 21:03:27 +00:00
alwaysReady = func ( ) bool { return true }
2015-09-08 18:50:39 +00:00
)
2017-02-07 14:08:45 +00:00
var (
noScheduleTolerations = [ ] v1 . Toleration { { Key : "dedicated" , Value : "user1" , Effect : "NoSchedule" } }
noScheduleTaints = [ ] v1 . Taint { { Key : "dedicated" , Value : "user1" , Effect : "NoSchedule" } }
2017-06-28 09:27:24 +00:00
noExecuteTaints = [ ] v1 . Taint { { Key : "dedicated" , Value : "user1" , Effect : "NoExecute" } }
2017-02-09 01:33:59 +00:00
)
2017-03-13 21:15:43 +00:00
func nowPointer ( ) * metav1 . Time {
now := metav1 . Now ( )
return & now
}
2017-02-21 17:06:45 +00:00
var (
nodeNotReady = [ ] v1 . Taint { {
2018-09-28 02:37:38 +00:00
Key : schedulerapi . TaintNodeNotReady ,
2017-02-21 17:06:45 +00:00
Effect : v1 . TaintEffectNoExecute ,
2017-03-13 21:15:43 +00:00
TimeAdded : nowPointer ( ) ,
2017-02-21 17:06:45 +00:00
} }
nodeUnreachable = [ ] v1 . Taint { {
2018-09-28 02:37:38 +00:00
Key : schedulerapi . TaintNodeUnreachable ,
2017-02-21 17:06:45 +00:00
Effect : v1 . TaintEffectNoExecute ,
2017-03-13 21:15:43 +00:00
TimeAdded : nowPointer ( ) ,
2017-02-21 17:06:45 +00:00
} }
)
2018-02-14 18:35:38 +00:00
func newDaemonSet ( name string ) * apps . DaemonSet {
2017-05-17 23:53:46 +00:00
two := int32 ( 2 )
2018-02-14 18:35:38 +00:00
return & apps . DaemonSet {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2017-02-26 00:22:54 +00:00
UID : uuid . NewUUID ( ) ,
2015-09-08 18:50:39 +00:00
Name : name ,
2017-01-22 03:36:02 +00:00
Namespace : metav1 . NamespaceDefault ,
2015-09-08 18:50:39 +00:00
} ,
2018-02-14 18:35:38 +00:00
Spec : apps . DaemonSetSpec {
2017-05-17 23:53:46 +00:00
RevisionHistoryLimit : & two ,
2018-02-14 18:35:38 +00:00
UpdateStrategy : apps . DaemonSetUpdateStrategy {
Type : apps . OnDeleteDaemonSetStrategyType ,
2017-05-17 23:53:46 +00:00
} ,
2016-12-03 18:57:26 +00:00
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
2016-11-18 20:50:17 +00:00
Template : v1 . PodTemplateSpec {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2015-09-08 18:50:39 +00:00
Labels : simpleDaemonSetLabel ,
} ,
2016-11-18 20:50:17 +00:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2015-09-08 18:50:39 +00:00
{
2018-10-05 19:59:38 +00:00
Image : "foo/bar" ,
2016-11-18 20:50:17 +00:00
TerminationMessagePath : v1 . TerminationMessagePathDefault ,
ImagePullPolicy : v1 . PullIfNotPresent ,
2015-09-08 18:50:39 +00:00
SecurityContext : securitycontext . ValidSecurityContextWithContainerDefaults ( ) ,
} ,
} ,
2016-11-18 20:50:17 +00:00
DNSPolicy : v1 . DNSDefault ,
2015-09-08 18:50:39 +00:00
} ,
} ,
} ,
}
}
2018-02-14 18:35:38 +00:00
func newRollbackStrategy ( ) * apps . DaemonSetUpdateStrategy {
2017-05-20 00:34:04 +00:00
one := intstr . FromInt ( 1 )
2018-02-14 18:35:38 +00:00
return & apps . DaemonSetUpdateStrategy {
Type : apps . RollingUpdateDaemonSetStrategyType ,
RollingUpdate : & apps . RollingUpdateDaemonSet { MaxUnavailable : & one } ,
2017-05-20 00:34:04 +00:00
}
}
2018-02-14 18:35:38 +00:00
func newOnDeleteStrategy ( ) * apps . DaemonSetUpdateStrategy {
return & apps . DaemonSetUpdateStrategy {
Type : apps . OnDeleteDaemonSetStrategyType ,
2017-05-20 00:34:04 +00:00
}
}
2018-02-14 18:35:38 +00:00
func updateStrategies ( ) [ ] * apps . DaemonSetUpdateStrategy {
return [ ] * apps . DaemonSetUpdateStrategy { newOnDeleteStrategy ( ) , newRollbackStrategy ( ) }
2017-05-20 00:34:04 +00:00
}
2016-11-18 20:50:17 +00:00
func newNode ( name string , label map [ string ] string ) * v1 . Node {
return & v1 . Node {
2018-05-01 14:54:37 +00:00
TypeMeta : metav1 . TypeMeta { APIVersion : "v1" } ,
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2015-09-08 18:50:39 +00:00
Name : name ,
Labels : label ,
2018-10-10 07:44:59 +00:00
Namespace : metav1 . NamespaceNone ,
2015-09-08 18:50:39 +00:00
} ,
2016-11-18 20:50:17 +00:00
Status : v1 . NodeStatus {
Conditions : [ ] v1 . NodeCondition {
{ Type : v1 . NodeReady , Status : v1 . ConditionTrue } ,
2015-10-29 01:01:34 +00:00
} ,
2016-11-18 20:50:17 +00:00
Allocatable : v1 . ResourceList {
v1 . ResourcePods : resource . MustParse ( "100" ) ,
2016-07-01 17:02:51 +00:00
} ,
2015-10-29 01:01:34 +00:00
} ,
2015-09-08 18:50:39 +00:00
}
}
func addNodes ( nodeStore cache . Store , startIndex , numNodes int , label map [ string ] string ) {
for i := startIndex ; i < startIndex + numNodes ; i ++ {
nodeStore . Add ( newNode ( fmt . Sprintf ( "node-%d" , i ) , label ) )
}
}
2018-02-14 18:35:38 +00:00
func newPod ( podName string , nodeName string , label map [ string ] string , ds * apps . DaemonSet ) * v1 . Pod {
2017-05-17 23:53:46 +00:00
// Add hash unique label to the pod
newLabels := label
2017-06-09 18:03:38 +00:00
var podSpec v1 . PodSpec
// Copy pod spec from DaemonSet template, or use a default one if DaemonSet is nil
2017-05-17 23:53:46 +00:00
if ds != nil {
2018-07-12 00:01:38 +00:00
hash := controller . ComputeHash ( & ds . Spec . Template , ds . Status . CollisionCount )
2018-02-14 18:35:38 +00:00
newLabels = labelsutil . CloneAndAddLabel ( label , apps . DefaultDaemonSetUniqueLabelKey , hash )
2017-06-09 18:03:38 +00:00
podSpec = ds . Spec . Template . Spec
} else {
podSpec = v1 . PodSpec {
2016-11-18 20:50:17 +00:00
Containers : [ ] v1 . Container {
2015-09-08 18:50:39 +00:00
{
2018-10-05 19:59:38 +00:00
Image : "foo/bar" ,
2016-11-18 20:50:17 +00:00
TerminationMessagePath : v1 . TerminationMessagePathDefault ,
ImagePullPolicy : v1 . PullIfNotPresent ,
2015-09-08 18:50:39 +00:00
SecurityContext : securitycontext . ValidSecurityContextWithContainerDefaults ( ) ,
} ,
} ,
2017-06-09 18:03:38 +00:00
}
}
// Add node name to the pod
if len ( nodeName ) > 0 {
podSpec . NodeName = nodeName
}
pod := & v1 . Pod {
2018-05-01 14:54:37 +00:00
TypeMeta : metav1 . TypeMeta { APIVersion : "v1" } ,
2017-06-09 18:03:38 +00:00
ObjectMeta : metav1 . ObjectMeta {
GenerateName : podName ,
Labels : newLabels ,
Namespace : metav1 . NamespaceDefault ,
2015-09-08 18:50:39 +00:00
} ,
2017-06-09 18:03:38 +00:00
Spec : podSpec ,
2015-09-08 18:50:39 +00:00
}
2017-01-14 06:55:53 +00:00
pod . Name = names . SimpleNameGenerator . GenerateName ( podName )
2017-02-26 00:22:54 +00:00
if ds != nil {
2017-08-02 10:05:37 +00:00
pod . OwnerReferences = [ ] metav1 . OwnerReference { * metav1 . NewControllerRef ( ds , controllerKind ) }
2017-02-26 00:22:54 +00:00
}
2015-09-08 18:50:39 +00:00
return pod
}
2018-02-14 18:35:38 +00:00
func addPods ( podStore cache . Store , nodeName string , label map [ string ] string , ds * apps . DaemonSet , number int ) {
2015-09-08 18:50:39 +00:00
for i := 0 ; i < number ; i ++ {
2017-05-17 23:53:46 +00:00
pod := newPod ( fmt . Sprintf ( "%s-" , nodeName ) , nodeName , label , ds )
podStore . Add ( pod )
2015-09-08 18:50:39 +00:00
}
}
2018-02-14 18:35:38 +00:00
func addFailedPods ( podStore cache . Store , nodeName string , label map [ string ] string , ds * apps . DaemonSet , number int ) {
2017-01-24 22:49:35 +00:00
for i := 0 ; i < number ; i ++ {
2017-02-26 00:22:54 +00:00
pod := newPod ( fmt . Sprintf ( "%s-" , nodeName ) , nodeName , label , ds )
2017-01-24 22:49:35 +00:00
pod . Status = v1 . PodStatus { Phase : v1 . PodFailed }
podStore . Add ( pod )
}
}
2017-02-16 10:18:16 +00:00
type fakePodControl struct {
sync . Mutex
* controller . FakePodControl
podStore cache . Store
podIDMap map [ string ] * v1 . Pod
}
func newFakePodControl ( ) * fakePodControl {
podIDMap := make ( map [ string ] * v1 . Pod )
return & fakePodControl {
FakePodControl : & controller . FakePodControl { } ,
podIDMap : podIDMap }
}
2017-02-25 18:56:58 +00:00
func ( f * fakePodControl ) CreatePodsOnNode ( nodeName , namespace string , template * v1 . PodTemplateSpec , object runtime . Object , controllerRef * metav1 . OwnerReference ) error {
2017-02-16 10:18:16 +00:00
f . Lock ( )
defer f . Unlock ( )
2017-02-25 18:56:58 +00:00
if err := f . FakePodControl . CreatePodsOnNode ( nodeName , namespace , template , object , controllerRef ) ; err != nil {
2017-02-16 10:18:16 +00:00
return fmt . Errorf ( "failed to create pod on node %q" , nodeName )
}
pod := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Labels : template . Labels ,
Namespace : namespace ,
GenerateName : fmt . Sprintf ( "%s-" , nodeName ) ,
} ,
}
2017-10-16 11:41:50 +00:00
if err := legacyscheme . Scheme . Convert ( & template . Spec , & pod . Spec , nil ) ; err != nil {
2017-02-16 10:18:16 +00:00
return fmt . Errorf ( "unable to convert pod template: %v" , err )
}
if len ( nodeName ) != 0 {
pod . Spec . NodeName = nodeName
}
pod . Name = names . SimpleNameGenerator . GenerateName ( fmt . Sprintf ( "%s-" , nodeName ) )
f . podStore . Update ( pod )
f . podIDMap [ pod . Name ] = pod
return nil
}
2018-03-08 02:09:54 +00:00
func ( f * fakePodControl ) CreatePodsWithControllerRef ( namespace string , template * v1 . PodTemplateSpec , object runtime . Object , controllerRef * metav1 . OwnerReference ) error {
f . Lock ( )
defer f . Unlock ( )
if err := f . FakePodControl . CreatePodsWithControllerRef ( namespace , template , object , controllerRef ) ; err != nil {
return fmt . Errorf ( "failed to create pod for DaemonSet" )
}
pod := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Labels : template . Labels ,
Namespace : namespace ,
} ,
}
pod . Name = names . SimpleNameGenerator . GenerateName ( fmt . Sprintf ( "%p-" , pod ) )
if err := legacyscheme . Scheme . Convert ( & template . Spec , & pod . Spec , nil ) ; err != nil {
return fmt . Errorf ( "unable to convert pod template: %v" , err )
}
f . podStore . Update ( pod )
f . podIDMap [ pod . Name ] = pod
return nil
}
2017-02-16 10:18:16 +00:00
func ( f * fakePodControl ) DeletePod ( namespace string , podID string , object runtime . Object ) error {
f . Lock ( )
defer f . Unlock ( )
if err := f . FakePodControl . DeletePod ( namespace , podID , object ) ; err != nil {
return fmt . Errorf ( "failed to delete pod %q" , podID )
}
pod , ok := f . podIDMap [ podID ]
if ! ok {
return fmt . Errorf ( "pod %q does not exist" , podID )
}
f . podStore . Delete ( pod )
delete ( f . podIDMap , podID )
return nil
}
2017-02-06 18:35:50 +00:00
type daemonSetsController struct {
* DaemonSetsController
2017-05-28 03:26:57 +00:00
dsStore cache . Store
2017-06-03 01:02:01 +00:00
historyStore cache . Store
2017-05-28 03:26:57 +00:00
podStore cache . Store
nodeStore cache . Store
fakeRecorder * record . FakeRecorder
2017-02-06 18:35:50 +00:00
}
2016-09-15 20:27:47 +00:00
2017-10-31 14:19:55 +00:00
func newTestController ( initialObjects ... runtime . Object ) ( * daemonSetsController , * fakePodControl , * fake . Clientset , error ) {
2017-02-06 18:35:50 +00:00
clientset := fake . NewSimpleClientset ( initialObjects ... )
2017-02-08 21:18:21 +00:00
informerFactory := informers . NewSharedInformerFactory ( clientset , controller . NoResyncPeriodFunc ( ) )
2017-02-06 18:35:50 +00:00
2017-10-31 14:19:55 +00:00
dsc , err := NewDaemonSetsController (
2018-02-14 18:35:38 +00:00
informerFactory . Apps ( ) . V1 ( ) . DaemonSets ( ) ,
informerFactory . Apps ( ) . V1 ( ) . ControllerRevisions ( ) ,
2017-02-06 18:35:50 +00:00
informerFactory . Core ( ) . V1 ( ) . Pods ( ) ,
informerFactory . Core ( ) . V1 ( ) . Nodes ( ) ,
clientset ,
2018-08-15 14:03:39 +00:00
flowcontrol . NewFakeBackOff ( 50 * time . Millisecond , 500 * time . Millisecond , clock . NewFakeClock ( time . Now ( ) ) ) ,
2017-02-06 18:35:50 +00:00
)
2017-10-31 14:19:55 +00:00
if err != nil {
return nil , nil , nil , err
}
2017-05-28 03:26:57 +00:00
fakeRecorder := record . NewFakeRecorder ( 100 )
2017-06-06 12:42:40 +00:00
dsc . eventRecorder = fakeRecorder
2016-09-15 20:27:47 +00:00
2017-06-06 12:42:40 +00:00
dsc . podStoreSynced = alwaysReady
dsc . nodeStoreSynced = alwaysReady
dsc . dsStoreSynced = alwaysReady
dsc . historyStoreSynced = alwaysReady
2017-02-16 10:18:16 +00:00
podControl := newFakePodControl ( )
2017-06-06 12:42:40 +00:00
dsc . podControl = podControl
2017-02-16 10:18:16 +00:00
podControl . podStore = informerFactory . Core ( ) . V1 ( ) . Pods ( ) . Informer ( ) . GetStore ( )
2017-02-06 18:35:50 +00:00
return & daemonSetsController {
2017-06-06 12:42:40 +00:00
dsc ,
2018-02-14 18:35:38 +00:00
informerFactory . Apps ( ) . V1 ( ) . DaemonSets ( ) . Informer ( ) . GetStore ( ) ,
informerFactory . Apps ( ) . V1 ( ) . ControllerRevisions ( ) . Informer ( ) . GetStore ( ) ,
2017-02-06 18:35:50 +00:00
informerFactory . Core ( ) . V1 ( ) . Pods ( ) . Informer ( ) . GetStore ( ) ,
informerFactory . Core ( ) . V1 ( ) . Nodes ( ) . Informer ( ) . GetStore ( ) ,
2017-05-28 03:26:57 +00:00
fakeRecorder ,
2017-10-31 14:19:55 +00:00
} , podControl , clientset , nil
2015-09-08 18:50:39 +00:00
}
2018-08-15 14:03:39 +00:00
func resetCounters ( manager * daemonSetsController ) {
manager . podControl . ( * fakePodControl ) . Clear ( )
fakeRecorder := record . NewFakeRecorder ( 100 )
manager . eventRecorder = fakeRecorder
manager . fakeRecorder = fakeRecorder
}
2017-06-06 12:42:40 +00:00
func validateSyncDaemonSets ( t * testing . T , manager * daemonSetsController , fakePodControl * fakePodControl , expectedCreates , expectedDeletes int , expectedEvents int ) {
2015-09-21 23:30:02 +00:00
if len ( fakePodControl . Templates ) != expectedCreates {
t . Errorf ( "Unexpected number of creates. Expected %d, saw %d\n" , expectedCreates , len ( fakePodControl . Templates ) )
2015-09-08 18:50:39 +00:00
}
2015-09-21 23:30:02 +00:00
if len ( fakePodControl . DeletePodName ) != expectedDeletes {
t . Errorf ( "Unexpected number of deletes. Expected %d, saw %d\n" , expectedDeletes , len ( fakePodControl . DeletePodName ) )
2015-09-08 18:50:39 +00:00
}
2017-06-06 12:42:40 +00:00
if len ( manager . fakeRecorder . Events ) != expectedEvents {
t . Errorf ( "Unexpected number of events. Expected %d, saw %d\n" , expectedEvents , len ( manager . fakeRecorder . Events ) )
}
2017-02-25 18:56:58 +00:00
// Every Pod created should have a ControllerRef.
if got , want := len ( fakePodControl . ControllerRefs ) , expectedCreates ; got != want {
t . Errorf ( "len(ControllerRefs) = %v, want %v" , got , want )
}
// Make sure the ControllerRefs are correct.
for _ , controllerRef := range fakePodControl . ControllerRefs {
2018-02-14 18:35:38 +00:00
if got , want := controllerRef . APIVersion , "apps/v1" ; got != want {
2017-02-25 18:56:58 +00:00
t . Errorf ( "controllerRef.APIVersion = %q, want %q" , got , want )
}
if got , want := controllerRef . Kind , "DaemonSet" ; got != want {
t . Errorf ( "controllerRef.Kind = %q, want %q" , got , want )
}
if controllerRef . Controller == nil || * controllerRef . Controller != true {
t . Errorf ( "controllerRef.Controller is not set to true" )
}
}
2015-09-08 18:50:39 +00:00
}
2018-02-14 18:35:38 +00:00
func syncAndValidateDaemonSets ( t * testing . T , manager * daemonSetsController , ds * apps . DaemonSet , podControl * fakePodControl , expectedCreates , expectedDeletes int , expectedEvents int ) {
2015-09-08 18:50:39 +00:00
key , err := controller . KeyFunc ( ds )
if err != nil {
t . Errorf ( "Could not get key for daemon." )
}
manager . syncHandler ( key )
2017-06-06 12:42:40 +00:00
validateSyncDaemonSets ( t , manager , podControl , expectedCreates , expectedDeletes , expectedEvents )
2015-09-08 18:50:39 +00:00
}
2017-02-16 10:18:16 +00:00
// clearExpectations copies the FakePodControl to PodStore and clears the create and delete expectations.
2018-02-14 18:35:38 +00:00
func clearExpectations ( t * testing . T , manager * daemonSetsController , ds * apps . DaemonSet , fakePodControl * fakePodControl ) {
2017-02-16 10:18:16 +00:00
fakePodControl . Clear ( )
key , err := controller . KeyFunc ( ds )
if err != nil {
t . Errorf ( "Could not get key for daemon." )
return
}
manager . expectations . DeleteExpectations ( key )
}
2016-05-19 21:16:34 +00:00
func TestDeleteFinalStateUnknown ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 1 , nil )
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
// DeletedFinalStateUnknown should queue the embedded DS if found.
manager . deleteDaemonset ( cache . DeletedFinalStateUnknown { Key : "foo" , Obj : ds } )
enqueuedKey , _ := manager . queue . Get ( )
if enqueuedKey . ( string ) != "default/foo" {
t . Errorf ( "expected delete of DeletedFinalStateUnknown to enqueue the daemonset but found: %#v" , enqueuedKey )
}
2017-05-20 00:34:04 +00:00
}
2016-05-19 21:16:34 +00:00
}
}
2017-02-16 10:18:16 +00:00
func markPodsReady ( store cache . Store ) {
// mark pods as ready
for _ , obj := range store . List ( ) {
pod := obj . ( * v1 . Pod )
2017-03-14 13:40:53 +00:00
markPodReady ( pod )
2017-02-16 10:18:16 +00:00
}
}
2017-03-14 13:40:53 +00:00
func markPodReady ( pod * v1 . Pod ) {
condition := v1 . PodCondition { Type : v1 . PodReady , Status : v1 . ConditionTrue }
podutil . UpdatePodCondition ( & pod . Status , & condition )
}
2015-09-08 18:50:39 +00:00
// DaemonSets without node selectors should launch pods on every node.
func TestSimpleDaemonSetLaunchesPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 5 , nil )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 5 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
2018-03-08 02:09:54 +00:00
// When ScheduleDaemonSetPods is enabled, DaemonSets without node selectors should
// launch pods on every node by NodeAffinity.
func TestSimpleDaemonSetScheduleDaemonSetPodsLaunchesPods ( t * testing . T ) {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , true ) ( )
2018-03-08 02:09:54 +00:00
nodeNum := 5
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , nodeNum , nil )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , nodeNum , 0 , 0 )
// Check for ScheduleDaemonSetPods feature
if len ( podControl . podIDMap ) != nodeNum {
t . Fatalf ( "failed to create pods for DaemonSet when enabled ScheduleDaemonSetPods." )
}
nodeMap := make ( map [ string ] * v1 . Node )
for _ , node := range manager . nodeStore . List ( ) {
n := node . ( * v1 . Node )
nodeMap [ n . Name ] = n
}
if len ( nodeMap ) != nodeNum {
t . Fatalf ( "not enough nodes in the store, expected: %v, got: %v" ,
nodeNum , len ( nodeMap ) )
}
for _ , pod := range podControl . podIDMap {
if len ( pod . Spec . NodeName ) != 0 {
t . Fatalf ( "the hostname of pod %v should be empty, but got %s" ,
pod . Name , pod . Spec . NodeName )
}
if pod . Spec . Affinity == nil {
t . Fatalf ( "the Affinity of pod %s is nil." , pod . Name )
}
if pod . Spec . Affinity . NodeAffinity == nil {
t . Fatalf ( "the NodeAffinity of pod %s is nil." , pod . Name )
}
nodeSelector := pod . Spec . Affinity . NodeAffinity . RequiredDuringSchedulingIgnoredDuringExecution
if nodeSelector == nil {
t . Fatalf ( "the node selector of pod %s is nil." , pod . Name )
}
if len ( nodeSelector . NodeSelectorTerms ) != 1 {
2018-09-11 17:58:33 +00:00
t . Fatalf ( "incorrect number of node selector terms in pod %s, expected: 1, got: %d." ,
2018-03-08 02:09:54 +00:00
pod . Name , len ( nodeSelector . NodeSelectorTerms ) )
}
2018-09-11 17:58:33 +00:00
if len ( nodeSelector . NodeSelectorTerms [ 0 ] . MatchFields ) != 1 {
2018-10-11 04:52:39 +00:00
t . Fatalf ( "incorrect number of fields in node selector term for pod %s, expected: 1, got: %d." ,
2018-09-11 17:58:33 +00:00
pod . Name , len ( nodeSelector . NodeSelectorTerms [ 0 ] . MatchFields ) )
2018-03-08 02:09:54 +00:00
}
2018-09-11 17:58:33 +00:00
field := nodeSelector . NodeSelectorTerms [ 0 ] . MatchFields [ 0 ]
2018-09-28 02:37:38 +00:00
if field . Key == schedulerapi . NodeFieldSelectorKeyNodeName {
2018-09-11 17:58:33 +00:00
if field . Operator != v1 . NodeSelectorOpIn {
2018-03-08 02:09:54 +00:00
t . Fatalf ( "the operation of hostname NodeAffinity is not %v" , v1 . NodeSelectorOpIn )
}
2018-09-11 17:58:33 +00:00
if len ( field . Values ) != 1 {
t . Fatalf ( "incorrect hostname in node affinity: expected 1, got %v" , len ( field . Values ) )
2018-03-08 02:09:54 +00:00
}
2018-09-11 17:58:33 +00:00
delete ( nodeMap , field . Values [ 0 ] )
2018-03-08 02:09:54 +00:00
}
}
if len ( nodeMap ) != 0 {
t . Fatalf ( "did not foud pods on nodes %+v" , nodeMap )
}
}
}
2017-07-11 04:04:35 +00:00
// Simulate a cluster with 100 nodes, but simulate a limit (like a quota limit)
// of 10 pods, and verify that the ds doesn't make 100 create calls per sync pass
func TestSimpleDaemonSetPodCreateErrors ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
podControl . FakePodControl . CreateLimit = 10
addNodes ( manager . nodeStore , 0 , podControl . FakePodControl . CreateLimit * 10 , nil )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , podControl . FakePodControl . CreateLimit , 0 , 0 )
expectedLimit := 0
for pass := uint8 ( 0 ) ; expectedLimit <= podControl . FakePodControl . CreateLimit ; pass ++ {
expectedLimit += controller . SlowStartInitialBatchSize << pass
}
if podControl . FakePodControl . CreateCallCount > expectedLimit {
t . Errorf ( "Unexpected number of create calls. Expected <= %d, saw %d\n" , podControl . FakePodControl . CreateLimit * 2 , podControl . FakePodControl . CreateCallCount )
}
2017-07-11 04:04:35 +00:00
2018-09-11 17:58:33 +00:00
}
2017-07-11 04:04:35 +00:00
}
}
2017-03-07 23:01:11 +00:00
func TestSimpleDaemonSetUpdatesStatusAfterLaunchingPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , clientset , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-03-07 23:01:11 +00:00
2018-09-11 17:58:33 +00:00
var updated * apps . DaemonSet
clientset . PrependReactor ( "update" , "daemonsets" , func ( action core . Action ) ( handled bool , ret runtime . Object , err error ) {
if action . GetSubresource ( ) != "status" {
return false , nil , nil
}
if u , ok := action . ( core . UpdateAction ) ; ok {
updated = u . GetObject ( ) . ( * apps . DaemonSet )
}
2017-05-20 00:34:04 +00:00
return false , nil , nil
2018-09-11 17:58:33 +00:00
} )
2017-03-07 23:01:11 +00:00
2018-09-11 17:58:33 +00:00
manager . dsStore . Add ( ds )
addNodes ( manager . nodeStore , 0 , 5 , nil )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 5 , 0 , 0 )
2017-03-07 23:01:11 +00:00
2018-09-11 17:58:33 +00:00
// Make sure the single sync() updated Status already for the change made
// during the manage() phase.
if got , want := updated . Status . CurrentNumberScheduled , int32 ( 5 ) ; got != want {
t . Errorf ( "Status.CurrentNumberScheduled = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-03-07 23:01:11 +00:00
}
}
2016-03-18 23:14:07 +00:00
// DaemonSets should do nothing if there aren't any nodes
2015-09-08 18:50:39 +00:00
func TestNoNodesDoesNothing ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , podControl , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
2016-03-18 23:14:07 +00:00
// DaemonSets without node selectors should launch on a single node in a
// single node cluster.
2015-09-08 18:50:39 +00:00
func TestOneNodeDaemonLaunchesPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . nodeStore . Add ( newNode ( "only-node" , nil ) )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
2016-02-10 23:38:27 +00:00
// DaemonSets should place onto NotReady nodes
2017-09-08 18:44:45 +00:00
func TestNotReadyNodeDaemonDoesLaunchPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
node := newNode ( "not-ready" , nil )
node . Status . Conditions = [ ] v1 . NodeCondition {
{ Type : v1 . NodeReady , Status : v1 . ConditionFalse } ,
}
manager . nodeStore . Add ( node )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
2017-05-20 00:34:04 +00:00
}
2015-10-29 01:01:34 +00:00
}
2015-11-16 16:17:37 +00:00
}
2016-11-18 20:50:17 +00:00
func resourcePodSpec ( nodeName , memory , cpu string ) v1 . PodSpec {
return v1 . PodSpec {
2016-04-28 04:02:41 +00:00
NodeName : nodeName ,
2016-11-18 20:50:17 +00:00
Containers : [ ] v1 . Container { {
Resources : v1 . ResourceRequirements {
2016-04-28 04:02:41 +00:00
Requests : allocatableResources ( memory , cpu ) ,
2016-01-28 06:13:05 +00:00
} ,
} } ,
}
2016-04-28 04:02:41 +00:00
}
2017-11-07 12:31:20 +00:00
func resourceContainerSpec ( memory , cpu string ) v1 . ResourceRequirements {
2017-11-08 08:33:09 +00:00
return v1 . ResourceRequirements {
2017-11-07 12:31:20 +00:00
Requests : allocatableResources ( memory , cpu ) ,
}
}
2017-05-28 03:26:57 +00:00
func resourcePodSpecWithoutNodeName ( memory , cpu string ) v1 . PodSpec {
return v1 . PodSpec {
Containers : [ ] v1 . Container { {
Resources : v1 . ResourceRequirements {
Requests : allocatableResources ( memory , cpu ) ,
} ,
} } ,
}
}
2016-11-18 20:50:17 +00:00
func allocatableResources ( memory , cpu string ) v1 . ResourceList {
return v1 . ResourceList {
v1 . ResourceMemory : resource . MustParse ( memory ) ,
v1 . ResourceCPU : resource . MustParse ( cpu ) ,
v1 . ResourcePods : resource . MustParse ( "100" ) ,
2016-04-28 04:02:41 +00:00
}
}
2018-09-11 17:58:33 +00:00
// When ScheduleDaemonSetPods is disabled, DaemonSets should not place onto nodes with insufficient free resource
2016-11-29 09:54:09 +00:00
func TestInsufficientCapacityNodeDaemonDoesNotLaunchPod ( t * testing . T ) {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , false ) ( )
2017-05-20 00:34:04 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec := resourcePodSpec ( "too-much-mem" , "75M" , "75m" )
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec
2017-10-31 14:19:55 +00:00
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-05-20 00:34:04 +00:00
node := newNode ( "too-much-mem" , nil )
node . Status . Allocatable = allocatableResources ( "100M" , "200m" )
manager . nodeStore . Add ( node )
manager . podStore . Add ( & v1 . Pod {
Spec : podSpec ,
} )
manager . dsStore . Add ( ds )
2017-06-06 12:42:40 +00:00
switch strategy . Type {
2018-02-14 18:35:38 +00:00
case apps . OnDeleteDaemonSetStrategyType :
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 2 )
2018-02-14 18:35:38 +00:00
case apps . RollingUpdateDaemonSetStrategyType :
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 3 )
default :
t . Fatalf ( "unexpected UpdateStrategy %+v" , strategy )
}
2017-05-20 00:34:04 +00:00
}
2016-01-28 06:13:05 +00:00
}
2016-12-14 22:25:35 +00:00
// DaemonSets should not unschedule a daemonset pod from a node with insufficient free resource
2017-05-24 13:59:45 +00:00
func TestInsufficientCapacityNodeDaemonDoesNotUnscheduleRunningPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec := resourcePodSpec ( "too-much-mem" , "75M" , "75m" )
podSpec . NodeName = "too-much-mem"
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
node := newNode ( "too-much-mem" , nil )
node . Status . Allocatable = allocatableResources ( "100M" , "200m" )
manager . nodeStore . Add ( node )
manager . podStore . Add ( & v1 . Pod {
Spec : podSpec ,
} )
manager . dsStore . Add ( ds )
switch strategy . Type {
case apps . OnDeleteDaemonSetStrategyType :
if ! utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) {
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 2 )
} else {
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
}
case apps . RollingUpdateDaemonSetStrategyType :
if ! utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) {
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 3 )
} else {
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
}
default :
t . Fatalf ( "unexpected UpdateStrategy %+v" , strategy )
}
}
}
}
// DaemonSets should only place onto nodes with sufficient free resource and matched node selector
func TestInsufficientCapacityNodeSufficientCapacityWithNodeLabelDaemonLaunchPod ( t * testing . T ) {
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
podSpec := resourcePodSpecWithoutNodeName ( "50M" , "75m" )
2017-05-20 00:34:04 +00:00
ds := newDaemonSet ( "foo" )
ds . Spec . Template . Spec = podSpec
2018-09-11 17:58:33 +00:00
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel
2017-10-31 14:19:55 +00:00
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2018-09-11 17:58:33 +00:00
node1 := newNode ( "not-enough-resource" , nil )
node1 . Status . Allocatable = allocatableResources ( "10M" , "20m" )
node2 := newNode ( "enough-resource" , simpleNodeLabel )
node2 . Status . Allocatable = allocatableResources ( "100M" , "200m" )
manager . nodeStore . Add ( node1 )
manager . nodeStore . Add ( node2 )
2017-05-20 00:34:04 +00:00
manager . dsStore . Add ( ds )
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
// we do not expect any event for insufficient free resource
if len ( manager . fakeRecorder . Events ) != 0 {
t . Fatalf ( "unexpected events, got %v, expected %v: %+v" , len ( manager . fakeRecorder . Events ) , 0 , manager . fakeRecorder . Events )
2017-06-06 12:42:40 +00:00
}
2017-05-20 00:34:04 +00:00
}
2016-12-14 22:25:35 +00:00
}
2018-09-11 17:58:33 +00:00
// When ScheduleDaemonSetPods is disabled, DaemonSetPods should launch onto node with terminated pods if there
// are sufficient resources.
2016-11-29 09:54:09 +00:00
func TestSufficientCapacityWithTerminatedPodsDaemonLaunchesPod ( t * testing . T ) {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , false ) ( )
2017-05-20 00:34:04 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec := resourcePodSpec ( "too-much-mem" , "75M" , "75m" )
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec
2017-10-31 14:19:55 +00:00
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-05-20 00:34:04 +00:00
node := newNode ( "too-much-mem" , nil )
node . Status . Allocatable = allocatableResources ( "100M" , "200m" )
manager . nodeStore . Add ( node )
manager . podStore . Add ( & v1 . Pod {
Spec : podSpec ,
Status : v1 . PodStatus { Phase : v1 . PodSucceeded } ,
} )
manager . dsStore . Add ( ds )
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 1 )
2017-05-20 00:34:04 +00:00
}
2016-04-06 18:47:16 +00:00
}
2018-09-11 17:58:33 +00:00
// When ScheduleDaemonSetPods is disabled, DaemonSets should place onto nodes with sufficient free resources.
2016-11-29 09:54:09 +00:00
func TestSufficientCapacityNodeDaemonLaunchesPod ( t * testing . T ) {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , false ) ( )
2018-09-11 17:58:33 +00:00
2017-05-20 00:34:04 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec := resourcePodSpec ( "not-too-much-mem" , "75M" , "75m" )
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec
2017-10-31 14:19:55 +00:00
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-05-20 00:34:04 +00:00
node := newNode ( "not-too-much-mem" , nil )
node . Status . Allocatable = allocatableResources ( "200M" , "200m" )
manager . nodeStore . Add ( node )
manager . podStore . Add ( & v1 . Pod {
Spec : podSpec ,
} )
manager . dsStore . Add ( ds )
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 1 )
2017-05-20 00:34:04 +00:00
}
2016-01-28 06:13:05 +00:00
}
2017-03-02 19:03:27 +00:00
// DaemonSet should launch a pod on a node with taint NetworkUnavailable condition.
func TestNetworkUnavailableNodeDaemonLaunchesPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "simple" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-03-02 19:03:27 +00:00
2018-09-11 17:58:33 +00:00
node := newNode ( "network-unavailable" , nil )
node . Status . Conditions = [ ] v1 . NodeCondition {
{ Type : v1 . NodeNetworkUnavailable , Status : v1 . ConditionTrue } ,
}
manager . nodeStore . Add ( node )
manager . dsStore . Add ( ds )
2017-03-02 19:03:27 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
}
2017-05-20 00:34:04 +00:00
}
2017-03-02 19:03:27 +00:00
}
2016-06-15 13:34:14 +00:00
// DaemonSets not take any actions when being deleted
func TestDontDoAnythingIfBeingDeleted ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec := resourcePodSpec ( "not-too-much-mem" , "75M" , "75m" )
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec
now := metav1 . Now ( )
ds . DeletionTimestamp = & now
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
node := newNode ( "not-too-much-mem" , nil )
node . Status . Allocatable = allocatableResources ( "200M" , "200m" )
manager . nodeStore . Add ( node )
manager . podStore . Add ( & v1 . Pod {
Spec : podSpec ,
} )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2017-03-11 01:13:51 +00:00
}
func TestDontDoAnythingIfBeingDeletedRace ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
// Bare client says it IS deleted.
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
now := metav1 . Now ( )
ds . DeletionTimestamp = & now
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 5 , nil )
2017-03-11 01:13:51 +00:00
2018-09-11 17:58:33 +00:00
// Lister (cache) says it's NOT deleted.
ds2 := * ds
ds2 . DeletionTimestamp = nil
manager . dsStore . Add ( & ds2 )
2017-03-11 01:13:51 +00:00
2018-09-11 17:58:33 +00:00
// The existence of a matching orphan should block all actions in this state.
pod := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , nil )
manager . podStore . Add ( pod )
2017-03-11 01:13:51 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
}
2017-05-20 00:34:04 +00:00
}
2016-06-15 13:34:14 +00:00
}
2018-09-11 17:58:33 +00:00
// When ScheduleDaemonSetPods is disabled, DaemonSets should not place onto nodes that would cause port conflicts.
2016-01-28 06:13:05 +00:00
func TestPortConflictNodeDaemonDoesNotLaunchPod ( t * testing . T ) {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , false ) ( )
2017-05-20 00:34:04 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec := v1 . PodSpec {
NodeName : "port-conflict" ,
Containers : [ ] v1 . Container { {
Ports : [ ] v1 . ContainerPort { {
HostPort : 666 ,
} } ,
2016-01-28 06:13:05 +00:00
} } ,
2017-05-20 00:34:04 +00:00
}
2017-10-31 14:19:55 +00:00
manager , podControl , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-05-20 00:34:04 +00:00
node := newNode ( "port-conflict" , nil )
manager . nodeStore . Add ( node )
manager . podStore . Add ( & v1 . Pod {
Spec : podSpec ,
} )
2016-03-03 06:15:20 +00:00
2017-05-20 00:34:04 +00:00
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec
manager . dsStore . Add ( ds )
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
2017-05-20 00:34:04 +00:00
}
2016-03-03 06:15:20 +00:00
}
// Test that if the node is already scheduled with a pod using a host port
// but belonging to the same daemonset, we don't delete that pod
//
// Issue: https://github.com/kubernetes/kubernetes/issues/22309
func TestPortConflictWithSameDaemonPodDoesNotDeletePod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec := v1 . PodSpec {
NodeName : "port-conflict" ,
Containers : [ ] v1 . Container { {
Ports : [ ] v1 . ContainerPort { {
HostPort : 666 ,
} } ,
2017-05-20 00:34:04 +00:00
} } ,
2018-09-11 17:58:33 +00:00
}
manager , podControl , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
node := newNode ( "port-conflict" , nil )
manager . nodeStore . Add ( node )
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec
manager . dsStore . Add ( ds )
pod := newPod ( ds . Name + "-" , node . Name , simpleDaemonSetLabel , ds )
manager . podStore . Add ( pod )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2016-03-03 06:15:20 +00:00
}
2015-10-29 01:01:34 +00:00
}
2016-01-28 06:13:05 +00:00
// DaemonSets should place onto nodes that would not cause port conflicts
func TestNoPortConflictNodeDaemonLaunchesPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec1 := v1 . PodSpec {
NodeName : "no-port-conflict" ,
Containers : [ ] v1 . Container { {
Ports : [ ] v1 . ContainerPort { {
HostPort : 6661 ,
} } ,
2017-05-20 00:34:04 +00:00
} } ,
2018-09-11 17:58:33 +00:00
}
podSpec2 := v1 . PodSpec {
NodeName : "no-port-conflict" ,
Containers : [ ] v1 . Container { {
Ports : [ ] v1 . ContainerPort { {
HostPort : 6662 ,
} } ,
2017-05-20 00:34:04 +00:00
} } ,
2018-09-11 17:58:33 +00:00
}
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec2
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
node := newNode ( "no-port-conflict" , nil )
manager . nodeStore . Add ( node )
manager . podStore . Add ( & v1 . Pod {
Spec : podSpec1 ,
} )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2016-01-28 06:13:05 +00:00
}
}
2016-03-18 23:14:07 +00:00
// DaemonSetController should not sync DaemonSets with empty pod selectors.
//
// issue https://github.com/kubernetes/kubernetes/pull/23223
func TestPodIsNotDeletedByDaemonsetWithEmptyLabelSelector ( t * testing . T ) {
// Create a misconfigured DaemonSet. An empty pod selector is invalid but could happen
// if we upgrade and make a backwards incompatible change.
//
// The node selector matches no nodes which mimics the behavior of kubectl delete.
//
// The DaemonSet should not schedule pods and should not delete scheduled pods in
// this case even though it's empty pod selector matches all pods. The DaemonSetController
// should detect this misconfiguration and choose not to sync the DaemonSet. We should
// not observe a deletion of the pod on node1.
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ls := metav1 . LabelSelector { }
ds . Spec . Selector = & ls
ds . Spec . Template . Spec . NodeSelector = map [ string ] string { "foo" : "bar" }
2017-03-11 01:13:51 +00:00
2018-09-11 17:58:33 +00:00
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . nodeStore . Add ( newNode ( "node1" , nil ) )
// Create pod not controlled by a daemonset.
manager . podStore . Add ( & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Labels : map [ string ] string { "bang" : "boom" } ,
Namespace : metav1 . NamespaceDefault ,
} ,
Spec : v1 . PodSpec {
NodeName : "node1" ,
} ,
} )
manager . dsStore . Add ( ds )
2016-03-18 23:14:07 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 1 )
}
2017-05-20 00:34:04 +00:00
}
2016-03-18 23:14:07 +00:00
}
2015-09-08 18:50:39 +00:00
// Controller should not create pods on nodes which have daemon pods, and should remove excess pods from nodes that have extra pods.
func TestDealsWithExistingPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . dsStore . Add ( ds )
addNodes ( manager . nodeStore , 0 , 5 , nil )
addPods ( manager . podStore , "node-1" , simpleDaemonSetLabel , ds , 1 )
addPods ( manager . podStore , "node-2" , simpleDaemonSetLabel , ds , 2 )
addPods ( manager . podStore , "node-3" , simpleDaemonSetLabel , ds , 5 )
addPods ( manager . podStore , "node-4" , simpleDaemonSetLabel2 , ds , 2 )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 2 , 5 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
// Daemon with node selector should launch pods on nodes matching selector.
func TestSelectorDaemonLaunchesPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
daemon := newDaemonSet ( "foo" )
daemon . Spec . UpdateStrategy = * strategy
daemon . Spec . Template . Spec . NodeSelector = simpleNodeLabel
manager , podControl , _ , err := newTestController ( daemon )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 4 , nil )
addNodes ( manager . nodeStore , 4 , 3 , simpleNodeLabel )
manager . dsStore . Add ( daemon )
syncAndValidateDaemonSets ( t , manager , daemon , podControl , 3 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
// Daemon with node selector should delete pods from nodes that do not satisfy selector.
func TestSelectorDaemonDeletesUnselectedPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . dsStore . Add ( ds )
addNodes ( manager . nodeStore , 0 , 5 , nil )
addNodes ( manager . nodeStore , 5 , 5 , simpleNodeLabel )
addPods ( manager . podStore , "node-0" , simpleDaemonSetLabel2 , ds , 2 )
addPods ( manager . podStore , "node-1" , simpleDaemonSetLabel , ds , 3 )
addPods ( manager . podStore , "node-1" , simpleDaemonSetLabel2 , ds , 1 )
addPods ( manager . podStore , "node-4" , simpleDaemonSetLabel , ds , 1 )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 5 , 4 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
// DaemonSet with node selector should launch pods on nodes matching selector, but also deal with existing pods on nodes.
func TestSelectorDaemonDealsWithExistingPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . dsStore . Add ( ds )
addNodes ( manager . nodeStore , 0 , 5 , nil )
addNodes ( manager . nodeStore , 5 , 5 , simpleNodeLabel )
addPods ( manager . podStore , "node-0" , simpleDaemonSetLabel , ds , 1 )
addPods ( manager . podStore , "node-1" , simpleDaemonSetLabel , ds , 3 )
addPods ( manager . podStore , "node-1" , simpleDaemonSetLabel2 , ds , 2 )
addPods ( manager . podStore , "node-2" , simpleDaemonSetLabel , ds , 4 )
addPods ( manager . podStore , "node-6" , simpleDaemonSetLabel , ds , 13 )
addPods ( manager . podStore , "node-7" , simpleDaemonSetLabel2 , ds , 4 )
addPods ( manager . podStore , "node-9" , simpleDaemonSetLabel , ds , 1 )
addPods ( manager . podStore , "node-9" , simpleDaemonSetLabel2 , ds , 1 )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 3 , 20 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
// DaemonSet with node selector which does not match any node labels should not launch pods.
func TestBadSelectorDaemonDoesNothing ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , podControl , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 4 , nil )
addNodes ( manager . nodeStore , 4 , 3 , simpleNodeLabel )
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel2
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
// DaemonSet with node name should launch pod on node with corresponding name.
func TestNameDaemonSetLaunchesPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec . NodeName = "node-0"
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 5 , nil )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
// DaemonSet with node name that does not exist should not launch pods.
func TestBadNameDaemonSetDoesNothing ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec . NodeName = "node-10"
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 5 , nil )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
// DaemonSet with node selector, and node name, matching a node, should launch a pod on the node.
func TestNameAndSelectorDaemonSetLaunchesPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel
ds . Spec . Template . Spec . NodeName = "node-6"
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 4 , nil )
addNodes ( manager . nodeStore , 4 , 3 , simpleNodeLabel )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
// DaemonSet with node selector that matches some nodes, and node name that matches a different node, should do nothing.
func TestInconsistentNameSelectorDaemonSetDoesNothing ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel
ds . Spec . Template . Spec . NodeName = "node-0"
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 4 , nil )
addNodes ( manager . nodeStore , 4 , 3 , simpleNodeLabel )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
}
}
}
// DaemonSet with node selector, matching some nodes, should launch pods on all the nodes.
func TestSelectorDaemonSetLaunchesPods ( t * testing . T ) {
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2017-05-20 00:34:04 +00:00
ds := newDaemonSet ( "foo" )
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel
2017-10-31 14:19:55 +00:00
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-05-20 00:34:04 +00:00
addNodes ( manager . nodeStore , 0 , 4 , nil )
addNodes ( manager . nodeStore , 4 , 3 , simpleNodeLabel )
manager . dsStore . Add ( ds )
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 3 , 0 , 0 )
2017-05-20 00:34:04 +00:00
}
2015-09-08 18:50:39 +00:00
}
2015-10-03 21:03:27 +00:00
2016-07-01 17:02:51 +00:00
// Daemon with node affinity should launch pods on nodes matching affinity.
func TestNodeAffinityDaemonLaunchesPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
daemon := newDaemonSet ( "foo" )
daemon . Spec . UpdateStrategy = * strategy
daemon . Spec . Template . Spec . Affinity = & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "color" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { simpleNodeLabel [ "color" ] } ,
} ,
2017-05-20 00:34:04 +00:00
} ,
2016-11-30 16:51:12 +00:00
} ,
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
}
2017-03-11 01:13:51 +00:00
2018-09-11 17:58:33 +00:00
manager , podControl , _ , err := newTestController ( daemon )
if err != nil {
t . Fatalf ( "rrror creating DaemonSetsController: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 4 , nil )
addNodes ( manager . nodeStore , 4 , 3 , simpleNodeLabel )
manager . dsStore . Add ( daemon )
syncAndValidateDaemonSets ( t , manager , daemon , podControl , 3 , 0 , 0 )
2017-10-31 14:19:55 +00:00
}
2017-05-20 00:34:04 +00:00
}
2016-07-01 17:02:51 +00:00
}
2016-10-05 07:16:41 +00:00
func TestNumberReadyStatus ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , clientset , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
2017-05-20 00:34:04 +00:00
}
2018-09-11 17:58:33 +00:00
var updated * apps . DaemonSet
clientset . PrependReactor ( "update" , "daemonsets" , func ( action core . Action ) ( handled bool , ret runtime . Object , err error ) {
if action . GetSubresource ( ) != "status" {
return false , nil , nil
}
if u , ok := action . ( core . UpdateAction ) ; ok {
updated = u . GetObject ( ) . ( * apps . DaemonSet )
}
return false , nil , nil
} )
addNodes ( manager . nodeStore , 0 , 2 , simpleNodeLabel )
addPods ( manager . podStore , "node-0" , simpleDaemonSetLabel , ds , 1 )
addPods ( manager . podStore , "node-1" , simpleDaemonSetLabel , ds , 1 )
manager . dsStore . Add ( ds )
2016-10-05 07:16:41 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
if updated . Status . NumberReady != 0 {
t . Errorf ( "Wrong daemon %s status: %v" , updated . Name , updated . Status )
}
2016-10-05 07:16:41 +00:00
2018-09-11 17:58:33 +00:00
selector , _ := metav1 . LabelSelectorAsSelector ( ds . Spec . Selector )
daemonPods , _ := manager . podLister . Pods ( ds . Namespace ) . List ( selector )
for _ , pod := range daemonPods {
condition := v1 . PodCondition { Type : v1 . PodReady , Status : v1 . ConditionTrue }
pod . Status . Conditions = append ( pod . Status . Conditions , condition )
}
2016-10-05 07:16:41 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
if updated . Status . NumberReady != 2 {
t . Errorf ( "Wrong daemon %s status: %v" , updated . Name , updated . Status )
}
2017-05-20 00:34:04 +00:00
}
2016-10-05 07:16:41 +00:00
}
}
2016-12-21 01:35:20 +00:00
func TestObservedGeneration ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds . Generation = 1
manager , podControl , clientset , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
2017-05-20 00:34:04 +00:00
}
2018-09-11 17:58:33 +00:00
var updated * apps . DaemonSet
clientset . PrependReactor ( "update" , "daemonsets" , func ( action core . Action ) ( handled bool , ret runtime . Object , err error ) {
if action . GetSubresource ( ) != "status" {
return false , nil , nil
}
if u , ok := action . ( core . UpdateAction ) ; ok {
updated = u . GetObject ( ) . ( * apps . DaemonSet )
}
return false , nil , nil
} )
2016-12-21 01:35:20 +00:00
2018-09-11 17:58:33 +00:00
addNodes ( manager . nodeStore , 0 , 1 , simpleNodeLabel )
addPods ( manager . podStore , "node-0" , simpleDaemonSetLabel , ds , 1 )
manager . dsStore . Add ( ds )
2016-12-21 01:35:20 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
if updated . Status . ObservedGeneration != ds . Generation {
t . Errorf ( "Wrong ObservedGeneration for daemon %s in status. Expected %d, got %d" , updated . Name , ds . Generation , updated . Status . ObservedGeneration )
}
2017-05-20 00:34:04 +00:00
}
2016-12-21 01:35:20 +00:00
}
}
2017-01-09 23:50:04 +00:00
2017-01-25 18:27:25 +00:00
// DaemonSet controller should kill all failed pods and create at most 1 pod on every node.
2017-01-24 22:49:35 +00:00
func TestDaemonKillFailedPods ( t * testing . T ) {
tests := [ ] struct {
2017-06-06 12:42:40 +00:00
numFailedPods , numNormalPods , expectedCreates , expectedDeletes , expectedEvents int
test string
2017-01-24 22:49:35 +00:00
} {
2017-06-06 12:42:40 +00:00
{ numFailedPods : 0 , numNormalPods : 1 , expectedCreates : 0 , expectedDeletes : 0 , expectedEvents : 0 , test : "normal (do nothing)" } ,
{ numFailedPods : 0 , numNormalPods : 0 , expectedCreates : 1 , expectedDeletes : 0 , expectedEvents : 0 , test : "no pods (create 1)" } ,
{ numFailedPods : 1 , numNormalPods : 0 , expectedCreates : 0 , expectedDeletes : 1 , expectedEvents : 1 , test : "1 failed pod (kill 1), 0 normal pod (create 0; will create in the next sync)" } ,
{ numFailedPods : 1 , numNormalPods : 3 , expectedCreates : 0 , expectedDeletes : 3 , expectedEvents : 1 , test : "1 failed pod (kill 1), 3 normal pods (kill 2)" } ,
2017-01-24 22:49:35 +00:00
}
for _ , test := range tests {
2018-08-15 14:03:39 +00:00
t . Run ( test . test , func ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . dsStore . Add ( ds )
addNodes ( manager . nodeStore , 0 , 1 , nil )
addFailedPods ( manager . podStore , "node-0" , simpleDaemonSetLabel , ds , test . numFailedPods )
addPods ( manager . podStore , "node-0" , simpleDaemonSetLabel , ds , test . numNormalPods )
syncAndValidateDaemonSets ( t , manager , ds , podControl , test . expectedCreates , test . expectedDeletes , test . expectedEvents )
2018-08-15 14:03:39 +00:00
}
}
} )
}
}
// DaemonSet controller needs to backoff when killing failed pods to avoid hot looping and fighting with kubelet.
func TestDaemonKillFailedPodsBackoff ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
t . Run ( string ( strategy . Type ) , func ( t * testing . T ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
manager . dsStore . Add ( ds )
addNodes ( manager . nodeStore , 0 , 1 , nil )
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
nodeName := "node-0"
pod := newPod ( fmt . Sprintf ( "%s-" , nodeName ) , nodeName , simpleDaemonSetLabel , ds )
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
// Add a failed Pod
pod . Status . Phase = v1 . PodFailed
err = manager . podStore . Add ( pod )
if err != nil {
t . Fatal ( err )
}
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
backoffKey := failedPodsBackoffKey ( ds , nodeName )
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
// First sync will delete the pod, initializing backoff
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 1 , 1 )
initialDelay := manager . failedPodsBackoff . Get ( backoffKey )
if initialDelay <= 0 {
t . Fatal ( "Initial delay is expected to be set." )
}
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
resetCounters ( manager )
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
// Immediate (second) sync gets limited by the backoff
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
delay := manager . failedPodsBackoff . Get ( backoffKey )
if delay != initialDelay {
t . Fatal ( "Backoff delay shouldn't be raised while waiting." )
}
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
resetCounters ( manager )
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
// Sleep to wait out backoff
fakeClock := manager . failedPodsBackoff . Clock
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
// Move just before the backoff end time
fakeClock . Sleep ( delay - 1 * time . Nanosecond )
if ! manager . failedPodsBackoff . IsInBackOffSinceUpdate ( backoffKey , fakeClock . Now ( ) ) {
t . Errorf ( "Backoff delay didn't last the whole waitout period." )
}
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
// Move to the backoff end time
fakeClock . Sleep ( 1 * time . Nanosecond )
if manager . failedPodsBackoff . IsInBackOffSinceUpdate ( backoffKey , fakeClock . Now ( ) ) {
t . Fatal ( "Backoff delay hasn't been reset after the period has passed." )
}
2018-08-15 14:03:39 +00:00
2018-09-11 17:58:33 +00:00
// After backoff time, it will delete the failed pod
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 1 , 1 )
} )
}
2017-01-24 22:49:35 +00:00
}
}
2017-06-28 09:27:24 +00:00
// Daemonset should not remove a running pod from a node if the pod doesn't
// tolerate the nodes NoSchedule taint
func TestNoScheduleTaintedDoesntEvicitRunningIntolerantPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "intolerant" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-06-28 09:27:24 +00:00
2018-09-11 17:58:33 +00:00
node := newNode ( "tainted" , nil )
manager . nodeStore . Add ( node )
setNodeTaint ( node , noScheduleTaints )
manager . podStore . Add ( newPod ( "keep-running-me" , "tainted" , simpleDaemonSetLabel , ds ) )
manager . dsStore . Add ( ds )
2017-06-28 09:27:24 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
}
2017-06-28 09:27:24 +00:00
}
}
// Daemonset should remove a running pod from a node if the pod doesn't
// tolerate the nodes NoExecute taint
func TestNoExecuteTaintedDoesEvicitRunningIntolerantPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "intolerant" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-06-28 09:27:24 +00:00
2018-09-11 17:58:33 +00:00
node := newNode ( "tainted" , nil )
manager . nodeStore . Add ( node )
setNodeTaint ( node , noExecuteTaints )
manager . podStore . Add ( newPod ( "stop-running-me" , "tainted" , simpleDaemonSetLabel , ds ) )
manager . dsStore . Add ( ds )
2017-06-28 09:27:24 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 1 , 0 )
}
2017-06-28 09:27:24 +00:00
}
}
2017-02-09 01:33:59 +00:00
// DaemonSet should not launch a pod on a tainted node when the pod doesn't tolerate that taint.
2017-06-28 09:27:24 +00:00
func TestTaintedNodeDaemonDoesNotLaunchIntolerantPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "intolerant" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-02-09 01:33:59 +00:00
2018-09-11 17:58:33 +00:00
node := newNode ( "tainted" , nil )
setNodeTaint ( node , noScheduleTaints )
manager . nodeStore . Add ( node )
manager . dsStore . Add ( ds )
2017-02-09 01:33:59 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
}
2017-05-20 00:34:04 +00:00
}
2017-02-09 01:33:59 +00:00
}
// DaemonSet should launch a pod on a tainted node when the pod can tolerate that taint.
func TestTaintedNodeDaemonLaunchesToleratePod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "tolerate" )
ds . Spec . UpdateStrategy = * strategy
setDaemonSetToleration ( ds , noScheduleTolerations )
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-02-09 01:33:59 +00:00
2018-09-11 17:58:33 +00:00
node := newNode ( "tainted" , nil )
setNodeTaint ( node , noScheduleTaints )
manager . nodeStore . Add ( node )
manager . dsStore . Add ( ds )
2017-02-09 01:33:59 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
}
2017-05-20 00:34:04 +00:00
}
2017-02-09 01:33:59 +00:00
}
2017-02-21 17:06:45 +00:00
// DaemonSet should launch a pod on a not ready node with taint notReady:NoExecute.
func TestNotReadyNodeDaemonLaunchesPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "simple" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-02-21 17:06:45 +00:00
2018-09-11 17:58:33 +00:00
node := newNode ( "tainted" , nil )
setNodeTaint ( node , nodeNotReady )
node . Status . Conditions = [ ] v1 . NodeCondition {
{ Type : v1 . NodeReady , Status : v1 . ConditionFalse } ,
}
manager . nodeStore . Add ( node )
manager . dsStore . Add ( ds )
2017-02-21 17:06:45 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
}
2017-05-20 00:34:04 +00:00
}
2017-02-21 17:06:45 +00:00
}
// DaemonSet should launch a pod on an unreachable node with taint unreachable:NoExecute.
func TestUnreachableNodeDaemonLaunchesPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "simple" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-02-21 17:06:45 +00:00
2018-09-11 17:58:33 +00:00
node := newNode ( "tainted" , nil )
setNodeTaint ( node , nodeUnreachable )
node . Status . Conditions = [ ] v1 . NodeCondition {
{ Type : v1 . NodeReady , Status : v1 . ConditionUnknown } ,
}
manager . nodeStore . Add ( node )
manager . dsStore . Add ( ds )
2017-02-21 17:06:45 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
}
2017-05-20 00:34:04 +00:00
}
2017-02-21 17:06:45 +00:00
}
2017-02-09 01:33:59 +00:00
// DaemonSet should launch a pod on an untainted node when the pod has tolerations.
func TestNodeDaemonLaunchesToleratePod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "tolerate" )
ds . Spec . UpdateStrategy = * strategy
setDaemonSetToleration ( ds , noScheduleTolerations )
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
addNodes ( manager . nodeStore , 0 , 1 , nil )
manager . dsStore . Add ( ds )
2017-02-09 01:33:59 +00:00
2018-09-11 17:58:33 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
}
2017-05-20 00:34:04 +00:00
}
2017-02-09 01:33:59 +00:00
}
2017-08-24 16:51:28 +00:00
// DaemonSet should launch a pod on a not ready node with taint notReady:NoExecute.
func TestDaemonSetRespectsTermination ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-08-24 16:51:28 +00:00
2018-09-11 17:58:33 +00:00
addNodes ( manager . nodeStore , 0 , 1 , simpleNodeLabel )
pod := newPod ( fmt . Sprintf ( "%s-" , "node-0" ) , "node-0" , simpleDaemonSetLabel , ds )
dt := metav1 . Now ( )
pod . DeletionTimestamp = & dt
manager . podStore . Add ( pod )
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
}
2017-08-24 16:51:28 +00:00
}
}
2017-02-07 14:08:45 +00:00
func setNodeTaint ( node * v1 . Node , taints [ ] v1 . Taint ) {
node . Spec . Taints = taints
2017-02-09 01:33:59 +00:00
}
2018-02-14 18:35:38 +00:00
func setDaemonSetToleration ( ds * apps . DaemonSet , tolerations [ ] v1 . Toleration ) {
2017-02-07 14:08:45 +00:00
ds . Spec . Template . Spec . Tolerations = tolerations
2017-02-09 01:33:59 +00:00
}
2018-11-29 09:18:32 +00:00
// DaemonSet should launch a pod even when the node with MemoryPressure/DiskPressure/PIDPressure taints.
2017-08-05 06:49:10 +00:00
func TestTaintPressureNodeDaemonLaunchesPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "critical" )
ds . Spec . UpdateStrategy = * strategy
setDaemonSetCritical ( ds )
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-08-05 06:49:10 +00:00
2018-09-11 17:58:33 +00:00
node := newNode ( "resources-pressure" , nil )
node . Status . Conditions = [ ] v1 . NodeCondition {
{ Type : v1 . NodeDiskPressure , Status : v1 . ConditionTrue } ,
{ Type : v1 . NodeMemoryPressure , Status : v1 . ConditionTrue } ,
2018-11-29 09:18:32 +00:00
{ Type : v1 . NodePIDPressure , Status : v1 . ConditionTrue } ,
2018-09-11 17:58:33 +00:00
}
node . Spec . Taints = [ ] v1 . Taint {
2018-09-28 02:37:38 +00:00
{ Key : schedulerapi . TaintNodeDiskPressure , Effect : v1 . TaintEffectNoSchedule } ,
{ Key : schedulerapi . TaintNodeMemoryPressure , Effect : v1 . TaintEffectNoSchedule } ,
2018-11-29 09:18:32 +00:00
{ Key : schedulerapi . TaintNodePIDPressure , Effect : v1 . TaintEffectNoSchedule } ,
2018-09-11 17:58:33 +00:00
}
manager . nodeStore . Add ( node )
2017-08-05 06:49:10 +00:00
2018-09-11 17:58:33 +00:00
// Enabling critical pod and taint nodes by condition feature gate should create critical pod
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . TaintNodesByCondition , true ) ( )
2018-09-11 17:58:33 +00:00
manager . dsStore . Add ( ds )
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 0 )
}
2017-08-05 06:49:10 +00:00
}
}
2018-09-11 17:58:33 +00:00
// When ScheduleDaemonSetPods is disabled, DaemonSet should launch a critical pod even when the node has insufficient free resource.
2017-02-24 01:14:46 +00:00
func TestInsufficientCapacityNodeDaemonLaunchesCriticalPod ( t * testing . T ) {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , false ) ( )
2017-05-20 00:34:04 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec := resourcePodSpec ( "too-much-mem" , "75M" , "75m" )
ds := newDaemonSet ( "critical" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec
setDaemonSetCritical ( ds )
2017-03-11 01:13:51 +00:00
2017-10-31 14:19:55 +00:00
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-05-20 00:34:04 +00:00
node := newNode ( "too-much-mem" , nil )
node . Status . Allocatable = allocatableResources ( "100M" , "200m" )
manager . nodeStore . Add ( node )
manager . podStore . Add ( & v1 . Pod {
Spec : podSpec ,
} )
// Without enabling critical pod annotation feature gate, we shouldn't create critical pod
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ExperimentalCriticalPodAnnotation , false ) ( )
2017-05-20 00:34:04 +00:00
manager . dsStore . Add ( ds )
2017-06-06 12:42:40 +00:00
switch strategy . Type {
2018-02-14 18:35:38 +00:00
case apps . OnDeleteDaemonSetStrategyType :
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 2 )
2018-02-14 18:35:38 +00:00
case apps . RollingUpdateDaemonSetStrategyType :
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 3 )
default :
t . Fatalf ( "unexpected UpdateStrategy %+v" , strategy )
}
2017-02-24 01:14:46 +00:00
2017-05-20 00:34:04 +00:00
// Enabling critical pod annotation feature gate should create critical pod
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ExperimentalCriticalPodAnnotation , true ) ( )
2017-06-06 12:42:40 +00:00
switch strategy . Type {
2018-02-14 18:35:38 +00:00
case apps . OnDeleteDaemonSetStrategyType :
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 2 )
2018-02-14 18:35:38 +00:00
case apps . RollingUpdateDaemonSetStrategyType :
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 1 , 0 , 3 )
default :
t . Fatalf ( "unexpected UpdateStrategy %+v" , strategy )
}
2017-05-20 00:34:04 +00:00
}
2017-02-24 01:14:46 +00:00
}
2018-09-11 17:58:33 +00:00
// When ScheduleDaemonSetPods is disabled, DaemonSets should NOT launch a critical pod when there are port conflicts.
2017-02-24 01:14:46 +00:00
func TestPortConflictNodeDaemonDoesNotLaunchCriticalPod ( t * testing . T ) {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , false ) ( )
2017-05-20 00:34:04 +00:00
for _ , strategy := range updateStrategies ( ) {
podSpec := v1 . PodSpec {
NodeName : "port-conflict" ,
Containers : [ ] v1 . Container { {
Ports : [ ] v1 . ContainerPort { {
HostPort : 666 ,
} } ,
2017-02-24 01:14:46 +00:00
} } ,
2017-05-20 00:34:04 +00:00
}
2017-10-31 14:19:55 +00:00
manager , podControl , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-05-20 00:34:04 +00:00
node := newNode ( "port-conflict" , nil )
manager . nodeStore . Add ( node )
manager . podStore . Add ( & v1 . Pod {
Spec : podSpec ,
} )
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ExperimentalCriticalPodAnnotation , true ) ( )
2017-05-20 00:34:04 +00:00
ds := newDaemonSet ( "critical" )
ds . Spec . UpdateStrategy = * strategy
ds . Spec . Template . Spec = podSpec
setDaemonSetCritical ( ds )
manager . dsStore . Add ( ds )
2017-06-06 12:42:40 +00:00
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
2017-02-24 01:14:46 +00:00
}
}
2018-02-14 18:35:38 +00:00
func setDaemonSetCritical ( ds * apps . DaemonSet ) {
2017-02-24 01:14:46 +00:00
ds . Namespace = api . NamespaceSystem
if ds . Spec . Template . ObjectMeta . Annotations == nil {
ds . Spec . Template . ObjectMeta . Annotations = make ( map [ string ] string )
}
ds . Spec . Template . ObjectMeta . Annotations [ kubelettypes . CriticalPodAnnotationKey ] = ""
}
2017-01-09 23:50:04 +00:00
func TestNodeShouldRunDaemonPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
var shouldCreate , wantToRun , shouldContinueRunning bool
if utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) {
shouldCreate = true
wantToRun = true
shouldContinueRunning = true
}
cases := [ ] struct {
predicateName string
podsOnNode [ ] * v1 . Pod
nodeCondition [ ] v1 . NodeCondition
nodeUnschedulable bool
ds * apps . DaemonSet
wantToRun , shouldCreate , shouldContinueRunning bool
err error
} {
{
predicateName : "ShouldRunDaemonPod" ,
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : resourcePodSpec ( "" , "50M" , "0.5" ) ,
2017-01-09 23:50:04 +00:00
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
wantToRun : true ,
shouldCreate : true ,
shouldContinueRunning : true ,
2017-01-09 23:50:04 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "InsufficientResourceError" ,
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : resourcePodSpec ( "" , "200M" , "0.5" ) ,
2017-01-09 23:50:04 +00:00
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
wantToRun : true ,
shouldCreate : shouldCreate ,
shouldContinueRunning : true ,
2017-01-09 23:50:04 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "ErrPodNotMatchHostName" ,
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : resourcePodSpec ( "other-node" , "50M" , "0.5" ) ,
2017-01-09 23:50:04 +00:00
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
wantToRun : false ,
shouldCreate : false ,
shouldContinueRunning : false ,
2017-01-09 23:50:04 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "ErrPodNotFitsHostPorts" ,
podsOnNode : [ ] * v1 . Pod {
{
2017-01-09 23:50:04 +00:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container { {
Ports : [ ] v1 . ContainerPort { {
HostPort : 666 ,
} } ,
} } ,
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container { {
Ports : [ ] v1 . ContainerPort { {
HostPort : 666 ,
} } ,
} } ,
} ,
} ,
} ,
} ,
wantToRun : wantToRun ,
shouldCreate : shouldCreate ,
shouldContinueRunning : shouldContinueRunning ,
2017-01-09 23:50:04 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "InsufficientResourceError" ,
podsOnNode : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container { {
Ports : [ ] v1 . ContainerPort { {
HostPort : 666 ,
} } ,
Resources : resourceContainerSpec ( "50M" , "0.5" ) ,
2017-11-07 12:31:20 +00:00
} } ,
2018-09-11 17:58:33 +00:00
} ,
2017-11-07 12:31:20 +00:00
} ,
} ,
2018-09-11 17:58:33 +00:00
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : resourcePodSpec ( "" , "100M" , "0.5" ) ,
2017-11-07 12:31:20 +00:00
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
wantToRun : true ,
shouldCreate : shouldCreate , // This is because we don't care about the resource constraints any more and let default scheduler handle it.
shouldContinueRunning : true ,
2017-11-07 12:31:20 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "ShouldRunDaemonPod" ,
podsOnNode : [ ] * v1 . Pod {
{
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container { {
Ports : [ ] v1 . ContainerPort { {
HostPort : 666 ,
} } ,
Resources : resourceContainerSpec ( "50M" , "0.5" ) ,
2017-11-07 12:31:20 +00:00
} } ,
2018-09-11 17:58:33 +00:00
} ,
2017-11-07 12:31:20 +00:00
} ,
} ,
2018-09-11 17:58:33 +00:00
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : resourcePodSpec ( "" , "50M" , "0.5" ) ,
2017-11-07 12:31:20 +00:00
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
wantToRun : true ,
shouldCreate : true ,
shouldContinueRunning : true ,
2017-11-07 12:31:20 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "ErrNodeSelectorNotMatch" ,
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : v1 . PodSpec {
NodeSelector : simpleDaemonSetLabel2 ,
} ,
2017-11-07 12:31:20 +00:00
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
wantToRun : false ,
shouldCreate : false ,
shouldContinueRunning : false ,
2017-11-07 12:31:20 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "ShouldRunDaemonPod" ,
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : v1 . PodSpec {
NodeSelector : simpleDaemonSetLabel ,
} ,
2017-11-07 12:31:20 +00:00
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
wantToRun : true ,
shouldCreate : true ,
shouldContinueRunning : true ,
2017-11-07 12:31:20 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "ErrPodAffinityNotMatch" ,
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "type" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "test" } ,
} ,
2017-11-08 12:35:12 +00:00
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
wantToRun : false ,
shouldCreate : false ,
shouldContinueRunning : false ,
2017-11-08 12:35:12 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "ShouldRunDaemonPod" ,
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : v1 . PodSpec {
Affinity : & v1 . Affinity {
NodeAffinity : & v1 . NodeAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : & v1 . NodeSelector {
NodeSelectorTerms : [ ] v1 . NodeSelectorTerm {
{
MatchExpressions : [ ] v1 . NodeSelectorRequirement {
{
Key : "type" ,
Operator : v1 . NodeSelectorOpIn ,
Values : [ ] string { "production" } ,
} ,
2017-11-08 12:35:12 +00:00
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
wantToRun : true ,
shouldCreate : true ,
shouldContinueRunning : true ,
2017-11-08 12:35:12 +00:00
} ,
2018-09-11 17:58:33 +00:00
{
predicateName : "ShouldRunDaemonPodOnUnscheduableNode" ,
ds : & apps . DaemonSet {
Spec : apps . DaemonSetSpec {
Selector : & metav1 . LabelSelector { MatchLabels : simpleDaemonSetLabel } ,
Template : v1 . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : simpleDaemonSetLabel ,
} ,
Spec : resourcePodSpec ( "" , "50M" , "0.5" ) ,
2018-02-28 08:11:01 +00:00
} ,
} ,
} ,
2018-09-11 17:58:33 +00:00
nodeUnschedulable : true ,
wantToRun : true ,
shouldCreate : true ,
shouldContinueRunning : true ,
2018-02-28 08:11:01 +00:00
} ,
2017-01-09 23:50:04 +00:00
}
2017-03-02 11:44:59 +00:00
2018-09-11 17:58:33 +00:00
for i , c := range cases {
for _ , strategy := range updateStrategies ( ) {
node := newNode ( "test-node" , simpleDaemonSetLabel )
node . Status . Conditions = append ( node . Status . Conditions , c . nodeCondition ... )
node . Status . Allocatable = allocatableResources ( "100M" , "1" )
node . Spec . Unschedulable = c . nodeUnschedulable
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . nodeStore . Add ( node )
for _ , p := range c . podsOnNode {
manager . podStore . Add ( p )
p . Spec . NodeName = "test-node"
manager . podNodeIndex . Add ( p )
}
c . ds . Spec . UpdateStrategy = * strategy
wantToRun , shouldRun , shouldContinueRunning , err := manager . nodeShouldRunDaemonPod ( node , c . ds )
2017-03-02 11:44:59 +00:00
2018-09-11 17:58:33 +00:00
if wantToRun != c . wantToRun {
t . Errorf ( "[%v] strategy: %v, predicateName: %v expected wantToRun: %v, got: %v" , i , c . ds . Spec . UpdateStrategy . Type , c . predicateName , c . wantToRun , wantToRun )
}
if shouldRun != c . shouldCreate {
t . Errorf ( "[%v] strategy: %v, predicateName: %v expected shouldRun: %v, got: %v" , i , c . ds . Spec . UpdateStrategy . Type , c . predicateName , c . shouldCreate , shouldRun )
}
if shouldContinueRunning != c . shouldContinueRunning {
t . Errorf ( "[%v] strategy: %v, predicateName: %v expected shouldContinueRunning: %v, got: %v" , i , c . ds . Spec . UpdateStrategy . Type , c . predicateName , c . shouldContinueRunning , shouldContinueRunning )
}
if err != c . err {
t . Errorf ( "[%v] strategy: %v, predicateName: %v expected err: %v, got: %v" , i , c . predicateName , c . ds . Spec . UpdateStrategy . Type , c . err , err )
2018-08-13 11:52:34 +00:00
}
2017-10-31 14:19:55 +00:00
}
2018-09-11 17:58:33 +00:00
}
}
}
2018-08-13 11:52:34 +00:00
2018-09-11 17:58:33 +00:00
// DaemonSets should be resynced when node labels or taints changed
func TestUpdateNode ( t * testing . T ) {
var enqueued bool
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
cases := [ ] struct {
test string
newNode * v1 . Node
oldNode * v1 . Node
ds * apps . DaemonSet
expectedEventsFunc func ( strategyType apps . DaemonSetUpdateStrategyType ) int
shouldEnqueue bool
expectedCreates func ( ) int
} {
{
test : "Nothing changed, should not enqueue" ,
oldNode : newNode ( "node1" , nil ) ,
newNode : newNode ( "node1" , nil ) ,
ds : func ( ) * apps . DaemonSet {
ds := newDaemonSet ( "ds" )
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel
return ds
} ( ) ,
shouldEnqueue : false ,
expectedCreates : func ( ) int { return 0 } ,
} ,
{
test : "Node labels changed" ,
oldNode : newNode ( "node1" , nil ) ,
newNode : newNode ( "node1" , simpleNodeLabel ) ,
ds : func ( ) * apps . DaemonSet {
ds := newDaemonSet ( "ds" )
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel
return ds
} ( ) ,
shouldEnqueue : true ,
expectedCreates : func ( ) int { return 0 } ,
} ,
{
test : "Node taints changed" ,
oldNode : func ( ) * v1 . Node {
node := newNode ( "node1" , nil )
setNodeTaint ( node , noScheduleTaints )
return node
} ( ) ,
newNode : newNode ( "node1" , nil ) ,
ds : newDaemonSet ( "ds" ) ,
shouldEnqueue : true ,
expectedCreates : func ( ) int { return 0 } ,
} ,
{
test : "Node Allocatable changed" ,
oldNode : newNode ( "node1" , nil ) ,
newNode : func ( ) * v1 . Node {
node := newNode ( "node1" , nil )
node . Status . Allocatable = allocatableResources ( "200M" , "200m" )
return node
} ( ) ,
ds : func ( ) * apps . DaemonSet {
ds := newDaemonSet ( "ds" )
ds . Spec . Template . Spec = resourcePodSpecWithoutNodeName ( "200M" , "200m" )
return ds
} ( ) ,
expectedEventsFunc : func ( strategyType apps . DaemonSetUpdateStrategyType ) int {
switch strategyType {
case apps . OnDeleteDaemonSetStrategyType :
if ! utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) {
return 2
}
return 0
case apps . RollingUpdateDaemonSetStrategyType :
if ! utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) {
return 3
}
return 0
default :
t . Fatalf ( "unexpected UpdateStrategy %+v" , strategyType )
}
return 0
} ,
shouldEnqueue : ! utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) ,
expectedCreates : func ( ) int {
if ! utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) {
return 0
} else {
return 1
}
} ,
} ,
}
for _ , c := range cases {
for _ , strategy := range updateStrategies ( ) {
manager , podControl , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . nodeStore . Add ( c . oldNode )
c . ds . Spec . UpdateStrategy = * strategy
manager . dsStore . Add ( c . ds )
2017-05-20 00:34:04 +00:00
2018-09-11 17:58:33 +00:00
expectedEvents := 0
if c . expectedEventsFunc != nil {
expectedEvents = c . expectedEventsFunc ( strategy . Type )
2017-05-20 00:34:04 +00:00
}
2018-09-11 17:58:33 +00:00
expectedCreates := 0
if c . expectedCreates != nil {
expectedCreates = c . expectedCreates ( )
}
syncAndValidateDaemonSets ( t , manager , c . ds , podControl , expectedCreates , 0 , expectedEvents )
2017-03-02 11:44:59 +00:00
2018-09-11 17:58:33 +00:00
manager . enqueueDaemonSet = func ( ds * apps . DaemonSet ) {
if ds . Name == "ds" {
enqueued = true
}
}
enqueued = false
manager . updateNode ( c . oldNode , c . newNode )
if enqueued != c . shouldEnqueue {
t . Errorf ( "Test case: '%s', expected: %t, got: %t" , c . test , c . shouldEnqueue , enqueued )
}
2017-05-20 00:34:04 +00:00
}
2017-03-02 11:44:59 +00:00
}
}
}
2017-02-26 00:22:54 +00:00
2017-07-24 12:08:35 +00:00
// DaemonSets should be resynced when non-daemon pods was deleted.
func TestDeleteNoDaemonPod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
2017-07-24 12:08:35 +00:00
var enqueued bool
cases := [ ] struct {
test string
node * v1 . Node
existPods [ ] * v1 . Pod
deletedPod * v1 . Pod
2018-02-14 18:35:38 +00:00
ds * apps . DaemonSet
2017-07-24 12:08:35 +00:00
shouldEnqueue bool
} {
{
test : "Deleted non-daemon pods to release resources" ,
node : func ( ) * v1 . Node {
node := newNode ( "node1" , nil )
node . Status . Conditions = [ ] v1 . NodeCondition {
{ Type : v1 . NodeReady , Status : v1 . ConditionTrue } ,
}
node . Status . Allocatable = allocatableResources ( "200M" , "200m" )
return node
} ( ) ,
existPods : func ( ) [ ] * v1 . Pod {
pods := [ ] * v1 . Pod { }
for i := 0 ; i < 4 ; i ++ {
podSpec := resourcePodSpec ( "node1" , "50M" , "50m" )
pods = append ( pods , & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "pod_%d" , i ) ,
} ,
Spec : podSpec ,
} )
}
return pods
} ( ) ,
deletedPod : func ( ) * v1 . Pod {
podSpec := resourcePodSpec ( "node1" , "50M" , "50m" )
return & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "pod_0" ,
} ,
Spec : podSpec ,
}
} ( ) ,
2018-02-14 18:35:38 +00:00
ds : func ( ) * apps . DaemonSet {
2017-07-24 12:08:35 +00:00
ds := newDaemonSet ( "ds" )
ds . Spec . Template . Spec = resourcePodSpec ( "" , "50M" , "50m" )
return ds
} ( ) ,
2018-09-11 17:58:33 +00:00
shouldEnqueue : ! utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) ,
2017-07-24 12:08:35 +00:00
} ,
{
test : "Deleted non-daemon pods (with controller) to release resources" ,
node : func ( ) * v1 . Node {
node := newNode ( "node1" , nil )
node . Status . Conditions = [ ] v1 . NodeCondition {
{ Type : v1 . NodeReady , Status : v1 . ConditionTrue } ,
}
node . Status . Allocatable = allocatableResources ( "200M" , "200m" )
return node
} ( ) ,
existPods : func ( ) [ ] * v1 . Pod {
pods := [ ] * v1 . Pod { }
for i := 0 ; i < 4 ; i ++ {
podSpec := resourcePodSpec ( "node1" , "50M" , "50m" )
pods = append ( pods , & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "pod_%d" , i ) ,
OwnerReferences : [ ] metav1 . OwnerReference {
{ Controller : func ( ) * bool { res := true ; return & res } ( ) } ,
} ,
} ,
Spec : podSpec ,
} )
}
return pods
} ( ) ,
deletedPod : func ( ) * v1 . Pod {
podSpec := resourcePodSpec ( "node1" , "50M" , "50m" )
return & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "pod_0" ,
OwnerReferences : [ ] metav1 . OwnerReference {
{ Controller : func ( ) * bool { res := true ; return & res } ( ) } ,
} ,
} ,
Spec : podSpec ,
}
} ( ) ,
2018-02-14 18:35:38 +00:00
ds : func ( ) * apps . DaemonSet {
2017-07-24 12:08:35 +00:00
ds := newDaemonSet ( "ds" )
ds . Spec . Template . Spec = resourcePodSpec ( "" , "50M" , "50m" )
return ds
} ( ) ,
2018-09-11 17:58:33 +00:00
shouldEnqueue : ! utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) ,
2017-07-24 12:08:35 +00:00
} ,
{
test : "Deleted no scheduled pods" ,
node : func ( ) * v1 . Node {
node := newNode ( "node1" , nil )
node . Status . Conditions = [ ] v1 . NodeCondition {
{ Type : v1 . NodeReady , Status : v1 . ConditionTrue } ,
}
node . Status . Allocatable = allocatableResources ( "200M" , "200m" )
return node
} ( ) ,
existPods : func ( ) [ ] * v1 . Pod {
pods := [ ] * v1 . Pod { }
for i := 0 ; i < 4 ; i ++ {
podSpec := resourcePodSpec ( "node1" , "50M" , "50m" )
pods = append ( pods , & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "pod_%d" , i ) ,
OwnerReferences : [ ] metav1 . OwnerReference {
{ Controller : func ( ) * bool { res := true ; return & res } ( ) } ,
} ,
} ,
Spec : podSpec ,
} )
}
return pods
} ( ) ,
deletedPod : func ( ) * v1 . Pod {
podSpec := resourcePodSpec ( "" , "50M" , "50m" )
return & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : "pod_5" ,
} ,
Spec : podSpec ,
}
} ( ) ,
2018-02-14 18:35:38 +00:00
ds : func ( ) * apps . DaemonSet {
2017-07-24 12:08:35 +00:00
ds := newDaemonSet ( "ds" )
ds . Spec . Template . Spec = resourcePodSpec ( "" , "50M" , "50m" )
return ds
} ( ) ,
shouldEnqueue : false ,
} ,
}
for _ , c := range cases {
for _ , strategy := range updateStrategies ( ) {
2017-10-31 14:19:55 +00:00
manager , podControl , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2017-07-24 12:08:35 +00:00
manager . nodeStore . Add ( c . node )
c . ds . Spec . UpdateStrategy = * strategy
manager . dsStore . Add ( c . ds )
for _ , pod := range c . existPods {
manager . podStore . Add ( pod )
}
switch strategy . Type {
2018-02-14 18:35:38 +00:00
case apps . OnDeleteDaemonSetStrategyType :
2018-09-11 17:58:33 +00:00
if utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) {
syncAndValidateDaemonSets ( t , manager , c . ds , podControl , 1 , 0 , 0 )
} else {
syncAndValidateDaemonSets ( t , manager , c . ds , podControl , 0 , 0 , 2 )
}
2018-02-14 18:35:38 +00:00
case apps . RollingUpdateDaemonSetStrategyType :
2018-09-11 17:58:33 +00:00
if utilfeature . DefaultFeatureGate . Enabled ( features . ScheduleDaemonSetPods ) {
syncAndValidateDaemonSets ( t , manager , c . ds , podControl , 1 , 0 , 0 )
} else {
syncAndValidateDaemonSets ( t , manager , c . ds , podControl , 0 , 0 , 3 )
}
2017-07-24 12:08:35 +00:00
default :
t . Fatalf ( "unexpected UpdateStrategy %+v" , strategy )
}
2018-02-14 18:35:38 +00:00
manager . enqueueDaemonSetRateLimited = func ( ds * apps . DaemonSet ) {
2017-07-24 12:08:35 +00:00
if ds . Name == "ds" {
enqueued = true
}
}
enqueued = false
manager . deletePod ( c . deletedPod )
if enqueued != c . shouldEnqueue {
t . Errorf ( "Test case: '%s', expected: %t, got: %t" , c . test , c . shouldEnqueue , enqueued )
}
}
}
}
2019-01-28 13:07:20 +00:00
func TestDeletePodForNotExistingNode ( t * testing . T ) {
for _ , f := range [ ] bool { true , false } {
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , podControl , _ , err := newTestController ( ds )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . dsStore . Add ( ds )
addNodes ( manager . nodeStore , 0 , 1 , nil )
addPods ( manager . podStore , "node-0" , simpleDaemonSetLabel , ds , 1 )
addPods ( manager . podStore , "node-1" , simpleDaemonSetLabel , ds , 1 )
2019-01-31 19:26:19 +00:00
if f {
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 1 , 0 )
} else {
syncAndValidateDaemonSets ( t , manager , ds , podControl , 0 , 0 , 0 )
}
2019-01-28 13:07:20 +00:00
}
}
}
2017-02-26 00:22:54 +00:00
func TestGetNodesToDaemonPods ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
ds2 := newDaemonSet ( "foo2" )
ds2 . Spec . UpdateStrategy = * strategy
manager , _ , _ , err := newTestController ( ds , ds2 )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
manager . dsStore . Add ( ds )
manager . dsStore . Add ( ds2 )
addNodes ( manager . nodeStore , 0 , 2 , nil )
// These pods should be returned.
wantedPods := [ ] * v1 . Pod {
newPod ( "matching-owned-0-" , "node-0" , simpleDaemonSetLabel , ds ) ,
newPod ( "matching-orphan-0-" , "node-0" , simpleDaemonSetLabel , nil ) ,
newPod ( "matching-owned-1-" , "node-1" , simpleDaemonSetLabel , ds ) ,
newPod ( "matching-orphan-1-" , "node-1" , simpleDaemonSetLabel , nil ) ,
}
failedPod := newPod ( "matching-owned-failed-pod-1-" , "node-1" , simpleDaemonSetLabel , ds )
failedPod . Status = v1 . PodStatus { Phase : v1 . PodFailed }
wantedPods = append ( wantedPods , failedPod )
for _ , pod := range wantedPods {
manager . podStore . Add ( pod )
}
2017-02-26 00:22:54 +00:00
2018-09-11 17:58:33 +00:00
// These pods should be ignored.
ignoredPods := [ ] * v1 . Pod {
newPod ( "non-matching-owned-0-" , "node-0" , simpleDaemonSetLabel2 , ds ) ,
newPod ( "non-matching-orphan-1-" , "node-1" , simpleDaemonSetLabel2 , nil ) ,
newPod ( "matching-owned-by-other-0-" , "node-0" , simpleDaemonSetLabel , ds2 ) ,
}
for _ , pod := range ignoredPods {
manager . podStore . Add ( pod )
}
2017-02-26 00:22:54 +00:00
2018-09-11 17:58:33 +00:00
nodesToDaemonPods , err := manager . getNodesToDaemonPods ( ds )
if err != nil {
t . Fatalf ( "getNodesToDaemonPods() error: %v" , err )
}
gotPods := map [ string ] bool { }
for node , pods := range nodesToDaemonPods {
for _ , pod := range pods {
if pod . Spec . NodeName != node {
t . Errorf ( "pod %v grouped into %v but belongs in %v" , pod . Name , node , pod . Spec . NodeName )
}
gotPods [ pod . Name ] = true
2017-05-20 00:34:04 +00:00
}
2017-02-26 00:22:54 +00:00
}
2018-09-11 17:58:33 +00:00
for _ , pod := range wantedPods {
if ! gotPods [ pod . Name ] {
t . Errorf ( "expected pod %v but didn't get it" , pod . Name )
}
delete ( gotPods , pod . Name )
}
for podName := range gotPods {
t . Errorf ( "unexpected pod %v was returned" , podName )
2017-05-20 00:34:04 +00:00
}
2017-02-26 00:22:54 +00:00
}
}
}
2017-02-26 01:34:14 +00:00
2017-05-24 13:59:45 +00:00
func TestAddNode ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2017-10-31 14:19:55 +00:00
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
2018-09-11 17:58:33 +00:00
node1 := newNode ( "node1" , nil )
ds := newDaemonSet ( "ds" )
ds . Spec . Template . Spec . NodeSelector = simpleNodeLabel
manager . dsStore . Add ( ds )
2017-05-20 00:34:04 +00:00
2018-09-11 17:58:33 +00:00
manager . addNode ( node1 )
if got , want := manager . queue . Len ( ) , 0 ; got != want {
2017-05-20 00:34:04 +00:00
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
2017-02-26 01:34:14 +00:00
2018-09-11 17:58:33 +00:00
node2 := newNode ( "node2" , simpleNodeLabel )
manager . addNode ( node2 )
2017-05-20 00:34:04 +00:00
if got , want := manager . queue . Len ( ) , 1 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
2018-09-11 17:58:33 +00:00
key , done := manager . queue . Get ( )
2017-05-20 00:34:04 +00:00
if key == nil || done {
2018-09-11 17:58:33 +00:00
t . Fatalf ( "failed to enqueue controller for node %v" , node2 . Name )
2017-05-20 00:34:04 +00:00
}
2018-09-11 17:58:33 +00:00
}
}
func TestAddPod ( t * testing . T ) {
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds1 := newDaemonSet ( "foo1" )
ds1 . Spec . UpdateStrategy = * strategy
ds2 := newDaemonSet ( "foo2" )
ds2 . Spec . UpdateStrategy = * strategy
manager . dsStore . Add ( ds1 )
manager . dsStore . Add ( ds2 )
pod1 := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , ds1 )
manager . addPod ( pod1 )
if got , want := manager . queue . Len ( ) , 1 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
key , done := manager . queue . Get ( )
if key == nil || done {
t . Fatalf ( "failed to enqueue controller for pod %v" , pod1 . Name )
}
expectedKey , _ := controller . KeyFunc ( ds1 )
if got , want := key . ( string ) , expectedKey ; got != want {
t . Errorf ( "queue.Get() = %v, want %v" , got , want )
}
pod2 := newPod ( "pod2-" , "node-0" , simpleDaemonSetLabel , ds2 )
manager . addPod ( pod2 )
if got , want := manager . queue . Len ( ) , 1 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
key , done = manager . queue . Get ( )
if key == nil || done {
t . Fatalf ( "failed to enqueue controller for pod %v" , pod2 . Name )
}
expectedKey , _ = controller . KeyFunc ( ds2 )
if got , want := key . ( string ) , expectedKey ; got != want {
t . Errorf ( "queue.Get() = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-02-26 01:34:14 +00:00
}
}
func TestAddPodOrphan ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds1 := newDaemonSet ( "foo1" )
ds1 . Spec . UpdateStrategy = * strategy
ds2 := newDaemonSet ( "foo2" )
ds2 . Spec . UpdateStrategy = * strategy
ds3 := newDaemonSet ( "foo3" )
ds3 . Spec . UpdateStrategy = * strategy
ds3 . Spec . Selector . MatchLabels = simpleDaemonSetLabel2
manager . dsStore . Add ( ds1 )
manager . dsStore . Add ( ds2 )
manager . dsStore . Add ( ds3 )
// Make pod an orphan. Expect matching sets to be queued.
pod := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , nil )
manager . addPod ( pod )
if got , want := manager . queue . Len ( ) , 2 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
if got , want := getQueuedKeys ( manager . queue ) , [ ] string { "default/foo1" , "default/foo2" } ; ! reflect . DeepEqual ( got , want ) {
t . Errorf ( "getQueuedKeys() = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-02-26 01:34:14 +00:00
}
}
func TestUpdatePod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds1 := newDaemonSet ( "foo1" )
ds1 . Spec . UpdateStrategy = * strategy
ds2 := newDaemonSet ( "foo2" )
ds2 . Spec . UpdateStrategy = * strategy
manager . dsStore . Add ( ds1 )
manager . dsStore . Add ( ds2 )
pod1 := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , ds1 )
prev := * pod1
bumpResourceVersion ( pod1 )
manager . updatePod ( & prev , pod1 )
if got , want := manager . queue . Len ( ) , 1 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
key , done := manager . queue . Get ( )
if key == nil || done {
t . Fatalf ( "failed to enqueue controller for pod %v" , pod1 . Name )
}
expectedKey , _ := controller . KeyFunc ( ds1 )
if got , want := key . ( string ) , expectedKey ; got != want {
t . Errorf ( "queue.Get() = %v, want %v" , got , want )
}
2017-02-26 01:34:14 +00:00
2018-09-11 17:58:33 +00:00
pod2 := newPod ( "pod2-" , "node-0" , simpleDaemonSetLabel , ds2 )
prev = * pod2
bumpResourceVersion ( pod2 )
manager . updatePod ( & prev , pod2 )
if got , want := manager . queue . Len ( ) , 1 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
key , done = manager . queue . Get ( )
if key == nil || done {
t . Fatalf ( "failed to enqueue controller for pod %v" , pod2 . Name )
}
expectedKey , _ = controller . KeyFunc ( ds2 )
if got , want := key . ( string ) , expectedKey ; got != want {
t . Errorf ( "queue.Get() = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-02-26 01:34:14 +00:00
}
}
func TestUpdatePodOrphanSameLabels ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds1 := newDaemonSet ( "foo1" )
ds1 . Spec . UpdateStrategy = * strategy
ds2 := newDaemonSet ( "foo2" )
ds2 . Spec . UpdateStrategy = * strategy
manager . dsStore . Add ( ds1 )
manager . dsStore . Add ( ds2 )
pod := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , nil )
prev := * pod
bumpResourceVersion ( pod )
manager . updatePod ( & prev , pod )
if got , want := manager . queue . Len ( ) , 0 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-02-26 01:34:14 +00:00
}
}
func TestUpdatePodOrphanWithNewLabels ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds1 := newDaemonSet ( "foo1" )
ds1 . Spec . UpdateStrategy = * strategy
ds2 := newDaemonSet ( "foo2" )
ds2 . Spec . UpdateStrategy = * strategy
manager . dsStore . Add ( ds1 )
manager . dsStore . Add ( ds2 )
pod := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , nil )
prev := * pod
prev . Labels = map [ string ] string { "foo2" : "bar2" }
bumpResourceVersion ( pod )
manager . updatePod ( & prev , pod )
if got , want := manager . queue . Len ( ) , 2 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
if got , want := getQueuedKeys ( manager . queue ) , [ ] string { "default/foo1" , "default/foo2" } ; ! reflect . DeepEqual ( got , want ) {
t . Errorf ( "getQueuedKeys() = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-02-26 01:34:14 +00:00
}
}
func TestUpdatePodChangeControllerRef ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
ds := newDaemonSet ( "foo" )
ds . Spec . UpdateStrategy = * strategy
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds1 := newDaemonSet ( "foo1" )
ds2 := newDaemonSet ( "foo2" )
manager . dsStore . Add ( ds1 )
manager . dsStore . Add ( ds2 )
pod := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , ds1 )
prev := * pod
prev . OwnerReferences = [ ] metav1 . OwnerReference { * metav1 . NewControllerRef ( ds2 , controllerKind ) }
bumpResourceVersion ( pod )
manager . updatePod ( & prev , pod )
if got , want := manager . queue . Len ( ) , 2 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-02-26 01:34:14 +00:00
}
}
func TestUpdatePodControllerRefRemoved ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds1 := newDaemonSet ( "foo1" )
ds1 . Spec . UpdateStrategy = * strategy
ds2 := newDaemonSet ( "foo2" )
ds2 . Spec . UpdateStrategy = * strategy
manager . dsStore . Add ( ds1 )
manager . dsStore . Add ( ds2 )
pod := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , ds1 )
prev := * pod
pod . OwnerReferences = nil
bumpResourceVersion ( pod )
manager . updatePod ( & prev , pod )
if got , want := manager . queue . Len ( ) , 2 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-02-26 01:34:14 +00:00
}
}
func TestDeletePod ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2017-05-20 00:34:04 +00:00
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds1 := newDaemonSet ( "foo1" )
ds1 . Spec . UpdateStrategy = * strategy
ds2 := newDaemonSet ( "foo2" )
ds2 . Spec . UpdateStrategy = * strategy
manager . dsStore . Add ( ds1 )
manager . dsStore . Add ( ds2 )
pod1 := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , ds1 )
manager . deletePod ( pod1 )
if got , want := manager . queue . Len ( ) , 1 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
key , done := manager . queue . Get ( )
if key == nil || done {
t . Fatalf ( "failed to enqueue controller for pod %v" , pod1 . Name )
}
expectedKey , _ := controller . KeyFunc ( ds1 )
if got , want := key . ( string ) , expectedKey ; got != want {
t . Errorf ( "queue.Get() = %v, want %v" , got , want )
}
2017-02-26 01:34:14 +00:00
2018-09-11 17:58:33 +00:00
pod2 := newPod ( "pod2-" , "node-0" , simpleDaemonSetLabel , ds2 )
manager . deletePod ( pod2 )
if got , want := manager . queue . Len ( ) , 1 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
key , done = manager . queue . Get ( )
if key == nil || done {
t . Fatalf ( "failed to enqueue controller for pod %v" , pod2 . Name )
}
expectedKey , _ = controller . KeyFunc ( ds2 )
if got , want := key . ( string ) , expectedKey ; got != want {
t . Errorf ( "queue.Get() = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-02-26 01:34:14 +00:00
}
}
func TestDeletePodOrphan ( t * testing . T ) {
2018-09-11 17:58:33 +00:00
for _ , f := range [ ] bool { true , false } {
2018-11-16 02:58:34 +00:00
defer utilfeaturetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ScheduleDaemonSetPods , f ) ( )
2018-09-11 17:58:33 +00:00
for _ , strategy := range updateStrategies ( ) {
manager , _ , _ , err := newTestController ( )
if err != nil {
t . Fatalf ( "error creating DaemonSets controller: %v" , err )
}
ds1 := newDaemonSet ( "foo1" )
ds1 . Spec . UpdateStrategy = * strategy
ds2 := newDaemonSet ( "foo2" )
ds2 . Spec . UpdateStrategy = * strategy
ds3 := newDaemonSet ( "foo3" )
ds3 . Spec . UpdateStrategy = * strategy
ds3 . Spec . Selector . MatchLabels = simpleDaemonSetLabel2
manager . dsStore . Add ( ds1 )
manager . dsStore . Add ( ds2 )
manager . dsStore . Add ( ds3 )
pod := newPod ( "pod1-" , "node-0" , simpleDaemonSetLabel , nil )
manager . deletePod ( pod )
if got , want := manager . queue . Len ( ) , 0 ; got != want {
t . Fatalf ( "queue.Len() = %v, want %v" , got , want )
}
2017-05-20 00:34:04 +00:00
}
2017-02-26 01:34:14 +00:00
}
}
func bumpResourceVersion ( obj metav1 . Object ) {
ver , _ := strconv . ParseInt ( obj . GetResourceVersion ( ) , 10 , 32 )
obj . SetResourceVersion ( strconv . FormatInt ( ver + 1 , 10 ) )
}
// getQueuedKeys returns a sorted list of keys in the queue.
// It can be used to quickly check that multiple keys are in there.
func getQueuedKeys ( queue workqueue . RateLimitingInterface ) [ ] string {
var keys [ ] string
count := queue . Len ( )
for i := 0 ; i < count ; i ++ {
key , done := queue . Get ( )
if done {
return keys
}
keys = append ( keys , key . ( string ) )
}
sort . Strings ( keys )
return keys
}