Merge pull request #70 from cmeury/status-command
status command retrieves release status
This commit is contained in:
		
						commit
						44241f675f
					
				|  | @ -134,6 +134,7 @@ COMMANDS: | ||||||
|      charts  sync charts from state file (helm upgrade --install) |      charts  sync charts from state file (helm upgrade --install) | ||||||
|      diff    diff charts from state file against env (helm diff) |      diff    diff charts from state file against env (helm diff) | ||||||
|      sync    sync all resources from state file (repos, charts and local chart deps) |      sync    sync all resources from state file (repos, charts and local chart deps) | ||||||
|  |      status  retrieve status of releases in state file | ||||||
|      delete  delete charts from state file (helm delete) |      delete  delete charts from state file (helm delete) | ||||||
| 
 | 
 | ||||||
| GLOBAL OPTIONS: | GLOBAL OPTIONS: | ||||||
|  |  | ||||||
|  | @ -59,6 +59,14 @@ func (helm *execer) SyncRelease(name, chart string, flags ...string) error { | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (helm *execer) ReleaseStatus(name string) error { | ||||||
|  | 	out, err := helm.exec(append([]string{"status", name})...) | ||||||
|  | 	if helm.writer != nil { | ||||||
|  | 		helm.writer.Write(out) | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (helm *execer) DecryptSecret(name string) (string, error) { | func (helm *execer) DecryptSecret(name string) (string, error) { | ||||||
| 	out, err := helm.exec(append([]string{"secrets", "dec", name})...) | 	out, err := helm.exec(append([]string{"secrets", "dec", name})...) | ||||||
| 	helm.write(out) | 	helm.write(out) | ||||||
|  |  | ||||||
|  | @ -155,6 +155,16 @@ func Test_DeleteRelease(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func Test_ReleaseStatus(t *testing.T) { | ||||||
|  | 	var buffer bytes.Buffer | ||||||
|  | 	helm := MockExecer(&buffer, "dev") | ||||||
|  | 	helm.ReleaseStatus("myRelease") | ||||||
|  | 	expected := "exec: helm status myRelease --kube-context dev\n" | ||||||
|  | 	if buffer.String() != expected { | ||||||
|  | 		t.Errorf("helmexec.ReleaseStatus()\nactual = %v\nexpect = %v", buffer.String(), expected) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func Test_exec(t *testing.T) { | func Test_exec(t *testing.T) { | ||||||
| 	var buffer bytes.Buffer | 	var buffer bytes.Buffer | ||||||
| 	helm := MockExecer(&buffer, "") | 	helm := MockExecer(&buffer, "") | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ type Interface interface { | ||||||
| 	UpdateDeps(chart string) error | 	UpdateDeps(chart string) error | ||||||
| 	SyncRelease(name, chart string, flags ...string) error | 	SyncRelease(name, chart string, flags ...string) error | ||||||
| 	DiffRelease(name, chart string, flags ...string) error | 	DiffRelease(name, chart string, flags ...string) error | ||||||
|  | 	ReleaseStatus(name string) error | ||||||
| 	DeleteRelease(name string) error | 	DeleteRelease(name string) error | ||||||
| 
 | 
 | ||||||
| 	DecryptSecret(name string) (string, error) | 	DecryptSecret(name string) (string, error) | ||||||
|  |  | ||||||
							
								
								
									
										32
									
								
								main.go
								
								
								
								
							
							
						
						
									
										32
									
								
								main.go
								
								
								
								
							|  | @ -218,6 +218,38 @@ func main() { | ||||||
| 				return clean(state, errs) | 				return clean(state, errs) | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:  "status", | ||||||
|  | 			Usage: "retrieve status of releases in state file", | ||||||
|  | 			Flags: []cli.Flag{ | ||||||
|  | 				cli.IntFlag{ | ||||||
|  | 					Name:  "concurrency", | ||||||
|  | 					Value: 0, | ||||||
|  | 					Usage: "maximum number of concurrent helm processes to run, 0 is unlimited", | ||||||
|  | 				}, | ||||||
|  | 				cli.StringFlag{ | ||||||
|  | 					Name:  "args", | ||||||
|  | 					Value: "", | ||||||
|  | 					Usage: "pass args to helm exec", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Action: func(c *cli.Context) error { | ||||||
|  | 				state, helm, err := before(c) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				workers := c.Int("concurrency") | ||||||
|  | 
 | ||||||
|  | 				args := c.String("args") | ||||||
|  | 				if len(args) > 0 { | ||||||
|  | 					helm.SetExtraArgs(strings.Split(args, " ")...) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				errs := state.ReleaseStatuses(helm, workers) | ||||||
|  | 				return clean(state, errs) | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			Name:  "delete", | 			Name:  "delete", | ||||||
| 			Usage: "delete charts from state file (helm delete)", | 			Usage: "delete charts from state file (helm delete)", | ||||||
|  |  | ||||||
|  | @ -298,6 +298,49 @@ func (state *HelmState) DiffReleases(helm helmexec.Interface, additionalValues [ | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (state *HelmState) ReleaseStatuses(helm helmexec.Interface, workerLimit int) []error { | ||||||
|  | 	var errs []error | ||||||
|  | 	jobQueue := make(chan ReleaseSpec) | ||||||
|  | 	doneQueue := make(chan bool) | ||||||
|  | 	errQueue := make(chan error) | ||||||
|  | 
 | ||||||
|  | 	if workerLimit < 1 { | ||||||
|  | 		workerLimit = len(state.Releases) | ||||||
|  | 	} | ||||||
|  | 	for w := 1; w <= workerLimit; w++ { | ||||||
|  | 		go func() { | ||||||
|  | 			for release := range jobQueue { | ||||||
|  | 				if err := helm.ReleaseStatus(release.Name); err != nil { | ||||||
|  | 					errQueue <- err | ||||||
|  | 				} | ||||||
|  | 				doneQueue <- true | ||||||
|  | 			} | ||||||
|  | 		}() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	go func() { | ||||||
|  | 		for _, release := range state.Releases { | ||||||
|  | 			jobQueue <- release | ||||||
|  | 		} | ||||||
|  | 		close(jobQueue) | ||||||
|  | 	}() | ||||||
|  | 
 | ||||||
|  | 	for i := 0; i < len(state.Releases); { | ||||||
|  | 		select { | ||||||
|  | 		case err := <-errQueue: | ||||||
|  | 			errs = append(errs, err) | ||||||
|  | 		case <-doneQueue: | ||||||
|  | 			i++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(errs) != 0 { | ||||||
|  | 		return errs | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // DeleteReleases wrapper for executing helm delete on the releases
 | // DeleteReleases wrapper for executing helm delete on the releases
 | ||||||
| func (state *HelmState) DeleteReleases(helm helmexec.Interface) []error { | func (state *HelmState) DeleteReleases(helm helmexec.Interface) []error { | ||||||
| 	var wg sync.WaitGroup | 	var wg sync.WaitGroup | ||||||
|  |  | ||||||
|  | @ -470,6 +470,7 @@ func Test_normalizeChart(t *testing.T) { | ||||||
| type mockHelmExec struct { | type mockHelmExec struct { | ||||||
| 	charts   []string | 	charts   []string | ||||||
| 	repo     []string | 	repo     []string | ||||||
|  | 	releases []string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (helm *mockHelmExec) UpdateDeps(chart string) error { | func (helm *mockHelmExec) UpdateDeps(chart string) error { | ||||||
|  | @ -496,6 +497,13 @@ func (helm *mockHelmExec) SyncRelease(name, chart string, flags ...string) error | ||||||
| func (helm *mockHelmExec) DiffRelease(name, chart string, flags ...string) error { | func (helm *mockHelmExec) DiffRelease(name, chart string, flags ...string) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | func (helm *mockHelmExec) ReleaseStatus(release string) error { | ||||||
|  | 	if strings.Contains(release, "error") { | ||||||
|  | 		return errors.New("error") | ||||||
|  | 	} | ||||||
|  | 	helm.releases = append(helm.releases, release) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
| func (helm *mockHelmExec) DeleteRelease(name string) error { | func (helm *mockHelmExec) DeleteRelease(name string) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | @ -591,3 +599,50 @@ func TestHelmState_UpdateDeps(t *testing.T) { | ||||||
| 		t.Errorf("HelmState.UpdateDeps() - no errors, but got: %v", len(errs)) | 		t.Errorf("HelmState.UpdateDeps() - no errors, but got: %v", len(errs)) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestHelmState_ReleaseStatuses(t *testing.T) { | ||||||
|  | 	tests := []struct { | ||||||
|  | 		name     string | ||||||
|  | 		releases []ReleaseSpec | ||||||
|  | 		helm     *mockHelmExec | ||||||
|  | 		want     []string | ||||||
|  | 		wantErr  bool | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			name: "happy path", | ||||||
|  | 			releases: []ReleaseSpec{ | ||||||
|  | 				{ | ||||||
|  | 					Name: "releaseA", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			helm: &mockHelmExec{}, | ||||||
|  | 			want: []string{"releaseA"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "happy path", | ||||||
|  | 			releases: []ReleaseSpec{ | ||||||
|  | 				{ | ||||||
|  | 					Name: "error", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			helm:    &mockHelmExec{}, | ||||||
|  | 			wantErr: true, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	for _, tt := range tests { | ||||||
|  | 		i := func(t *testing.T) { | ||||||
|  | 			state := &HelmState{ | ||||||
|  | 				Releases: tt.releases, | ||||||
|  | 			} | ||||||
|  | 			errs := state.ReleaseStatuses(tt.helm, 1) | ||||||
|  | 			if (errs != nil) != tt.wantErr { | ||||||
|  | 				t.Errorf("ReleaseStatuses() for %s error = %v, wantErr %v", tt.name, errs, tt.wantErr) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			if !reflect.DeepEqual(tt.helm.releases, tt.want) { | ||||||
|  | 				t.Errorf("HelmState.ReleaseStatuses() for [%s] = %v, want %v", tt.name, tt.helm.releases, tt.want) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		t.Run(tt.name, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue