Skip to content

Commit

Permalink
Add kubectl hooks for applying file(s) or kustomize (#1736)
Browse files Browse the repository at this point in the history
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
```
  • Loading branch information
javiplx authored Apr 6, 2021
1 parent 5cd0afc commit 261367e
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 12 deletions.
34 changes: 28 additions & 6 deletions pkg/event/bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import (
)

type Hook struct {
Name string `yaml:"name"`
Events []string `yaml:"events"`
Command string `yaml:"command"`
Args []string `yaml:"args"`
ShowLogs bool `yaml:"showlogs"`
Name string `yaml:"name"`
Events []string `yaml:"events"`
Command string `yaml:"command"`
Kubectl map[string]string `yaml:"kubectlApply,omitempty"`
Args []string `yaml:"args"`
ShowLogs bool `yaml:"showlogs"`
}

type event struct {
Expand Down Expand Up @@ -61,7 +62,28 @@ func (bus *Bus) Trigger(evt string, evtErr error, context map[string]interface{}

name := hook.Name
if name == "" {
name = hook.Command
if hook.Kubectl != nil {
name = "kubectlApply"
} else {
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)
Expand Down
68 changes: 62 additions & 6 deletions pkg/event/bus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,21 @@ func TestTrigger(t *testing.T) {
}{
{
"okhook1",
&Hook{"okhook1", []string{"foo"}, "ok", []string{}, true},
&Hook{"okhook1", []string{"foo"}, "ok", nil, []string{}, true},
"foo",
true,
"",
},
{
"okhooké",
&Hook{"okhook2", []string{"foo"}, "ok", []string{}, false},
&Hook{"okhook2", []string{"foo"}, "ok", nil, []string{}, false},
"foo",
true,
"",
},
{
"missinghook1",
&Hook{"okhook1", []string{"foo"}, "ok", []string{}, false},
&Hook{"okhook1", []string{"foo"}, "ok", nil, []string{}, false},
"bar",
false,
"",
Expand All @@ -71,18 +71,74 @@ func TestTrigger(t *testing.T) {
},
{
"nghook1",
&Hook{"nghook1", []string{"foo"}, "ng", []string{}, false},
&Hook{"nghook1", []string{"foo"}, "ng", nil, []string{}, false},
"foo",
false,
"hook[nghook1]: command `ng` failed: cmd failed due to invalid cmd: ng",
},
{
"nghook2",
&Hook{"nghook2", []string{"foo"}, "ok", []string{"ng"}, false},
&Hook{"nghook2", []string{"foo"}, "ok", nil, []string{"ng"}, false},
"foo",
false,
"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) {
return nil, fmt.Errorf("unexpected call to readFile: %s", filename)
Expand Down Expand Up @@ -117,7 +173,7 @@ func TestTrigger(t *testing.T) {

if c.expectedErr != "" {
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 {
t.Errorf("unexpected error for case \"%s\": expected=%s, actual=%v", c.name, c.expectedErr, err)
}
Expand Down

0 comments on commit 261367e

Please sign in to comment.