From 616ce8888e9d347ad91c3651d2dbff65a2bee12f Mon Sep 17 00:00:00 2001 From: Sunny Date: Thu, 7 Dec 2023 23:23:16 +0000 Subject: [PATCH] add replace remediated with released helper replaceRemediatedWithReleased() replaces remediated condition with released condition, retaining the transition time. This helps ensure that the last transition time of releases don't change when a release is marked from remediated to released. Signed-off-by: Sunny --- internal/reconcile/atomic_release.go | 23 ++++- internal/reconcile/atomic_release_test.go | 104 ++++++++++++++++++++++ 2 files changed, 123 insertions(+), 4 deletions(-) diff --git a/internal/reconcile/atomic_release.go b/internal/reconcile/atomic_release.go index 30e26a2cb..86b989da4 100644 --- a/internal/reconcile/atomic_release.go +++ b/internal/reconcile/atomic_release.go @@ -33,6 +33,7 @@ import ( "github.com/fluxcd/pkg/runtime/logger" "github.com/fluxcd/pkg/runtime/patch" "github.com/fluxcd/pkg/ssa/jsondiff" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v2 "github.com/fluxcd/helm-controller/api/v2beta2" "github.com/fluxcd/helm-controller/internal/action" @@ -322,10 +323,9 @@ func (r *AtomicRelease) actionForState(ctx context.Context, req *Request, state // having the same chart version and values. As a result, we are already // in-sync without performing a release action. if conditions.IsTrue(req.Object, v2.RemediatedCondition) { - conditions.Delete(req.Object, v2.RemediatedCondition) cur := req.Object.Status.History.Latest() msg := fmt.Sprintf(fmtUpgradeSuccess, cur.FullReleaseName(), cur.VersionedChartName()) - conditions.MarkTrue(req.Object, v2.ReleasedCondition, v2.UpgradeSucceededReason, msg) + replaceRemediatedWithReleased(req.Object, metav1.ConditionTrue, v2.UpgradeSucceededReason, msg) } return nil, nil @@ -401,10 +401,9 @@ func (r *AtomicRelease) actionForState(ctx context.Context, req *Request, state // a result, we are already in-sync without performing a release action, // the existing release needs to undergo testing. if conditions.IsTrue(req.Object, v2.RemediatedCondition) { - conditions.Delete(req.Object, v2.RemediatedCondition) cur := req.Object.Status.History.Latest() msg := fmt.Sprintf(fmtUpgradeSuccess, cur.FullReleaseName(), cur.VersionedChartName()) - conditions.MarkTrue(req.Object, v2.ReleasedCondition, v2.UpgradeSucceededReason, msg) + replaceRemediatedWithReleased(req.Object, metav1.ConditionTrue, v2.UpgradeSucceededReason, msg) } return NewTest(r.configFactory, r.eventRecorder), nil @@ -520,3 +519,19 @@ func timeoutForAction(action ActionReconciler, obj *v2.HelmRelease) time.Duratio return obj.GetTimeout().Duration } } + +// replaceRemediatedWithRelease replaces existing Remediated condition with +// Released condition, if present, for the given values, retaining the +// LastTransitionTime. +func replaceRemediatedWithReleased(obj *v2.HelmRelease, status metav1.ConditionStatus, reason, msg string) { + released := conditions.Get(obj, v2.RemediatedCondition) + if released != nil { + conditions.Delete(obj, v2.ReleasedCondition) + released.Status = status + released.Type = v2.ReleasedCondition + released.Reason = reason + released.Message = msg + conditions.Set(obj, released) + conditions.Delete(obj, v2.RemediatedCondition) + } +} diff --git a/internal/reconcile/atomic_release_test.go b/internal/reconcile/atomic_release_test.go index fab5df98d..2397938c3 100644 --- a/internal/reconcile/atomic_release_test.go +++ b/internal/reconcile/atomic_release_test.go @@ -1557,3 +1557,107 @@ func TestAtomicRelease_actionForState(t *testing.T) { }) } } + +func Test_replaceRemediatedWithRelease(t *testing.T) { + g := NewWithT(t) + timestamp, err := time.Parse(time.UnixDate, "Wed Feb 25 11:06:39 GMT 2015") + g.Expect(err).ToNot(HaveOccurred()) + + tests := []struct { + name string + conditions []metav1.Condition + wantConditions []metav1.Condition + }{ + { + name: "existing released and remediated conditions", + conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionFalse, + Reason: v2.UpgradeFailedReason, + Message: "upgrade failed", + ObservedGeneration: 1, + LastTransitionTime: metav1.NewTime(timestamp), + }, + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionTrue, + Reason: v2.RollbackSucceededReason, + Message: "rollback", + ObservedGeneration: 1, + LastTransitionTime: metav1.NewTime(timestamp), + }, + }, + wantConditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "foo", + ObservedGeneration: 1, + LastTransitionTime: metav1.NewTime(timestamp), + }, + }, + }, + { + name: "no released condition", + conditions: []metav1.Condition{ + { + Type: v2.RemediatedCondition, + Status: metav1.ConditionTrue, + Reason: v2.RollbackSucceededReason, + Message: "rollback", + ObservedGeneration: 1, + LastTransitionTime: metav1.NewTime(timestamp), + }, + }, + wantConditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionTrue, + Reason: v2.UpgradeSucceededReason, + Message: "foo", + ObservedGeneration: 1, + LastTransitionTime: metav1.NewTime(timestamp), + }, + }, + }, + { + name: "no remediated condition", + conditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionFalse, + Reason: v2.UpgradeFailedReason, + Message: "upgrade failed", + ObservedGeneration: 1, + LastTransitionTime: metav1.NewTime(timestamp), + }, + }, + wantConditions: []metav1.Condition{ + { + Type: v2.ReleasedCondition, + Status: metav1.ConditionFalse, + Reason: v2.UpgradeFailedReason, + Message: "upgrade failed", + ObservedGeneration: 1, + LastTransitionTime: metav1.NewTime(timestamp), + }, + }, + }, + { + name: "no released and remediated conditions", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + obj := &v2.HelmRelease{} + obj.Generation = 1 + obj.Status.Conditions = tt.conditions + replaceRemediatedWithReleased(obj, metav1.ConditionTrue, v2.UpgradeSucceededReason, "foo") + g.Expect(obj.Status.Conditions).To(Equal(tt.wantConditions)) + }) + } +}