From 2d47c581b063bb60a792e0e424a2a926f5b83708 Mon Sep 17 00:00:00 2001 From: suzaku Date: Mon, 8 Apr 2024 14:54:34 +0800 Subject: [PATCH] fix #8127, allow uninstall to keep resources As discussed in #8127, this can be handy when migrating Helm-managed resources to ArgoCD. Signed-off-by: suzaku --- cmd/helm/uninstall.go | 1 + pkg/action/uninstall.go | 35 ++++++++++++++++++++++------------- pkg/action/uninstall_test.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/cmd/helm/uninstall.go b/cmd/helm/uninstall.go index 9ced8fef0..34e6d6455 100644 --- a/cmd/helm/uninstall.go +++ b/cmd/helm/uninstall.go @@ -76,6 +76,7 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation") f.BoolVar(&client.IgnoreNotFound, "ignore-not-found", false, `Treat "release not found" as a successful uninstall`) f.BoolVar(&client.KeepHistory, "keep-history", false, "remove all associated resources and mark the release as deleted, but retain the release history") + f.BoolVar(&client.KeepResources, "keep-resources", false, "Only mark the release as deleted, but keep all associated resources") f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all the resources are deleted before returning. It will wait for as long as --timeout") f.StringVar(&client.DeletionPropagation, "cascade", "background", "Must be \"background\", \"orphan\", or \"foreground\". Selects the deletion cascading strategy for the dependents. Defaults to background.") f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go index 40d82243e..b82c400b5 100644 --- a/pkg/action/uninstall.go +++ b/pkg/action/uninstall.go @@ -41,6 +41,7 @@ type Uninstall struct { DryRun bool IgnoreNotFound bool KeepHistory bool + KeepResources bool Wait bool DeletionPropagation string Timeout time.Duration @@ -119,23 +120,31 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error) u.cfg.Log("uninstall: Failed to store updated release: %s", err) } - deletedResources, kept, errs := u.deleteRelease(rel) - if errs != nil { - u.cfg.Log("uninstall: Failed to delete release: %s", errs) - return nil, errors.Errorf("failed to delete release: %s", name) - } + var errs []error - if kept != "" { - kept = "These resources were kept due to the resource policy:\n" + kept - } - res.Info = kept + if !u.KeepResources { + var deletedResources kube.ResourceList + var kept string + deletedResources, kept, errs = u.deleteRelease(rel) + if errs != nil { + u.cfg.Log("uninstall: Failed to delete release: %s", errs) + return nil, errors.Errorf("failed to delete release: %s", name) + } - if u.Wait { - if kubeClient, ok := u.cfg.KubeClient.(kube.InterfaceExt); ok { - if err := kubeClient.WaitForDelete(deletedResources, u.Timeout); err != nil { - errs = append(errs, err) + if kept != "" { + kept = "These resources were kept due to the resource policy:\n" + kept + } + res.Info = kept + + if u.Wait { + if kubeClient, ok := u.cfg.KubeClient.(kube.InterfaceExt); ok { + if err := kubeClient.WaitForDelete(deletedResources, u.Timeout); err != nil { + errs = append(errs, err) + } } } + } else { + res.Info = "Associated resources were kept because --keep-resources was set" } if !u.DisableHooks { diff --git a/pkg/action/uninstall_test.go b/pkg/action/uninstall_test.go index 869ffb8c7..0c44c39ba 100644 --- a/pkg/action/uninstall_test.go +++ b/pkg/action/uninstall_test.go @@ -76,6 +76,34 @@ func TestUninstallRelease_deleteRelease(t *testing.T) { is.Contains(res.Info, expected) } +func TestUninstallRelease_keepResources(t *testing.T) { + is := assert.New(t) + + unAction := uninstallAction(t) + unAction.DisableHooks = true + unAction.DryRun = false + unAction.KeepResources = true + + rel := releaseStub() + rel.Name = "keep-resources" + rel.Manifest = `{ + "apiVersion": "v1", + "kind": "Secret", + "metadata": { + "name": "secret", + }, + "type": "Opaque", + "data": { + "password": "password" + } + }` + unAction.cfg.Releases.Create(rel) + res, err := unAction.Run(rel.Name) + is.NoError(err) + expected := "Associated resources were kept because --keep-resources was set" + is.Contains(res.Info, expected) +} + func TestUninstallRelease_Wait(t *testing.T) { is := assert.New(t)