diff --git a/main.go b/main.go index 80de8c24..a3eb66f9 100644 --- a/main.go +++ b/main.go @@ -143,6 +143,10 @@ func main() { Value: "", Usage: "pass args to helm exec", }, + cli.StringSliceFlag{ + Name: "set", + Usage: "additional values to be merged into the command", + }, cli.StringSliceFlag{ Name: "values", Usage: "additional value files to be merged into the command", @@ -166,6 +170,10 @@ func main() { Value: "", Usage: "pass args to helm exec", }, + cli.StringSliceFlag{ + Name: "set", + Usage: "additional values to be merged into the command", + }, cli.StringSliceFlag{ Name: "values", Usage: "additional value files to be merged into the command", @@ -206,6 +214,10 @@ func main() { Value: "", Usage: "pass args to helm template", }, + cli.StringSliceFlag{ + Name: "set", + Usage: "additional values to be merged into the command", + }, cli.StringSliceFlag{ Name: "values", Usage: "additional value files to be merged into the command", @@ -237,6 +249,10 @@ func main() { Value: "", Usage: "pass args to helm exec", }, + cli.StringSliceFlag{ + Name: "set", + Usage: "additional values to be merged into the command", + }, cli.StringSliceFlag{ Name: "values", Usage: "additional value files to be merged into the command", @@ -259,6 +275,10 @@ func main() { Name: "sync", Usage: "sync all resources from state file (repos, releases and chart deps)", Flags: []cli.Flag{ + cli.StringSliceFlag{ + Name: "set", + Usage: "additional values to be merged into the command", + }, cli.StringSliceFlag{ Name: "values", Usage: "additional value files to be merged into the command", @@ -286,6 +306,10 @@ func main() { Name: "apply", Usage: "apply all resources from state file only when there are changes", Flags: []cli.Flag{ + cli.StringSliceFlag{ + Name: "set", + Usage: "additional values to be merged into the command", + }, cli.StringSliceFlag{ Name: "values", Usage: "additional value files to be merged into the command", @@ -467,6 +491,10 @@ func NewUrfaveCliConfigImpl(c *cli.Context) (configImpl, error) { return conf, nil } +func (c configImpl) Set() []string { + return c.c.StringSlice("set") +} + func (c configImpl) Values() []string { return c.c.StringSlice("values") } @@ -539,11 +567,11 @@ func (c configImpl) Selectors() []string { return c.c.GlobalStringSlice("selector") } -func (c configImpl) Set() map[string]interface{} { +func (c configImpl) StateValuesSet() map[string]interface{} { return c.set } -func (c configImpl) ValuesFiles() []string { +func (c configImpl) StateValuesFiles() []string { return c.c.GlobalStringSlice("state-values-file") } diff --git a/pkg/app/app.go b/pkg/app/app.go index 663e403c..44124c94 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -61,8 +61,8 @@ func New(conf ConfigProvider) *App { HelmBinary: conf.HelmBinary(), Args: conf.Args(), FileOrDir: conf.FileOrDir(), - ValuesFiles: conf.ValuesFiles(), - Set: conf.Set(), + ValuesFiles: conf.StateValuesFiles(), + Set: conf.StateValuesSet(), helmExecer: helmexec.New(conf.Logger(), conf.KubeContext(), &helmexec.ShellRunner{ Logger: conf.Logger(), }), diff --git a/pkg/app/app_test.go b/pkg/app/app_test.go index 057e3ab1..8038515e 100644 --- a/pkg/app/app_test.go +++ b/pkg/app/app_test.go @@ -1791,6 +1791,11 @@ services: } type configImpl struct { + set []string +} + +func (c configImpl) Set() []string { + return c.set } func (c configImpl) Values() []string { @@ -1913,8 +1918,8 @@ releases: var helm = &mockHelmExec{} var wantReleases = []mockTemplates{ - {name: "myrelease1", chart: "mychart1", flags: []string{"--namespace", "testNamespace", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease1"}}, - {name: "myrelease2", chart: "mychart2", flags: []string{"--namespace", "testNamespace", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease2"}}, + {name: "myrelease1", chart: "mychart1", flags: []string{"--namespace", "testNamespace", "--set", "foo=a", "--set", "bar=b", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease1"}}, + {name: "myrelease2", chart: "mychart2", flags: []string{"--namespace", "testNamespace", "--set", "foo=a", "--set", "bar=b", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease2"}}, } var buffer bytes.Buffer @@ -1929,7 +1934,7 @@ releases: helmExecer: helm, Namespace: "testNamespace", }, files) - app.Template(configImpl{}) + app.Template(configImpl{set: []string{"foo=a", "bar=b"}}) for i := range wantReleases { if wantReleases[i].name != helm.templated[i].name { @@ -1939,7 +1944,7 @@ releases: t.Errorf("chart = [%v], want %v", helm.templated[i].chart, wantReleases[i].chart) } for j := range wantReleases[i].flags { - if j == 3 { + if j == 7 { matched, _ := regexp.Match(wantReleases[i].flags[j], []byte(helm.templated[i].flags[j])) if !matched { t.Errorf("HelmState.TemplateReleases() = [%v], want %v", helm.templated[i].flags[j], wantReleases[i].flags[j]) diff --git a/pkg/app/config.go b/pkg/app/config.go index 6e12cdf5..72a612ab 100644 --- a/pkg/app/config.go +++ b/pkg/app/config.go @@ -10,8 +10,8 @@ type ConfigProvider interface { KubeContext() string Namespace() string Selectors() []string - Set() map[string]interface{} - ValuesFiles() []string + StateValuesSet() map[string]interface{} + StateValuesFiles() []string Env() string loggingConfig @@ -36,6 +36,7 @@ type ApplyConfigProvider interface { Args() string Values() []string + Set() []string SkipDeps() bool SuppressSecrets() bool @@ -52,6 +53,7 @@ type SyncConfigProvider interface { Args() string Values() []string + Set() []string SkipDeps() bool concurrencyConfig @@ -62,6 +64,7 @@ type DiffConfigProvider interface { Args() string Values() []string + Set() []string SkipDeps() bool SuppressSecrets() bool @@ -104,6 +107,7 @@ type LintConfigProvider interface { Args() string Values() []string + Set() []string SkipDeps() bool concurrencyConfig @@ -113,6 +117,7 @@ type TemplateConfigProvider interface { Args() string Values() []string + Set() []string SkipDeps() bool OutputDir() string diff --git a/pkg/app/run.go b/pkg/app/run.go index 45ec8aa6..7ffd492f 100644 --- a/pkg/app/run.go +++ b/pkg/app/run.go @@ -140,6 +140,7 @@ func (r *Run) Apply(c ApplyConfigProvider) []error { diffOpts := &state.DiffOpts{ NoColor: c.NoColor(), Context: c.Context(), + Set: c.Set(), } releases, errs := st.DiffReleases(helm, c.Values(), c.Concurrency(), detailedExitCode, c.SuppressSecrets(), false, diffOpts) @@ -201,7 +202,10 @@ Do you really want to apply? r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...) st.Releases = rs - return st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency()) + syncOpts := &state.SyncOpts{ + Set: c.Set(), + } + return st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency(), syncOpts) } } } @@ -229,7 +233,12 @@ func (r *Run) Diff(c DiffConfigProvider) []error { r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...) - _, errs := st.DiffReleases(helm, c.Values(), c.Concurrency(), c.DetailedExitcode(), c.SuppressSecrets(), true) + opts := &state.DiffOpts{ + Context: c.Context(), + NoColor: c.NoColor(), + Set: c.Set(), + } + _, errs := st.DiffReleases(helm, c.Values(), c.Concurrency(), c.DetailedExitcode(), c.SuppressSecrets(), true, opts) return errs } @@ -253,30 +262,36 @@ func (r *Run) Sync(c SyncConfigProvider) []error { r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...) - errs := st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency()) + opts := &state.SyncOpts{ + Set: c.Set(), + } + errs := st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency(), opts) affectedReleases.DisplayAffectedReleases(c.Logger()) return errs } func (r *Run) Template(c TemplateConfigProvider) []error { - state := r.state + st := r.state helm := r.helm ctx := r.ctx if !c.SkipDeps() { - if errs := ctx.SyncReposOnce(state, helm); errs != nil && len(errs) > 0 { + if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 { return errs } - if errs := state.BuildDeps(helm); errs != nil && len(errs) > 0 { + if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 { return errs } } - if errs := state.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 { + if errs := st.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 { return errs } - args := argparser.GetArgs(c.Args(), state) - return state.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency()) + args := argparser.GetArgs(c.Args(), st) + opts := &state.TemplateOpts{ + Set: c.Set(), + } + return st.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), opts) } func (r *Run) Test(c TestConfigProvider) []error { @@ -290,23 +305,26 @@ func (r *Run) Test(c TestConfigProvider) []error { } func (r *Run) Lint(c LintConfigProvider) []error { - state := r.state + st := r.state helm := r.helm ctx := r.ctx values := c.Values() - args := argparser.GetArgs(c.Args(), state) + args := argparser.GetArgs(c.Args(), st) workers := c.Concurrency() if !c.SkipDeps() { - if errs := ctx.SyncReposOnce(state, helm); errs != nil && len(errs) > 0 { + if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 { return errs } - if errs := state.BuildDeps(helm); errs != nil && len(errs) > 0 { + if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 { return errs } } - if errs := state.PrepareReleases(helm, "lint"); errs != nil && len(errs) > 0 { + if errs := st.PrepareReleases(helm, "lint"); errs != nil && len(errs) > 0 { return errs } - return state.LintReleases(helm, values, args, workers) + opts := &state.LintOpts{ + Set: c.Set(), + } + return st.LintReleases(helm, values, args, workers, opts) } diff --git a/pkg/state/state.go b/pkg/state/state.go index cb402201..8f7dc0be 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -253,7 +253,12 @@ type syncPrepareResult struct { } // SyncReleases wrapper for executing helm upgrade on the releases -func (st *HelmState) prepareSyncReleases(helm helmexec.Interface, additionalValues []string, concurrency int) ([]syncPrepareResult, []error) { +func (st *HelmState) prepareSyncReleases(helm helmexec.Interface, additionalValues []string, concurrency int, opt ...SyncOpt) ([]syncPrepareResult, []error) { + opts := &SyncOpts{} + for _, o := range opt { + o.Apply(opts) + } + releases := []*ReleaseSpec{} for i, _ := range st.Releases { releases = append(releases, &st.Releases[i]) @@ -318,6 +323,12 @@ func (st *HelmState) prepareSyncReleases(helm helmexec.Interface, additionalValu flags = append(flags, "--values", valfile) } + if opts.Set != nil { + for _, s := range opts.Set { + flags = append(flags, "--set", s) + } + } + if len(errs) > 0 { results <- syncPrepareResult{errors: errs} continue @@ -372,9 +383,24 @@ func (st *HelmState) DetectReleasesToBeDeleted(helm helmexec.Interface) ([]*Rele return detected, nil } +type SyncOpts struct { + Set []string +} + +type SyncOpt interface{ Apply(*SyncOpts) } + +func (o *SyncOpts) Apply(opts *SyncOpts) { + *opts = *o +} + // SyncReleases wrapper for executing helm upgrade on the releases -func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helmexec.Interface, additionalValues []string, workerLimit int) []error { - preps, prepErrs := st.prepareSyncReleases(helm, additionalValues, workerLimit) +func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helmexec.Interface, additionalValues []string, workerLimit int, opt ...SyncOpt) []error { + opts := &SyncOpts{} + for _, o := range opt { + o.Apply(opts) + } + + preps, prepErrs := st.prepareSyncReleases(helm, additionalValues, workerLimit, opts) if len(prepErrs) > 0 { return prepErrs } @@ -550,8 +576,23 @@ func (st *HelmState) downloadCharts(helm helmexec.Interface, dir string, concurr return temp, nil } +type TemplateOpts struct { + Set []string +} + +type TemplateOpt interface{ Apply(*TemplateOpts) } + +func (o *TemplateOpts) Apply(opts *TemplateOpts) { + *opts = *o +} + // TemplateReleases wrapper for executing helm template on the releases -func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string, additionalValues []string, args []string, workerLimit int) []error { +func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string, additionalValues []string, args []string, workerLimit int, opt ...TemplateOpt) []error { + opts := &TemplateOpts{} + for _, o := range opt { + o.Apply(opts) + } + // Reset the extra args if already set, not to break `helm fetch` by adding the args intended for `lint` helm.SetExtraArgs() @@ -601,6 +642,12 @@ func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string, flags = append(flags, "--values", valfile) } + if opts.Set != nil { + for _, s := range opts.Set { + flags = append(flags, "--set", s) + } + } + if len(outputDir) > 0 { releaseOutputDir, err := st.GenerateOutputDir(outputDir, release) if err != nil { @@ -630,8 +677,23 @@ func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string, return nil } +type LintOpts struct { + Set []string +} + +type LintOpt interface{ Apply(*LintOpts) } + +func (o *LintOpts) Apply(opts *LintOpts) { + *opts = *o +} + // LintReleases wrapper for executing helm lint on the releases -func (st *HelmState) LintReleases(helm helmexec.Interface, additionalValues []string, args []string, workerLimit int) []error { +func (st *HelmState) LintReleases(helm helmexec.Interface, additionalValues []string, args []string, workerLimit int, opt ...LintOpt) []error { + opts := &LintOpts{} + for _, o := range opt { + o.Apply(opts) + } + // Reset the extra args if already set, not to break `helm fetch` by adding the args intended for `lint` helm.SetExtraArgs() @@ -677,6 +739,12 @@ func (st *HelmState) LintReleases(helm helmexec.Interface, additionalValues []st flags = append(flags, "--values", valfile) } + if opts.Set != nil { + for _, s := range opts.Set { + flags = append(flags, "--set", s) + } + } + if len(errs) == 0 { if err := helm.Lint(release.Name, temp[release.Name], flags...); err != nil { errs = append(errs, err) @@ -780,6 +848,12 @@ func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValu flags = append(flags, "--context", fmt.Sprintf("%d", opts.Context)) } + if opts.Set != nil { + for _, s := range opts.Set { + flags = append(flags, "--set", s) + } + } + if len(errs) > 0 { rsErrs := make([]*ReleaseError, len(errs)) for i, e := range errs { @@ -826,8 +900,9 @@ func (st *HelmState) createHelmContext(spec *ReleaseSpec, workerIndex int) helme } type DiffOpts struct { - NoColor bool Context int + NoColor bool + Set []string } func (o *DiffOpts) Apply(opts *DiffOpts) {