diff --git a/pkg/apis/extensions/types.go b/pkg/apis/extensions/types.go index 2a18b06e557..fc676ea6a0d 100644 --- a/pkg/apis/extensions/types.go +++ b/pkg/apis/extensions/types.go @@ -478,6 +478,10 @@ type DaemonSetStatus struct { // NumberReady is the number of nodes that should be running the daemon pod and have one // or more of the daemon pod running and ready. NumberReady int32 + + // ObservedGeneration is the most recent generation observed by the daemon set controller. + // +optional + ObservedGeneration int64 } // +genclient=true diff --git a/pkg/apis/extensions/v1beta1/types.go b/pkg/apis/extensions/v1beta1/types.go index eb687f0adc8..37212fcf9b8 100644 --- a/pkg/apis/extensions/v1beta1/types.go +++ b/pkg/apis/extensions/v1beta1/types.go @@ -568,6 +568,10 @@ type DaemonSetStatus struct { // NumberReady is the number of nodes that should be running the daemon pod and have one // or more of the daemon pod running and ready. NumberReady int32 `json:"numberReady" protobuf:"varint,4,opt,name=numberReady"` + + // ObservedGeneration is the most recent generation observed by the daemon set controller. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty" protobuf:"varint,5,opt,name=observedGeneration"` } // +genclient=true diff --git a/pkg/apis/extensions/validation/validation.go b/pkg/apis/extensions/validation/validation.go index 9434163f7ba..8b03025e877 100644 --- a/pkg/apis/extensions/validation/validation.go +++ b/pkg/apis/extensions/validation/validation.go @@ -109,6 +109,7 @@ func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *field. allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberMisscheduled), fldPath.Child("numberMisscheduled"))...) allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DesiredNumberScheduled), fldPath.Child("desiredNumberScheduled"))...) allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberReady), fldPath.Child("numberReady"))...) + allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(status.ObservedGeneration, fldPath.Child("observedGeneration"))...) return allErrs } diff --git a/pkg/apis/extensions/validation/validation_test.go b/pkg/apis/extensions/validation/validation_test.go index cb0ca2a98c3..173fb2c8cb6 100644 --- a/pkg/apis/extensions/validation/validation_test.go +++ b/pkg/apis/extensions/validation/validation_test.go @@ -80,6 +80,7 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: 2, DesiredNumberScheduled: 3, NumberReady: 1, + ObservedGeneration: 3, }, }, update: extensions.DaemonSet{ @@ -93,6 +94,7 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: -1, DesiredNumberScheduled: -3, NumberReady: -1, + ObservedGeneration: -3, }, }, }, @@ -108,6 +110,7 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: 2, DesiredNumberScheduled: 3, NumberReady: 1, + ObservedGeneration: 3, }, }, update: extensions.DaemonSet{ @@ -121,6 +124,7 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: 1, DesiredNumberScheduled: 3, NumberReady: 1, + ObservedGeneration: 3, }, }, }, @@ -136,6 +140,7 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: 2, DesiredNumberScheduled: 3, NumberReady: 1, + ObservedGeneration: 3, }, }, update: extensions.DaemonSet{ @@ -149,6 +154,7 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: -1, DesiredNumberScheduled: 3, NumberReady: 1, + ObservedGeneration: 3, }, }, }, @@ -164,6 +170,7 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: 2, DesiredNumberScheduled: 3, NumberReady: 1, + ObservedGeneration: 3, }, }, update: extensions.DaemonSet{ @@ -177,6 +184,7 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: 1, DesiredNumberScheduled: -3, NumberReady: 1, + ObservedGeneration: 3, }, }, }, @@ -192,6 +200,7 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: 2, DesiredNumberScheduled: 3, NumberReady: 1, + ObservedGeneration: 3, }, }, update: extensions.DaemonSet{ @@ -205,6 +214,37 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) { NumberMisscheduled: 1, DesiredNumberScheduled: 3, NumberReady: -1, + ObservedGeneration: 3, + }, + }, + }, + "negative ObservedGeneration": { + old: extensions.DaemonSet{ + ObjectMeta: api.ObjectMeta{ + Name: "abc", + Namespace: api.NamespaceDefault, + ResourceVersion: "10", + }, + Status: extensions.DaemonSetStatus{ + CurrentNumberScheduled: 1, + NumberMisscheduled: 2, + DesiredNumberScheduled: 3, + NumberReady: 1, + ObservedGeneration: 3, + }, + }, + update: extensions.DaemonSet{ + ObjectMeta: api.ObjectMeta{ + Name: "abc", + Namespace: api.NamespaceDefault, + ResourceVersion: "10", + }, + Status: extensions.DaemonSetStatus{ + CurrentNumberScheduled: 1, + NumberMisscheduled: 1, + DesiredNumberScheduled: 3, + NumberReady: 1, + ObservedGeneration: -3, }, }, }, diff --git a/pkg/controller/daemon/daemoncontroller.go b/pkg/controller/daemon/daemoncontroller.go index f5de5acbd10..af8d747516f 100644 --- a/pkg/controller/daemon/daemoncontroller.go +++ b/pkg/controller/daemon/daemoncontroller.go @@ -540,7 +540,8 @@ func storeDaemonSetStatus(dsClient unversionedextensions.DaemonSetInterface, ds if int(ds.Status.DesiredNumberScheduled) == desiredNumberScheduled && int(ds.Status.CurrentNumberScheduled) == currentNumberScheduled && int(ds.Status.NumberMisscheduled) == numberMisscheduled && - int(ds.Status.NumberReady) == numberReady { + int(ds.Status.NumberReady) == numberReady && + ds.Status.ObservedGeneration >= ds.Generation { return nil } @@ -553,6 +554,7 @@ func storeDaemonSetStatus(dsClient unversionedextensions.DaemonSetInterface, ds var updateErr, getErr error for i := 0; i < StatusUpdateRetries; i++ { + toUpdate.Status.ObservedGeneration = ds.Generation toUpdate.Status.DesiredNumberScheduled = int32(desiredNumberScheduled) toUpdate.Status.CurrentNumberScheduled = int32(currentNumberScheduled) toUpdate.Status.NumberMisscheduled = int32(numberMisscheduled) diff --git a/pkg/controller/daemon/daemoncontroller_test.go b/pkg/controller/daemon/daemoncontroller_test.go index 904fd940fec..ab8fb5b03d4 100644 --- a/pkg/controller/daemon/daemoncontroller_test.go +++ b/pkg/controller/daemon/daemoncontroller_test.go @@ -609,3 +609,28 @@ func TestNumberReadyStatus(t *testing.T) { t.Errorf("Wrong daemon %s status: %v", updated.Name, updated.Status) } } + +func TestObservedGeneration(t *testing.T) { + daemon := newDaemonSet("foo") + daemon.Generation = 1 + manager, podControl, clientset := newTestController() + var updated *extensions.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().(*extensions.DaemonSet) + } + return false, nil, nil + }) + + addNodes(manager.nodeStore.Store, 0, 1, simpleNodeLabel) + addPods(manager.podStore.Indexer, "node-0", simpleDaemonSetLabel, 1) + manager.dsStore.Add(daemon) + + syncAndValidateDaemonSets(t, manager, daemon, podControl, 0, 0) + if updated.Status.ObservedGeneration != daemon.Generation { + t.Errorf("Wrong ObservedGeneration for daemon %s in status. Expected %d, got %d", updated.Name, daemon.Generation, updated.Status.ObservedGeneration) + } +}