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
|
||||||
|
|
|
||||||
|
|
@ -468,8 +468,9 @@ func Test_normalizeChart(t *testing.T) {
|
||||||
// mocking helmexec.Interface
|
// mocking helmexec.Interface
|
||||||
|
|
||||||
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