Add global hooks (#1301)
Changes: * Add global hooks * Add top level hooks field to yaml spec * Add functions for global prepare and cleanup events * Call global prepare and cleanup events in withPreparedCharts function * Update README * Add helmfileCommand variable to withPreparedCharts Pass the information on what helmfileCommand has been run down from the top level functions through withReposAndPreparedCharts and withPreparedCharts.
This commit is contained in:
parent
0f86cc9b87
commit
f16d96bc8f
13
README.md
13
README.md
|
|
@ -983,6 +983,19 @@ Now, replace `echo` with any command you like, and rewrite `args` that actually
|
|||
For templating, imagine that you created a hook that generates a helm chart on-the-fly by running an external tool like ksonnet, kustomize, or your own template engine.
|
||||
It will allow you to write your helm releases with any language you like, while still leveraging goodies provided by helm.
|
||||
|
||||
### Global Hooks
|
||||
In contrast to the per release hooks mentioned above these are run only once at the very beginning and end of the execution of a helmfile command and only the `prepare` and `cleanup` hooks are available respectively.
|
||||
|
||||
They use the same syntax as per release hooks, but at the top level of your helmfile:
|
||||
``` yaml
|
||||
hooks:
|
||||
- events: ["prepare", "cleanup"]
|
||||
showlogs: true
|
||||
command: "echo"
|
||||
args: ["{{`{{.Environment.Name}}`}}", "{{`{{.Release.Name}}`}}", "{{`{{.HelmfileCommand}}`}}\
|
||||
"]
|
||||
```
|
||||
|
||||
### Helmfile + Kustomize
|
||||
|
||||
Do you prefer `kustomize` to write and organize your Kubernetes apps, but still want to leverage helm's useful features
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ func Init(app *App) *App {
|
|||
|
||||
func (a *App) Deps(c DepsConfigProvider) error {
|
||||
return a.ForEachStateFiltered(func(run *Run) (errs []error) {
|
||||
prepErrs := run.withReposAndPreparedCharts(false, c.SkipRepos(), func() {
|
||||
prepErrs := run.withReposAndPreparedCharts(false, c.SkipRepos(), "deps", func() {
|
||||
errs = run.Deps(c)
|
||||
})
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ func (a *App) Deps(c DepsConfigProvider) error {
|
|||
|
||||
func (a *App) Repos(c ReposConfigProvider) error {
|
||||
return a.ForEachStateFiltered(func(run *Run) (errs []error) {
|
||||
err := run.withPreparedCharts(false, func() {
|
||||
err := run.withPreparedCharts(false, "repos", func() {
|
||||
errs = run.Repos(c)
|
||||
})
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ func (a *App) Repos(c ReposConfigProvider) error {
|
|||
|
||||
func (a *App) DeprecatedSyncCharts(c DeprecatedChartsConfigProvider) error {
|
||||
return a.ForEachStateFiltered(func(run *Run) (errs []error) {
|
||||
err := run.withPreparedCharts(false, func() {
|
||||
err := run.withPreparedCharts(false, "charts", func() {
|
||||
errs = run.DeprecatedSyncCharts(c)
|
||||
})
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ func (a *App) Diff(c DiffConfigProvider) error {
|
|||
|
||||
var errs []error
|
||||
|
||||
prepErrs := run.withReposAndPreparedCharts(false, c.SkipDeps(), func() {
|
||||
prepErrs := run.withReposAndPreparedCharts(false, c.SkipDeps(), "diff", func() {
|
||||
msg, matched, affected, errs = run.Diff(c)
|
||||
})
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ func (a *App) Diff(c DiffConfigProvider) error {
|
|||
|
||||
func (a *App) Template(c TemplateConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
prepErrs := run.withReposAndPreparedCharts(true, c.SkipDeps(), func() {
|
||||
prepErrs := run.withReposAndPreparedCharts(true, c.SkipDeps(), "template", func() {
|
||||
ok, errs = a.template(run, c)
|
||||
})
|
||||
|
||||
|
|
@ -216,7 +216,7 @@ func (a *App) Template(c TemplateConfigProvider) error {
|
|||
|
||||
func (a *App) Lint(c LintConfigProvider) error {
|
||||
return a.ForEachStateFiltered(func(run *Run) (errs []error) {
|
||||
prepErrs := run.withReposAndPreparedCharts(true, c.SkipDeps(), func() {
|
||||
prepErrs := run.withReposAndPreparedCharts(true, c.SkipDeps(), "lint", func() {
|
||||
errs = run.Lint(c)
|
||||
})
|
||||
|
||||
|
|
@ -228,7 +228,7 @@ func (a *App) Lint(c LintConfigProvider) error {
|
|||
|
||||
func (a *App) Sync(c SyncConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
prepErrs := run.withReposAndPreparedCharts(false, c.SkipDeps(), func() {
|
||||
prepErrs := run.withReposAndPreparedCharts(false, c.SkipDeps(), "sync", func() {
|
||||
ok, errs = a.sync(run, c)
|
||||
})
|
||||
|
||||
|
|
@ -248,7 +248,7 @@ func (a *App) Apply(c ApplyConfigProvider) error {
|
|||
opts = append(opts, SetRetainValuesFiles(c.RetainValuesFiles()))
|
||||
|
||||
err := a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
prepErrs := run.withReposAndPreparedCharts(false, c.SkipDeps(), func() {
|
||||
prepErrs := run.withReposAndPreparedCharts(false, c.SkipDeps(), "apply", func() {
|
||||
matched, updated, es := a.apply(run, c)
|
||||
|
||||
mut.Lock()
|
||||
|
|
@ -278,7 +278,7 @@ func (a *App) Apply(c ApplyConfigProvider) error {
|
|||
|
||||
func (a *App) Status(c StatusesConfigProvider) error {
|
||||
return a.ForEachStateFiltered(func(run *Run) (errs []error) {
|
||||
err := run.withPreparedCharts(false, func() {
|
||||
err := run.withPreparedCharts(false, "status", func() {
|
||||
errs = run.Status(c)
|
||||
})
|
||||
|
||||
|
|
@ -292,7 +292,7 @@ func (a *App) Status(c StatusesConfigProvider) error {
|
|||
|
||||
func (a *App) Delete(c DeleteConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
err := run.withPreparedCharts(false, func() {
|
||||
err := run.withPreparedCharts(false, "delete", func() {
|
||||
ok, errs = a.delete(run, c.Purge(), c)
|
||||
})
|
||||
|
||||
|
|
@ -306,7 +306,7 @@ func (a *App) Delete(c DeleteConfigProvider) error {
|
|||
|
||||
func (a *App) Destroy(c DestroyConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
err := run.withPreparedCharts(false, func() {
|
||||
err := run.withPreparedCharts(false, "destroy", func() {
|
||||
ok, errs = a.delete(run, true, c)
|
||||
})
|
||||
|
||||
|
|
@ -326,7 +326,7 @@ func (a *App) Test(c TestConfigProvider) error {
|
|||
"or set helm.sh/hook-delete-policy\n")
|
||||
}
|
||||
|
||||
err := run.withPreparedCharts(false, func() {
|
||||
err := run.withPreparedCharts(false, "test", func() {
|
||||
errs = run.Test(c)
|
||||
})
|
||||
|
||||
|
|
@ -340,7 +340,7 @@ func (a *App) Test(c TestConfigProvider) error {
|
|||
|
||||
func (a *App) PrintState(c StateConfigProvider) error {
|
||||
return a.VisitDesiredStatesWithReleasesFiltered(a.FileOrDir, func(st *state.HelmState) (errs []error) {
|
||||
err := NewRun(st, nil, NewContext()).withPreparedCharts(false, func() {
|
||||
err := NewRun(st, nil, NewContext()).withPreparedCharts(false, "build", func() {
|
||||
state, err := st.ToYaml()
|
||||
if err != nil {
|
||||
errs = []error{err}
|
||||
|
|
@ -363,7 +363,7 @@ func (a *App) ListReleases(c ListConfigProvider) error {
|
|||
var releases []*HelmRelease
|
||||
|
||||
err := a.VisitDesiredStatesWithReleasesFiltered(a.FileOrDir, func(st *state.HelmState) []error {
|
||||
err := NewRun(st, nil, NewContext()).withPreparedCharts(false, func() {
|
||||
err := NewRun(st, nil, NewContext()).withPreparedCharts(false, "list", func() {
|
||||
|
||||
//var releases m
|
||||
for _, r := range st.Releases {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func (r *Run) askForConfirmation(msg string) bool {
|
|||
return AskForConfirmation(msg)
|
||||
}
|
||||
|
||||
func (r *Run) withReposAndPreparedCharts(forceDownload bool, skipRepos bool, f func()) []error {
|
||||
func (r *Run) withReposAndPreparedCharts(forceDownload bool, skipRepos bool, helmfileCommand string, f func()) []error {
|
||||
if !skipRepos {
|
||||
ctx := r.ctx
|
||||
if errs := ctx.SyncReposOnce(r.state, r.helm); errs != nil && len(errs) > 0 {
|
||||
|
|
@ -40,14 +40,14 @@ func (r *Run) withReposAndPreparedCharts(forceDownload bool, skipRepos bool, f f
|
|||
}
|
||||
}
|
||||
|
||||
if err := r.withPreparedCharts(forceDownload, f); err != nil {
|
||||
if err := r.withPreparedCharts(forceDownload, helmfileCommand, f); err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Run) withPreparedCharts(forceDownload bool, f func()) error {
|
||||
func (r *Run) withPreparedCharts(forceDownload bool, helmfileCommand string, f func()) error {
|
||||
if r.ReleaseToChart != nil {
|
||||
panic("Run.PrepareCharts can be called only once")
|
||||
}
|
||||
|
|
@ -59,7 +59,11 @@ func (r *Run) withPreparedCharts(forceDownload bool, f func()) error {
|
|||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
releaseToChart, errs := state.PrepareCharts(r.helm, r.state, dir, 2, "template", forceDownload)
|
||||
if _, err = r.state.TriggerGlobalPrepareEvent(helmfileCommand); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
releaseToChart, errs := state.PrepareCharts(r.helm, r.state, dir, 2, helmfileCommand, forceDownload)
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%v", errs)
|
||||
|
|
@ -75,7 +79,9 @@ func (r *Run) withPreparedCharts(forceDownload bool, f func()) error {
|
|||
|
||||
f()
|
||||
|
||||
return nil
|
||||
_, err = r.state.TriggerGlobalCleanupEvent(helmfileCommand)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Run) Deps(c DepsConfigProvider) []error {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ type HelmState struct {
|
|||
Selectors []string `yaml:"-"`
|
||||
ApiVersions []string `yaml:"apiVersions,omitempty"`
|
||||
|
||||
// Hooks is a list of extension points paired with operations, that are executed in specific points of the lifecycle of releases defined in helmfile
|
||||
Hooks []event.Hook `yaml:"hooks,omitempty"`
|
||||
|
||||
Templates map[string]TemplateSpec `yaml:"templates"`
|
||||
|
||||
Env environment.Environment `yaml:"-"`
|
||||
|
|
@ -1441,6 +1444,30 @@ func (st *HelmState) PrepareReleases(helm helmexec.Interface, helmfileCommand st
|
|||
return nil
|
||||
}
|
||||
|
||||
func (st *HelmState) TriggerGlobalPrepareEvent(helmfileCommand string) (bool, error) {
|
||||
return st.triggerGlobalReleaseEvent("prepare", nil, helmfileCommand)
|
||||
}
|
||||
|
||||
func (st *HelmState) TriggerGlobalCleanupEvent(helmfileCommand string) (bool, error) {
|
||||
return st.triggerGlobalReleaseEvent("cleanup", nil, helmfileCommand)
|
||||
}
|
||||
|
||||
func (st *HelmState) triggerGlobalReleaseEvent(evt string, evtErr error, helmfileCmd string) (bool, error) {
|
||||
bus := &event.Bus{
|
||||
Hooks: st.Hooks,
|
||||
StateFilePath: st.FilePath,
|
||||
BasePath: st.basePath,
|
||||
Namespace: st.OverrideNamespace,
|
||||
Env: st.Env,
|
||||
Logger: st.logger,
|
||||
ReadFile: st.readFile,
|
||||
}
|
||||
data := map[string]interface{}{
|
||||
"HelmfileCommand": helmfileCmd,
|
||||
}
|
||||
return bus.Trigger(evt, evtErr, data)
|
||||
}
|
||||
|
||||
func (st *HelmState) triggerPrepareEvent(r *ReleaseSpec, helmfileCommand string) (bool, error) {
|
||||
return st.triggerReleaseEvent("prepare", nil, r, helmfileCommand)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue