123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550 |
- /*
- Copyright 2015 The Kubernetes Authors.
- 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"
- "reflect"
- "sort"
- "strconv"
- "sync"
- "testing"
- "time"
- apps "k8s.io/api/apps/v1"
- v1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/util/clock"
- "k8s.io/apimachinery/pkg/util/intstr"
- "k8s.io/apimachinery/pkg/util/uuid"
- "k8s.io/apiserver/pkg/storage/names"
- "k8s.io/client-go/informers"
- "k8s.io/client-go/kubernetes/fake"
- core "k8s.io/client-go/testing"
- "k8s.io/client-go/tools/cache"
- "k8s.io/client-go/tools/record"
- "k8s.io/client-go/util/flowcontrol"
- "k8s.io/client-go/util/workqueue"
- "k8s.io/kubernetes/pkg/api/legacyscheme"
- podutil "k8s.io/kubernetes/pkg/api/v1/pod"
- api "k8s.io/kubernetes/pkg/apis/core"
- "k8s.io/kubernetes/pkg/apis/scheduling"
- "k8s.io/kubernetes/pkg/controller"
- "k8s.io/kubernetes/pkg/securitycontext"
- labelsutil "k8s.io/kubernetes/pkg/util/labels"
- )
- 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"}
- alwaysReady = func() bool { return true }
- )
- var (
- noScheduleTolerations = []v1.Toleration{{Key: "dedicated", Value: "user1", Effect: "NoSchedule"}}
- noScheduleTaints = []v1.Taint{{Key: "dedicated", Value: "user1", Effect: "NoSchedule"}}
- noExecuteTaints = []v1.Taint{{Key: "dedicated", Value: "user1", Effect: "NoExecute"}}
- )
- func nowPointer() *metav1.Time {
- now := metav1.Now()
- return &now
- }
- var (
- nodeNotReady = []v1.Taint{{
- Key: v1.TaintNodeNotReady,
- Effect: v1.TaintEffectNoExecute,
- TimeAdded: nowPointer(),
- }}
- nodeUnreachable = []v1.Taint{{
- Key: v1.TaintNodeUnreachable,
- Effect: v1.TaintEffectNoExecute,
- TimeAdded: nowPointer(),
- }}
- )
- func newDaemonSet(name string) *apps.DaemonSet {
- two := int32(2)
- return &apps.DaemonSet{
- ObjectMeta: metav1.ObjectMeta{
- UID: uuid.NewUUID(),
- Name: name,
- Namespace: metav1.NamespaceDefault,
- },
- Spec: apps.DaemonSetSpec{
- RevisionHistoryLimit: &two,
- UpdateStrategy: apps.DaemonSetUpdateStrategy{
- Type: apps.OnDeleteDaemonSetStrategyType,
- },
- Selector: &metav1.LabelSelector{MatchLabels: simpleDaemonSetLabel},
- Template: v1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: simpleDaemonSetLabel,
- },
- Spec: v1.PodSpec{
- Containers: []v1.Container{
- {
- Image: "foo/bar",
- TerminationMessagePath: v1.TerminationMessagePathDefault,
- ImagePullPolicy: v1.PullIfNotPresent,
- SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
- },
- },
- DNSPolicy: v1.DNSDefault,
- },
- },
- },
- }
- }
- func newRollbackStrategy() *apps.DaemonSetUpdateStrategy {
- one := intstr.FromInt(1)
- return &apps.DaemonSetUpdateStrategy{
- Type: apps.RollingUpdateDaemonSetStrategyType,
- RollingUpdate: &apps.RollingUpdateDaemonSet{MaxUnavailable: &one},
- }
- }
- func newOnDeleteStrategy() *apps.DaemonSetUpdateStrategy {
- return &apps.DaemonSetUpdateStrategy{
- Type: apps.OnDeleteDaemonSetStrategyType,
- }
- }
- func updateStrategies() []*apps.DaemonSetUpdateStrategy {
- return []*apps.DaemonSetUpdateStrategy{newOnDeleteStrategy(), newRollbackStrategy()}
- }
- func newNode(name string, label map[string]string) *v1.Node {
- return &v1.Node{
- TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Labels: label,
- Namespace: metav1.NamespaceNone,
- },
- Status: v1.NodeStatus{
- Conditions: []v1.NodeCondition{
- {Type: v1.NodeReady, Status: v1.ConditionTrue},
- },
- Allocatable: v1.ResourceList{
- v1.ResourcePods: resource.MustParse("100"),
- },
- },
- }
- }
- 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))
- }
- }
- func newPod(podName string, nodeName string, label map[string]string, ds *apps.DaemonSet) *v1.Pod {
- // Add hash unique label to the pod
- newLabels := label
- var podSpec v1.PodSpec
- // Copy pod spec from DaemonSet template, or use a default one if DaemonSet is nil
- if ds != nil {
- hash := controller.ComputeHash(&ds.Spec.Template, ds.Status.CollisionCount)
- newLabels = labelsutil.CloneAndAddLabel(label, apps.DefaultDaemonSetUniqueLabelKey, hash)
- podSpec = ds.Spec.Template.Spec
- } else {
- podSpec = v1.PodSpec{
- Containers: []v1.Container{
- {
- Image: "foo/bar",
- TerminationMessagePath: v1.TerminationMessagePathDefault,
- ImagePullPolicy: v1.PullIfNotPresent,
- SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
- },
- },
- }
- }
- // Add node name to the pod
- if len(nodeName) > 0 {
- podSpec.NodeName = nodeName
- }
- pod := &v1.Pod{
- TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: podName,
- Labels: newLabels,
- Namespace: metav1.NamespaceDefault,
- },
- Spec: podSpec,
- }
- pod.Name = names.SimpleNameGenerator.GenerateName(podName)
- if ds != nil {
- pod.OwnerReferences = []metav1.OwnerReference{*metav1.NewControllerRef(ds, controllerKind)}
- }
- return pod
- }
- func addPods(podStore cache.Store, nodeName string, label map[string]string, ds *apps.DaemonSet, number int) {
- for i := 0; i < number; i++ {
- pod := newPod(fmt.Sprintf("%s-", nodeName), nodeName, label, ds)
- podStore.Add(pod)
- }
- }
- func addFailedPods(podStore cache.Store, nodeName string, label map[string]string, ds *apps.DaemonSet, number int) {
- for i := 0; i < number; i++ {
- pod := newPod(fmt.Sprintf("%s-", nodeName), nodeName, label, ds)
- pod.Status = v1.PodStatus{Phase: v1.PodFailed}
- podStore.Add(pod)
- }
- }
- type fakePodControl struct {
- sync.Mutex
- *controller.FakePodControl
- podStore cache.Store
- podIDMap map[string]*v1.Pod
- expectations controller.ControllerExpectationsInterface
- dsc *daemonSetsController
- }
- func newFakePodControl() *fakePodControl {
- podIDMap := make(map[string]*v1.Pod)
- return &fakePodControl{
- FakePodControl: &controller.FakePodControl{},
- podIDMap: podIDMap,
- }
- }
- func (f *fakePodControl) CreatePodsOnNode(nodeName, namespace string, template *v1.PodTemplateSpec, object runtime.Object, controllerRef *metav1.OwnerReference) error {
- f.Lock()
- defer f.Unlock()
- if err := f.FakePodControl.CreatePodsOnNode(nodeName, namespace, template, object, controllerRef); err != nil {
- 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),
- },
- }
- if err := legacyscheme.Scheme.Convert(&template.Spec, &pod.Spec, nil); err != nil {
- 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
- ds := object.(*apps.DaemonSet)
- dsKey, _ := controller.KeyFunc(ds)
- f.expectations.CreationObserved(dsKey)
- return nil
- }
- 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
- ds := object.(*apps.DaemonSet)
- dsKey, _ := controller.KeyFunc(ds)
- f.expectations.CreationObserved(dsKey)
- return nil
- }
- 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)
- ds := object.(*apps.DaemonSet)
- dsKey, _ := controller.KeyFunc(ds)
- f.expectations.DeletionObserved(dsKey)
- return nil
- }
- type daemonSetsController struct {
- *DaemonSetsController
- dsStore cache.Store
- historyStore cache.Store
- podStore cache.Store
- nodeStore cache.Store
- fakeRecorder *record.FakeRecorder
- }
- func newTestController(initialObjects ...runtime.Object) (*daemonSetsController, *fakePodControl, *fake.Clientset, error) {
- clientset := fake.NewSimpleClientset(initialObjects...)
- informerFactory := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc())
- dsc, err := NewDaemonSetsController(
- informerFactory.Apps().V1().DaemonSets(),
- informerFactory.Apps().V1().ControllerRevisions(),
- informerFactory.Core().V1().Pods(),
- informerFactory.Core().V1().Nodes(),
- clientset,
- flowcontrol.NewFakeBackOff(50*time.Millisecond, 500*time.Millisecond, clock.NewFakeClock(time.Now())),
- )
- if err != nil {
- return nil, nil, nil, err
- }
- fakeRecorder := record.NewFakeRecorder(100)
- dsc.eventRecorder = fakeRecorder
- dsc.podStoreSynced = alwaysReady
- dsc.nodeStoreSynced = alwaysReady
- dsc.dsStoreSynced = alwaysReady
- dsc.historyStoreSynced = alwaysReady
- podControl := newFakePodControl()
- dsc.podControl = podControl
- podControl.podStore = informerFactory.Core().V1().Pods().Informer().GetStore()
- newDsc := &daemonSetsController{
- dsc,
- informerFactory.Apps().V1().DaemonSets().Informer().GetStore(),
- informerFactory.Apps().V1().ControllerRevisions().Informer().GetStore(),
- informerFactory.Core().V1().Pods().Informer().GetStore(),
- informerFactory.Core().V1().Nodes().Informer().GetStore(),
- fakeRecorder,
- }
- podControl.expectations = newDsc.expectations
- return newDsc, podControl, clientset, nil
- }
- func resetCounters(manager *daemonSetsController) {
- manager.podControl.(*fakePodControl).Clear()
- fakeRecorder := record.NewFakeRecorder(100)
- manager.eventRecorder = fakeRecorder
- manager.fakeRecorder = fakeRecorder
- }
- func validateSyncDaemonSets(t *testing.T, manager *daemonSetsController, fakePodControl *fakePodControl, expectedCreates, expectedDeletes int, expectedEvents int) {
- if len(fakePodControl.Templates) != expectedCreates {
- t.Errorf("Unexpected number of creates. Expected %d, saw %d\n", expectedCreates, len(fakePodControl.Templates))
- }
- if len(fakePodControl.DeletePodName) != expectedDeletes {
- t.Errorf("Unexpected number of deletes. Expected %d, saw %d\n", expectedDeletes, len(fakePodControl.DeletePodName))
- }
- if len(manager.fakeRecorder.Events) != expectedEvents {
- t.Errorf("Unexpected number of events. Expected %d, saw %d\n", expectedEvents, len(manager.fakeRecorder.Events))
- }
- // 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 {
- if got, want := controllerRef.APIVersion, "apps/v1"; got != want {
- 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")
- }
- }
- }
- func syncAndValidateDaemonSets(t *testing.T, manager *daemonSetsController, ds *apps.DaemonSet, podControl *fakePodControl, expectedCreates, expectedDeletes int, expectedEvents int) {
- key, err := controller.KeyFunc(ds)
- if err != nil {
- t.Errorf("Could not get key for daemon.")
- }
- manager.syncHandler(key)
- validateSyncDaemonSets(t, manager, podControl, expectedCreates, expectedDeletes, expectedEvents)
- }
- // clearExpectations copies the FakePodControl to PodStore and clears the create and delete expectations.
- func clearExpectations(t *testing.T, manager *daemonSetsController, ds *apps.DaemonSet, fakePodControl *fakePodControl) {
- fakePodControl.Clear()
- key, err := controller.KeyFunc(ds)
- if err != nil {
- t.Errorf("Could not get key for daemon.")
- return
- }
- manager.expectations.DeleteExpectations(key)
- }
- func TestDeleteFinalStateUnknown(t *testing.T) {
- 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)
- }
- }
- }
- func markPodsReady(store cache.Store) {
- // mark pods as ready
- for _, obj := range store.List() {
- pod := obj.(*v1.Pod)
- markPodReady(pod)
- }
- }
- func markPodReady(pod *v1.Pod) {
- condition := v1.PodCondition{Type: v1.PodReady, Status: v1.ConditionTrue}
- podutil.UpdatePodCondition(&pod.Status, &condition)
- }
- // DaemonSets without node selectors should launch pods on every node.
- func TestSimpleDaemonSetLaunchesPods(t *testing.T) {
- 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)
- }
- }
- // DaemonSets without node selectors should launch pods on every node by NodeAffinity.
- func TestSimpleDaemonSetScheduleDaemonSetPodsLaunchesPods(t *testing.T) {
- 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)
- if len(podControl.podIDMap) != nodeNum {
- t.Fatalf("failed to create pods for DaemonSet")
- }
- 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 {
- t.Fatalf("incorrect number of node selector terms in pod %s, expected: 1, got: %d.",
- pod.Name, len(nodeSelector.NodeSelectorTerms))
- }
- if len(nodeSelector.NodeSelectorTerms[0].MatchFields) != 1 {
- t.Fatalf("incorrect number of fields in node selector term for pod %s, expected: 1, got: %d.",
- pod.Name, len(nodeSelector.NodeSelectorTerms[0].MatchFields))
- }
- field := nodeSelector.NodeSelectorTerms[0].MatchFields[0]
- if field.Key == api.ObjectNameField {
- if field.Operator != v1.NodeSelectorOpIn {
- t.Fatalf("the operation of hostname NodeAffinity is not %v", v1.NodeSelectorOpIn)
- }
- if len(field.Values) != 1 {
- t.Fatalf("incorrect hostname in node affinity: expected 1, got %v", len(field.Values))
- }
- delete(nodeMap, field.Values[0])
- }
- }
- if len(nodeMap) != 0 {
- t.Fatalf("did not foud pods on nodes %+v", nodeMap)
- }
- }
- }
- // 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) {
- 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)
- }
- }
- }
- func TestDaemonSetPodCreateExpectationsError(t *testing.T) {
- strategies := updateStrategies()
- for _, strategy := range strategies {
- 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
- creationExpectations := 100
- addNodes(manager.nodeStore, 0, 100, nil)
- manager.dsStore.Add(ds)
- syncAndValidateDaemonSets(t, manager, ds, podControl, podControl.FakePodControl.CreateLimit, 0, 0)
- dsKey, err := controller.KeyFunc(ds)
- if err != nil {
- t.Fatalf("error get DaemonSets controller key: %v", err)
- }
- if !manager.expectations.SatisfiedExpectations(dsKey) {
- t.Errorf("Unsatisfied pod creation expectatitons. Expected %d", creationExpectations)
- }
- }
- }
- func TestSimpleDaemonSetUpdatesStatusAfterLaunchingPods(t *testing.T) {
- 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)
- }
- 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
- })
- manager.dsStore.Add(ds)
- addNodes(manager.nodeStore, 0, 5, nil)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 5, 0, 0)
- // 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)
- }
- }
- }
- // DaemonSets should do nothing if there aren't any nodes
- func TestNoNodesDoesNothing(t *testing.T) {
- 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)
- }
- }
- // DaemonSets without node selectors should launch on a single node in a
- // single node cluster.
- func TestOneNodeDaemonLaunchesPod(t *testing.T) {
- 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)
- }
- }
- // DaemonSets should place onto NotReady nodes
- func TestNotReadyNodeDaemonDoesLaunchPod(t *testing.T) {
- 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)
- }
- }
- func resourcePodSpec(nodeName, memory, cpu string) v1.PodSpec {
- return v1.PodSpec{
- NodeName: nodeName,
- Containers: []v1.Container{{
- Resources: v1.ResourceRequirements{
- Requests: allocatableResources(memory, cpu),
- },
- }},
- }
- }
- func resourceContainerSpec(memory, cpu string) v1.ResourceRequirements {
- return v1.ResourceRequirements{
- Requests: allocatableResources(memory, cpu),
- }
- }
- func resourcePodSpecWithoutNodeName(memory, cpu string) v1.PodSpec {
- return v1.PodSpec{
- Containers: []v1.Container{{
- Resources: v1.ResourceRequirements{
- Requests: allocatableResources(memory, cpu),
- },
- }},
- }
- }
- 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"),
- }
- }
- // DaemonSets should not unschedule a daemonset pod from a node with insufficient free resource
- func TestInsufficientCapacityNodeDaemonDoesNotUnscheduleRunningPod(t *testing.T) {
- 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:
- syncAndValidateDaemonSets(t, manager, ds, podControl, 1, 0, 0)
- case apps.RollingUpdateDaemonSetStrategyType:
- 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) {
- podSpec := resourcePodSpecWithoutNodeName("50M", "75m")
- ds := newDaemonSet("foo")
- ds.Spec.Template.Spec = podSpec
- ds.Spec.Template.Spec.NodeSelector = simpleNodeLabel
- manager, podControl, _, err := newTestController(ds)
- if err != nil {
- t.Fatalf("error creating DaemonSets controller: %v", err)
- }
- 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)
- manager.dsStore.Add(ds)
- 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)
- }
- }
- // DaemonSet should launch a pod on a node with taint NetworkUnavailable condition.
- func TestNetworkUnavailableNodeDaemonLaunchesPod(t *testing.T) {
- 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)
- }
- node := newNode("network-unavailable", nil)
- node.Status.Conditions = []v1.NodeCondition{
- {Type: v1.NodeNetworkUnavailable, Status: v1.ConditionTrue},
- }
- manager.nodeStore.Add(node)
- manager.dsStore.Add(ds)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 1, 0, 0)
- }
- }
- // DaemonSets not take any actions when being deleted
- func TestDontDoAnythingIfBeingDeleted(t *testing.T) {
- 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)
- }
- }
- func TestDontDoAnythingIfBeingDeletedRace(t *testing.T) {
- 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)
- // Lister (cache) says it's NOT deleted.
- ds2 := *ds
- ds2.DeletionTimestamp = nil
- manager.dsStore.Add(&ds2)
- // The existence of a matching orphan should block all actions in this state.
- pod := newPod("pod1-", "node-0", simpleDaemonSetLabel, nil)
- manager.podStore.Add(pod)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0, 0)
- }
- }
- // 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) {
- for _, strategy := range updateStrategies() {
- podSpec := v1.PodSpec{
- NodeName: "port-conflict",
- Containers: []v1.Container{{
- Ports: []v1.ContainerPort{{
- HostPort: 666,
- }},
- }},
- }
- 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)
- }
- }
- // DaemonSets should place onto nodes that would not cause port conflicts
- func TestNoPortConflictNodeDaemonLaunchesPod(t *testing.T) {
- for _, strategy := range updateStrategies() {
- podSpec1 := v1.PodSpec{
- NodeName: "no-port-conflict",
- Containers: []v1.Container{{
- Ports: []v1.ContainerPort{{
- HostPort: 6661,
- }},
- }},
- }
- podSpec2 := v1.PodSpec{
- NodeName: "no-port-conflict",
- Containers: []v1.Container{{
- Ports: []v1.ContainerPort{{
- HostPort: 6662,
- }},
- }},
- }
- 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)
- }
- }
- // 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.
- 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"}
- 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)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0, 1)
- }
- }
- // 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) {
- 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)
- }
- }
- // Daemon with node selector should launch pods on nodes matching selector.
- func TestSelectorDaemonLaunchesPods(t *testing.T) {
- 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)
- }
- }
- // Daemon with node selector should delete pods from nodes that do not satisfy selector.
- func TestSelectorDaemonDeletesUnselectedPods(t *testing.T) {
- 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)
- }
- }
- // DaemonSet with node selector should launch pods on nodes matching selector, but also deal with existing pods on nodes.
- func TestSelectorDaemonDealsWithExistingPods(t *testing.T) {
- 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)
- }
- }
- // DaemonSet with node selector which does not match any node labels should not launch pods.
- func TestBadSelectorDaemonDoesNothing(t *testing.T) {
- 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)
- }
- }
- // DaemonSet with node name should launch pod on node with corresponding name.
- func TestNameDaemonSetLaunchesPods(t *testing.T) {
- 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)
- }
- }
- // DaemonSet with node name that does not exist should not launch pods.
- func TestBadNameDaemonSetDoesNothing(t *testing.T) {
- 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)
- }
- }
- // DaemonSet with node selector, and node name, matching a node, should launch a pod on the node.
- func TestNameAndSelectorDaemonSetLaunchesPods(t *testing.T) {
- 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)
- }
- }
- // DaemonSet with node selector that matches some nodes, and node name that matches a different node, should do nothing.
- func TestInconsistentNameSelectorDaemonSetDoesNothing(t *testing.T) {
- 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) {
- ds := newDaemonSet("foo")
- ds.Spec.Template.Spec.NodeSelector = simpleNodeLabel
- 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, 3, 0, 0)
- }
- // Daemon with node affinity should launch pods on nodes matching affinity.
- func TestNodeAffinityDaemonLaunchesPods(t *testing.T) {
- 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"]},
- },
- },
- },
- },
- },
- },
- }
- 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)
- }
- }
- func TestNumberReadyStatus(t *testing.T) {
- 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)
- }
- 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)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0, 0)
- if updated.Status.NumberReady != 0 {
- t.Errorf("Wrong daemon %s status: %v", updated.Name, updated.Status)
- }
- 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)
- }
- syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0, 0)
- if updated.Status.NumberReady != 2 {
- t.Errorf("Wrong daemon %s status: %v", updated.Name, updated.Status)
- }
- }
- }
- func TestObservedGeneration(t *testing.T) {
- 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)
- }
- 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, 1, simpleNodeLabel)
- addPods(manager.podStore, "node-0", simpleDaemonSetLabel, ds, 1)
- manager.dsStore.Add(ds)
- 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)
- }
- }
- }
- // DaemonSet controller should kill all failed pods and create at most 1 pod on every node.
- func TestDaemonKillFailedPods(t *testing.T) {
- tests := []struct {
- numFailedPods, numNormalPods, expectedCreates, expectedDeletes, expectedEvents int
- test string
- }{
- {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)"},
- }
- for _, test := range tests {
- t.Run(test.test, func(t *testing.T) {
- 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)
- }
- })
- }
- }
- // DaemonSet controller needs to backoff when killing failed pods to avoid hot looping and fighting with kubelet.
- func TestDaemonKillFailedPodsBackoff(t *testing.T) {
- for _, strategy := range updateStrategies() {
- t.Run(string(strategy.Type), func(t *testing.T) {
- 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)
- nodeName := "node-0"
- pod := newPod(fmt.Sprintf("%s-", nodeName), nodeName, simpleDaemonSetLabel, ds)
- // Add a failed Pod
- pod.Status.Phase = v1.PodFailed
- err = manager.podStore.Add(pod)
- if err != nil {
- t.Fatal(err)
- }
- backoffKey := failedPodsBackoffKey(ds, nodeName)
- // 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.")
- }
- resetCounters(manager)
- // 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.")
- }
- resetCounters(manager)
- // Sleep to wait out backoff
- fakeClock := manager.failedPodsBackoff.Clock
- // 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.")
- }
- // 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.")
- }
- // After backoff time, it will delete the failed pod
- syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 1, 1)
- })
- }
- }
- // 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) {
- 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)
- }
- 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)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0, 0)
- }
- }
- // Daemonset should remove a running pod from a node if the pod doesn't
- // tolerate the nodes NoExecute taint
- func TestNoExecuteTaintedDoesEvicitRunningIntolerantPod(t *testing.T) {
- 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)
- }
- 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)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 1, 0)
- }
- }
- // DaemonSet should not launch a pod on a tainted node when the pod doesn't tolerate that taint.
- func TestTaintedNodeDaemonDoesNotLaunchIntolerantPod(t *testing.T) {
- 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)
- }
- node := newNode("tainted", nil)
- setNodeTaint(node, noScheduleTaints)
- manager.nodeStore.Add(node)
- manager.dsStore.Add(ds)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0, 0)
- }
- }
- // DaemonSet should launch a pod on a tainted node when the pod can tolerate that taint.
- func TestTaintedNodeDaemonLaunchesToleratePod(t *testing.T) {
- 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)
- }
- node := newNode("tainted", nil)
- setNodeTaint(node, noScheduleTaints)
- manager.nodeStore.Add(node)
- manager.dsStore.Add(ds)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 1, 0, 0)
- }
- }
- // DaemonSet should launch a pod on a not ready node with taint notReady:NoExecute.
- func TestNotReadyNodeDaemonLaunchesPod(t *testing.T) {
- 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)
- }
- 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)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 1, 0, 0)
- }
- }
- // DaemonSet should launch a pod on an unreachable node with taint unreachable:NoExecute.
- func TestUnreachableNodeDaemonLaunchesPod(t *testing.T) {
- 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)
- }
- 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)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 1, 0, 0)
- }
- }
- // DaemonSet should launch a pod on an untainted node when the pod has tolerations.
- func TestNodeDaemonLaunchesToleratePod(t *testing.T) {
- 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)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 1, 0, 0)
- }
- }
- // DaemonSet should launch a pod on a not ready node with taint notReady:NoExecute.
- func TestDaemonSetRespectsTermination(t *testing.T) {
- 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, 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)
- }
- }
- func setNodeTaint(node *v1.Node, taints []v1.Taint) {
- node.Spec.Taints = taints
- }
- func setDaemonSetToleration(ds *apps.DaemonSet, tolerations []v1.Toleration) {
- ds.Spec.Template.Spec.Tolerations = tolerations
- }
- // DaemonSet should launch a pod even when the node with MemoryPressure/DiskPressure/PIDPressure taints.
- func TestTaintPressureNodeDaemonLaunchesPod(t *testing.T) {
- 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)
- }
- node := newNode("resources-pressure", nil)
- node.Status.Conditions = []v1.NodeCondition{
- {Type: v1.NodeDiskPressure, Status: v1.ConditionTrue},
- {Type: v1.NodeMemoryPressure, Status: v1.ConditionTrue},
- {Type: v1.NodePIDPressure, Status: v1.ConditionTrue},
- }
- node.Spec.Taints = []v1.Taint{
- {Key: v1.TaintNodeDiskPressure, Effect: v1.TaintEffectNoSchedule},
- {Key: v1.TaintNodeMemoryPressure, Effect: v1.TaintEffectNoSchedule},
- {Key: v1.TaintNodePIDPressure, Effect: v1.TaintEffectNoSchedule},
- }
- manager.nodeStore.Add(node)
- manager.dsStore.Add(ds)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 1, 0, 0)
- }
- }
- func setDaemonSetCritical(ds *apps.DaemonSet) {
- ds.Namespace = api.NamespaceSystem
- if ds.Spec.Template.ObjectMeta.Annotations == nil {
- ds.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
- }
- podPriority := scheduling.SystemCriticalPriority
- ds.Spec.Template.Spec.Priority = &podPriority
- }
- func TestNodeShouldRunDaemonPod(t *testing.T) {
- shouldRun := true
- shouldContinueRunning := true
- cases := []struct {
- predicateName string
- podsOnNode []*v1.Pod
- nodeCondition []v1.NodeCondition
- nodeUnschedulable bool
- ds *apps.DaemonSet
- shouldRun, 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"),
- },
- },
- },
- shouldRun: true,
- shouldContinueRunning: true,
- },
- {
- 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"),
- },
- },
- },
- shouldRun: shouldRun,
- shouldContinueRunning: true,
- },
- {
- 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"),
- },
- },
- },
- shouldRun: false,
- shouldContinueRunning: false,
- },
- {
- predicateName: "ErrPodNotFitsHostPorts",
- podsOnNode: []*v1.Pod{
- {
- Spec: v1.PodSpec{
- Containers: []v1.Container{{
- Ports: []v1.ContainerPort{{
- HostPort: 666,
- }},
- }},
- },
- },
- },
- 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,
- }},
- }},
- },
- },
- },
- },
- shouldRun: shouldRun,
- shouldContinueRunning: shouldContinueRunning,
- },
- {
- predicateName: "InsufficientResourceError",
- podsOnNode: []*v1.Pod{
- {
- Spec: v1.PodSpec{
- Containers: []v1.Container{{
- Ports: []v1.ContainerPort{{
- HostPort: 666,
- }},
- Resources: resourceContainerSpec("50M", "0.5"),
- }},
- },
- },
- },
- ds: &apps.DaemonSet{
- Spec: apps.DaemonSetSpec{
- Selector: &metav1.LabelSelector{MatchLabels: simpleDaemonSetLabel},
- Template: v1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: simpleDaemonSetLabel,
- },
- Spec: resourcePodSpec("", "100M", "0.5"),
- },
- },
- },
- shouldRun: shouldRun, // This is because we don't care about the resource constraints any more and let default scheduler handle it.
- shouldContinueRunning: true,
- },
- {
- predicateName: "ShouldRunDaemonPod",
- podsOnNode: []*v1.Pod{
- {
- Spec: v1.PodSpec{
- Containers: []v1.Container{{
- Ports: []v1.ContainerPort{{
- HostPort: 666,
- }},
- Resources: resourceContainerSpec("50M", "0.5"),
- }},
- },
- },
- },
- ds: &apps.DaemonSet{
- Spec: apps.DaemonSetSpec{
- Selector: &metav1.LabelSelector{MatchLabels: simpleDaemonSetLabel},
- Template: v1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: simpleDaemonSetLabel,
- },
- Spec: resourcePodSpec("", "50M", "0.5"),
- },
- },
- },
- shouldRun: true,
- shouldContinueRunning: true,
- },
- {
- 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,
- },
- },
- },
- },
- shouldRun: false,
- shouldContinueRunning: false,
- },
- {
- 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,
- },
- },
- },
- },
- shouldRun: true,
- shouldContinueRunning: true,
- },
- {
- 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"},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- shouldRun: false,
- shouldContinueRunning: false,
- },
- {
- 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"},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- },
- shouldRun: true,
- shouldContinueRunning: true,
- },
- {
- 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"),
- },
- },
- },
- nodeUnschedulable: true,
- shouldRun: true,
- shouldContinueRunning: true,
- },
- }
- 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
- shouldRun, shouldContinueRunning, err := manager.nodeShouldRunDaemonPod(node, c.ds)
- if shouldRun != c.shouldRun {
- t.Errorf("[%v] strategy: %v, predicateName: %v expected shouldRun: %v, got: %v", i, c.ds.Spec.UpdateStrategy.Type, c.predicateName, c.shouldRun, 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)
- }
- }
- }
- }
- // DaemonSets should be resynced when node labels or taints changed
- func TestUpdateNode(t *testing.T) {
- var enqueued bool
- 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:
- return 0
- case apps.RollingUpdateDaemonSetStrategyType:
- return 0
- default:
- t.Fatalf("unexpected UpdateStrategy %+v", strategyType)
- }
- return 0
- },
- shouldEnqueue: false,
- expectedCreates: func() int {
- 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)
- expectedEvents := 0
- if c.expectedEventsFunc != nil {
- expectedEvents = c.expectedEventsFunc(strategy.Type)
- }
- expectedCreates := 0
- if c.expectedCreates != nil {
- expectedCreates = c.expectedCreates()
- }
- syncAndValidateDaemonSets(t, manager, c.ds, podControl, expectedCreates, 0, expectedEvents)
- 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)
- }
- }
- }
- }
- // DaemonSets should be resynced when non-daemon pods was deleted.
- func TestDeleteNoDaemonPod(t *testing.T) {
- var enqueued bool
- cases := []struct {
- test string
- node *v1.Node
- existPods []*v1.Pod
- deletedPod *v1.Pod
- ds *apps.DaemonSet
- 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,
- }
- }(),
- ds: func() *apps.DaemonSet {
- ds := newDaemonSet("ds")
- ds.Spec.Template.Spec = resourcePodSpec("", "50M", "50m")
- return ds
- }(),
- shouldEnqueue: false,
- },
- {
- 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,
- }
- }(),
- ds: func() *apps.DaemonSet {
- ds := newDaemonSet("ds")
- ds.Spec.Template.Spec = resourcePodSpec("", "50M", "50m")
- return ds
- }(),
- shouldEnqueue: false,
- },
- {
- 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,
- }
- }(),
- ds: func() *apps.DaemonSet {
- ds := newDaemonSet("ds")
- ds.Spec.Template.Spec = resourcePodSpec("", "50M", "50m")
- return ds
- }(),
- shouldEnqueue: false,
- },
- }
- 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.node)
- c.ds.Spec.UpdateStrategy = *strategy
- manager.dsStore.Add(c.ds)
- for _, pod := range c.existPods {
- manager.podStore.Add(pod)
- }
- switch strategy.Type {
- case apps.OnDeleteDaemonSetStrategyType, apps.RollingUpdateDaemonSetStrategyType:
- syncAndValidateDaemonSets(t, manager, c.ds, podControl, 1, 0, 0)
- default:
- t.Fatalf("unexpected UpdateStrategy %+v", strategy)
- }
- enqueued = false
- manager.deletePod(c.deletedPod)
- if enqueued != c.shouldEnqueue {
- t.Errorf("Test case: '%s', expected: %t, got: %t", c.test, c.shouldEnqueue, enqueued)
- }
- }
- }
- }
- func TestDeleteUnscheduledPodForNotExistingNode(t *testing.T) {
- 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)
- podScheduledUsingAffinity := newPod("pod1-node-3", "", simpleDaemonSetLabel, ds)
- podScheduledUsingAffinity.Spec.Affinity = &v1.Affinity{
- NodeAffinity: &v1.NodeAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
- NodeSelectorTerms: []v1.NodeSelectorTerm{
- {
- MatchFields: []v1.NodeSelectorRequirement{
- {
- Key: api.ObjectNameField,
- Operator: v1.NodeSelectorOpIn,
- Values: []string{"node-2"},
- },
- },
- },
- },
- },
- },
- }
- manager.podStore.Add(podScheduledUsingAffinity)
- syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 1, 0)
- }
- }
- func TestGetNodesToDaemonPods(t *testing.T) {
- 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)
- }
- // 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)
- }
- 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
- }
- }
- 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)
- }
- }
- }
- func TestAddNode(t *testing.T) {
- manager, _, _, err := newTestController()
- if err != nil {
- t.Fatalf("error creating DaemonSets controller: %v", err)
- }
- node1 := newNode("node1", nil)
- ds := newDaemonSet("ds")
- ds.Spec.Template.Spec.NodeSelector = simpleNodeLabel
- manager.dsStore.Add(ds)
- manager.addNode(node1)
- if got, want := manager.queue.Len(), 0; got != want {
- t.Fatalf("queue.Len() = %v, want %v", got, want)
- }
- node2 := newNode("node2", simpleNodeLabel)
- manager.addNode(node2)
- 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 node %v", node2.Name)
- }
- }
- func TestAddPod(t *testing.T) {
- 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)
- }
- }
- }
- func TestAddPodOrphan(t *testing.T) {
- 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)
- }
- }
- }
- func TestUpdatePod(t *testing.T) {
- 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)
- }
- 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)
- }
- }
- }
- func TestUpdatePodOrphanSameLabels(t *testing.T) {
- 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)
- }
- }
- }
- func TestUpdatePodOrphanWithNewLabels(t *testing.T) {
- 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)
- }
- }
- }
- func TestUpdatePodChangeControllerRef(t *testing.T) {
- 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)
- }
- }
- }
- func TestUpdatePodControllerRefRemoved(t *testing.T) {
- 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)
- }
- }
- }
- func TestDeletePod(t *testing.T) {
- 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)
- }
- 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)
- }
- }
- }
- func TestDeletePodOrphan(t *testing.T) {
- 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)
- }
- }
- }
- 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
- }
|