Skip to content

Commit 6e768b3

Browse files
authored
Merge pull request fluxcd#729 from fluxcd/observed-gen-no-condition
reconcile: Set observed gen only when conditions exist
2 parents 7aa0814 + 3213179 commit 6e768b3

File tree

2 files changed

+85
-6
lines changed

2 files changed

+85
-6
lines changed

internal/reconcile/reconcile.go

+18-4
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,11 @@ func ComputeReconcileResult(obj conditions.Setter, res Result, recErr error, rb
128128
switch t := recErr.(type) {
129129
case *serror.Stalling:
130130
if res == ResultEmpty {
131+
conditions.MarkStalled(obj, t.Reason, t.Error())
131132
// The current generation has been reconciled successfully and it
132133
// has resulted in a stalled state. Return no error to stop further
133134
// requeuing.
134-
pOpts = append(pOpts, patch.WithStatusObservedGeneration{})
135-
conditions.MarkStalled(obj, t.Reason, t.Error())
135+
pOpts = addPatchOptionWithStatusObservedGeneration(obj, pOpts)
136136
return pOpts, result, nil
137137
}
138138
// NOTE: Non-empty result with stalling error indicates that the
@@ -150,7 +150,7 @@ func ComputeReconcileResult(obj conditions.Setter, res Result, recErr error, rb
150150
if t.Ignore {
151151
// The current generation has been reconciled successfully with
152152
// no-op result. Update status observed generation.
153-
pOpts = append(pOpts, patch.WithStatusObservedGeneration{})
153+
pOpts = addPatchOptionWithStatusObservedGeneration(obj, pOpts)
154154
conditions.Delete(obj, meta.ReconcilingCondition)
155155
return pOpts, result, nil
156156
}
@@ -159,7 +159,7 @@ func ComputeReconcileResult(obj conditions.Setter, res Result, recErr error, rb
159159
// state. If a requeue is requested, the current generation has not been
160160
// reconciled successfully.
161161
if res != ResultRequeue {
162-
pOpts = append(pOpts, patch.WithStatusObservedGeneration{})
162+
pOpts = addPatchOptionWithStatusObservedGeneration(obj, pOpts)
163163
}
164164
conditions.Delete(obj, meta.StalledCondition)
165165
default:
@@ -207,3 +207,17 @@ func FailureRecovery(oldObj, newObj conditions.Getter, failConditions []string)
207207
}
208208
return failuresBefore > 0
209209
}
210+
211+
// addPatchOptionWithStatusObservedGeneration adds patch option
212+
// WithStatusObservedGeneration to the provided patch option slice only if there
213+
// is any condition present on the object, and returns it. This is necessary to
214+
// prevent setting status observed generation without any effectual observation.
215+
// An object must have some condition in the status if it has been observed.
216+
// TODO: Move this to fluxcd/pkg/runtime/patch package after it has proven its
217+
// need.
218+
func addPatchOptionWithStatusObservedGeneration(obj conditions.Setter, opts []patch.Option) []patch.Option {
219+
if len(obj.GetConditions()) > 0 {
220+
opts = append(opts, patch.WithStatusObservedGeneration{})
221+
}
222+
return opts
223+
}

internal/reconcile/reconcile_test.go

+67-2
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,17 @@ func TestComputeReconcileResult(t *testing.T) {
7171
afterFunc func(t *WithT, obj conditions.Setter, patchOpts *patch.HelperOptions)
7272
}{
7373
{
74-
name: "successful result",
75-
result: ResultSuccess,
74+
name: "successful result",
75+
result: ResultSuccess,
76+
beforeFunc: func(obj conditions.Setter) {
77+
conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "foo")
78+
},
7679
recErr: nil,
7780
wantResult: ctrl.Result{RequeueAfter: testSuccessInterval},
7881
wantErr: false,
82+
assertConditions: []metav1.Condition{
83+
*conditions.TrueCondition(meta.ReadyCondition, meta.SucceededReason, "foo"),
84+
},
7985
afterFunc: func(t *WithT, obj conditions.Setter, patchOpts *patch.HelperOptions) {
8086
t.Expect(patchOpts.IncludeStatusObservedGeneration).To(BeTrue())
8187
},
@@ -85,10 +91,14 @@ func TestComputeReconcileResult(t *testing.T) {
8591
result: ResultSuccess,
8692
beforeFunc: func(obj conditions.Setter) {
8793
conditions.MarkReconciling(obj, "NewRevision", "new revision")
94+
conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "foo")
8895
},
8996
recErr: nil,
9097
wantResult: ctrl.Result{RequeueAfter: testSuccessInterval},
9198
wantErr: false,
99+
assertConditions: []metav1.Condition{
100+
*conditions.TrueCondition(meta.ReadyCondition, meta.SucceededReason, "foo"),
101+
},
92102
afterFunc: func(t *WithT, obj conditions.Setter, patchOpts *patch.HelperOptions) {
93103
t.Expect(patchOpts.IncludeStatusObservedGeneration).To(BeTrue())
94104
t.Expect(conditions.IsUnknown(obj, meta.ReconcilingCondition)).To(BeTrue())
@@ -367,3 +377,58 @@ func TestFailureRecovery(t *testing.T) {
367377
})
368378
}
369379
}
380+
381+
func TestAddOptionWithStatusObservedGeneration(t *testing.T) {
382+
tests := []struct {
383+
name string
384+
beforeFunc func(obj conditions.Setter)
385+
patchOpts []patch.Option
386+
want bool
387+
}{
388+
{
389+
name: "no conditions",
390+
want: false,
391+
},
392+
{
393+
name: "some condition",
394+
beforeFunc: func(obj conditions.Setter) {
395+
conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "foo")
396+
},
397+
want: true,
398+
},
399+
{
400+
name: "existing option with conditions",
401+
beforeFunc: func(obj conditions.Setter) {
402+
conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "foo")
403+
},
404+
patchOpts: []patch.Option{patch.WithForceOverwriteConditions{}, patch.WithStatusObservedGeneration{}},
405+
want: true,
406+
},
407+
{
408+
name: "existing option, no conditions, can't remove",
409+
patchOpts: []patch.Option{patch.WithForceOverwriteConditions{}, patch.WithStatusObservedGeneration{}},
410+
want: true,
411+
},
412+
}
413+
414+
for _, tt := range tests {
415+
t.Run(tt.name, func(t *testing.T) {
416+
g := NewWithT(t)
417+
418+
obj := &sourcev1.GitRepository{}
419+
420+
if tt.beforeFunc != nil {
421+
tt.beforeFunc(obj)
422+
}
423+
424+
tt.patchOpts = addPatchOptionWithStatusObservedGeneration(obj, tt.patchOpts)
425+
426+
// Apply the options and evaluate the result.
427+
options := &patch.HelperOptions{}
428+
for _, opt := range tt.patchOpts {
429+
opt.ApplyToHelper(options)
430+
}
431+
g.Expect(options.IncludeStatusObservedGeneration).To(Equal(tt.want))
432+
})
433+
}
434+
}

0 commit comments

Comments
 (0)