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,18 +2,21 @@ 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 { | ||||||
| 	Name    string   `yaml:"name"` | 	Name     string   `yaml:"name"` | ||||||
| 	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