mirror of
https://github.com/helmfile/helmfile.git
synced 2026-09-30 22:10:54 +02:00
In order to maintain predictable deployments, as developer I want to generate and use "lock files" for all chart versions retrieved from a helmfile. This change solves it by (1)enhancing `helmfile deps` to generate a lock file containing all the direct chart dependencies of each helmfile state file and (2)making other helmfile sub-commands reads the lock file and merge the locked version numbers to the helmfile state file being processed. The lock file is named after the helmfile state file being locked, so that you can have multiple set of the helmfile state file and the lock file pairs in a directory. When `helmfile deps` are not explicitly run before commands like `sync`, all the helmfile behavior should remain as before. Let's say you have `helmfile.1.yaml`: ``` repositories: - name: stable url: https://kubernetes-charts.storage.googleapis.com releases: - name: envoy chart: stable/envoy - name: envoy2 chart: stable/envoy ``` `helmfile deps` generates `helmfile.1.lock` that looks like: ``` dependencies: - name: envoy repository: https://kubernetes-charts.storage.googleapis.com version: 1.5.0 digest: sha256:e43b05c8528ea8ef1560f4980a519719ad2a634658abde0a98daefdb83a104e9 generated: 2019-05-14T16:45:37.78205+09:00 ``` Under the hood, `helmfile deps` creates a temporary local helm chart with a dummy `Chart.yaml` and `requirements.yaml` deduced from the `helmfile.yaml` content, then runs `helm dependency update` to produce od update the corresponding `requirements.lock` file. `helmfile` then renames it to match the name of the targeted helmfile state file and moves it, so that it becomes adjacent to each `helmfile.yaml`. Other `helmfile` commands like `sync`, `diiff`, `apply`, `lint` read chart version numbers from the lock file. Resolves #483
622 lines
18 KiB
Go
622 lines
18 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/roboll/helmfile/args"
|
|
"github.com/roboll/helmfile/cmd"
|
|
"github.com/roboll/helmfile/helmexec"
|
|
"github.com/roboll/helmfile/pkg/app"
|
|
"github.com/roboll/helmfile/state"
|
|
"github.com/urfave/cli"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
var Version string
|
|
|
|
var logger *zap.SugaredLogger
|
|
|
|
func configureLogging(c *cli.Context) error {
|
|
// Valid levels:
|
|
// https://github.com/uber-go/zap/blob/7e7e266a8dbce911a49554b945538c5b950196b8/zapcore/level.go#L126
|
|
logLevel := c.GlobalString("log-level")
|
|
if c.GlobalBool("quiet") {
|
|
logLevel = "warn"
|
|
}
|
|
var level zapcore.Level
|
|
err := level.Set(logLevel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logger = helmexec.NewLogger(os.Stderr, logLevel)
|
|
if c.App.Metadata == nil {
|
|
// Auto-initialised in 1.19.0
|
|
// https://github.com/urfave/cli/blob/master/CHANGELOG.md#1190---2016-11-19
|
|
c.App.Metadata = make(map[string]interface{})
|
|
}
|
|
c.App.Metadata["logger"] = logger
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
|
|
cliApp := cli.NewApp()
|
|
cliApp.Name = "helmfile"
|
|
cliApp.Usage = ""
|
|
cliApp.Version = Version
|
|
cliApp.Flags = []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "helm-binary, b",
|
|
Usage: "path to helm binary",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "file, f",
|
|
Usage: "load config from file or directory. defaults to `helmfile.yaml` or `helmfile.d`(means `helmfile.d/*.yaml`) in this preference",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "environment, e",
|
|
Usage: "specify the environment name. defaults to `default`",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "quiet, q",
|
|
Usage: "Silence output. Equivalent to log-level warn",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "kube-context",
|
|
Usage: "Set kubectl context. Uses current context by default",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "log-level",
|
|
Usage: "Set log level, default info",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "namespace, n",
|
|
Usage: "Set namespace. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }}",
|
|
},
|
|
cli.StringSliceFlag{
|
|
Name: "selector, l",
|
|
Usage: `Only run using the releases that match labels. Labels can take the form of foo=bar or foo!=bar.
|
|
A release must match all labels in a group in order to be used. Multiple groups can be specified at once.
|
|
--selector tier=frontend,tier!=proxy --selector tier=backend. Will match all frontend, non-proxy releases AND all backend releases.
|
|
The name of a release can be used as a label. --selector name=myrelease`,
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "interactive, i",
|
|
Usage: "Request confirmation before attempting to modify clusters",
|
|
},
|
|
}
|
|
|
|
cliApp.Before = configureLogging
|
|
cliApp.Commands = []cli.Command{
|
|
cmd.Deps(),
|
|
{
|
|
Name: "repos",
|
|
Usage: "sync repositories from state file (helm repo add && helm repo update)",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "args",
|
|
Value: "",
|
|
Usage: "pass args to helm exec",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
return cmd.VisitAllDesiredStates(c, func(state *state.HelmState, helm helmexec.Interface, ctx app.Context) (bool, []error) {
|
|
args := args.GetArgs(c.String("args"), state)
|
|
if len(args) > 0 {
|
|
helm.SetExtraArgs(args...)
|
|
}
|
|
|
|
errs := ctx.SyncReposOnce(state, helm)
|
|
|
|
ok := len(state.Repositories) > 0 && len(errs) == 0
|
|
|
|
return ok, errs
|
|
})
|
|
},
|
|
},
|
|
{
|
|
Name: "charts",
|
|
Usage: "DEPRECATED: sync releases from state file (helm upgrade --install)",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "args",
|
|
Value: "",
|
|
Usage: "pass args to helm exec",
|
|
},
|
|
cli.StringSliceFlag{
|
|
Name: "values",
|
|
Usage: "additional value files to be merged into the command",
|
|
},
|
|
cli.IntFlag{
|
|
Name: "concurrency",
|
|
Value: 0,
|
|
Usage: "maximum number of concurrent helm processes to run, 0 is unlimited",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
affectedReleases := state.AffectedReleases{}
|
|
errs := findAndIterateOverDesiredStatesUsingFlags(c, func(st *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
|
return executeSyncCommand(c, &affectedReleases, st, helm)
|
|
})
|
|
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
|
return errs
|
|
},
|
|
},
|
|
{
|
|
Name: "diff",
|
|
Usage: "diff releases from state file against env (helm diff)",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "args",
|
|
Value: "",
|
|
Usage: "pass args to helm exec",
|
|
},
|
|
cli.StringSliceFlag{
|
|
Name: "values",
|
|
Usage: "additional value files to be merged into the command",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "skip-deps",
|
|
Usage: "skip running `helm repo update` and `helm dependency build`",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "detailed-exitcode",
|
|
Usage: "return a non-zero exit code when there are changes",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "suppress-secrets",
|
|
Usage: "suppress secrets in the output. highly recommended to specify on CI/CD use-cases",
|
|
},
|
|
cli.IntFlag{
|
|
Name: "concurrency",
|
|
Value: 0,
|
|
Usage: "maximum number of concurrent helm processes to run, 0 is unlimited",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
|
if !c.Bool("skip-deps") {
|
|
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, "diff"); errs != nil && len(errs) > 0 {
|
|
return errs
|
|
}
|
|
|
|
_, errs := executeDiffCommand(c, state, helm, c.Bool("detailed-exitcode"), c.Bool("suppress-secrets"))
|
|
return errs
|
|
})
|
|
},
|
|
},
|
|
{
|
|
Name: "template",
|
|
Usage: "template releases from state file against env (helm template)",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "args",
|
|
Value: "",
|
|
Usage: "pass args to helm template",
|
|
},
|
|
cli.StringSliceFlag{
|
|
Name: "values",
|
|
Usage: "additional value files to be merged into the command",
|
|
},
|
|
cli.IntFlag{
|
|
Name: "concurrency",
|
|
Value: 0,
|
|
Usage: "maximum number of concurrent downloads of release charts",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "skip-deps",
|
|
Usage: "skip running `helm repo update` and `helm dependency build`",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
|
if !c.Bool("skip-deps") {
|
|
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
|
|
}
|
|
return executeTemplateCommand(c, state, helm)
|
|
})
|
|
},
|
|
},
|
|
{
|
|
Name: "lint",
|
|
Usage: "lint charts from state file (helm lint)",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "args",
|
|
Value: "",
|
|
Usage: "pass args to helm exec",
|
|
},
|
|
cli.StringSliceFlag{
|
|
Name: "values",
|
|
Usage: "additional value files to be merged into the command",
|
|
},
|
|
cli.IntFlag{
|
|
Name: "concurrency",
|
|
Value: 0,
|
|
Usage: "maximum number of concurrent downloads of release charts",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
|
values := c.StringSlice("values")
|
|
args := args.GetArgs(c.String("args"), state)
|
|
workers := c.Int("concurrency")
|
|
if errs := ctx.SyncReposOnce(state, 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)
|
|
})
|
|
},
|
|
},
|
|
{
|
|
Name: "sync",
|
|
Usage: "sync all resources from state file (repos, releases and chart deps)",
|
|
Flags: []cli.Flag{
|
|
cli.StringSliceFlag{
|
|
Name: "values",
|
|
Usage: "additional value files to be merged into the command",
|
|
},
|
|
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",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "skip-deps",
|
|
Usage: "skip running `helm repo update` and `helm dependency build`",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
affectedReleases := state.AffectedReleases{}
|
|
errs := findAndIterateOverDesiredStatesUsingFlags(c, func(st *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
|
if !c.Bool("skip-deps") {
|
|
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
|
|
}
|
|
return executeSyncCommand(c, &affectedReleases, st, helm)
|
|
})
|
|
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
|
return errs
|
|
},
|
|
},
|
|
{
|
|
Name: "apply",
|
|
Usage: "apply all resources from state file only when there are changes",
|
|
Flags: []cli.Flag{
|
|
cli.StringSliceFlag{
|
|
Name: "values",
|
|
Usage: "additional value files to be merged into the command",
|
|
},
|
|
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",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "suppress-secrets",
|
|
Usage: "suppress secrets in the diff output. highly recommended to specify on CI/CD use-cases",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "skip-deps",
|
|
Usage: "skip running `helm repo update` and `helm dependency build`",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
affectedReleases := state.AffectedReleases{}
|
|
errs := findAndIterateOverDesiredStatesUsingFlags(c, func(st *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
|
if !c.Bool("skip-deps") {
|
|
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
|
|
}
|
|
|
|
releases, errs := executeDiffCommand(c, st, helm, true, c.Bool("suppress-secrets"))
|
|
|
|
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.App.Metadata["logger"].(*zap.SugaredLogger)
|
|
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.GlobalBool("interactive")
|
|
if !interactive || interactive && askForConfirmation(msg) {
|
|
rs := []state.ReleaseSpec{}
|
|
for _, r := range releases {
|
|
rs = append(rs, *r)
|
|
}
|
|
for _, r := range releasesToBeDeleted {
|
|
rs = append(rs, *r)
|
|
}
|
|
|
|
st.Releases = rs
|
|
return executeSyncCommand(c, &affectedReleases, st, helm)
|
|
}
|
|
}
|
|
}
|
|
|
|
return fatalErrs
|
|
})
|
|
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
|
return 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 {
|
|
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
|
workers := c.Int("concurrency")
|
|
|
|
args := args.GetArgs(c.String("args"), state)
|
|
if len(args) > 0 {
|
|
helm.SetExtraArgs(args...)
|
|
}
|
|
|
|
return state.ReleaseStatuses(helm, workers)
|
|
})
|
|
},
|
|
},
|
|
{
|
|
Name: "delete",
|
|
Usage: "DEPRECATED: delete releases from state file (helm delete)",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "args",
|
|
Value: "",
|
|
Usage: "pass args to helm exec",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "purge",
|
|
Usage: "purge releases i.e. free release names and histories",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
affectedReleases := state.AffectedReleases{}
|
|
errs := cmd.FindAndIterateOverDesiredStatesUsingFlagsWithReverse(c, true, func(state *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
|
purge := c.Bool("purge")
|
|
|
|
args := args.GetArgs(c.String("args"), state)
|
|
if len(args) > 0 {
|
|
helm.SetExtraArgs(args...)
|
|
}
|
|
|
|
names := make([]string, len(state.Releases))
|
|
for i, r := range 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.GlobalBool("interactive")
|
|
if !interactive || interactive && askForConfirmation(msg) {
|
|
return state.DeleteReleases(&affectedReleases, helm, purge)
|
|
}
|
|
return nil
|
|
})
|
|
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
|
return errs
|
|
},
|
|
},
|
|
{
|
|
Name: "destroy",
|
|
Usage: "deletes and then purges releases",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "args",
|
|
Value: "",
|
|
Usage: "pass args to helm exec",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
affectedReleases := state.AffectedReleases{}
|
|
errs := cmd.FindAndIterateOverDesiredStatesUsingFlagsWithReverse(c, true, func(state *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
|
args := args.GetArgs(c.String("args"), state)
|
|
if len(args) > 0 {
|
|
helm.SetExtraArgs(args...)
|
|
}
|
|
|
|
names := make([]string, len(state.Releases))
|
|
for i, r := range 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.GlobalBool("interactive")
|
|
if !interactive || interactive && askForConfirmation(msg) {
|
|
return state.DeleteReleases(&affectedReleases, helm, true)
|
|
}
|
|
return nil
|
|
})
|
|
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
|
return errs
|
|
},
|
|
},
|
|
{
|
|
Name: "test",
|
|
Usage: "test releases from state file (helm test)",
|
|
Flags: []cli.Flag{
|
|
cli.BoolFlag{
|
|
Name: "cleanup",
|
|
Usage: "delete test pods upon completion",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "args",
|
|
Value: "",
|
|
Usage: "pass additional args to helm exec",
|
|
},
|
|
cli.IntFlag{
|
|
Name: "timeout",
|
|
Value: 300,
|
|
Usage: "maximum time for tests to run before being considered failed",
|
|
},
|
|
cli.IntFlag{
|
|
Name: "concurrency",
|
|
Value: 0,
|
|
Usage: "maximum number of concurrent helm processes to run, 0 is unlimited",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
|
cleanup := c.Bool("cleanup")
|
|
timeout := c.Int("timeout")
|
|
concurrency := c.Int("concurrency")
|
|
|
|
args := args.GetArgs(c.String("args"), state)
|
|
if len(args) > 0 {
|
|
helm.SetExtraArgs(args...)
|
|
}
|
|
|
|
return state.TestReleases(helm, cleanup, timeout, concurrency)
|
|
})
|
|
},
|
|
},
|
|
}
|
|
|
|
err := cliApp.Run(os.Args)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
os.Exit(3)
|
|
}
|
|
}
|
|
|
|
func executeSyncCommand(c *cli.Context, affectedReleases *state.AffectedReleases, state *state.HelmState, helm helmexec.Interface) []error {
|
|
args := args.GetArgs(c.String("args"), state)
|
|
if len(args) > 0 {
|
|
helm.SetExtraArgs(args...)
|
|
}
|
|
|
|
values := c.StringSlice("values")
|
|
workers := c.Int("concurrency")
|
|
|
|
return state.SyncReleases(affectedReleases, helm, values, workers)
|
|
}
|
|
|
|
func executeTemplateCommand(c *cli.Context, state *state.HelmState, helm helmexec.Interface) []error {
|
|
args := args.GetArgs(c.String("args"), state)
|
|
values := c.StringSlice("values")
|
|
workers := c.Int("concurrency")
|
|
|
|
return state.TemplateReleases(helm, values, args, workers)
|
|
}
|
|
|
|
func executeDiffCommand(c *cli.Context, st *state.HelmState, helm helmexec.Interface, detailedExitCode, suppressSecrets bool) ([]*state.ReleaseSpec, []error) {
|
|
args := args.GetArgs(c.String("args"), st)
|
|
if len(args) > 0 {
|
|
helm.SetExtraArgs(args...)
|
|
}
|
|
|
|
values := c.StringSlice("values")
|
|
workers := c.Int("concurrency")
|
|
triggerCleanupEvents := c.Command.HasName("diff")
|
|
|
|
return st.DiffReleases(helm, values, workers, detailedExitCode, suppressSecrets, triggerCleanupEvents)
|
|
}
|
|
|
|
func findAndIterateOverDesiredStatesUsingFlags(c *cli.Context, converge func(*state.HelmState, helmexec.Interface, app.Context) []error) error {
|
|
return cmd.FindAndIterateOverDesiredStatesUsingFlagsWithReverse(c, false, converge)
|
|
}
|