diff --git a/pkg/action/hooks.go b/pkg/action/hooks.go index c2faf6e1a..21321bd84 100644 --- a/pkg/action/hooks.go +++ b/pkg/action/hooks.go @@ -66,6 +66,7 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, StartedAt: helmtime.Now(), Phase: release.HookPhaseRunning, } + cfg.recordRelease(rl) // As long as the implementation of WatchUntilReady does not panic, HookPhaseFailed or HookPhaseSucceeded // should always be set by this function. If we fail to do that for any reason, then HookPhaseUnknown is @@ -96,6 +97,8 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, h.LastRun.Phase = release.HookPhaseSucceeded } + cfg.recordRelease(rl) + // If all hooks are successful, check the annotation of each hook to determine whether the hook should be deleted // under succeeded condition. If so, then clear the corresponding resource object in each hook for _, h := range executingHooks { diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go index 40d82243e..0b002f037 100644 --- a/pkg/action/uninstall.go +++ b/pkg/action/uninstall.go @@ -100,9 +100,6 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error) } u.cfg.Log("uninstall: Deleting %s", name) - rel.Info.Status = release.StatusUninstalling - rel.Info.Deleted = helmtime.Now() - rel.Info.Description = "Deletion in progress (or silently failed)" res := &release.UninstallReleaseResponse{Release: rel} if !u.DisableHooks { @@ -115,6 +112,10 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error) // From here on out, the release is currently considered to be in StatusUninstalling // state. + rel.Info.Status = release.StatusUninstalling + rel.Info.Deleted = helmtime.Now() + rel.Info.Description = "Deletion in progress (or silently failed)" + if err := u.cfg.Releases.Update(rel); err != nil { u.cfg.Log("uninstall: Failed to store updated release: %s", err) } diff --git a/pkg/action/uninstall_test.go b/pkg/action/uninstall_test.go index 869ffb8c7..9caa02d92 100644 --- a/pkg/action/uninstall_test.go +++ b/pkg/action/uninstall_test.go @@ -24,14 +24,86 @@ import ( kubefake "helm.sh/helm/v3/pkg/kube/fake" "helm.sh/helm/v3/pkg/release" + rspb "helm.sh/helm/v3/pkg/release" ) func uninstallAction(t *testing.T) *Uninstall { config := actionConfigFixture(t) + unAction := NewUninstall(config) return unAction } +func getPreDeleteRelease(exitCode uint8) *rspb.Release { + rel := releaseStub() + rel.Name = "chart-with-pre-delete-hook" + rel.Manifest = fmt.Sprintf(`{ + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "release-name-assert-job", + "labels": { + "app.kubernetes.io/managed-by": "service", + "app.kubernetes.io/instance": "release-name", + "app.kubernetes.io/version": "1.0.0", + "helm.sh/chart": "pre-delete-hook-chart" + }, + "annotations": { + "helm.sh/hook": "pre-delete", + "helm.sh/hook-weight": "5", + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded" + } + }, + "spec": { + "restartPolicy": "Never", + "containers": [ + { + "name": "assert-chart-removal", + "image": "alpine:latest", + "command": [ + "/bin/ash" + ], + "args": [ + "-c", + "#!/bin/ash\nexit %v\n" + ] + } + ] + } + }`, exitCode) + + return rel +} + +func uninstallWithPreDeleteHookSetup(t *testing.T, shouldError bool) ([]*rspb.Release, *assert.Assertions) { + unAction := uninstallAction(t) + kc, ok := unAction.cfg.KubeClient.(*kubefake.FailingKubeClient) + if !ok { + t.Fatalf("Failed casting KubeClient to FailingKubeClient") + } + + if shouldError { + kc.CreateError = fmt.Errorf("Could not delete Pod") + } + + var errorCode uint8 = 0 + + if shouldError { + errorCode = 0 + } + rel := getPreDeleteRelease(uint8(errorCode)) + unAction.cfg.Releases.Create(rel) + unAction.Run(rel.Name) + + rels, _ := unAction.cfg.Releases.List(func(rl *rspb.Release) bool { + return rl.Info.Status == release.StatusDeployed + }) + + is := assert.New(t) + + return rels, is +} + func TestUninstallRelease_ignoreNotFound(t *testing.T) { unAction := uninstallAction(t) unAction.DryRun = false @@ -43,6 +115,18 @@ func TestUninstallRelease_ignoreNotFound(t *testing.T) { is.NoError(err) } +func TestUninstallWithPreDeleteHookFailure(t *testing.T) { + releases, is := uninstallWithPreDeleteHookSetup(t, true) + + is.Len(releases, 1) +} + +func TestUninstallWithPreDeleteHookSuccess(t *testing.T) { + releases, is := uninstallWithPreDeleteHookSetup(t, false) + + is.Len(releases, 0) +} + func TestUninstallRelease_deleteRelease(t *testing.T) { is := assert.New(t)