diff --git a/helmexec/exec.go b/helmexec/exec.go index 0d3ffdde..4d887c1d 100644 --- a/helmexec/exec.go +++ b/helmexec/exec.go @@ -110,6 +110,13 @@ func (helm *execer) ReleaseStatus(name string) error { return err } +func (helm *execer) List(filter string) (string, error) { + helm.logger.Infof("Listing releases matching %v", filter) + out, err := helm.exec(append([]string{"list", filter})...) + helm.write(out) + return string(out), err +} + func (helm *execer) DecryptSecret(name string) (string, error) { // Prevents https://github.com/roboll/helmfile/issues/258 helm.decryptionMutex.Lock() diff --git a/helmexec/helmexec.go b/helmexec/helmexec.go index 96322383..5d6c65df 100644 --- a/helmexec/helmexec.go +++ b/helmexec/helmexec.go @@ -17,6 +17,6 @@ type Interface interface { ReleaseStatus(name string) error DeleteRelease(name string, flags ...string) error TestRelease(name string, flags ...string) error - + List(filter string) (string, error) DecryptSecret(name string) (string, error) } diff --git a/state/state.go b/state/state.go index d92dada6..3059c608 100644 --- a/state/state.go +++ b/state/state.go @@ -252,24 +252,25 @@ func (st *HelmState) prepareSyncReleases(helm helmexec.Interface, additionalValu return res, errs } +func isReleaseInstalled(helm helmexec.Interface, release ReleaseSpec) (bool, error) { + out, err := helm.List("^" + release.Name + "$") + if err != nil { + return false, err + } else if out != "" { + return true, nil + } + return false, nil +} + func (st *HelmState) DetectReleasesToBeDeleted(helm helmexec.Interface) ([]*ReleaseSpec, error) { detected := []*ReleaseSpec{} for i, _ := range st.Releases { release := st.Releases[i] if release.Installed != nil && !*release.Installed { - err := helm.ReleaseStatus(release.Name) + installed, err := isReleaseInstalled(helm, release) if err != nil { - switch e := err.(type) { - case *exec.ExitError: - // Propagate any non-zero exit status from the external command like `helm` that is failed under the hood - status := e.Sys().(syscall.WaitStatus) - if status.ExitStatus() != 1 { - return nil, e - } - default: - return nil, e - } - } else { + return nil, err + } else if installed { detected = append(detected, &release) } } @@ -304,7 +305,10 @@ func (st *HelmState) SyncReleases(helm helmexec.Interface, additionalValues []st chart := normalizeChart(st.basePath, release.Chart) var relErr *ReleaseError if release.Installed != nil && !*release.Installed { - if err := helm.ReleaseStatus(release.Name); err == nil { + installed, err := isReleaseInstalled(helm, *release) + if err != nil { + relErr = &ReleaseError{release, err} + } else if installed { if err := helm.DeleteRelease(release.Name, "--purge"); err != nil { relErr = &ReleaseError{release, err} } diff --git a/state/state_test.go b/state/state_test.go index 7be4afeb..7706453c 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -614,6 +614,9 @@ func (helm *mockHelmExec) ReleaseStatus(release string) error { func (helm *mockHelmExec) DeleteRelease(name string, flags ...string) error { return nil } +func (helm *mockHelmExec) List(filter string) (string, error) { + return "", nil +} func (helm *mockHelmExec) DecryptSecret(name string) (string, error) { return "", nil }