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