Add `kubectl` hooks for applying file(s) or kustomize (#1736)
This enables you to write a `kubectl-apply` hook more declaratively than writing `command` and `args`:
```
releases:
- name: myapp
chart: mychart
hooks:
- events: ["presync"]
kubectlApply:
filename: path/to/manifests
#kustomize: path/to/kustomize
```
This commit is contained in:
parent
5cd0afcfa0
commit
261367e7e9
|
|
@ -15,6 +15,7 @@ type Hook struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
Events []string `yaml:"events"`
|
Events []string `yaml:"events"`
|
||||||
Command string `yaml:"command"`
|
Command string `yaml:"command"`
|
||||||
|
Kubectl map[string]string `yaml:"kubectlApply,omitempty"`
|
||||||
Args []string `yaml:"args"`
|
Args []string `yaml:"args"`
|
||||||
ShowLogs bool `yaml:"showlogs"`
|
ShowLogs bool `yaml:"showlogs"`
|
||||||
}
|
}
|
||||||
|
|
@ -61,8 +62,29 @@ func (bus *Bus) Trigger(evt string, evtErr error, context map[string]interface{}
|
||||||
|
|
||||||
name := hook.Name
|
name := hook.Name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
|
if hook.Kubectl != nil {
|
||||||
|
name = "kubectlApply"
|
||||||
|
} else {
|
||||||
name = hook.Command
|
name = hook.Command
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hook.Kubectl != nil {
|
||||||
|
if hook.Command != "" {
|
||||||
|
bus.Logger.Warnf("warn: ignoring command '%s' given within a kubectlApply hook", hook.Command)
|
||||||
|
}
|
||||||
|
hook.Command = "kubectl"
|
||||||
|
if val, found := hook.Kubectl["filename"]; found {
|
||||||
|
if _, found := hook.Kubectl["kustomize"]; found {
|
||||||
|
return false, fmt.Errorf("hook[%s]: kustomize & filename cannot be used together", name)
|
||||||
|
}
|
||||||
|
hook.Args = append([]string{"apply", "-f"}, val)
|
||||||
|
} else if val, found := hook.Kubectl["kustomize"]; found {
|
||||||
|
hook.Args = append([]string{"apply", "-k"}, val)
|
||||||
|
} else {
|
||||||
|
return false, fmt.Errorf("hook[%s]: either kustomize or filename must be given", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "%s: basePath=%s\n", bus.StateFilePath, bus.BasePath)
|
fmt.Fprintf(os.Stderr, "%s: basePath=%s\n", bus.StateFilePath, bus.BasePath)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,21 +43,21 @@ func TestTrigger(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"okhook1",
|
"okhook1",
|
||||||
&Hook{"okhook1", []string{"foo"}, "ok", []string{}, true},
|
&Hook{"okhook1", []string{"foo"}, "ok", nil, []string{}, true},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"okhooké",
|
"okhooké",
|
||||||
&Hook{"okhook2", []string{"foo"}, "ok", []string{}, false},
|
&Hook{"okhook2", []string{"foo"}, "ok", nil, []string{}, false},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"missinghook1",
|
"missinghook1",
|
||||||
&Hook{"okhook1", []string{"foo"}, "ok", []string{}, false},
|
&Hook{"okhook1", []string{"foo"}, "ok", nil, []string{}, false},
|
||||||
"bar",
|
"bar",
|
||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
|
|
@ -71,18 +71,74 @@ func TestTrigger(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nghook1",
|
"nghook1",
|
||||||
&Hook{"nghook1", []string{"foo"}, "ng", []string{}, false},
|
&Hook{"nghook1", []string{"foo"}, "ng", nil, []string{}, 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", []string{"ng"}, false},
|
&Hook{"nghook2", []string{"foo"}, "ok", nil, []string{"ng"}, 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",
|
||||||
|
&Hook{"okkubeapply1", []string{"foo"}, "", map[string]string{"kustomize": "kustodir"}, []string{}, false},
|
||||||
|
"foo",
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"okkubeapply2",
|
||||||
|
&Hook{"okkubeapply2", []string{"foo"}, "", map[string]string{"filename": "resource.yaml"}, []string{}, false},
|
||||||
|
"foo",
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kokubeapply",
|
||||||
|
&Hook{"kokubeapply", []string{"foo"}, "", map[string]string{"kustomize": "kustodir", "filename": "resource.yaml"}, []string{}, true},
|
||||||
|
"foo",
|
||||||
|
false,
|
||||||
|
"hook[kokubeapply]: kustomize & filename cannot be used together",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kokubeapply2",
|
||||||
|
&Hook{"kokubeapply2", []string{"foo"}, "", map[string]string{}, []string{}, true},
|
||||||
|
"foo",
|
||||||
|
false,
|
||||||
|
"hook[kokubeapply2]: either kustomize or filename must be given",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kokubeapply3",
|
||||||
|
&Hook{"", []string{"foo"}, "", map[string]string{}, []string{}, true},
|
||||||
|
"foo",
|
||||||
|
false,
|
||||||
|
"hook[kubectlApply]: either kustomize or filename must be given",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warnkubeapply1",
|
||||||
|
&Hook{"warnkubeapply1", []string{"foo"}, "ok", map[string]string{"filename": "resource.yaml"}, []string{}, true},
|
||||||
|
"foo",
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warnkubeapply2",
|
||||||
|
&Hook{"warnkubeapply2", []string{"foo"}, "", map[string]string{"filename": "resource.yaml"}, []string{"ng"}, true},
|
||||||
|
"foo",
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warnkubeapply3",
|
||||||
|
&Hook{"warnkubeapply3", []string{"foo"}, "ok", map[string]string{"filename": "resource.yaml"}, []string{"ng"}, true},
|
||||||
|
"foo",
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
readFile := func(filename string) ([]byte, error) {
|
readFile := func(filename string) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("unexpected call to readFile: %s", filename)
|
return nil, fmt.Errorf("unexpected call to readFile: %s", filename)
|
||||||
|
|
@ -117,7 +173,7 @@ func TestTrigger(t *testing.T) {
|
||||||
|
|
||||||
if c.expectedErr != "" {
|
if c.expectedErr != "" {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("error expected, but not occurred")
|
t.Errorf("error expected for case \"%s\", but not occurred", c.name)
|
||||||
} else if err.Error() != c.expectedErr {
|
} else if err.Error() != c.expectedErr {
|
||||||
t.Errorf("unexpected error for case \"%s\": expected=%s, actual=%v", c.name, c.expectedErr, err)
|
t.Errorf("unexpected error for case \"%s\": expected=%s, actual=%v", c.name, c.expectedErr, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue