Only run preapply or presync
Signed-off-by: Anton Bretting <sajfer@gmail.com>
This commit is contained in:
parent
1a3c11dffd
commit
db81f18095
|
|
@ -1330,6 +1330,7 @@ func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, bool, []error) {
|
||||||
for _, hook := range release.Hooks {
|
for _, hook := range release.Hooks {
|
||||||
if slices.Contains(hook.Events, "preapply") {
|
if slices.Contains(hook.Events, "preapply") {
|
||||||
releasesWithPreApply = append(releasesWithPreApply, release)
|
releasesWithPreApply = append(releasesWithPreApply, release)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1380,6 +1381,7 @@ Do you really want to apply?
|
||||||
a.Logger.Infof("\nRunning preapply hook for %s:", release.Name)
|
a.Logger.Infof("\nRunning preapply hook for %s:", release.Name)
|
||||||
if _, err := st.TriggerPreapplyEvent(&release, "apply"); err != nil {
|
if _, err := st.TriggerPreapplyEvent(&release, "apply"); err != nil {
|
||||||
syncErrs = append(syncErrs, err)
|
syncErrs = append(syncErrs, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,38 @@ releases:
|
||||||
labels:
|
labels:
|
||||||
app: test
|
app: test
|
||||||
hooks:
|
hooks:
|
||||||
- events: ["preapply", "presync"]
|
- events: ["prepare", "preapply", "presync"]
|
||||||
|
command: echo
|
||||||
|
showlogs: true
|
||||||
|
args: ["foo"]
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
selectors: []string{"name=foo"},
|
||||||
|
upgraded: []exectest.Release{
|
||||||
|
{Name: "foo"},
|
||||||
|
},
|
||||||
|
diffs: map[exectest.DiffKey]error{
|
||||||
|
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||||
|
},
|
||||||
|
error: "",
|
||||||
|
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
|
||||||
|
concurrency: 1,
|
||||||
|
logLevel: "info",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("apply release with preapply hook", func(t *testing.T) {
|
||||||
|
check(t, testcase{
|
||||||
|
files: map[string]string{
|
||||||
|
"/path/to/helmfile.yaml": `
|
||||||
|
releases:
|
||||||
|
- name: foo
|
||||||
|
chart: incubator/raw
|
||||||
|
namespace: default
|
||||||
|
labels:
|
||||||
|
app: test
|
||||||
|
hooks:
|
||||||
|
- events: ["presync"]
|
||||||
command: echo
|
command: echo
|
||||||
showlogs: true
|
showlogs: true
|
||||||
args: ["foo"]
|
args: ["foo"]
|
||||||
|
|
|
||||||
|
|
@ -1340,34 +1340,4 @@ foo 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
|
||||||
concurrency: 1,
|
concurrency: 1,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("apply release with preapply hook", func(t *testing.T) {
|
|
||||||
check(t, testcase{
|
|
||||||
files: map[string]string{
|
|
||||||
"/path/to/helmfile.yaml": `
|
|
||||||
releases:
|
|
||||||
- name: foo
|
|
||||||
chart: incubator/raw
|
|
||||||
namespace: default
|
|
||||||
labels:
|
|
||||||
app: test
|
|
||||||
hooks:
|
|
||||||
- events: ["preapply"]
|
|
||||||
command: echo
|
|
||||||
showlogs: true
|
|
||||||
args: ["foo"]
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
selectors: []string{"name=foo"},
|
|
||||||
upgraded: []exectest.Release{
|
|
||||||
{Name: "foo"},
|
|
||||||
},
|
|
||||||
diffs: map[exectest.DiffKey]error{
|
|
||||||
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
|
||||||
},
|
|
||||||
error: "",
|
|
||||||
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
|
|
||||||
concurrency: 1,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
processing file "helmfile.yaml" in directory "."
|
||||||
|
first-pass rendering starting for "helmfile.yaml.part.0": inherited=&{default map[] map[]}, overrode=<nil>
|
||||||
|
first-pass uses: &{default map[] map[]}
|
||||||
|
first-pass rendering output of "helmfile.yaml.part.0":
|
||||||
|
0:
|
||||||
|
1: releases:
|
||||||
|
2: - name: foo
|
||||||
|
3: chart: incubator/raw
|
||||||
|
4: namespace: default
|
||||||
|
5: labels:
|
||||||
|
6: app: test
|
||||||
|
7: hooks:
|
||||||
|
8: - events: ["preapply"]
|
||||||
|
9: command: echo
|
||||||
|
10: showlogs: true
|
||||||
|
11: args: ["foo"]
|
||||||
|
12:
|
||||||
|
|
||||||
|
first-pass produced: &{default map[] map[]}
|
||||||
|
first-pass rendering result of "helmfile.yaml.part.0": {default map[] map[]}
|
||||||
|
vals:
|
||||||
|
map[]
|
||||||
|
defaultVals:[]
|
||||||
|
second-pass rendering result of "helmfile.yaml.part.0":
|
||||||
|
0:
|
||||||
|
1: releases:
|
||||||
|
2: - name: foo
|
||||||
|
3: chart: incubator/raw
|
||||||
|
4: namespace: default
|
||||||
|
5: labels:
|
||||||
|
6: app: test
|
||||||
|
7: hooks:
|
||||||
|
8: - events: ["preapply"]
|
||||||
|
9: command: echo
|
||||||
|
10: showlogs: true
|
||||||
|
11: args: ["foo"]
|
||||||
|
12:
|
||||||
|
|
||||||
|
merged environment: &{default map[] map[]}
|
||||||
|
1 release(s) matching name=foo found in helmfile.yaml
|
||||||
|
|
||||||
|
Affected releases are:
|
||||||
|
foo (incubator/raw) UPDATED
|
||||||
|
Releases with preapply hooks:
|
||||||
|
foo (incubator/raw)
|
||||||
|
|
||||||
|
Running preapply hook for foo:
|
||||||
|
hook[echo]: stateFilePath=helmfile.yaml, basePath=.
|
||||||
|
hook[echo]: triggered by event "preapply"
|
||||||
|
|
||||||
|
echo:XlBWj> foo
|
||||||
|
hook[echo]: foo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
hook[preapply] logs | foo
|
||||||
|
hook[preapply] logs |
|
||||||
|
processing 1 groups of releases in this order:
|
||||||
|
GROUP RELEASES
|
||||||
|
1 default/default/foo
|
||||||
|
|
||||||
|
processing releases in group 1/1: default/default/foo
|
||||||
|
getting deployed release version failed:unexpected list key: {^foo$ --kube-contextdefault--deleting--deployed--failed--pending}
|
||||||
|
|
||||||
|
UPDATED RELEASES:
|
||||||
|
NAME CHART VERSION
|
||||||
|
foo incubator/raw
|
||||||
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
|
|
||||||
|
hook[prepare] logs | foo
|
||||||
|
hook[prepare] logs |
|
||||||
|
|
||||||
Running preapply hook for foo:
|
Running preapply hook for foo:
|
||||||
|
|
||||||
hook[preapply] logs | foo
|
hook[preapply] logs | foo
|
||||||
hook[preapply] logs |
|
hook[preapply] logs |
|
||||||
|
hook[echo]: already executed by "preapply", skipping "presync"
|
||||||
|
|
||||||
|
|
||||||
UPDATED RELEASES:
|
UPDATED RELEASES:
|
||||||
NAME CHART VERSION
|
NAME CHART VERSION
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
hook[presync] logs | foo
|
||||||
|
hook[presync] logs |
|
||||||
|
|
||||||
|
UPDATED RELEASES:
|
||||||
|
NAME CHART VERSION
|
||||||
|
foo incubator/raw
|
||||||
|
|
||||||
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||||
"github.com/helmfile/helmfile/pkg/helmexec"
|
"github.com/helmfile/helmfile/pkg/helmexec"
|
||||||
"github.com/helmfile/helmfile/pkg/tmpl"
|
"github.com/helmfile/helmfile/pkg/tmpl"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Hook struct {
|
type Hook struct {
|
||||||
|
|
@ -19,6 +21,7 @@ type Hook struct {
|
||||||
Kubectl map[string]string `yaml:"kubectlApply,omitempty"`
|
Kubectl map[string]string `yaml:"kubectlApply,omitempty"`
|
||||||
Args []string `yaml:"args"`
|
Args []string `yaml:"args"`
|
||||||
ShowLogs bool `yaml:"showlogs"`
|
ShowLogs bool `yaml:"showlogs"`
|
||||||
|
Executed bool `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type event struct {
|
type event struct {
|
||||||
|
|
@ -71,6 +74,10 @@ func (bus *Bus) Trigger(evt string, evtErr error, context map[string]interface{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if slices.Contains(hook.Events, "preapply") && evt == "presync" && hook.Executed {
|
||||||
|
bus.Logger.Infof("hook[%s]: already executed by \"preapply\", skipping \"%s\"\n", name, evt)
|
||||||
|
continue
|
||||||
|
}
|
||||||
if hook.Kubectl != nil {
|
if hook.Kubectl != nil {
|
||||||
if hook.Command != "" {
|
if hook.Command != "" {
|
||||||
bus.Logger.Warnf("warn: ignoring command '%s' given within a kubectlApply hook", hook.Command)
|
bus.Logger.Warnf("warn: ignoring command '%s' given within a kubectlApply hook", hook.Command)
|
||||||
|
|
|
||||||
|
|
@ -41,21 +41,21 @@ func TestTrigger(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"okhook1",
|
"okhook1",
|
||||||
&Hook{"okhook1", []string{"foo"}, "ok", nil, []string{}, true},
|
&Hook{"okhook1", []string{"foo"}, "ok", nil, []string{}, true, false},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"okhooké",
|
"okhooké",
|
||||||
&Hook{"okhook2", []string{"foo"}, "ok", nil, []string{}, false},
|
&Hook{"okhook2", []string{"foo"}, "ok", nil, []string{}, false, false},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"missinghook1",
|
"missinghook1",
|
||||||
&Hook{"okhook1", []string{"foo"}, "ok", nil, []string{}, false},
|
&Hook{"okhook1", []string{"foo"}, "ok", nil, []string{}, false, false},
|
||||||
"bar",
|
"bar",
|
||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
|
|
@ -69,70 +69,70 @@ func TestTrigger(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nghook1",
|
"nghook1",
|
||||||
&Hook{"nghook1", []string{"foo"}, "ng", nil, []string{}, false},
|
&Hook{"nghook1", []string{"foo"}, "ng", nil, []string{}, false, false},
|
||||||
"foo",
|
"foo",
|
||||||
false,
|
false,
|
||||||
"hook[nghook1]: command `ng` failed: cmd failed due to invalid cmd: ng",
|
"hook[nghook1]: command `ng` failed: cmd failed due to invalid cmd: ng",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nghook2",
|
"nghook2",
|
||||||
&Hook{"nghook2", []string{"foo"}, "ok", nil, []string{"ng"}, false},
|
&Hook{"nghook2", []string{"foo"}, "ok", nil, []string{"ng"}, false, false},
|
||||||
"foo",
|
"foo",
|
||||||
false,
|
false,
|
||||||
"hook[nghook2]: command `ok` failed: cmd failed due to invalid arg: ng",
|
"hook[nghook2]: command `ok` failed: cmd failed due to invalid arg: ng",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"okkubeapply1",
|
"okkubeapply1",
|
||||||
&Hook{"okkubeapply1", []string{"foo"}, "", map[string]string{"kustomize": "kustodir"}, []string{}, false},
|
&Hook{"okkubeapply1", []string{"foo"}, "", map[string]string{"kustomize": "kustodir"}, []string{}, false, false},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"okkubeapply2",
|
"okkubeapply2",
|
||||||
&Hook{"okkubeapply2", []string{"foo"}, "", map[string]string{"filename": "resource.yaml"}, []string{}, false},
|
&Hook{"okkubeapply2", []string{"foo"}, "", map[string]string{"filename": "resource.yaml"}, []string{}, false, false},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kokubeapply",
|
"kokubeapply",
|
||||||
&Hook{"kokubeapply", []string{"foo"}, "", map[string]string{"kustomize": "kustodir", "filename": "resource.yaml"}, []string{}, true},
|
&Hook{"kokubeapply", []string{"foo"}, "", map[string]string{"kustomize": "kustodir", "filename": "resource.yaml"}, []string{}, true, false},
|
||||||
"foo",
|
"foo",
|
||||||
false,
|
false,
|
||||||
"hook[kokubeapply]: kustomize & filename cannot be used together",
|
"hook[kokubeapply]: kustomize & filename cannot be used together",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kokubeapply2",
|
"kokubeapply2",
|
||||||
&Hook{"kokubeapply2", []string{"foo"}, "", map[string]string{}, []string{}, true},
|
&Hook{"kokubeapply2", []string{"foo"}, "", map[string]string{}, []string{}, true, false},
|
||||||
"foo",
|
"foo",
|
||||||
false,
|
false,
|
||||||
"hook[kokubeapply2]: either kustomize or filename must be given",
|
"hook[kokubeapply2]: either kustomize or filename must be given",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kokubeapply3",
|
"kokubeapply3",
|
||||||
&Hook{"", []string{"foo"}, "", map[string]string{}, []string{}, true},
|
&Hook{"", []string{"foo"}, "", map[string]string{}, []string{}, true, false},
|
||||||
"foo",
|
"foo",
|
||||||
false,
|
false,
|
||||||
"hook[kubectlApply]: either kustomize or filename must be given",
|
"hook[kubectlApply]: either kustomize or filename must be given",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"warnkubeapply1",
|
"warnkubeapply1",
|
||||||
&Hook{"warnkubeapply1", []string{"foo"}, "ok", map[string]string{"filename": "resource.yaml"}, []string{}, true},
|
&Hook{"warnkubeapply1", []string{"foo"}, "ok", map[string]string{"filename": "resource.yaml"}, []string{}, true, false},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"warnkubeapply2",
|
"warnkubeapply2",
|
||||||
&Hook{"warnkubeapply2", []string{"foo"}, "", map[string]string{"filename": "resource.yaml"}, []string{"ng"}, true},
|
&Hook{"warnkubeapply2", []string{"foo"}, "", map[string]string{"filename": "resource.yaml"}, []string{"ng"}, true, false},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"warnkubeapply3",
|
"warnkubeapply3",
|
||||||
&Hook{"warnkubeapply3", []string{"foo"}, "ok", map[string]string{"filename": "resource.yaml"}, []string{"ng"}, true},
|
&Hook{"warnkubeapply3", []string{"foo"}, "ok", map[string]string{"filename": "resource.yaml"}, []string{"ng"}, true, false},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,15 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/imdario/mergo"
|
"github.com/imdario/mergo"
|
||||||
|
"github.com/variantdev/chartify"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
|
"github.com/helmfile/helmfile/pkg/environment"
|
||||||
|
"github.com/helmfile/helmfile/pkg/event"
|
||||||
|
"github.com/helmfile/helmfile/pkg/helmexec"
|
||||||
|
"github.com/helmfile/helmfile/pkg/remote"
|
||||||
|
"github.com/helmfile/helmfile/pkg/tmpl"
|
||||||
|
|
||||||
"github.com/tatsushid/go-prettytable"
|
"github.com/tatsushid/go-prettytable"
|
||||||
"github.com/variantdev/chartify"
|
"github.com/variantdev/chartify"
|
||||||
"github.com/variantdev/vals"
|
"github.com/variantdev/vals"
|
||||||
|
|
@ -2256,6 +2265,16 @@ func (st *HelmState) TriggerPreapplyEvent(r *ReleaseSpec, helmfileCommand string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *HelmState) triggerReleaseEvent(evt string, evtErr error, r *ReleaseSpec, helmfileCmd string) (bool, error) {
|
func (st *HelmState) triggerReleaseEvent(evt string, evtErr error, r *ReleaseSpec, helmfileCmd string) (bool, error) {
|
||||||
|
|
||||||
|
var stateRelease ReleaseSpec
|
||||||
|
|
||||||
|
for id, release := range st.Releases {
|
||||||
|
if release.Name == r.Name {
|
||||||
|
stateRelease = st.Releases[id]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bus := &event.Bus{
|
bus := &event.Bus{
|
||||||
Hooks: r.Hooks,
|
Hooks: r.Hooks,
|
||||||
StateFilePath: st.FilePath,
|
StateFilePath: st.FilePath,
|
||||||
|
|
@ -2272,7 +2291,18 @@ func (st *HelmState) triggerReleaseEvent(evt string, evtErr error, r *ReleaseSpe
|
||||||
"Release": r,
|
"Release": r,
|
||||||
"HelmfileCommand": helmfileCmd,
|
"HelmfileCommand": helmfileCmd,
|
||||||
}
|
}
|
||||||
return bus.Trigger(evt, evtErr, data)
|
|
||||||
|
executed, err := bus.Trigger(evt, evtErr, data)
|
||||||
|
|
||||||
|
if executed {
|
||||||
|
for id, hook := range stateRelease.Hooks {
|
||||||
|
if slices.Contains(hook.Events, evt) {
|
||||||
|
stateRelease.Hooks[id].Executed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return executed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveDeps returns a copy of this helmfile state with the concrete chart version numbers filled in for remote chart dependencies
|
// ResolveDeps returns a copy of this helmfile state with the concrete chart version numbers filled in for remote chart dependencies
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue