303 lines
7.5 KiB
Go
303 lines
7.5 KiB
Go
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/roboll/helmfile/pkg/argparser"
|
|
"github.com/roboll/helmfile/pkg/helmexec"
|
|
"github.com/roboll/helmfile/pkg/state"
|
|
"strings"
|
|
)
|
|
|
|
type Run struct {
|
|
state *state.HelmState
|
|
helm helmexec.Interface
|
|
ctx Context
|
|
|
|
Ask func(string) bool
|
|
}
|
|
|
|
func NewRun(st *state.HelmState, helm helmexec.Interface, ctx Context) *Run {
|
|
return &Run{state: st, helm: helm, ctx: ctx}
|
|
}
|
|
|
|
func (r *Run) askForConfirmation(msg string) bool {
|
|
if r.Ask != nil {
|
|
return r.Ask(msg)
|
|
}
|
|
return AskForConfirmation(msg)
|
|
}
|
|
|
|
func (r *Run) Deps(c DepsConfigProvider) []error {
|
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
|
|
|
return r.state.UpdateDeps(r.helm)
|
|
}
|
|
|
|
func (r *Run) Repos(c ReposConfigProvider) []error {
|
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
|
|
|
return r.ctx.SyncReposOnce(r.state, r.helm)
|
|
}
|
|
|
|
func (r *Run) DeprecatedSyncCharts(c DeprecatedChartsConfigProvider) []error {
|
|
st := r.state
|
|
helm := r.helm
|
|
|
|
affectedReleases := state.AffectedReleases{}
|
|
errs := st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency())
|
|
affectedReleases.DisplayAffectedReleases(c.Logger())
|
|
return errs
|
|
}
|
|
|
|
func (r *Run) Status(c StatusesConfigProvider) []error {
|
|
workers := c.Concurrency()
|
|
|
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
|
|
|
return r.state.ReleaseStatuses(r.helm, workers)
|
|
}
|
|
|
|
func (r *Run) Delete(c DeleteConfigProvider) []error {
|
|
affectedReleases := state.AffectedReleases{}
|
|
purge := c.Purge()
|
|
|
|
errs := []error{}
|
|
|
|
names := make([]string, len(r.state.Releases))
|
|
for i, r := range r.state.Releases {
|
|
names[i] = fmt.Sprintf(" %s (%s)", r.Name, r.Chart)
|
|
}
|
|
|
|
msg := fmt.Sprintf(`Affected releases are:
|
|
%s
|
|
|
|
Do you really want to delete?
|
|
Helmfile will delete all your releases, as shown above.
|
|
|
|
`, strings.Join(names, "\n"))
|
|
interactive := c.Interactive()
|
|
if !interactive || interactive && r.askForConfirmation(msg) {
|
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
|
|
|
errs = r.state.DeleteReleases(&affectedReleases, r.helm, purge)
|
|
}
|
|
affectedReleases.DisplayAffectedReleases(c.Logger())
|
|
return errs
|
|
}
|
|
|
|
func (r *Run) Destroy(c DestroyConfigProvider) []error {
|
|
errs := []error{}
|
|
affectedReleases := state.AffectedReleases{}
|
|
|
|
names := make([]string, len(r.state.Releases))
|
|
for i, r := range r.state.Releases {
|
|
names[i] = fmt.Sprintf(" %s (%s)", r.Name, r.Chart)
|
|
}
|
|
|
|
msg := fmt.Sprintf(`Affected releases are:
|
|
%s
|
|
|
|
Do you really want to delete?
|
|
Helmfile will delete all your releases, as shown above.
|
|
|
|
`, strings.Join(names, "\n"))
|
|
interactive := c.Interactive()
|
|
if !interactive || interactive && r.askForConfirmation(msg) {
|
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
|
|
|
errs = r.state.DeleteReleases(&affectedReleases, r.helm, true)
|
|
}
|
|
affectedReleases.DisplayAffectedReleases(c.Logger())
|
|
return errs
|
|
}
|
|
|
|
func (r *Run) Apply(c ApplyConfigProvider) []error {
|
|
st := r.state
|
|
helm := r.helm
|
|
ctx := r.ctx
|
|
|
|
affectedReleases := state.AffectedReleases{}
|
|
if !c.SkipDeps() {
|
|
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
}
|
|
if errs := st.PrepareReleases(helm, "apply"); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
|
|
// helm must be 2.11+ and helm-diff should be provided `--detailed-exitcode` in order for `helmfile apply` to work properly
|
|
detailedExitCode := true
|
|
|
|
releases, errs := st.DiffReleases(helm, c.Values(), c.Concurrency(), detailedExitCode, c.SuppressSecrets(), false)
|
|
|
|
releasesToBeDeleted, err := st.DetectReleasesToBeDeleted(helm)
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
|
|
fatalErrs := []error{}
|
|
|
|
noError := true
|
|
for _, e := range errs {
|
|
switch err := e.(type) {
|
|
case *state.ReleaseError:
|
|
if err.Code != 2 {
|
|
noError = false
|
|
fatalErrs = append(fatalErrs, e)
|
|
}
|
|
default:
|
|
noError = false
|
|
fatalErrs = append(fatalErrs, e)
|
|
}
|
|
}
|
|
|
|
// sync only when there are changes
|
|
if noError {
|
|
if len(releases) == 0 && len(releasesToBeDeleted) == 0 {
|
|
// TODO better way to get the logger
|
|
logger := c.Logger()
|
|
logger.Infof("")
|
|
logger.Infof("No affected releases")
|
|
} else {
|
|
names := []string{}
|
|
for _, r := range releases {
|
|
names = append(names, fmt.Sprintf(" %s (%s) UPDATED", r.Name, r.Chart))
|
|
}
|
|
for _, r := range releasesToBeDeleted {
|
|
names = append(names, fmt.Sprintf(" %s (%s) DELETED", r.Name, r.Chart))
|
|
}
|
|
|
|
msg := fmt.Sprintf(`Affected releases are:
|
|
%s
|
|
|
|
Do you really want to apply?
|
|
Helmfile will apply all your changes, as shown above.
|
|
|
|
`, strings.Join(names, "\n"))
|
|
interactive := c.Interactive()
|
|
if !interactive || interactive && r.askForConfirmation(msg) {
|
|
rs := []state.ReleaseSpec{}
|
|
for _, r := range releases {
|
|
rs = append(rs, *r)
|
|
}
|
|
for _, r := range releasesToBeDeleted {
|
|
rs = append(rs, *r)
|
|
}
|
|
|
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
|
|
|
st.Releases = rs
|
|
return st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency())
|
|
}
|
|
}
|
|
}
|
|
|
|
affectedReleases.DisplayAffectedReleases(c.Logger())
|
|
return fatalErrs
|
|
}
|
|
|
|
func (r *Run) Diff(c DiffConfigProvider) []error {
|
|
st := r.state
|
|
helm := r.helm
|
|
ctx := r.ctx
|
|
|
|
if !c.SkipDeps() {
|
|
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
}
|
|
if errs := st.PrepareReleases(helm, "diff"); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
|
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
|
|
|
_, errs := st.DiffReleases(helm, c.Values(), c.Concurrency(), c.DetailedExitcode(), c.SuppressSecrets(), true)
|
|
return errs
|
|
}
|
|
|
|
func (r *Run) Sync(c SyncConfigProvider) []error {
|
|
st := r.state
|
|
helm := r.helm
|
|
ctx := r.ctx
|
|
|
|
affectedReleases := state.AffectedReleases{}
|
|
if !c.SkipDeps() {
|
|
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
}
|
|
if errs := st.PrepareReleases(helm, "sync"); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
|
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
|
|
|
errs := st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency())
|
|
affectedReleases.DisplayAffectedReleases(c.Logger())
|
|
return errs
|
|
}
|
|
|
|
func (r *Run) Template(c TemplateConfigProvider) []error {
|
|
state := r.state
|
|
helm := r.helm
|
|
ctx := r.ctx
|
|
|
|
if !c.SkipDeps() {
|
|
if errs := ctx.SyncReposOnce(state, helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
if errs := state.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
}
|
|
if errs := state.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
|
|
args := argparser.GetArgs(c.Args(), state)
|
|
return state.TemplateReleases(helm, c.Values(), args, c.Concurrency())
|
|
}
|
|
|
|
func (r *Run) Test(c TestConfigProvider) []error {
|
|
cleanup := c.Cleanup()
|
|
timeout := c.Timeout()
|
|
concurrency := c.Concurrency()
|
|
|
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
|
|
|
return r.state.TestReleases(r.helm, cleanup, timeout, concurrency)
|
|
}
|
|
|
|
func (r *Run) Lint(c LintConfigProvider) []error {
|
|
state := r.state
|
|
helm := r.helm
|
|
ctx := r.ctx
|
|
|
|
values := c.Values()
|
|
args := argparser.GetArgs(c.Args(), state)
|
|
workers := c.Concurrency()
|
|
if !c.SkipDeps() {
|
|
if errs := ctx.SyncReposOnce(state, helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
if errs := state.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
}
|
|
if errs := state.PrepareReleases(helm, "lint"); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
return state.LintReleases(helm, values, args, workers)
|
|
}
|