@@ -3,7 +3,6 @@ package csidrivernodeservicecontroller
33import (
44 "context"
55 "fmt"
6- clocktesting "k8s.io/utils/clock/testing"
76 "os"
87 "sort"
98 "strings"
@@ -19,6 +18,8 @@ import (
1918 coreinformers "k8s.io/client-go/informers"
2019 fakecore "k8s.io/client-go/kubernetes/fake"
2120 core "k8s.io/client-go/testing"
21+ "k8s.io/client-go/tools/cache"
22+ clocktesting "k8s.io/utils/clock/testing"
2223
2324 "github.com/google/go-cmp/cmp"
2425 opv1 "github.com/openshift/api/operator/v1"
@@ -100,7 +101,7 @@ func newTestContext(test testCase, t *testing.T) *testContext {
100101 }
101102
102103 // Add global reactors
103- addGenerationReactor (coreClient )
104+ addGenerationReactor (coreClient , coreInformerFactory . Apps (). V1 (). DaemonSets (). Informer (). GetStore () )
104105
105106 // fakeDriverInstance also fulfils the OperatorClient interface
106107 fakeOperatorClient := v1helpers .NewFakeOperatorClientWithObjectMeta (
@@ -331,8 +332,18 @@ func withDaemonSetTLSConfig() daemonSetModifier {
331332 }
332333}
333334
335+ func withDaemonSetAnnotation (annotation string , value string ) daemonSetModifier {
336+ return func (instance * appsv1.DaemonSet ) * appsv1.DaemonSet {
337+ if instance .Annotations == nil {
338+ instance .Annotations = map [string ]string {}
339+ }
340+ instance .Annotations [annotation ] = value
341+ return instance
342+ }
343+ }
344+
334345// This reactor is always enabled and bumps DaemonSet generation when they get updated.
335- func addGenerationReactor (client * fakecore.Clientset ) {
346+ func addGenerationReactor (client * fakecore.Clientset , store cache. Store ) {
336347 client .PrependReactor ("*" , "daemonsets" , func (action core.Action ) (handled bool , ret runtime.Object , err error ) {
337348 switch a := action .(type ) {
338349 case core.CreateActionImpl :
@@ -343,7 +354,20 @@ func addGenerationReactor(client *fakecore.Clientset) {
343354 case core.UpdateActionImpl :
344355 object := a .GetObject ()
345356 ds := object .(* appsv1.DaemonSet )
346- ds .Generation ++
357+
358+ // Bump generation only when the spec changes.
359+ // Explicitly, do not bump it on annotation change - the API server does not do it either.
360+ oldDSObject , exists , err := store .GetByKey (ds .Namespace + "/" + ds .Name )
361+ if err != nil {
362+ return false , nil , err
363+ }
364+ if ! exists {
365+ return false , nil , fmt .Errorf ("DaemonSet %s not found" , cache .MetaObjectToName (ds ))
366+ }
367+ oldDS := oldDSObject .(* appsv1.DaemonSet )
368+ if ! equality .Semantic .DeepEqual (oldDS .Spec , ds .Spec ) {
369+ ds .Generation ++
370+ }
347371 return false , ds , nil
348372 }
349373 return false , nil , nil
@@ -426,6 +450,7 @@ func TestSync(t *testing.T) {
426450 },
427451 },
428452 {
453+ name : "no change" ,
429454 // DaemonSet is fully deployed and its status is synced to CR
430455 manifestFunc : makeFakeManifest ,
431456 images : defaultImages (),
@@ -434,15 +459,45 @@ func TestSync(t *testing.T) {
434459 argsLevel2 ,
435460 defaultImages (),
436461 withDaemonSetGeneration (1 , 1 ),
437- withDaemonSetStatus (replica1 , replica1 , replica1 , replica0 )),
462+ withDaemonSetStatus (replica1 , replica1 , replica1 , replica0 ),
463+ withDaemonSetAnnotation (stableGenerationAnnotationName , "1" )),
438464 driver : makeFakeDriverInstance (withGenerations (1 )),
439465 },
440466 expectedObjects : testObjects {
441467 daemonSet : getDaemonSet (
442468 argsLevel2 ,
443469 defaultImages (),
444470 withDaemonSetGeneration (1 , 1 ),
445- withDaemonSetStatus (replica1 , replica1 , replica1 , replica0 )),
471+ withDaemonSetStatus (replica1 , replica1 , replica1 , replica0 ),
472+ withDaemonSetAnnotation (stableGenerationAnnotationName , "1" )),
473+ driver : makeFakeDriverInstance (
474+ // withStatus(replica1),
475+ withGenerations (1 ),
476+ withTrueConditions (conditionAvailable ),
477+ withFalseConditions (conditionProgressing )),
478+ },
479+ },
480+ {
481+ name : "finished progressing" ,
482+ // DaemonSet is fully deployed and its status is synced to CR
483+ manifestFunc : makeFakeManifest ,
484+ images : defaultImages (),
485+ initialObjects : testObjects {
486+ daemonSet : getDaemonSet (
487+ argsLevel2 ,
488+ defaultImages (),
489+ withDaemonSetGeneration (1 , 1 ),
490+ withDaemonSetStatus (replica1 , replica1 , replica1 , replica0 ),
491+ withDaemonSetAnnotation (stableGenerationAnnotationName , "0" )),
492+ driver : makeFakeDriverInstance (withGenerations (1 )),
493+ },
494+ expectedObjects : testObjects {
495+ daemonSet : getDaemonSet (
496+ argsLevel2 ,
497+ defaultImages (),
498+ withDaemonSetGeneration (1 , 1 ),
499+ withDaemonSetStatus (replica1 , replica1 , replica1 , replica0 ),
500+ withDaemonSetAnnotation (stableGenerationAnnotationName , "1" )), // The current generation has reached stability
446501 driver : makeFakeDriverInstance (
447502 // withStatus(replica1),
448503 withGenerations (1 ),
@@ -490,7 +545,8 @@ func TestSync(t *testing.T) {
490545 argsLevel2 ,
491546 defaultImages (),
492547 withDaemonSetGeneration (1 , 1 ),
493- withDaemonSetStatus (replica0 , replica0 , replica1 , replica1 )), // the DaemonSet is updating 1 pod
548+ withDaemonSetStatus (replica0 , replica0 , replica1 , replica1 ), // the DaemonSet is updating 1 pod
549+ withDaemonSetAnnotation (stableGenerationAnnotationName , "0" )), // and the current generation was not stable yet
494550 driver : makeFakeDriverInstance (
495551 // withStatus(replica1),
496552 withGenerations (1 ),
@@ -502,7 +558,8 @@ func TestSync(t *testing.T) {
502558 argsLevel2 ,
503559 defaultImages (),
504560 withDaemonSetGeneration (1 , 1 ),
505- withDaemonSetStatus (replica0 , replica0 , replica1 , replica1 )), // no change to the DaemonSet
561+ withDaemonSetStatus (replica0 , replica0 , replica1 , replica1 ),
562+ withDaemonSetAnnotation (stableGenerationAnnotationName , "0" )), // and the current generation was not stable yet
506563 driver : makeFakeDriverInstance (
507564 // withStatus(replica0),
508565 withGenerations (1 ),
@@ -658,6 +715,38 @@ func TestSync(t *testing.T) {
658715 withFalseConditions (conditionAvailable )), // Degraded is set later on
659716 },
660717 },
718+ {
719+ // DaemonSet is updating pods
720+ name : "missing pods - not progressing" ,
721+ manifestFunc : makeFakeManifest ,
722+ images : defaultImages (),
723+ initialObjects : testObjects {
724+ daemonSet : getDaemonSet (
725+ argsLevel2 ,
726+ defaultImages (),
727+ withDaemonSetGeneration (1 , 1 ),
728+ withDaemonSetStatus (replica0 , replica0 , replica1 , replica1 ), // the DaemonSet is updating 1 pod
729+ withDaemonSetAnnotation (stableGenerationAnnotationName , "1" )), // But the current generation was stable in the past
730+ driver : makeFakeDriverInstance (
731+ // withStatus(replica1),
732+ withGenerations (1 ),
733+ withTrueConditions (conditionAvailable ),
734+ withFalseConditions (conditionProgressing )),
735+ },
736+ expectedObjects : testObjects {
737+ daemonSet : getDaemonSet (
738+ argsLevel2 ,
739+ defaultImages (),
740+ withDaemonSetGeneration (1 , 1 ),
741+ withDaemonSetStatus (replica0 , replica0 , replica1 , replica1 ),
742+ withDaemonSetAnnotation (stableGenerationAnnotationName , "1" )), // no change to the DaemonSet
743+ driver : makeFakeDriverInstance (
744+ // withStatus(replica0),
745+ withGenerations (1 ), // But the current generation was stable in the past
746+ withTrueConditions (conditionAvailable ),
747+ withFalseConditions (conditionProgressing )), // The operator is not Progressing
748+ },
749+ },
661750 }
662751
663752 for _ , test := range testCases {
0 commit comments