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` | ||||
| - `command` | ||||
| - `args` | ||||
| - `showlogs` | ||||
| 
 | ||||
| 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: | ||||
| 
 | ||||
|  | @ -857,6 +858,7 @@ releases: | |||
|   # *snip* | ||||
|   hooks: | ||||
|   - events: ["prepare", "cleanup"] | ||||
|     showlogs: true | ||||
|     command: "echo" | ||||
|     args: ["{{`{{.Environment.Name}}`}}", "{{`{{.Release.Name}}`}}", "{{`{{.HelmfileCommand}}`}}\ | ||||
| "] | ||||
|  |  | |||
|  | @ -2,18 +2,21 @@ package event | |||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/roboll/helmfile/pkg/environment" | ||||
| 	"github.com/roboll/helmfile/pkg/helmexec" | ||||
| 	"github.com/roboll/helmfile/pkg/tmpl" | ||||
| 	"go.uber.org/zap" | ||||
| 	"os" | ||||
| ) | ||||
| 
 | ||||
| type Hook struct { | ||||
| 	Name    string   `yaml:"name"` | ||||
| 	Events  []string `yaml:"events"` | ||||
| 	Command string   `yaml:"command"` | ||||
| 	Args    []string `yaml:"args"` | ||||
| 	Name     string   `yaml:"name"` | ||||
| 	Events   []string `yaml:"events"` | ||||
| 	Command  string   `yaml:"command"` | ||||
| 	Args     []string `yaml:"args"` | ||||
| 	ShowLogs bool     `yaml:"showlogs"` | ||||
| } | ||||
| 
 | ||||
| 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{}) | ||||
| 		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 { | ||||
| 			return false, fmt.Errorf("hook[%s]: command `%s` failed: %v", name, command, err) | ||||
|  |  | |||
|  | @ -2,10 +2,13 @@ package event | |||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/roboll/helmfile/pkg/environment" | ||||
| 	"github.com/roboll/helmfile/pkg/helmexec" | ||||
| 	"os" | ||||
| 	"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") | ||||
|  | @ -35,14 +38,21 @@ func TestTrigger(t *testing.T) { | |||
| 	}{ | ||||
| 		{ | ||||
| 			"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", | ||||
| 			true, | ||||
| 			"", | ||||
| 		}, | ||||
| 		{ | ||||
| 			"missinghook1", | ||||
| 			&Hook{"okhook1", []string{"foo"}, "ok", []string{}}, | ||||
| 			&Hook{"okhook1", []string{"foo"}, "ok", []string{}, false}, | ||||
| 			"bar", | ||||
| 			false, | ||||
| 			"", | ||||
|  | @ -56,14 +66,14 @@ func TestTrigger(t *testing.T) { | |||
| 		}, | ||||
| 		{ | ||||
| 			"nghook1", | ||||
| 			&Hook{"nghook1", []string{"foo"}, "ng", []string{}}, | ||||
| 			&Hook{"nghook1", []string{"foo"}, "ng", []string{}, false}, | ||||
| 			"foo", | ||||
| 			false, | ||||
| 			"hook[nghook1]: command `ng` failed: cmd failed due to invalid cmd: ng", | ||||
| 		}, | ||||
| 		{ | ||||
| 			"nghook2", | ||||
| 			&Hook{"nghook2", []string{"foo"}, "ok", []string{"ng"}}, | ||||
| 			&Hook{"nghook2", []string{"foo"}, "ok", []string{"ng"}, false}, | ||||
| 			"foo", | ||||
| 			false, | ||||
| 			"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 { | ||||
| 			hooks = append(hooks, *c.hook) | ||||
| 		} | ||||
| 		observer, observedLogs := observer.New(zap.InfoLevel) | ||||
| 		zeLogger := zap.New(observer).Sugar() | ||||
| 		bus := &Bus{ | ||||
| 			Hooks:         hooks, | ||||
| 			StateFilePath: "path/to/helmfile.yaml", | ||||
| 			BasePath:      "path/to", | ||||
| 			Namespace:     "myns", | ||||
| 			Env:           environment.Environment{Name: "prod"}, | ||||
| 			Logger:        logger, | ||||
| 			Logger:        zeLogger, | ||||
| 			ReadFile:      readFile, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -109,5 +121,8 @@ func TestTrigger(t *testing.T) { | |||
| 				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