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) | ||||
|      diff    diff charts from state file against env (helm diff) | ||||
|      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) | ||||
| 
 | ||||
| GLOBAL OPTIONS: | ||||
|  |  | |||
|  | @ -59,6 +59,14 @@ func (helm *execer) SyncRelease(name, chart string, flags ...string) error { | |||
| 	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) { | ||||
| 	out, err := helm.exec(append([]string{"secrets", "dec", name})...) | ||||
| 	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) { | ||||
| 	var buffer bytes.Buffer | ||||
| 	helm := MockExecer(&buffer, "") | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ type Interface interface { | |||
| 	UpdateDeps(chart string) error | ||||
| 	SyncRelease(name, chart string, flags ...string) error | ||||
| 	DiffRelease(name, chart string, flags ...string) error | ||||
| 	ReleaseStatus(name string) error | ||||
| 	DeleteRelease(name string) error | ||||
| 
 | ||||
| 	DecryptSecret(name string) (string, error) | ||||
|  |  | |||
							
								
								
									
										32
									
								
								main.go
								
								
								
								
							
							
						
						
									
										32
									
								
								main.go
								
								
								
								
							|  | @ -218,6 +218,38 @@ func main() { | |||
| 				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", | ||||
| 			Usage: "delete charts from state file (helm delete)", | ||||
|  |  | |||
|  | @ -298,6 +298,49 @@ func (state *HelmState) DiffReleases(helm helmexec.Interface, additionalValues [ | |||
| 	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
 | ||||
| func (state *HelmState) DeleteReleases(helm helmexec.Interface) []error { | ||||
| 	var wg sync.WaitGroup | ||||
|  |  | |||
|  | @ -470,6 +470,7 @@ func Test_normalizeChart(t *testing.T) { | |||
| type mockHelmExec struct { | ||||
| 	charts   []string | ||||
| 	repo     []string | ||||
| 	releases []string | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
| 	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 { | ||||
| 	return nil | ||||
| } | ||||
|  | @ -591,3 +599,50 @@ func TestHelmState_UpdateDeps(t *testing.T) { | |||
| 		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