diff --git a/cmd/template.go b/cmd/template.go index 8cf8d178..c5a1f64d 100644 --- a/cmd/template.go +++ b/cmd/template.go @@ -45,6 +45,7 @@ func NewTemplateCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.BoolVar(&templateOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`) f.BoolVar(&templateOptions.SkipCleanup, "skip-cleanup", false, "Stop cleaning up temporary values generated by helmfile and helm-secrets. Useful for debugging. Don't use in production for security") f.StringVar(&templateOptions.PostRenderer, "post-renderer", "", `pass --post-renderer to "helm template" or "helm upgrade --install"`) + f.StringVar(&templateOptions.KubeVersion, "kube-version", "", `pass --kube-version to "helm template". Overrides kubeVersion in helmfile.yaml`) return cmd } diff --git a/pkg/app/app.go b/pkg/app/app.go index d9557e28..d4c10127 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -1884,6 +1884,7 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) { SkipCleanup: c.SkipCleanup(), SkipTests: c.SkipTests(), PostRenderer: c.PostRenderer(), + KubeVersion: c.KubeVersion(), } return st.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), c.Validate(), opts) }) diff --git a/pkg/app/app_test.go b/pkg/app/app_test.go index 5c2b2897..792c81ba 100644 --- a/pkg/app/app_test.go +++ b/pkg/app/app_test.go @@ -2097,6 +2097,7 @@ type configImpl struct { includeNeeds bool includeTransitiveNeeds bool skipCharts bool + kubeVersion string } func (c configImpl) Selectors() []string { @@ -2179,6 +2180,10 @@ func (c configImpl) PostRenderer() string { return "" } +func (c configImpl) KubeVersion() string { + return c.kubeVersion +} + type applyConfig struct { args string values []string @@ -2213,6 +2218,7 @@ type applyConfig struct { waitForJobs bool reuseValues bool postRenderer string + kubeVersion string // template-only options includeCRDs, skipTests bool @@ -2361,6 +2367,10 @@ func (a applyConfig) PostRenderer() string { return a.postRenderer } +func (a applyConfig) KubeVersion() string { + return a.kubeVersion +} + type depsConfig struct { skipRepos bool includeTransitiveNeeds bool diff --git a/pkg/app/config.go b/pkg/app/config.go index 18cde3e7..3ba235f4 100644 --- a/pkg/app/config.go +++ b/pkg/app/config.go @@ -208,6 +208,7 @@ type TemplateConfigProvider interface { SkipTests() bool OutputDir() string IncludeCRDs() bool + KubeVersion() string DAGConfig diff --git a/pkg/config/template.go b/pkg/config/template.go index 95fbe855..00b6e455 100644 --- a/pkg/config/template.go +++ b/pkg/config/template.go @@ -34,6 +34,8 @@ type TemplateOptions struct { SkipCleanup bool // Propagate '--post-renderer' to helmv3 template and helm install PostRenderer string + // KubeVersion is the kube-version flag + KubeVersion string } // NewTemplateOptions creates a new Apply @@ -123,3 +125,8 @@ func (t *TemplateImpl) Values() []string { func (t *TemplateImpl) PostRenderer() string { return t.TemplateOptions.PostRenderer } + +// KubeVersion returns the the KubeVersion. +func (t *TemplateImpl) KubeVersion() string { + return t.TemplateOptions.KubeVersion +} diff --git a/pkg/state/state.go b/pkg/state/state.go index 20d37f99..9404c827 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -1040,6 +1040,7 @@ type ChartPrepareOptions struct { OutputDirTemplate string IncludeTransitiveNeeds bool Concurrency int + KubeVersion string } type chartPrepareResult struct { @@ -1384,6 +1385,7 @@ type TemplateOpts struct { IncludeCRDs bool SkipTests bool PostRenderer string + KubeVersion string } type TemplateOpt interface{ Apply(*TemplateOpts) } @@ -2540,13 +2542,14 @@ func (st *HelmState) flagsForTemplate(helm helmexec.Interface, release *ReleaseS flags = st.appendHelmXFlags(flags, release) - flags = st.appendApiVersionsFlags(flags, release) - postRenderer := "" + kubeVersion := "" if opt != nil { postRenderer = opt.PostRenderer + kubeVersion = opt.KubeVersion } flags = st.appendPostRenderFlags(flags, release, postRenderer) + flags = st.appendApiVersionsFlags(flags, release, kubeVersion) common, files, err := st.namespaceAndValuesFlags(helm, release, workerIndex) if err != nil { @@ -2579,7 +2582,11 @@ func (st *HelmState) flagsForDiff(helm helmexec.Interface, release *ReleaseSpec, flags = append(flags, "--disable-validation") } - flags = st.appendApiVersionsFlags(flags, release) + // TODO: + // `helm diff` has `--kube-version` flag from v3.5.0, but only respected when `helm diff upgrade --disable-validation`. + // `helm template --validate` and `helm upgrade --dry-run` ignore `--kube-version` flag. + // For the moment, not specifying kubeVersion. + flags = st.appendApiVersionsFlags(flags, release, "") flags = st.appendConnectionFlags(flags, release) @@ -2622,7 +2629,7 @@ func (st *HelmState) appendValuesControlModeFlag(flags []string, reuseValues boo return flags } -func (st *HelmState) appendApiVersionsFlags(flags []string, r *ReleaseSpec) []string { +func (st *HelmState) appendApiVersionsFlags(flags []string, r *ReleaseSpec, kubeVersion string) []string { if len(r.ApiVersions) != 0 { for _, a := range r.ApiVersions { flags = append(flags, "--api-versions", a) @@ -2633,9 +2640,12 @@ func (st *HelmState) appendApiVersionsFlags(flags []string, r *ReleaseSpec) []st } } - if r.KubeVersion != "" { + switch { + case kubeVersion != "": + flags = append(flags, "--kube-version", kubeVersion) + case r.KubeVersion != "": flags = append(flags, "--kube-version", r.KubeVersion) - } else if st.KubeVersion != "" { + case st.KubeVersion != "": flags = append(flags, "--kube-version", st.KubeVersion) } diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go index 3ef3816c..b23ad9a0 100644 --- a/pkg/state/state_test.go +++ b/pkg/state/state_test.go @@ -736,12 +736,13 @@ func TestHelmState_flagsForTemplate(t *testing.T) { postRendererRelease := "foo-release.sh" tests := []struct { - name string - version *semver.Version - defaults HelmSpec - release *ReleaseSpec - want []string - wantErr string + name string + version *semver.Version + defaults HelmSpec + release *ReleaseSpec + templateOpts TemplateOpts + want []string + wantErr string }{ { name: "post-renderer-flags-use-helmdefault", @@ -810,6 +811,55 @@ func TestHelmState_flagsForTemplate(t *testing.T) { "--namespace", "test-namespace", }, }, + { + name: "kube-version-flag-should-be-used", + defaults: HelmSpec{ + Verify: false, + CreateNamespace: &enable, + }, + version: semver.MustParse("3.10.0"), + release: &ReleaseSpec{ + Chart: "test/chart", + Version: "0.1", + Verify: &disable, + Name: "test-charts", + Namespace: "test-namespace", + CreateNamespace: &disable, + }, + templateOpts: TemplateOpts{ + KubeVersion: "1.100", + }, + want: []string{ + "--version", "0.1", + "--kube-version", "1.100", + "--namespace", "test-namespace", + }, + }, + { + name: "kube-version-flag-should-be-respected", + defaults: HelmSpec{ + Verify: false, + CreateNamespace: &enable, + }, + version: semver.MustParse("3.10.0"), + release: &ReleaseSpec{ + Chart: "test/chart", + Version: "0.1", + Verify: &disable, + Name: "test-charts", + Namespace: "test-namespace", + CreateNamespace: &disable, + KubeVersion: "1.25", + }, + templateOpts: TemplateOpts{ + KubeVersion: "1.100", + }, + want: []string{ + "--version", "0.1", + "--kube-version", "1.100", + "--namespace", "test-namespace", + }, + }, } for i := range tests { tt := tests[i] @@ -827,7 +877,7 @@ func TestHelmState_flagsForTemplate(t *testing.T) { Version: tt.version, } - args, _, err := state.flagsForTemplate(helm, tt.release, 0, &TemplateOpts{}) + args, _, err := state.flagsForTemplate(helm, tt.release, 0, &(tt.templateOpts)) if err != nil && tt.wantErr == "" { t.Errorf("unexpected error flagsForUpgrade: %v", err) }