mirror of
https://github.com/helmfile/helmfile.git
synced 2026-10-19 02:11:17 +02:00
Various U/X improvements for helmfile apply (#586)
* Various U/X improvements for `helmfile apply` This improves the U/X of `helmfile apply`, by allowing you to selectively apply sub-helmfiles. When you have two or more sub-helmfiles processed, typing `n` to cancel the first doesn't automatically stop the whole helmfile execution. Instead, it proceeds by diffing the next sub-helmfile, and asks you to apply it, which should be what the user would expect. To support this workflow, I have suppressed useless exec logs, correct exit status when diff exists in sub-helmfiles but not in the parent helmfile, and made the final error message emitted by helmfile better. More concretely, this moves more output from `helm` to STDERR and the `debug` log-level. The overall output from `helmfile` should be a bit more cleaner especially for `apply`, `sync`, `diff` and perhaps other `helmfile` sub-commands, too. For example, when one of release failed, `helmfile`'s final error message now includes the error message from the failed `helm` execution, like seen in the last line: ``` List of updated releases : RELEASE CHART VERSION envoy stable/envoy 1.5.0 List of releases in error : RELEASE envoy2 in ./helmfile.yaml: in .helmfiles[0]: in /Users/c-ykuoka/helmfile/helmfile.1.yaml: failed processing release envoy2: helm exited with status 1: Error: UPGRADE FAILED: "envoy2" has no deployed releases ``` This way you can better understand what caused helmfile to finally fail. `helmfile` has been streaminig a lot of stdout and stderr contents from the `helm` commands regardless of the helmfile's log-level. It has been suppressed by default and moved to the `debug` log-level. You will see that it helps you focus on what was the cause of a failure. While working on the above, I found an another bug that made `--detailed-exitcode` useless in some case. That is, `helmfile diff --detailed-exitcode`, when any diff existed only in sub-helmfiles, has been returning an exit code of `1`. It should return `2` when any release had diff and no release had an error, regardless of the target is a sub-helmfile or a parent helmfile. Why? Because that's what `--detailed-exitcode` meant for! After this PR gets merged, `helmfile diff --detailed-exitcode` propery return exit code `2` in such cases. Fixes #543 Resolves #540
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package state
|
||||
|
||||
import "fmt"
|
||||
|
||||
const ReleaseErrorCodeFailure = 1
|
||||
|
||||
type ReleaseError struct {
|
||||
*ReleaseSpec
|
||||
err error
|
||||
Code int
|
||||
}
|
||||
|
||||
func (e *ReleaseError) Error() string {
|
||||
return fmt.Sprintf("failed processing release %s: %v", e.Name, e.err.Error())
|
||||
}
|
||||
|
||||
func newReleaseError(release *ReleaseSpec, err error) *ReleaseError {
|
||||
return &ReleaseError{release, err, ReleaseErrorCodeFailure}
|
||||
}
|
||||
+14
-37
@@ -15,9 +15,6 @@ import (
|
||||
|
||||
"regexp"
|
||||
|
||||
"os/exec"
|
||||
"syscall"
|
||||
|
||||
"net/url"
|
||||
|
||||
"github.com/roboll/helmfile/environment"
|
||||
@@ -202,15 +199,6 @@ func (st *HelmState) SyncRepos(helm RepoUpdater) []error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ReleaseError struct {
|
||||
*ReleaseSpec
|
||||
underlying error
|
||||
}
|
||||
|
||||
func (e *ReleaseError) Error() string {
|
||||
return e.underlying.Error()
|
||||
}
|
||||
|
||||
type syncResult struct {
|
||||
errors []*ReleaseError
|
||||
}
|
||||
@@ -250,7 +238,7 @@ func (st *HelmState) prepareSyncReleases(helm helmexec.Interface, additionalValu
|
||||
|
||||
flags, flagsErr := st.flagsForUpgrade(helm, release, workerIndex)
|
||||
if flagsErr != nil {
|
||||
results <- syncPrepareResult{errors: []*ReleaseError{&ReleaseError{release, flagsErr}}}
|
||||
results <- syncPrepareResult{errors: []*ReleaseError{newReleaseError(release, flagsErr)}}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -258,14 +246,14 @@ func (st *HelmState) prepareSyncReleases(helm helmexec.Interface, additionalValu
|
||||
for _, value := range additionalValues {
|
||||
valfile, err := filepath.Abs(value)
|
||||
if err != nil {
|
||||
errs = append(errs, &ReleaseError{release, err})
|
||||
errs = append(errs, newReleaseError(release, err))
|
||||
}
|
||||
|
||||
ok, err := st.fileExists(valfile)
|
||||
if err != nil {
|
||||
errs = append(errs, &ReleaseError{release, err})
|
||||
errs = append(errs, newReleaseError(release, err))
|
||||
} else if !ok {
|
||||
errs = append(errs, &ReleaseError{release, fmt.Errorf("file does not exist: %s", valfile)})
|
||||
errs = append(errs, newReleaseError(release, fmt.Errorf("file does not exist: %s", valfile)))
|
||||
}
|
||||
flags = append(flags, "--values", valfile)
|
||||
}
|
||||
@@ -351,22 +339,22 @@ func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helme
|
||||
context := st.createHelmContext(release, workerIndex)
|
||||
|
||||
if _, err := st.triggerPresyncEvent(release, "sync"); err != nil {
|
||||
relErr = &ReleaseError{release, err}
|
||||
relErr = newReleaseError(release, err)
|
||||
} else if !release.Desired() {
|
||||
installed, err := st.isReleaseInstalled(context, helm, *release)
|
||||
if err != nil {
|
||||
relErr = &ReleaseError{release, err}
|
||||
relErr = newReleaseError(release, err)
|
||||
} else if installed {
|
||||
if err := helm.DeleteRelease(context, release.Name, "--purge"); err != nil {
|
||||
affectedReleases.Failed = append(affectedReleases.Failed, release)
|
||||
relErr = &ReleaseError{release, err}
|
||||
relErr = newReleaseError(release, err)
|
||||
} else {
|
||||
affectedReleases.Deleted = append(affectedReleases.Deleted, release)
|
||||
}
|
||||
}
|
||||
} else if err := helm.SyncRelease(context, release.Name, chart, flags...); err != nil {
|
||||
affectedReleases.Failed = append(affectedReleases.Failed, release)
|
||||
relErr = &ReleaseError{release, err}
|
||||
relErr = newReleaseError(release, err)
|
||||
} else {
|
||||
affectedReleases.Upgraded = append(affectedReleases.Upgraded, release)
|
||||
installedVersion, err := st.getDeployedVersion(context, helm, release)
|
||||
@@ -612,18 +600,8 @@ func (st *HelmState) LintReleases(helm helmexec.Interface, additionalValues []st
|
||||
return nil
|
||||
}
|
||||
|
||||
type DiffError struct {
|
||||
*ReleaseSpec
|
||||
err error
|
||||
Code int
|
||||
}
|
||||
|
||||
func (e *DiffError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
type diffResult struct {
|
||||
err *DiffError
|
||||
err *ReleaseError
|
||||
}
|
||||
|
||||
type diffPrepareResult struct {
|
||||
@@ -691,7 +669,7 @@ func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValu
|
||||
if len(errs) > 0 {
|
||||
rsErrs := make([]*ReleaseError, len(errs))
|
||||
for i, e := range errs {
|
||||
rsErrs[i] = &ReleaseError{release, e}
|
||||
rsErrs[i] = newReleaseError(release, e)
|
||||
}
|
||||
results <- diffPrepareResult{errors: rsErrs}
|
||||
} else {
|
||||
@@ -762,12 +740,11 @@ func (st *HelmState) DiffReleases(helm helmexec.Interface, additionalValues []st
|
||||
release := prep.release
|
||||
if err := helm.DiffRelease(st.createHelmContext(release, workerIndex), release.Name, normalizeChart(st.basePath, release.Chart), flags...); err != nil {
|
||||
switch e := err.(type) {
|
||||
case *exec.ExitError:
|
||||
case helmexec.ExitError:
|
||||
// Propagate any non-zero exit status from the external command like `helm` that is failed under the hood
|
||||
status := e.Sys().(syscall.WaitStatus)
|
||||
results <- diffResult{&DiffError{release, err, status.ExitStatus()}}
|
||||
results <- diffResult{&ReleaseError{release, err, e.ExitStatus()}}
|
||||
default:
|
||||
results <- diffResult{&DiffError{release, err, 0}}
|
||||
results <- diffResult{&ReleaseError{release, err, 0}}
|
||||
}
|
||||
} else {
|
||||
// diff succeeded, found no changes
|
||||
@@ -925,7 +902,7 @@ func (st *HelmState) PrepareRelease(helm helmexec.Interface, helmfileCommand str
|
||||
|
||||
for _, release := range st.Releases {
|
||||
if _, err := st.triggerPrepareEvent(&release, helmfileCommand); err != nil {
|
||||
errs = append(errs, &ReleaseError{&release, err})
|
||||
errs = append(errs, newReleaseError(&release, err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user