From 49996c77e4a5a5bce9bb3ae8a31a53358d83c9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20B=C3=BCcker?= Date: Tue, 1 Sep 2026 11:45:42 +0200 Subject: [PATCH] Recover from drifted Ready/Released status conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a post-action status condition patch failed for a HelmRelease that was just installed or upgraded (e.g. due to version conflicts), but history was successfully persisted, a HelmRelease could be stranded with `Ready=Unknown` while actually being completely installed in the cluster. Subsequent reconciliations of the HelmRelease would not correct that drift as the pre-existing correction mechanism required a `Released` status condition to exist. However, since that would've been created in the same patch as the missing `Ready` update, that would always fail. This fix extends the existing correction mechanism to allow for a missing `Released` status condition, in which case it will resort to `status.lastAttemptedReleaseAction` or `status.history` to determine the desired state for `Ready` and `Released`. Signed-off-by: Peter Bücker Assisted-by: cursor/grok-4.6 --- internal/reconcile/atomic_release.go | 16 ++++++ internal/reconcile/atomic_release_test.go | 59 +++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/internal/reconcile/atomic_release.go b/internal/reconcile/atomic_release.go index 8025e22d9..5f5a1f1b3 100644 --- a/internal/reconcile/atomic_release.go +++ b/internal/reconcile/atomic_release.go @@ -372,6 +372,22 @@ func (r *AtomicRelease) actionForState(ctx context.Context, req *Request, state reason, msgFmt = v2.InstallSucceededReason, fmtInstallSuccess case v2.UpgradeFailedReason: reason, msgFmt = v2.UpgradeSucceededReason, fmtUpgradeSuccess + default: + // Released may be missing after a failed post-action + // condition patch while history was persisted. Derive + // the success reason from the last attempted action. + action := req.Object.Status.LastAttemptedReleaseAction + if action == "" { + if cur := req.Object.Status.History.Latest(); cur != nil { + action = cur.Action + } + } + switch action { + case v2.ReleaseActionInstall: + reason, msgFmt = v2.InstallSucceededReason, fmtInstallSuccess + case v2.ReleaseActionUpgrade: + reason, msgFmt = v2.UpgradeSucceededReason, fmtUpgradeSuccess + } } if reason != "" { cur := req.Object.Status.History.Latest() diff --git a/internal/reconcile/atomic_release_test.go b/internal/reconcile/atomic_release_test.go index 7637c3bc4..55bf6ea09 100644 --- a/internal/reconcile/atomic_release_test.go +++ b/internal/reconcile/atomic_release_test.go @@ -1574,6 +1574,65 @@ func TestAtomicRelease_actionForState(t *testing.T) { *conditions.TrueCondition(meta.ReadyCondition, v2.InstallSucceededReason, "install succeeded"), }, }, + { + name: "in-sync release with missing released condition after install", + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + {Version: 1}, + }, + LastAttemptedReleaseAction: v2.ReleaseActionInstall, + Conditions: []metav1.Condition{ + *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "Running 'install' action"), + }, + } + }, + state: ReleaseState{Status: ReleaseStatusInSync}, + want: nil, + assertConditions: []metav1.Condition{ + *conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason, "install succeeded"), + *conditions.TrueCondition(meta.ReadyCondition, v2.InstallSucceededReason, "install succeeded"), + }, + }, + { + name: "in-sync release with missing released condition after upgrade", + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + {Version: 2}, + }, + LastAttemptedReleaseAction: v2.ReleaseActionUpgrade, + Conditions: []metav1.Condition{ + *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "Running 'upgrade' action"), + }, + } + }, + state: ReleaseState{Status: ReleaseStatusInSync}, + want: nil, + assertConditions: []metav1.Condition{ + *conditions.TrueCondition(v2.ReleasedCondition, v2.UpgradeSucceededReason, "upgrade succeeded"), + *conditions.TrueCondition(meta.ReadyCondition, v2.UpgradeSucceededReason, "upgrade succeeded"), + }, + }, + { + name: "in-sync release with missing released condition recovers from history action", + status: func(releases []*helmrelease.Release) v2.HelmReleaseStatus { + return v2.HelmReleaseStatus{ + History: v2.Snapshots{ + {Version: 1, Action: v2.ReleaseActionInstall}, + }, + Conditions: []metav1.Condition{ + *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "Running 'install' action"), + }, + } + }, + state: ReleaseState{Status: ReleaseStatusInSync}, + want: nil, + assertConditions: []metav1.Condition{ + *conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason, "install succeeded"), + *conditions.TrueCondition(meta.ReadyCondition, v2.InstallSucceededReason, "install succeeded"), + }, + }, { name: "locked release triggers unlock action", state: ReleaseState{Status: ReleaseStatusLocked},