From ee8ea507a6c33eb0ce288059856c37fdee88f4d0 Mon Sep 17 00:00:00 2001 From: KUOKA Yusuke Date: Thu, 23 Jul 2020 01:09:36 +0900 Subject: [PATCH] Add pre/postuninstall hooks (#1375) Exmple: ``` releases: - name: test2 chart: stable/mysql installed: false hooks: - events: - prepare - preuninstall - postuninstall - cleanup showlogs: true command: "echo" args: - "event name = {{` {{ .Event.Name `}} }}" ``` Output: ``` helmfile apply Listing releases matching ^test2$ test2 default 1 2020-07-23 00:51:44.975478 +0900 JST deployed mysql-1.6.6 5.7.30 helmfile.yaml: basePath=. hook[preuninstall] logs | event name = preuninstall hook[preuninstall] logs | Deleting test2 release "test2" uninstalled helmfile.yaml: basePath=. hook[postuninstall] logs | event name = postuninstall hook[postuninstall] logs | helmfile.yaml: basePath=. hook[cleanup] logs | event name = cleanup hook[cleanup] logs | DELETED RELEASES: NAME test2 ``` Resolves #802 --- README.md | 12 ++++++++++-- pkg/state/state.go | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 94269720..f5ea456d 100644 --- a/README.md +++ b/README.md @@ -957,6 +957,8 @@ Currently supported `events` are: - `prepare` - `presync` +- `preuninstall` +- `postuninstall` - `postsync` - `cleanup` @@ -964,9 +966,15 @@ Hooks associated to `prepare` events are triggered after each release in your he Hooks associated to `cleanup` events are triggered after each release is processed. -Hooks associated to `presync` events are triggered before each release is applied to the remote cluster. This is the ideal event to execute any commands that may mutate the cluster state as it will not be run for read-only operations like `lint`, `diff` or `template`. +Hooks associated to `presync` events are triggered before each release is applied to the remote cluster. +This is the ideal event to execute any commands that may mutate the cluster state as it will not be run for read-only operations like `lint`, `diff` or `template`. -Hooks associated to `postsync` events are triggered after each release is applied to the remote cluster. This is the ideal event to execute any commands that may mutate the cluster state as it will not be run for read-only operations like `lint`, `diff` or `template`. +`preuninstall` hooks are triggered immediately before a release is uninstalled as part of `helmfile apply`, `helmfile sync`, `helmfile delete`, and `helmfile destroy`. + +Hooks associated to `postsync` events are triggered after each release is applied to the remote cluster. +This is the ideal event to execute any commands that may mutate the cluster state as it will not be run for read-only operations like `lint`, `diff` or `template`. + +`postuninstall` hooks are triggered immediately after successful uninstall of a release while running `helmfile apply`, `helmfile sync`, `helmfile delete`, `helmfile destroy`. The following is an example hook that just prints the contextual information provided to hook: diff --git a/pkg/state/state.go b/pkg/state/state.go index 47893a99..aa717f3e 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "errors" "fmt" - "github.com/variantdev/chartify" "io" "io/ioutil" "os" @@ -19,6 +18,8 @@ import ( "sync" "text/template" + "github.com/variantdev/chartify" + "github.com/roboll/helmfile/pkg/environment" "github.com/roboll/helmfile/pkg/event" "github.com/roboll/helmfile/pkg/helmexec" @@ -547,8 +548,13 @@ func (st *HelmState) DeleteReleasesForSync(affectedReleases *AffectedReleases, h } deletionFlags := st.appendConnectionFlags(args, release) m.Lock() - - if err := helm.DeleteRelease(context, release.Name, deletionFlags...); err != nil { + if _, err := st.triggerReleaseEvent("preuninstall", nil, release, "sync"); err != nil { + affectedReleases.Failed = append(affectedReleases.Failed, release) + relErr = newReleaseFailedError(release, err) + } else if err := helm.DeleteRelease(context, release.Name, deletionFlags...); err != nil { + affectedReleases.Failed = append(affectedReleases.Failed, release) + relErr = newReleaseFailedError(release, err) + } else if _, err := st.triggerReleaseEvent("postuninstall", nil, release, "sync"); err != nil { affectedReleases.Failed = append(affectedReleases.Failed, release) relErr = newReleaseFailedError(release, err) } else { @@ -652,8 +658,13 @@ func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helme } deletionFlags := st.appendConnectionFlags(args, release) m.Lock() - - if err := helm.DeleteRelease(context, release.Name, deletionFlags...); err != nil { + if _, err := st.triggerReleaseEvent("preuninstall", nil, release, "sync"); err != nil { + affectedReleases.Failed = append(affectedReleases.Failed, release) + relErr = newReleaseFailedError(release, err) + } else if err := helm.DeleteRelease(context, release.Name, deletionFlags...); err != nil { + affectedReleases.Failed = append(affectedReleases.Failed, release) + relErr = newReleaseFailedError(release, err) + } else if _, err := st.triggerReleaseEvent("postuninstall", nil, release, "sync"); err != nil { affectedReleases.Failed = append(affectedReleases.Failed, release) relErr = newReleaseFailedError(release, err) } else { @@ -1309,13 +1320,24 @@ func (st *HelmState) DeleteReleases(affectedReleases *AffectedReleases, helm hel } context := st.createHelmContext(&release, workerIndex) + if _, err := st.triggerReleaseEvent("preuninstall", nil, &release, "delete"); err != nil { + affectedReleases.Failed = append(affectedReleases.Failed, &release) + + return err + } + if err := helm.DeleteRelease(context, release.Name, flags...); err != nil { affectedReleases.Failed = append(affectedReleases.Failed, &release) return err - } else { - affectedReleases.Deleted = append(affectedReleases.Deleted, &release) - return nil } + + if _, err := st.triggerReleaseEvent("postuninstall", nil, &release, "delete"); err != nil { + affectedReleases.Failed = append(affectedReleases.Failed, &release) + return err + } + + affectedReleases.Deleted = append(affectedReleases.Deleted, &release) + return nil }) }