From 8bb0b372268b45b260593061450f1c9dca9ddbb8 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Mon, 13 Nov 2023 21:21:43 +0100 Subject: [PATCH 1/2] fix(uninstall): supersede deployed releases This ensures that when `helm uninstall` is run with `--keep-history` any release in a `deployed` state other than the last release (e.g. due to a failed upgrade) is being marked as `superseded`. As a by-effect, running `helm upgrade` on a release which has been uninstalled after an upgrade failure now no longer works. But instead fails with a `"" has no deployed releases` error. Which is the (likely) intended behavior, and prevents other side-effects like rolling back to a release version which happened before the uninstall if `--atomic` (or `--rollback-on-failure`) was provided. Signed-off-by: Hidde Beydals (cherry picked from commit 2f1ecc7100868be90d302a299d707c70a7f45276) --- .../uninstall-keep-history-earlier-deployed.txt | 1 + cmd/helm/uninstall_test.go | 9 +++++++++ pkg/action/uninstall.go | 14 ++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 cmd/helm/testdata/output/uninstall-keep-history-earlier-deployed.txt diff --git a/cmd/helm/testdata/output/uninstall-keep-history-earlier-deployed.txt b/cmd/helm/testdata/output/uninstall-keep-history-earlier-deployed.txt new file mode 100644 index 000000000..f5454b88d --- /dev/null +++ b/cmd/helm/testdata/output/uninstall-keep-history-earlier-deployed.txt @@ -0,0 +1 @@ +release "aeneas" uninstalled diff --git a/cmd/helm/uninstall_test.go b/cmd/helm/uninstall_test.go index 23b61058e..129362ce2 100644 --- a/cmd/helm/uninstall_test.go +++ b/cmd/helm/uninstall_test.go @@ -57,6 +57,15 @@ func TestUninstall(t *testing.T) { golden: "output/uninstall-keep-history.txt", rels: []*release.Release{release.Mock(&release.MockReleaseOptions{Name: "aeneas"})}, }, + { + name: "keep history with earlier deployed release", + cmd: "uninstall aeneas --keep-history", + golden: "output/uninstall-keep-history-earlier-deployed.txt", + rels: []*release.Release{ + release.Mock(&release.MockReleaseOptions{Name: "aeneas", Version: 1, Status: release.StatusDeployed}), + release.Mock(&release.MockReleaseOptions{Name: "aeneas", Version: 2, Status: release.StatusFailed}), + }, + }, { name: "wait", cmd: "uninstall aeneas --wait", diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go index ac0c4fee8..c30cb65e2 100644 --- a/pkg/action/uninstall.go +++ b/pkg/action/uninstall.go @@ -28,6 +28,7 @@ import ( "helm.sh/helm/v3/pkg/kube" "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/releaseutil" + "helm.sh/helm/v3/pkg/storage/driver" helmtime "helm.sh/helm/v3/pkg/time" ) @@ -170,6 +171,19 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error) u.cfg.Log("uninstall: Failed to store updated release: %s", err) } + // Supersede all previous deployments, see issue #12556 (which is a + // variation on #2941). + deployed, err := u.cfg.Releases.DeployedAll(name) + if err != nil && !errors.Is(err, driver.ErrNoDeployedReleases) { + return nil, err + } + for _, reli := range deployed { + reli.Info.Status = release.StatusSuperseded + if err = u.cfg.Releases.Update(reli); err != nil { + u.cfg.Log("uninstall: Failed to store updated release: %s", err) + } + } + if len(errs) > 0 { return res, errors.Errorf("uninstallation completed with %d error(s): %s", len(errs), joinErrors(errs)) } From 0cd9a60723d2fde199a625582ff068f5a253886c Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Mon, 13 Nov 2023 22:02:07 +0100 Subject: [PATCH 2/2] fix(rollback): `errors.Is` instead of string comp Signed-off-by: Hidde Beydals (cherry picked from commit d158708fbfb08bc452d1733d9b8cc4c7dc9f8902) --- pkg/action/rollback.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index b0be17d13..fcaaab177 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -26,6 +26,7 @@ import ( "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/storage/driver" helmtime "helm.sh/helm/v3/pkg/time" ) @@ -249,7 +250,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas } deployed, err := r.cfg.Releases.DeployedAll(currentRelease.Name) - if err != nil && !strings.Contains(err.Error(), "has no deployed releases") { + if err != nil && !errors.Is(err, driver.ErrNoDeployedReleases) { return nil, err } // Supersede all previous deployments, see issue #2941.