From ad258463b6e02594378df228062da24eaa0582b7 Mon Sep 17 00:00:00 2001 From: Alessio Dionisi Date: Wed, 13 Sep 2023 13:58:53 +0200 Subject: [PATCH] feat: add an option to set a custom kustomize binary (#1012) Signed-off-by: Alessio Dionisi --- cmd/root.go | 1 + docs/index.md | 5 ++++- go.mod | 2 +- go.sum | 4 ++-- pkg/app/app.go | 13 ++++++++----- pkg/app/config.go | 1 + pkg/app/desired_state_file_loader.go | 12 +++++++----- pkg/config/global.go | 9 ++++++++- pkg/state/create.go | 19 +++++++++++++++---- pkg/state/create_test.go | 8 ++++---- pkg/state/state.go | 4 +++- .../output.yaml | 1 + 12 files changed, 55 insertions(+), 24 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 0d66fac4..9038987f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -115,6 +115,7 @@ func NewRootCmd(globalConfig *config.GlobalOptions) (*cobra.Command, error) { func setGlobalOptionsForRootCmd(fs *pflag.FlagSet, globalOptions *config.GlobalOptions) { fs.StringVarP(&globalOptions.HelmBinary, "helm-binary", "b", app.DefaultHelmBinary, "Path to the helm binary") + fs.StringVarP(&globalOptions.KustomizeBinary, "kustomize-binary", "k", app.DefaultKustomizeBinary, "Path to the kustomize binary") fs.StringVarP(&globalOptions.File, "file", "f", "", "load config from file or directory. defaults to \"`helmfile.yaml`\" or \"helmfile.yaml.gotmpl\" or \"helmfile.d\" (means \"helmfile.d/*.yaml\" or \"helmfile.d/*.yaml.gotmpl\") in this preference. Specify - to load the config from the standard input.") fs.StringVarP(&globalOptions.Environment, "environment", "e", "", `specify the environment name. Overrides "HELMFILE_ENVIRONMENT" OS environment variable when specified. defaults to "default"`) fs.StringArrayVar(&globalOptions.StateValuesSet, "state-values-set", nil, "set state values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2). Used to override .Values within the helmfile template (not values template).") diff --git a/docs/index.md b/docs/index.md index 727eac4a..7b486c9f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -167,6 +167,8 @@ repositories: # Path to alternative helm binary (--helm-binary) helmBinary: path/to/helm3 +# Path to alternative kustomize binary (--kustomize-binary) +kustomizeBinary: path/to/kustomize # Path to alternative lock file. The default is .lock, i.e for helmfile.yaml it's helmfile.lock. lockFilePath: path/to/lock.file @@ -554,6 +556,7 @@ Flags: -h, --help help for helmfile -i, --interactive Request confirmation before attempting to modify clusters --kube-context string Set kubectl context. Uses current context by default + -k, --kustomize-binary string Path to the kustomize binary (default "kustomize") --log-level string Set log level, default info (default "info") -n, --namespace string Set namespace. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }} --no-color Output without color @@ -565,7 +568,7 @@ Flags: --skip-deps skip running "helm repo update" and "helm dependency build" --state-values-file stringArray specify state values in a YAML file. Used to override .Values within the helmfile template (not values template). --state-values-set stringArray set state values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2). Used to override .Values within the helmfile template (not values template). - --strip-args-values-on-exit-error On exit error, strip the values of the args + --strip-args-values-on-exit-error Strip the potential secret values of the helm command args contained in a helmfile error message (default true) -v, --version version for helmfile Use "helmfile [command] --help" for more information about a command. diff --git a/go.mod b/go.mod index f80956c4..bd4a16e4 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/google/go-cmp v0.5.9 github.com/gosuri/uitable v0.0.4 github.com/hashicorp/go-getter v1.7.2 - github.com/helmfile/chartify v0.15.0 + github.com/helmfile/chartify v0.16.0 github.com/helmfile/vals v0.27.1 github.com/imdario/mergo v0.3.16 github.com/spf13/cobra v1.7.0 diff --git a/go.sum b/go.sum index 75303c67..40477a98 100644 --- a/go.sum +++ b/go.sum @@ -687,8 +687,8 @@ github.com/hashicorp/vault/sdk v0.4.1/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaak github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/helmfile/chartify v0.15.0 h1:dxDPK1GdGhijJ7bw2hYmq9mmp3Q6jvNGDoJc1LtTybg= -github.com/helmfile/chartify v0.15.0/go.mod h1:7pmJlGn79CDMBD1+NbDJtE3L7q0hZf5GyBCJrV78vLA= +github.com/helmfile/chartify v0.16.0 h1:dJhLUQuB5EklmfOS8zt5ljofvh0bhGUc3EsnXK7u4q0= +github.com/helmfile/chartify v0.16.0/go.mod h1:7pmJlGn79CDMBD1+NbDJtE3L7q0hZf5GyBCJrV78vLA= github.com/helmfile/vals v0.27.1 h1:j1EzMeq5lCEePqmwNYpi2w791gDscKeKF95YpB4flig= github.com/helmfile/vals v0.27.1/go.mod h1:VV8Wy8Bvm/K0hTb3f3H80P1NWollaRGRi8+nkWaS15E= github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8= diff --git a/pkg/app/app.go b/pkg/app/app.go index c529926c..606c5b5f 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -30,6 +30,7 @@ var Cancel goContext.CancelFunc type App struct { OverrideKubeContext string OverrideHelmBinary string + OverrideKustomizeBinary string EnableLiveOutput bool StripArgsValuesOnExitError bool DisableForceUpdate bool @@ -74,6 +75,7 @@ func New(conf ConfigProvider) *App { return Init(&App{ OverrideKubeContext: conf.KubeContext(), OverrideHelmBinary: conf.HelmBinary(), + OverrideKustomizeBinary: conf.KustomizeBinary(), EnableLiveOutput: conf.EnableLiveOutput(), StripArgsValuesOnExitError: conf.StripArgsValuesOnExitError(), DisableForceUpdate: conf.DisableForceUpdate(), @@ -758,11 +760,12 @@ func (a *App) loadDesiredStateFromYaml(file string, opts ...LoadOpts) (*state.He logger: a.Logger, remote: a.remote, - overrideKubeContext: a.OverrideKubeContext, - overrideHelmBinary: a.OverrideHelmBinary, - enableLiveOutput: a.EnableLiveOutput, - getHelm: a.getHelm, - valsRuntime: a.valsRuntime, + overrideKubeContext: a.OverrideKubeContext, + overrideHelmBinary: a.OverrideHelmBinary, + overrideKustomizeBinary: a.OverrideKustomizeBinary, + enableLiveOutput: a.EnableLiveOutput, + getHelm: a.getHelm, + valsRuntime: a.valsRuntime, } return ld.Load(file, op) diff --git a/pkg/app/config.go b/pkg/app/config.go index 712ab130..14cd840c 100644 --- a/pkg/app/config.go +++ b/pkg/app/config.go @@ -5,6 +5,7 @@ import "go.uber.org/zap" type ConfigProvider interface { Args() string HelmBinary() string + KustomizeBinary() string EnableLiveOutput() bool StripArgsValuesOnExitError() bool DisableForceUpdate() bool diff --git a/pkg/app/desired_state_file_loader.go b/pkg/app/desired_state_file_loader.go index b059628e..04e7bbad 100644 --- a/pkg/app/desired_state_file_loader.go +++ b/pkg/app/desired_state_file_loader.go @@ -20,13 +20,15 @@ import ( ) const ( - DefaultHelmBinary = state.DefaultHelmBinary + DefaultHelmBinary = state.DefaultHelmBinary + DefaultKustomizeBinary = state.DefaultKustomizeBinary ) type desiredStateLoader struct { - overrideKubeContext string - overrideHelmBinary string - enableLiveOutput bool + overrideKubeContext string + overrideHelmBinary string + overrideKustomizeBinary string + enableLiveOutput bool env string namespace string @@ -152,7 +154,7 @@ func (ld *desiredStateLoader) loadFileWithOverrides(inheritedEnv, overrodeEnv *e } func (a *desiredStateLoader) underlying() *state.StateCreator { - c := state.NewCreator(a.logger, a.fs, a.valsRuntime, a.getHelm, a.overrideHelmBinary, a.remote, a.enableLiveOutput, a.lockFilePath) + c := state.NewCreator(a.logger, a.fs, a.valsRuntime, a.getHelm, a.overrideHelmBinary, a.overrideKustomizeBinary, a.remote, a.enableLiveOutput, a.lockFilePath) c.LoadFile = a.loadFile return c } diff --git a/pkg/config/global.go b/pkg/config/global.go index 923c9c1f..0132fe1a 100644 --- a/pkg/config/global.go +++ b/pkg/config/global.go @@ -13,8 +13,10 @@ import ( // GlobalOptions is the global configuration for the Helmfile CLI. type GlobalOptions struct { - // helmBinary is the path to the Helm binary. + // HelmBinary is the path to the Helm binary. HelmBinary string + // KustomizeBinary is the path to the Kustomize binary. + KustomizeBinary string // File is the path to the Helmfile. File string // Environment is the name of the environment to use. @@ -93,6 +95,11 @@ func (g *GlobalImpl) HelmBinary() string { return g.GlobalOptions.HelmBinary } +// KustomizeBinary returns the path to the Kustomize binary. +func (g *GlobalImpl) KustomizeBinary() string { + return g.GlobalOptions.KustomizeBinary +} + // KubeContext returns the name of the kubectl context to use. func (g *GlobalImpl) KubeContext() string { return g.GlobalOptions.KubeContext diff --git a/pkg/state/create.go b/pkg/state/create.go index c25e705a..361be7d7 100644 --- a/pkg/state/create.go +++ b/pkg/state/create.go @@ -18,7 +18,8 @@ import ( ) const ( - DefaultHelmBinary = "helm" + DefaultHelmBinary = "helm" + DefaultKustomizeBinary = "kustomize" ) type StateLoadError struct { @@ -53,6 +54,8 @@ type StateCreator struct { overrideHelmBinary string + overrideKustomizeBinary string + enableLiveOutput bool remote *remote.Remote @@ -60,7 +63,7 @@ type StateCreator struct { lockFile string } -func NewCreator(logger *zap.SugaredLogger, fs *filesystem.FileSystem, valsRuntime vals.Evaluator, getHelm func(*HelmState) helmexec.Interface, overrideHelmBinary string, remote *remote.Remote, enableLiveOutput bool, lockFile string) *StateCreator { +func NewCreator(logger *zap.SugaredLogger, fs *filesystem.FileSystem, valsRuntime vals.Evaluator, getHelm func(*HelmState) helmexec.Interface, overrideHelmBinary string, overrideKustomizeBinary string, remote *remote.Remote, enableLiveOutput bool, lockFile string) *StateCreator { return &StateCreator{ logger: logger, @@ -69,8 +72,9 @@ func NewCreator(logger *zap.SugaredLogger, fs *filesystem.FileSystem, valsRuntim valsRuntime: valsRuntime, getHelm: getHelm, - overrideHelmBinary: overrideHelmBinary, - enableLiveOutput: enableLiveOutput, + overrideHelmBinary: overrideHelmBinary, + overrideKustomizeBinary: overrideKustomizeBinary, + enableLiveOutput: enableLiveOutput, remote: remote, @@ -131,6 +135,13 @@ func (c *StateCreator) Parse(content []byte, baseDir, file string) (*HelmState, state.DefaultHelmBinary = DefaultHelmBinary } + if c.overrideKustomizeBinary != "" && c.overrideKustomizeBinary != DefaultKustomizeBinary { + state.DefaultKustomizeBinary = c.overrideKustomizeBinary + } else if state.DefaultKustomizeBinary == "" { + // Let `helmfile --kustomize-binary ""` not break this helmfile run + state.DefaultKustomizeBinary = DefaultKustomizeBinary + } + state.logger = c.logger state.valsRuntime = c.valsRuntime diff --git a/pkg/state/create_test.go b/pkg/state/create_test.go index f1d930ce..46b1e072 100644 --- a/pkg/state/create_test.go +++ b/pkg/state/create_test.go @@ -84,7 +84,7 @@ func (testEnv stateTestEnv) MustLoadStateWithEnableLiveOutput(t *testing.T, file } r := remote.NewRemote(logger, testFs.Cwd, testFs.ToFileSystem()) - state, err := NewCreator(logger, testFs.ToFileSystem(), nil, nil, "", r, enableLiveOutput, ""). + state, err := NewCreator(logger, testFs.ToFileSystem(), nil, nil, "", "", r, enableLiveOutput, ""). ParseAndLoad([]byte(yamlContent), filepath.Dir(file), file, envName, true, true, nil, nil) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -154,7 +154,7 @@ releaseNamespace: mynamespace env := environment.Environment{ Name: "production", } - state, err := NewCreator(logger, testFs.ToFileSystem(), nil, nil, "", r, false, ""). + state, err := NewCreator(logger, testFs.ToFileSystem(), nil, nil, "", "", r, false, ""). ParseAndLoad(yamlContent, filepath.Dir(yamlFile), yamlFile, "production", true, true, &env, nil) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -241,7 +241,7 @@ overrideNamespace: myns testFs.Cwd = "/example/path/to" r := remote.NewRemote(logger, testFs.Cwd, testFs.ToFileSystem()) - state, err := NewCreator(logger, testFs.ToFileSystem(), nil, nil, "", r, false, ""). + state, err := NewCreator(logger, testFs.ToFileSystem(), nil, nil, "", "", r, false, ""). ParseAndLoad(yamlContent, filepath.Dir(yamlFile), yamlFile, "production", true, true, nil, nil) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -525,7 +525,7 @@ releaseContext: testFs.Cwd = "/example/path/to" r := remote.NewRemote(logger, testFs.Cwd, testFs.ToFileSystem()) - state, err := NewCreator(logger, testFs.ToFileSystem(), nil, nil, "", r, false, ""). + state, err := NewCreator(logger, testFs.ToFileSystem(), nil, nil, "", "", r, false, ""). ParseAndLoad(yamlContent, filepath.Dir(yamlFile), yamlFile, "production", true, true, nil, nil) if err != nil { t.Fatalf("unexpected error: %v", err) diff --git a/pkg/state/state.go b/pkg/state/state.go index 05cbb914..02e15fad 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -43,7 +43,8 @@ const ( // ReleaseSetSpec is release set spec type ReleaseSetSpec struct { - DefaultHelmBinary string `yaml:"helmBinary,omitempty"` + DefaultHelmBinary string `yaml:"helmBinary,omitempty"` + DefaultKustomizeBinary string `yaml:"kustomizeBinary,omitempty"` // DefaultValues is the default values to be overrode by environment values and command-line overrides DefaultValues []any `yaml:"values,omitempty"` @@ -1199,6 +1200,7 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre if chartification != nil && helmfileCommand != "pull" { c := chartify.New( chartify.HelmBin(st.DefaultHelmBinary), + chartify.KustomizeBin(st.DefaultKustomizeBinary), chartify.UseHelm3(true), chartify.WithLogf(st.logger.Debugf), ) diff --git a/test/e2e/template/helmfile/testdata/snapshot/issue_2098_release_template_needs/output.yaml b/test/e2e/template/helmfile/testdata/snapshot/issue_2098_release_template_needs/output.yaml index 03b8ec8a..97d3f08a 100644 --- a/test/e2e/template/helmfile/testdata/snapshot/issue_2098_release_template_needs/output.yaml +++ b/test/e2e/template/helmfile/testdata/snapshot/issue_2098_release_template_needs/output.yaml @@ -3,6 +3,7 @@ filepath: input.yaml helmBinary: helm +kustomizeBinary: kustomize environments: default: {} repositories: