diff --git a/pkg/state/helmx.go b/pkg/state/helmx.go index 0a75df98..bf7bd46a 100644 --- a/pkg/state/helmx.go +++ b/pkg/state/helmx.go @@ -13,10 +13,12 @@ import ( "github.com/helmfile/chartify" "helm.sh/helm/v4/pkg/storage/driver" + "github.com/helmfile/helmfile/pkg/filesystem" "github.com/helmfile/helmfile/pkg/helmexec" "github.com/helmfile/helmfile/pkg/kubedog" "github.com/helmfile/helmfile/pkg/remote" "github.com/helmfile/helmfile/pkg/resource" + "github.com/helmfile/helmfile/pkg/tmpl" ) type Dependency struct { @@ -115,7 +117,7 @@ func (st *HelmState) appendPostRenderFlags(flags []string, release *ReleaseSpec, } // append post-renderer-args flags to helm flags -func (st *HelmState) appendPostRenderArgsFlags(flags []string, release *ReleaseSpec, postRendererArgs []string) []string { +func (st *HelmState) appendPostRenderArgsFlags(flags []string, release *ReleaseSpec, postRendererArgs []string) ([]string, error) { postRendererArgsFlags := []string{} switch { case len(release.PostRendererArgs) != 0: @@ -123,14 +125,44 @@ func (st *HelmState) appendPostRenderArgsFlags(flags []string, release *ReleaseS case len(postRendererArgs) != 0: postRendererArgsFlags = postRendererArgs case len(st.HelmDefaults.PostRendererArgs) != 0: - postRendererArgsFlags = st.HelmDefaults.PostRendererArgs + rendered, err := st.renderPostRendererArgs(release, st.HelmDefaults.PostRendererArgs) + if err != nil { + return nil, err + } + postRendererArgsFlags = rendered } for _, arg := range postRendererArgsFlags { if arg != "" { flags = append(flags, "--post-renderer-args="+arg) } } - return flags + return flags, nil +} + +func (st *HelmState) renderPostRendererArgs(release *ReleaseSpec, args []string) ([]string, error) { + vals := st.RenderedValues + if vals == nil { + vals = make(map[string]any) + } + + fs := st.fs + if fs == nil { + fs = filesystem.DefaultFileSystem() + } + + tmplData := st.createReleaseTemplateData(release, vals) + renderer := tmpl.NewFileRenderer(fs, st.basePath, tmplData) + + result := make([]string, 0, len(args)) + for _, arg := range args { + rendered, err := renderer.RenderTemplateContentToString([]byte(arg)) + if err != nil { + return nil, fmt.Errorf("failed rendering postRendererArg %q for release %q: %w", arg, release.Name, err) + } + result = append(result, rendered) + } + + return result, nil } // append skip-schema-validation flags to helm flags diff --git a/pkg/state/state.go b/pkg/state/state.go index 8a82e85e..d63f6404 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -3627,7 +3627,10 @@ func (st *HelmState) flagsForUpgrade(helm helmexec.Interface, release *ReleaseSp if opt != nil { postRendererArgs = opt.PostRendererArgs } - flags = st.appendPostRenderArgsFlags(flags, release, postRendererArgs) + flags, err = st.appendPostRenderArgsFlags(flags, release, postRendererArgs) + if err != nil { + return nil, nil, err + } skipSchemaValidation := false if opt != nil { @@ -3670,7 +3673,10 @@ func (st *HelmState) flagsForTemplate(helm helmexec.Interface, release *ReleaseS skipSchemaValidation = opt.SkipSchemaValidation } flags = st.appendPostRenderFlags(flags, release, postRenderer, helm) - flags = st.appendPostRenderArgsFlags(flags, release, postRendererArgs) + flags, err := st.appendPostRenderArgsFlags(flags, release, postRendererArgs) + if err != nil { + return nil, nil, err + } flags = st.appendApiVersionsFlags(flags, release, kubeVersion) flags = st.appendChartDownloadFlags(flags, release) flags = st.appendShowOnlyFlags(flags, showOnly) @@ -3793,7 +3799,11 @@ func (st *HelmState) flagsForDiff(helm helmexec.Interface, release *ReleaseSpec, if opt != nil { postRendererArgs = opt.PostRendererArgs } - flags = st.appendPostRenderArgsFlags(flags, release, postRendererArgs) + var err error + flags, err = st.appendPostRenderArgsFlags(flags, release, postRendererArgs) + if err != nil { + return nil, nil, err + } skipSchemaValidation := false if opt != nil { @@ -3823,7 +3833,6 @@ func (st *HelmState) flagsForDiff(helm helmexec.Interface, release *ReleaseSpec, takeOwnership = opt.TakeOwnership } - var err error flags, err = st.appendTakeOwnershipFlagsForDiff(flags, release, takeOwnership, pluginsDir) if err != nil { return nil, nil, err diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go index 9f1038df..d188cd57 100644 --- a/pkg/state/state_test.go +++ b/pkg/state/state_test.go @@ -1048,6 +1048,51 @@ func TestHelmState_flagsForUpgrade(t *testing.T) { "--namespace", "test-namespace", }, }, + { + name: "post-renderer-args-helmdefault-templated-with-release-name", + defaults: HelmSpec{ + Verify: false, + CreateNamespace: &enable, + PostRendererArgs: []string{"{{ .Release.Name }}", "--chart={{ .Release.Chart }}"}, + }, + version: semver.MustParse("3.10.0"), + release: &ReleaseSpec{ + Chart: "test/chart", + Version: "0.1", + Verify: &disable, + Name: "my-release", + Namespace: "test-namespace", + CreateNamespace: &disable, + }, + want: []string{ + "--version", "0.1", + "--post-renderer-args=my-release", + "--post-renderer-args=--chart=test/chart", + "--namespace", "test-namespace", + }, + }, + { + name: "post-renderer-args-helmdefault-templated-with-namespace", + defaults: HelmSpec{ + Verify: false, + CreateNamespace: &enable, + PostRendererArgs: []string{"{{ .Release.Namespace }}/{{ .Release.Name }}"}, + }, + version: semver.MustParse("3.10.0"), + release: &ReleaseSpec{ + Chart: "test/chart", + Version: "0.1", + Verify: &disable, + Name: "my-release", + Namespace: "test-namespace", + CreateNamespace: &disable, + }, + want: []string{ + "--version", "0.1", + "--post-renderer-args=test-namespace/my-release", + "--namespace", "test-namespace", + }, + }, { name: "description-from-release", defaults: HelmSpec{ diff --git a/test/integration/run.sh b/test/integration/run.sh index e6b491ec..2637ae0c 100755 --- a/test/integration/run.sh +++ b/test/integration/run.sh @@ -116,6 +116,7 @@ ${kubectl} create namespace ${test_ns} || fail "Could not create namespace ${tes . ${dir}/test-cases/yaml-overwrite.sh . ${dir}/test-cases/chart-needs.sh . ${dir}/test-cases/postrender.sh +. ${dir}/test-cases/postrender-defaults-args.sh . ${dir}/test-cases/issue-2515.sh . ${dir}/test-cases/chartify.sh . ${dir}/test-cases/deps-mr-1011.sh diff --git a/test/integration/test-cases/postrender-defaults-args.sh b/test/integration/test-cases/postrender-defaults-args.sh new file mode 100644 index 00000000..1c1b6699 --- /dev/null +++ b/test/integration/test-cases/postrender-defaults-args.sh @@ -0,0 +1,25 @@ +postrender_defaults_args_case_input_dir="${cases_dir}/postrender-defaults-args/input" +postrender_defaults_args_case_output_dir="${cases_dir}/postrender-defaults-args/output" + +# Helm 4 requires post-renderers to be plugins +if [ "${HELMFILE_HELM4}" = "1" ]; then + info "Installing echo-args post-renderer plugin for Helm 4" + ${helm} plugin uninstall echo-args &>/dev/null || true + ${helm} plugin install ${postrender_defaults_args_case_input_dir}/helm-plugin-echo-args ${PLUGIN_INSTALL_FLAGS} || fail "Failed to install echo-args plugin" +fi + +config_file="helmfile.yaml.gotmpl" +postrender_defaults_args_tmp=$(mktemp -d) + +test_start "postrender-defaults-args template" +info "Running helmfile template with helmDefaults.postRendererArgs containing {{ .Release.Name }}" +${helmfile} -f ${postrender_defaults_args_case_input_dir}/${config_file} template --concurrency 1 &> ${postrender_defaults_args_tmp}/template.out || fail "\"helmfile template\" shouldn't fail" + +info "Verifying that helmDefaults.postRendererArgs were templated with release names" +grep -q "name: rendered-arg-foo" ${postrender_defaults_args_tmp}/template.out || fail "Expected postRendererArg 'foo' for release foo, but not found in output" +grep -q "name: rendered-arg-bar" ${postrender_defaults_args_tmp}/template.out || fail "Expected postRendererArg 'bar' for release bar, but not found in output" + +info "Verifying that literal template expression was NOT passed" +grep -q "rendered-arg-{{ .Release.Name }}" ${postrender_defaults_args_tmp}/template.out && fail "Template expression was NOT rendered (found literal {{ .Release.Name }})" + +test_pass "postrender-defaults-args template" diff --git a/test/integration/test-cases/postrender-defaults-args/input/echo-args.bash b/test/integration/test-cases/postrender-defaults-args/input/echo-args.bash new file mode 100755 index 00000000..41fc557c --- /dev/null +++ b/test/integration/test-cases/postrender-defaults-args/input/echo-args.bash @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +arg=$1 +cat +echo "---" +cat <