feat: optionally show logs for hooks (#699)
Resolves #689 This adds a new yaml entry for the hook definition to allow the users to specifcy if they want to show the `command` logs or not. here is an example. ``` releases: - name: myapp chart: mychart # *snip* hooks: - events: ["cleanup"] showlogs: true command: "kubectl" args: ["get", "ingress"] ``` this will display the following output: ``` hook[cleanup] logs | NAME HOSTS ADDRESS PORTS AGE hook[cleanup] logs | catalog-gateway tdc.foo 80 2d6h hook[cleanup] logs | dataset foobar.barr.foo.xxxxxxx.com 80 2d6h hook[cleanup] logs | rating fooba.barr.foo.xxxxxxx.com 80 2d6h hook[cleanup] logs | sharing foobar.barr.foo.xxxxxxx.com 80 2d6h hook[cleanup] logs | tpsvc-iam-dev foo.barr.foo.xxxxxxx.com 80 2d6h hook[cleanup] logs | tpsvc-iam-front bar.barr.foo.xxxxxxx.com 80 2d6h ```
This commit is contained in:
parent
f61334d9bb
commit
ddb5be1b9d
|
|
@ -829,9 +829,10 @@ A Helmfile hook is a per-release extension point that is composed of:
|
||||||
- `events`
|
- `events`
|
||||||
- `command`
|
- `command`
|
||||||
- `args`
|
- `args`
|
||||||
|
- `showlogs`
|
||||||
|
|
||||||
Helmfile triggers various `events` while it is running.
|
Helmfile triggers various `events` while it is running.
|
||||||
Once `events` are triggered, associated `hooks` are executed, by running the `command` with `args`.
|
Once `events` are triggered, associated `hooks` are executed, by running the `command` with `args`. The standard output of the `command` will be displayed if `showlogs` is set and it's value is `true`.
|
||||||
|
|
||||||
Currently supported `events` are:
|
Currently supported `events` are:
|
||||||
|
|
||||||
|
|
@ -857,6 +858,7 @@ releases:
|
||||||
# *snip*
|
# *snip*
|
||||||
hooks:
|
hooks:
|
||||||
- events: ["prepare", "cleanup"]
|
- events: ["prepare", "cleanup"]
|
||||||
|
showlogs: true
|
||||||
command: "echo"
|
command: "echo"
|
||||||
args: ["{{`{{.Environment.Name}}`}}", "{{`{{.Release.Name}}`}}", "{{`{{.HelmfileCommand}}`}}\
|
args: ["{{`{{.Environment.Name}}`}}", "{{`{{.Release.Name}}`}}", "{{`{{.HelmfileCommand}}`}}\
|
||||||
"]
|
"]
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/roboll/helmfile/pkg/environment"
|
"github.com/roboll/helmfile/pkg/environment"
|
||||||
"github.com/roboll/helmfile/pkg/helmexec"
|
"github.com/roboll/helmfile/pkg/helmexec"
|
||||||
"github.com/roboll/helmfile/pkg/tmpl"
|
"github.com/roboll/helmfile/pkg/tmpl"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Hook struct {
|
type Hook struct {
|
||||||
|
|
@ -14,6 +16,7 @@ type Hook struct {
|
||||||
Events []string `yaml:"events"`
|
Events []string `yaml:"events"`
|
||||||
Command string `yaml:"command"`
|
Command string `yaml:"command"`
|
||||||
Args []string `yaml:"args"`
|
Args []string `yaml:"args"`
|
||||||
|
ShowLogs bool `yaml:"showlogs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type event struct {
|
type event struct {
|
||||||
|
|
@ -90,6 +93,10 @@ func (bus *Bus) Trigger(evt string, context map[string]interface{}) (bool, error
|
||||||
|
|
||||||
bytes, err := bus.Runner.Execute(command, args, map[string]string{})
|
bytes, err := bus.Runner.Execute(command, args, map[string]string{})
|
||||||
bus.Logger.Debugf("hook[%s]: %s\n", name, string(bytes))
|
bus.Logger.Debugf("hook[%s]: %s\n", name, string(bytes))
|
||||||
|
if hook.ShowLogs {
|
||||||
|
prefix := fmt.Sprintf("\nhook[%s] logs | ", evt)
|
||||||
|
bus.Logger.Infow(prefix + strings.ReplaceAll(string(bytes), "\n", prefix))
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("hook[%s]: command `%s` failed: %v", name, command, err)
|
return false, fmt.Errorf("hook[%s]: command `%s` failed: %v", name, command, err)
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@ package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/roboll/helmfile/pkg/environment"
|
|
||||||
"github.com/roboll/helmfile/pkg/helmexec"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/roboll/helmfile/pkg/environment"
|
||||||
|
"github.com/roboll/helmfile/pkg/helmexec"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zaptest/observer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger = helmexec.NewLogger(os.Stdout, "warn")
|
var logger = helmexec.NewLogger(os.Stdout, "warn")
|
||||||
|
|
@ -35,14 +38,21 @@ func TestTrigger(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"okhook1",
|
"okhook1",
|
||||||
&Hook{"okhook1", []string{"foo"}, "ok", []string{}},
|
&Hook{"okhook1", []string{"foo"}, "ok", []string{}, true},
|
||||||
|
"foo",
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"okhooké",
|
||||||
|
&Hook{"okhook2", []string{"foo"}, "ok", []string{}, false},
|
||||||
"foo",
|
"foo",
|
||||||
true,
|
true,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"missinghook1",
|
"missinghook1",
|
||||||
&Hook{"okhook1", []string{"foo"}, "ok", []string{}},
|
&Hook{"okhook1", []string{"foo"}, "ok", []string{}, false},
|
||||||
"bar",
|
"bar",
|
||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
|
|
@ -56,14 +66,14 @@ func TestTrigger(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nghook1",
|
"nghook1",
|
||||||
&Hook{"nghook1", []string{"foo"}, "ng", []string{}},
|
&Hook{"nghook1", []string{"foo"}, "ng", []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"}},
|
&Hook{"nghook2", []string{"foo"}, "ok", []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",
|
||||||
|
|
@ -77,13 +87,15 @@ func TestTrigger(t *testing.T) {
|
||||||
if c.hook != nil {
|
if c.hook != nil {
|
||||||
hooks = append(hooks, *c.hook)
|
hooks = append(hooks, *c.hook)
|
||||||
}
|
}
|
||||||
|
observer, observedLogs := observer.New(zap.InfoLevel)
|
||||||
|
zeLogger := zap.New(observer).Sugar()
|
||||||
bus := &Bus{
|
bus := &Bus{
|
||||||
Hooks: hooks,
|
Hooks: hooks,
|
||||||
StateFilePath: "path/to/helmfile.yaml",
|
StateFilePath: "path/to/helmfile.yaml",
|
||||||
BasePath: "path/to",
|
BasePath: "path/to",
|
||||||
Namespace: "myns",
|
Namespace: "myns",
|
||||||
Env: environment.Environment{Name: "prod"},
|
Env: environment.Environment{Name: "prod"},
|
||||||
Logger: logger,
|
Logger: zeLogger,
|
||||||
ReadFile: readFile,
|
ReadFile: readFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,5 +121,8 @@ func TestTrigger(t *testing.T) {
|
||||||
t.Errorf("unexpected error for case \"%s\": %v", c.name, err)
|
t.Errorf("unexpected error for case \"%s\": %v", c.name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if observedLogs.Len() != 0 && !hooks[0].ShowLogs {
|
||||||
|
t.Errorf("unexpected error for case \"%s\": Logs should not be created : %v", c.name, observedLogs.All())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue