commit
24810a45ae
|
|
@ -1183,6 +1183,7 @@ Once `events` are triggered, associated `hooks` are executed, by running the `co
|
|||
Currently supported `events` are:
|
||||
|
||||
- `prepare`
|
||||
- `preapply`
|
||||
- `presync`
|
||||
- `preuninstall`
|
||||
- `postuninstall`
|
||||
|
|
@ -1192,9 +1193,12 @@ Currently supported `events` are:
|
|||
Hooks associated to `prepare` events are triggered after each release in your helmfile is loaded from YAML, before execution.
|
||||
`prepare` hooks are triggered on the release as long as it is not excluded by the helmfile selector(e.g. `helmfile -l key=value`).
|
||||
|
||||
Hooks associated to `presync` events are triggered before each release is applied to the remote cluster.
|
||||
Hooks associated to `presync` events are triggered before each release is installed or upgraded on 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`.
|
||||
|
||||
`preapply` hooks are triggered before a release is uninstalled, installed, or upgraded as part of `helmfile apply`.
|
||||
This is the ideal event to hook into when you are going to use `helmfile apply` for every kind of change, and you want the hook to be called only when any kind of change is being made.
|
||||
|
||||
`preuninstall` hooks are triggered immediately before a release is uninstalled as part of `helmfile apply`, `helmfile sync`, `helmfile delete`, and `helmfile destroy`.
|
||||
|
||||
`postuninstall` hooks are triggered immediately after successful uninstall of a release while running `helmfile apply`, `helmfile sync`, `helmfile delete`, `helmfile destroy`.
|
||||
|
|
|
|||
3
go.mod
3
go.mod
|
|
@ -29,12 +29,14 @@ require (
|
|||
github.com/variantdev/vals v0.18.0
|
||||
go.uber.org/multierr v1.6.0
|
||||
go.uber.org/zap v1.23.0
|
||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gotest.tools v2.2.0+incompatible
|
||||
helm.sh/helm/v3 v3.8.1
|
||||
k8s.io/apimachinery v0.24.4
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
@ -194,7 +196,6 @@ require (
|
|||
k8s.io/client-go v0.23.4 // indirect
|
||||
k8s.io/klog/v2 v2.60.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
|
||||
oras.land/oras-go v1.1.0 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.10.1 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -1373,6 +1373,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
|
|
|||
|
|
@ -790,7 +790,7 @@ func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*sta
|
|||
go func() {
|
||||
sig := <-sigs
|
||||
|
||||
errs := []error{fmt.Errorf("Received [%s] to shutdown ", sig)}
|
||||
errs := []error{fmt.Errorf("received [%s] to shutdown ", sig)}
|
||||
_ = context{app: a, st: st, retainValues: defOpts.RetainValuesFiles}.clean(errs)
|
||||
// See http://tldp.org/LDP/abs/html/exitcodes.html
|
||||
switch sig {
|
||||
|
|
@ -1342,7 +1342,7 @@ Do you really want to apply?
|
|||
a.Logger.Debug(*infoMsg)
|
||||
}
|
||||
|
||||
applyErrs := []error{}
|
||||
var applyErrs []error
|
||||
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
|
||||
|
|
@ -1355,15 +1355,27 @@ Do you really want to apply?
|
|||
// We deleted releases by traversing the DAG in reverse order
|
||||
if len(releasesToBeDeleted) > 0 {
|
||||
_, deletionErrs := withDAG(st, helm, a.Logger, state.PlanOptions{Reverse: true, SelectedReleases: toDelete, SkipNeeds: true}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
|
||||
var rs []state.ReleaseSpec
|
||||
var (
|
||||
rs []state.ReleaseSpec
|
||||
preapplyErrors []error
|
||||
)
|
||||
|
||||
for _, r := range subst.Releases {
|
||||
release := r
|
||||
if r2, ok := releasesToBeDeleted[state.ReleaseToID(&release)]; ok {
|
||||
if _, err := st.TriggerPreapplyEvent(&r2, "apply"); err != nil {
|
||||
preapplyErrors = append(applyErrs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
rs = append(rs, r2)
|
||||
}
|
||||
}
|
||||
|
||||
if len(preapplyErrors) > 0 {
|
||||
return preapplyErrors
|
||||
}
|
||||
|
||||
subst.Releases = rs
|
||||
|
||||
return subst.DeleteReleasesForSync(&affectedReleases, helm, c.Concurrency())
|
||||
|
|
@ -1377,15 +1389,27 @@ Do you really want to apply?
|
|||
// We upgrade releases by traversing the DAG
|
||||
if len(releasesToBeUpdated) > 0 {
|
||||
_, updateErrs := withDAG(st, helm, a.Logger, state.PlanOptions{SelectedReleases: toUpdate, Reverse: false, SkipNeeds: true, IncludeTransitiveNeeds: c.IncludeTransitiveNeeds()}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
|
||||
var rs []state.ReleaseSpec
|
||||
var (
|
||||
rs []state.ReleaseSpec
|
||||
preapplyErrors []error
|
||||
)
|
||||
|
||||
for _, r := range subst.Releases {
|
||||
release := r
|
||||
if r2, ok := releasesToBeUpdated[state.ReleaseToID(&release)]; ok {
|
||||
if _, err := st.TriggerPreapplyEvent(&r2, "apply"); err != nil {
|
||||
preapplyErrors = append(applyErrs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
rs = append(rs, r2)
|
||||
}
|
||||
}
|
||||
|
||||
if len(preapplyErrors) > 0 {
|
||||
return preapplyErrors
|
||||
}
|
||||
|
||||
subst.Releases = rs
|
||||
|
||||
syncOpts := state.SyncOpts{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,485 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/variantdev/vals"
|
||||
|
||||
"github.com/helmfile/helmfile/pkg/exectest"
|
||||
"github.com/helmfile/helmfile/pkg/helmexec"
|
||||
"github.com/helmfile/helmfile/pkg/testhelper"
|
||||
)
|
||||
|
||||
func TestApply_hooks(t *testing.T) {
|
||||
type fields struct {
|
||||
skipNeeds bool
|
||||
includeNeeds bool
|
||||
includeTransitiveNeeds bool
|
||||
}
|
||||
|
||||
type testcase struct {
|
||||
fields fields
|
||||
ns string
|
||||
concurrency int
|
||||
skipDiffOnInstall bool
|
||||
error string
|
||||
files map[string]string
|
||||
selectors []string
|
||||
lists map[exectest.ListKey]string
|
||||
diffs map[exectest.DiffKey]error
|
||||
upgraded []exectest.Release
|
||||
deleted []exectest.Release
|
||||
log string
|
||||
logLevel string
|
||||
}
|
||||
|
||||
check := func(t *testing.T, tc testcase) {
|
||||
t.Helper()
|
||||
|
||||
wantUpgrades := tc.upgraded
|
||||
wantDeletes := tc.deleted
|
||||
|
||||
var helm = &exectest.Helm{
|
||||
FailOnUnexpectedList: true,
|
||||
FailOnUnexpectedDiff: true,
|
||||
Lists: tc.lists,
|
||||
Diffs: tc.diffs,
|
||||
DiffMutex: &sync.Mutex{},
|
||||
ChartsMutex: &sync.Mutex{},
|
||||
ReleasesMutex: &sync.Mutex{},
|
||||
}
|
||||
|
||||
bs := &bytes.Buffer{}
|
||||
|
||||
func() {
|
||||
t.Helper()
|
||||
|
||||
logReader, logWriter := io.Pipe()
|
||||
|
||||
logFlushed := &sync.WaitGroup{}
|
||||
// Ensure all the log is consumed into `bs` by calling `logWriter.Close()` followed by `logFlushed.Wait()`
|
||||
logFlushed.Add(1)
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(logReader)
|
||||
for scanner.Scan() {
|
||||
bs.Write(scanner.Bytes())
|
||||
bs.WriteString("\n")
|
||||
}
|
||||
logFlushed.Done()
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
// This is here to avoid data-trace on bytes buffer `bs` to capture logs
|
||||
if err := logWriter.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logFlushed.Wait()
|
||||
}()
|
||||
|
||||
logger := helmexec.NewLogger(logWriter, tc.logLevel)
|
||||
|
||||
valsRuntime, err := vals.New(vals.Options{CacheSize: 32})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error creating vals runtime: %v", err)
|
||||
}
|
||||
|
||||
app := appWithFs(&App{
|
||||
OverrideHelmBinary: DefaultHelmBinary,
|
||||
OverrideKubeContext: "default",
|
||||
Env: "default",
|
||||
Logger: logger,
|
||||
helms: map[helmKey]helmexec.Interface{
|
||||
createHelmKey("helm", "default"): helm,
|
||||
},
|
||||
valsRuntime: valsRuntime,
|
||||
}, tc.files)
|
||||
|
||||
if tc.ns != "" {
|
||||
app.Namespace = tc.ns
|
||||
}
|
||||
|
||||
if tc.selectors != nil {
|
||||
app.Selectors = tc.selectors
|
||||
}
|
||||
|
||||
syncErr := app.Apply(applyConfig{
|
||||
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
||||
concurrency: tc.concurrency,
|
||||
logger: logger,
|
||||
skipDiffOnInstall: tc.skipDiffOnInstall,
|
||||
skipNeeds: tc.fields.skipNeeds,
|
||||
includeNeeds: tc.fields.includeNeeds,
|
||||
includeTransitiveNeeds: tc.fields.includeTransitiveNeeds,
|
||||
})
|
||||
|
||||
var gotErr string
|
||||
if syncErr != nil {
|
||||
gotErr = syncErr.Error()
|
||||
}
|
||||
|
||||
if d := cmp.Diff(tc.error, gotErr); d != "" {
|
||||
t.Fatalf("unexpected error: want (-), got (+): %s", d)
|
||||
}
|
||||
|
||||
if len(wantUpgrades) > len(helm.Releases) {
|
||||
t.Fatalf("insufficient number of upgrades: got %d, want %d", len(helm.Releases), len(wantUpgrades))
|
||||
}
|
||||
|
||||
for relIdx := range wantUpgrades {
|
||||
if wantUpgrades[relIdx].Name != helm.Releases[relIdx].Name {
|
||||
t.Errorf("releases[%d].name: got %q, want %q", relIdx, helm.Releases[relIdx].Name, wantUpgrades[relIdx].Name)
|
||||
}
|
||||
for flagIdx := range wantUpgrades[relIdx].Flags {
|
||||
if wantUpgrades[relIdx].Flags[flagIdx] != helm.Releases[relIdx].Flags[flagIdx] {
|
||||
t.Errorf("releases[%d].flags[%d]: got %v, want %v", relIdx, flagIdx, helm.Releases[relIdx].Flags[flagIdx], wantUpgrades[relIdx].Flags[flagIdx])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(wantDeletes) > len(helm.Deleted) {
|
||||
t.Fatalf("insufficient number of deletes: got %d, want %d", len(helm.Deleted), len(wantDeletes))
|
||||
}
|
||||
|
||||
for relIdx := range wantDeletes {
|
||||
if wantDeletes[relIdx].Name != helm.Deleted[relIdx].Name {
|
||||
t.Errorf("releases[%d].name: got %q, want %q", relIdx, helm.Deleted[relIdx].Name, wantDeletes[relIdx].Name)
|
||||
}
|
||||
for flagIdx := range wantDeletes[relIdx].Flags {
|
||||
if wantDeletes[relIdx].Flags[flagIdx] != helm.Deleted[relIdx].Flags[flagIdx] {
|
||||
t.Errorf("releaes[%d].flags[%d]: got %v, want %v", relIdx, flagIdx, helm.Deleted[relIdx].Flags[flagIdx], wantDeletes[relIdx].Flags[flagIdx])
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if tc.log != "" {
|
||||
actual := bs.String()
|
||||
|
||||
diff, exists := testhelper.Diff(tc.log, actual, 3)
|
||||
if exists {
|
||||
t.Errorf("unexpected log:\nDIFF\n%s\nEOD", diff)
|
||||
}
|
||||
} else {
|
||||
assertEqualsToSnapshot(t, "log", bs.String())
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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: ["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
|
||||
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("hooks for no-diff release", 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:
|
||||
# only prepare and cleanup are run
|
||||
- events: ["prepare", "preapply", "presync", "cleanup"]
|
||||
command: echo
|
||||
showlogs: true
|
||||
args: ["foo"]
|
||||
`,
|
||||
},
|
||||
selectors: []string{"app=test"},
|
||||
diffs: map[exectest.DiffKey]error{
|
||||
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: nil,
|
||||
},
|
||||
error: "",
|
||||
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
|
||||
concurrency: 1,
|
||||
logLevel: "info",
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("hooks are run on enabled release", func(t *testing.T) {
|
||||
check(t, testcase{
|
||||
files: map[string]string{
|
||||
"/path/to/helmfile.yaml": `
|
||||
values:
|
||||
- bar:
|
||||
enabled: true
|
||||
|
||||
releases:
|
||||
- name: foo
|
||||
chart: incubator/raw
|
||||
namespace: default
|
||||
labels:
|
||||
app: test
|
||||
hooks:
|
||||
- events: ["prepare", "preapply", "presync"]
|
||||
command: echo
|
||||
showlogs: true
|
||||
args: ["foo"]
|
||||
- name: bar
|
||||
condition: bar.enabled
|
||||
chart: incubator/raw
|
||||
namespace: default
|
||||
labels:
|
||||
app: test
|
||||
hooks:
|
||||
- events: ["prepare", "preapply", "presync"]
|
||||
command: echo
|
||||
showlogs: true
|
||||
args: ["bar"]
|
||||
`,
|
||||
},
|
||||
selectors: []string{"app=test"},
|
||||
upgraded: []exectest.Release{
|
||||
{Name: "foo"},
|
||||
{Name: "bar"},
|
||||
},
|
||||
diffs: map[exectest.DiffKey]error{
|
||||
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
{Name: "bar", 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("hooks are not run on disabled release", func(t *testing.T) {
|
||||
check(t, testcase{
|
||||
files: map[string]string{
|
||||
"/path/to/helmfile.yaml": `
|
||||
values:
|
||||
- bar:
|
||||
enabled: false
|
||||
|
||||
releases:
|
||||
- name: foo
|
||||
chart: incubator/raw
|
||||
namespace: default
|
||||
labels:
|
||||
app: test
|
||||
hooks:
|
||||
- events: ["prepare", "preapply", "presync"]
|
||||
command: echo
|
||||
showlogs: true
|
||||
args: ["foo"]
|
||||
- name: bar
|
||||
condition: bar.enabled
|
||||
chart: incubator/raw
|
||||
namespace: default
|
||||
labels:
|
||||
app: test
|
||||
hooks:
|
||||
- events: ["prepare", "preapply", "presync"]
|
||||
command: echo
|
||||
showlogs: true
|
||||
args: ["bar"]
|
||||
`,
|
||||
},
|
||||
selectors: []string{"app=test"},
|
||||
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("hooks are run on to-be-uninstalled release", 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: ["prepare", "preapply", "presync"]
|
||||
command: echo
|
||||
showlogs: true
|
||||
args: ["foo"]
|
||||
- name: bar
|
||||
installed: false
|
||||
chart: incubator/raw
|
||||
namespace: default
|
||||
labels:
|
||||
app: test
|
||||
hooks:
|
||||
- events: ["prepare", "preapply", "presync"]
|
||||
command: echo
|
||||
showlogs: true
|
||||
args: ["bar"]
|
||||
`,
|
||||
},
|
||||
selectors: []string{"app=test"},
|
||||
lists: map[exectest.ListKey]string{
|
||||
{Filter: "^foo$", Flags: helmV2ListFlags}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
|
||||
foo 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
|
||||
`,
|
||||
{Filter: "^bar$", Flags: helmV2ListFlags}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
|
||||
bar 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
|
||||
`,
|
||||
},
|
||||
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("hooks are not run on alreadyd uninstalled release", 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: ["prepare", "preapply", "presync"]
|
||||
command: echo
|
||||
showlogs: true
|
||||
args: ["foo"]
|
||||
- name: bar
|
||||
installed: false
|
||||
chart: incubator/raw
|
||||
namespace: default
|
||||
labels:
|
||||
app: test
|
||||
hooks:
|
||||
- events: ["prepare", "preapply", "presync"]
|
||||
command: echo
|
||||
showlogs: true
|
||||
args: ["bar"]
|
||||
`,
|
||||
},
|
||||
selectors: []string{"app=test"},
|
||||
lists: map[exectest.ListKey]string{
|
||||
{Filter: "^foo$", Flags: helmV2ListFlags}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
|
||||
foo 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
|
||||
`,
|
||||
{Filter: "^bar$", Flags: helmV2ListFlags}: ``,
|
||||
},
|
||||
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",
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -137,7 +137,7 @@ func TestApply_2(t *testing.T) {
|
|||
}
|
||||
for flagIdx := range wantUpgrades[relIdx].Flags {
|
||||
if wantUpgrades[relIdx].Flags[flagIdx] != helm.Releases[relIdx].Flags[flagIdx] {
|
||||
t.Errorf("releaes[%d].flags[%d]: got %v, want %v", relIdx, flagIdx, helm.Releases[relIdx].Flags[flagIdx], wantUpgrades[relIdx].Flags[flagIdx])
|
||||
t.Errorf("releases[%d].flags[%d]: got %v, want %v", relIdx, flagIdx, helm.Releases[relIdx].Flags[flagIdx], wantUpgrades[relIdx].Flags[flagIdx])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,10 +47,10 @@ GROUP RELEASES
|
|||
2 default//foo
|
||||
|
||||
processing releases in group 1/2: default//baz, default//bar
|
||||
getting deployed release version failed:unexpected list key: listkey(filter=^baz$,flags=--kube-contextdefault--deleting--deployed--failed--pending) in
|
||||
getting deployed release version failed:unexpected list key: listkey(filter=^bar$,flags=--kube-contextdefault--deleting--deployed--failed--pending) in
|
||||
getting deployed release version failed:unexpected list key: listkey(filter=^baz$,flags=--kube-contextdefault--deleting--deployed--failed--pending) not found in
|
||||
getting deployed release version failed:unexpected list key: listkey(filter=^bar$,flags=--kube-contextdefault--deleting--deployed--failed--pending) not found in
|
||||
processing releases in group 2/2: default//foo
|
||||
getting deployed release version failed:unexpected list key: listkey(filter=^foo$,flags=--kube-contextdefault--deleting--deployed--failed--pending) in
|
||||
getting deployed release version failed:unexpected list key: listkey(filter=^foo$,flags=--kube-contextdefault--deleting--deployed--failed--pending) not found in
|
||||
|
||||
UPDATED RELEASES:
|
||||
NAME CHART VERSION
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
hook[prepare] logs | foo
|
||||
hook[prepare] logs |
|
||||
|
||||
hook[preapply] logs | foo
|
||||
hook[preapply] logs |
|
||||
|
||||
hook[presync] logs | foo
|
||||
hook[presync] logs |
|
||||
|
||||
UPDATED RELEASES:
|
||||
NAME CHART VERSION
|
||||
foo incubator/raw
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
hook[presync] logs | foo
|
||||
hook[presync] logs |
|
||||
|
||||
UPDATED RELEASES:
|
||||
NAME CHART VERSION
|
||||
foo incubator/raw
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
hook[preapply] logs | foo
|
||||
hook[preapply] logs |
|
||||
|
||||
UPDATED RELEASES:
|
||||
NAME CHART VERSION
|
||||
foo incubator/raw
|
||||
|
||||
14
pkg/app/testdata/testapply_hooks/hooks_are_not_run_on_alreadyd_uninstalled_release/log
vendored
Normal file
14
pkg/app/testdata/testapply_hooks/hooks_are_not_run_on_alreadyd_uninstalled_release/log
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
hook[prepare] logs | foo
|
||||
hook[prepare] logs |
|
||||
|
||||
hook[preapply] logs | foo
|
||||
hook[preapply] logs |
|
||||
|
||||
hook[presync] logs | foo
|
||||
hook[presync] logs |
|
||||
|
||||
UPDATED RELEASES:
|
||||
NAME CHART VERSION
|
||||
foo incubator/raw 3.1.0
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
hook[prepare] logs | foo
|
||||
hook[prepare] logs |
|
||||
|
||||
hook[preapply] logs | foo
|
||||
hook[preapply] logs |
|
||||
|
||||
hook[presync] logs | foo
|
||||
hook[presync] logs |
|
||||
|
||||
UPDATED RELEASES:
|
||||
NAME CHART VERSION
|
||||
foo incubator/raw
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
hook[prepare] logs | foo
|
||||
hook[prepare] logs |
|
||||
|
||||
hook[prepare] logs | bar
|
||||
hook[prepare] logs |
|
||||
|
||||
hook[preapply] logs | foo
|
||||
hook[preapply] logs |
|
||||
|
||||
hook[preapply] logs | bar
|
||||
hook[preapply] logs |
|
||||
|
||||
hook[presync] logs | foo
|
||||
hook[presync] logs |
|
||||
|
||||
hook[presync] logs | bar
|
||||
hook[presync] logs |
|
||||
|
||||
UPDATED RELEASES:
|
||||
NAME CHART VERSION
|
||||
foo incubator/raw
|
||||
bar incubator/raw
|
||||
|
||||
24
pkg/app/testdata/testapply_hooks/hooks_are_run_on_to-be-uninstalled_release/log
vendored
Normal file
24
pkg/app/testdata/testapply_hooks/hooks_are_run_on_to-be-uninstalled_release/log
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
hook[prepare] logs | foo
|
||||
hook[prepare] logs |
|
||||
|
||||
hook[preapply] logs | bar
|
||||
hook[preapply] logs |
|
||||
|
||||
hook[presync] logs | bar
|
||||
hook[presync] logs |
|
||||
|
||||
hook[preapply] logs | foo
|
||||
hook[preapply] logs |
|
||||
|
||||
hook[presync] logs | foo
|
||||
hook[presync] logs |
|
||||
|
||||
UPDATED RELEASES:
|
||||
NAME CHART VERSION
|
||||
foo incubator/raw 3.1.0
|
||||
|
||||
|
||||
DELETED RELEASES:
|
||||
NAME
|
||||
bar
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
hook[prepare] logs | foo
|
||||
hook[prepare] logs |
|
||||
|
||||
hook[cleanup] logs | foo
|
||||
hook[cleanup] logs |
|
||||
|
|
@ -161,7 +161,7 @@ func (helm *Helm) List(context helmexec.HelmContext, filter string, flags ...str
|
|||
for k := range helm.Lists {
|
||||
keys = append(keys, k.String())
|
||||
}
|
||||
return "", fmt.Errorf("unexpected list key: %v in %v", key, strings.Join(keys, ", "))
|
||||
return "", fmt.Errorf("unexpected list key: %v not found in %v", key, strings.Join(keys, ", "))
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2251,6 +2251,10 @@ func (st *HelmState) triggerPostsyncEvent(r *ReleaseSpec, evtErr error, helmfile
|
|||
return st.triggerReleaseEvent("postsync", evtErr, r, helmfileCommand)
|
||||
}
|
||||
|
||||
func (st *HelmState) TriggerPreapplyEvent(r *ReleaseSpec, helmfileCommand string) (bool, error) {
|
||||
return st.triggerReleaseEvent("preapply", nil, r, helmfileCommand)
|
||||
}
|
||||
|
||||
func (st *HelmState) triggerReleaseEvent(evt string, evtErr error, r *ReleaseSpec, helmfileCmd string) (bool, error) {
|
||||
bus := &event.Bus{
|
||||
Hooks: r.Hooks,
|
||||
|
|
@ -2268,6 +2272,7 @@ func (st *HelmState) triggerReleaseEvent(evt string, evtErr error, r *ReleaseSpe
|
|||
"Release": r,
|
||||
"HelmfileCommand": helmfileCmd,
|
||||
}
|
||||
|
||||
return bus.Trigger(evt, evtErr, data)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue