change dry-run to be used per default on sync and apply for chartify to achieve consistent behavior. For template prodive option --template-args

Signed-off-by: Kerstin Albers <kerstinzuzej@gmail.com>
This commit is contained in:
KATechDev 2025-09-30 17:15:18 +02:00 committed by Kerstin Albers
parent bc3ceabee7
commit f53fb4f37f
15 changed files with 172 additions and 165 deletions

View File

@ -42,7 +42,6 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&applyOptions.StripTrailingCR, "strip-trailing-cr", false, "strip trailing carriage return on input") f.BoolVar(&applyOptions.StripTrailingCR, "strip-trailing-cr", false, "strip trailing carriage return on input")
f.StringVar(&applyOptions.DiffArgs, "diff-args", "", `pass args to helm helm-diff`) f.StringVar(&applyOptions.DiffArgs, "diff-args", "", `pass args to helm helm-diff`)
f.StringVar(&applyOptions.SyncArgs, "sync-args", "", `pass args to helm upgrade`) f.StringVar(&applyOptions.SyncArgs, "sync-args", "", `pass args to helm upgrade`)
f.StringVar(&applyOptions.TemplateArgs, "template-args", "", `pass args to helm template`)
f.StringVar(&globalCfg.GlobalOptions.Args, "args", "", "pass args to helm exec") f.StringVar(&globalCfg.GlobalOptions.Args, "args", "", "pass args to helm exec")
f.BoolVar(&applyOptions.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.BoolVar(&applyOptions.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.BoolVar(&applyOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present") f.BoolVar(&applyOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present")

View File

@ -50,7 +50,7 @@ func NewTemplateCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&templateOptions.SkipSchemaValidation, "skip-schema-validation", false, `pass skip-schema-validation to "helm template" or "helm upgrade --install"`) f.BoolVar(&templateOptions.SkipSchemaValidation, "skip-schema-validation", false, `pass skip-schema-validation to "helm template" or "helm upgrade --install"`)
f.StringVar(&templateOptions.KubeVersion, "kube-version", "", `pass --kube-version to "helm template". Overrides kubeVersion in helmfile.yaml`) f.StringVar(&templateOptions.KubeVersion, "kube-version", "", `pass --kube-version to "helm template". Overrides kubeVersion in helmfile.yaml`)
f.StringArrayVar(&templateOptions.ShowOnly, "show-only", nil, `pass --show-only to "helm template"`) f.StringArrayVar(&templateOptions.ShowOnly, "show-only", nil, `pass --show-only to "helm template"`)
f.StringVar(&templateOptions.TemplateArgs, "template-args", "", `pass args to helm template`) f.StringVar(&templateOptions.TemplateArgs, "template-args", "", `pass extra args to "helm template" (e.g., --dry-run=server)`)
return cmd return cmd
} }

View File

@ -371,6 +371,8 @@ func (a *App) Sync(c SyncConfigProvider) error {
IncludeTransitiveNeeds: c.IncludeNeeds(), IncludeTransitiveNeeds: c.IncludeNeeds(),
Validate: c.Validate(), Validate: c.Validate(),
Concurrency: c.Concurrency(), Concurrency: c.Concurrency(),
// Ensure lookup during chartify pre-render connects to cluster
TemplateArgs: "--dry-run=server",
}, func() { }, func() {
ok, errs = a.sync(run, c) ok, errs = a.sync(run, c)
}) })
@ -407,7 +409,8 @@ func (a *App) Apply(c ApplyConfigProvider) error {
Validate: c.Validate(), Validate: c.Validate(),
Concurrency: c.Concurrency(), Concurrency: c.Concurrency(),
IncludeTransitiveNeeds: c.IncludeNeeds(), IncludeTransitiveNeeds: c.IncludeNeeds(),
TemplateArgs: c.TemplateArgs(), // Ensure lookup during chartify pre-render connects to cluster
TemplateArgs: "--dry-run=server",
}, func() { }, func() {
matched, updated, es := a.apply(run, c) matched, updated, es := a.apply(run, c)
@ -1954,6 +1957,7 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
KubeVersion: c.KubeVersion(), KubeVersion: c.KubeVersion(),
ShowOnly: c.ShowOnly(), ShowOnly: c.ShowOnly(),
SkipSchemaValidation: c.SkipSchemaValidation(), SkipSchemaValidation: c.SkipSchemaValidation(),
TemplateArgs: c.TemplateArgs(),
} }
return st.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), c.Validate(), opts) return st.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), c.Validate(), opts)
}) })

View File

@ -2109,7 +2109,6 @@ type configImpl struct {
includeTransitiveNeeds bool includeTransitiveNeeds bool
skipCharts bool skipCharts bool
kubeVersion string kubeVersion string
templateArgs string
} }
func (c configImpl) Selectors() []string { func (c configImpl) Selectors() []string {
@ -2208,10 +2207,6 @@ func (c configImpl) KubeVersion() string {
return c.kubeVersion return c.kubeVersion
} }
func (c configImpl) TemplateArgs() string {
return c.templateArgs
}
func (c configImpl) SkipSchemaValidation() bool { func (c configImpl) SkipSchemaValidation() bool {
return c.skipSchemaValidation return c.skipSchemaValidation
} }
@ -2220,6 +2215,11 @@ func (c configImpl) ShowOnly() []string {
return nil return nil
} }
// TemplateArgs satisfies TemplateConfigProvider for template-specific extra flags
func (c configImpl) TemplateArgs() string {
return ""
}
type applyConfig struct { type applyConfig struct {
args string args string
cascade string cascade string
@ -2251,7 +2251,6 @@ type applyConfig struct {
skipDiffOnInstall bool skipDiffOnInstall bool
syncArgs string syncArgs string
diffArgs string diffArgs string
templateArgs string
logger *zap.SugaredLogger logger *zap.SugaredLogger
wait bool wait bool
waitRetries int waitRetries int
@ -2404,10 +2403,6 @@ func (a applyConfig) DiffArgs() string {
return a.diffArgs return a.diffArgs
} }
func (a applyConfig) TemplateArgs() string {
return a.templateArgs
}
// helmfile-template-only flags // helmfile-template-only flags
func (a applyConfig) IncludeCRDs() bool { func (a applyConfig) IncludeCRDs() bool {
return a.includeCRDs return a.includeCRDs
@ -2456,6 +2451,11 @@ func (a applyConfig) ShowOnly() []string {
return a.showOnly return a.showOnly
} }
// TemplateArgs satisfies TemplateConfigProvider for template-specific extra flags
func (a applyConfig) TemplateArgs() string {
return ""
}
func (a applyConfig) HideNotes() bool { func (a applyConfig) HideNotes() bool {
return a.hideNotes return a.hideNotes
} }

View File

@ -8,7 +8,6 @@ import (
"strings" "strings"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/helmfile/chartify"
"github.com/helmfile/helmfile/pkg/helmexec" "github.com/helmfile/helmfile/pkg/helmexec"
"github.com/helmfile/helmfile/pkg/state" "github.com/helmfile/helmfile/pkg/state"
@ -43,14 +42,6 @@ func (r *Run) askForConfirmation(msg string) bool {
return AskForConfirmation(msg) return AskForConfirmation(msg)
} }
type Chartifier struct {
runner *chartify.Runner
}
func (c *Chartifier) Chartify(release, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) {
return c.runner.Chartify(release, dirOrChart, opts...)
}
func (r *Run) prepareChartsIfNeeded(helmfileCommand string, dir string, concurrency int, opts state.ChartPrepareOptions) (map[state.PrepareChartKey]string, error) { func (r *Run) prepareChartsIfNeeded(helmfileCommand string, dir string, concurrency int, opts state.ChartPrepareOptions) (map[state.PrepareChartKey]string, error) {
// Skip chart preparation for certain commands // Skip chart preparation for certain commands
skipCommands := []string{"write-values", "list"} skipCommands := []string{"write-values", "list"}
@ -58,15 +49,7 @@ func (r *Run) prepareChartsIfNeeded(helmfileCommand string, dir string, concurre
return nil, nil return nil, nil
} }
chartifier := &Chartifier{ releaseToChart, errs := r.state.PrepareCharts(r.helm, dir, concurrency, helmfileCommand, opts)
runner: chartify.New(
chartify.HelmBin(r.state.DefaultHelmBinary),
chartify.KustomizeBin(r.state.DefaultKustomizeBinary),
chartify.UseHelm3(true),
chartify.WithLogf(r.state.Logger().Debugf)),
}
releaseToChart, errs := r.state.PrepareCharts(r.helm, chartifier, dir, concurrency, helmfileCommand, opts)
if len(errs) > 0 { if len(errs) > 0 {
return nil, fmt.Errorf("%v", errs) return nil, fmt.Errorf("%v", errs)
} }

View File

@ -72,9 +72,6 @@ type ApplyOptions struct {
TakeOwnership bool TakeOwnership bool
SyncReleaseLabels bool SyncReleaseLabels bool
// TemplateArgs is the list of arguments to pass to helm template
TemplateArgs string
} }
// NewApply creates a new Apply // NewApply creates a new Apply
@ -256,6 +253,11 @@ func (a *ApplyImpl) SuppressOutputLineRegex() []string {
return a.ApplyOptions.SuppressOutputLineRegex return a.ApplyOptions.SuppressOutputLineRegex
} }
// TemplateArgs returns extra args for helm template; not applicable to apply, return empty.
func (a *ApplyImpl) TemplateArgs() string {
return ""
}
// SyncArgs returns the SyncArgs. // SyncArgs returns the SyncArgs.
func (a *ApplyImpl) SyncArgs() string { func (a *ApplyImpl) SyncArgs() string {
return a.ApplyOptions.SyncArgs return a.ApplyOptions.SyncArgs
@ -275,8 +277,3 @@ func (a *ApplyImpl) TakeOwnership() bool {
func (a *ApplyImpl) SyncReleaseLabels() bool { func (a *ApplyImpl) SyncReleaseLabels() bool {
return a.ApplyOptions.SyncReleaseLabels return a.ApplyOptions.SyncReleaseLabels
} }
// TemplateArgs returns the TemplateArgs.
func (a *ApplyImpl) TemplateArgs() string {
return a.ApplyOptions.TemplateArgs
}

View File

@ -44,7 +44,7 @@ type TemplateOptions struct {
KubeVersion string KubeVersion string
// Propagate '--show-only` to helm template // Propagate '--show-only` to helm template
ShowOnly []string ShowOnly []string
// TemplateArgs // TemplateArgs are extra args appended to helm template (e.g., --dry-run=server)
TemplateArgs string TemplateArgs string
} }
@ -161,7 +161,7 @@ func (t *TemplateImpl) ShowOnly() []string {
return t.TemplateOptions.ShowOnly return t.TemplateOptions.ShowOnly
} }
// TemplateArgs returns the TemplateArgs // TemplateArgs returns the extra args for helm template.
func (t *TemplateImpl) TemplateArgs() string { func (t *TemplateImpl) TemplateArgs() string {
return t.TemplateOptions.TemplateArgs return t.TemplateOptions.TemplateArgs
} }

View File

@ -1209,16 +1209,6 @@ type PrepareChartKey struct {
Namespace, Name, KubeContext string Namespace, Name, KubeContext string
} }
func (st *HelmState) Logger() *zap.SugaredLogger {
return st.logger
}
type Chartifier interface {
// Chartify creates a temporary Helm chart from a directory or a remote chart, and applies various transformations.
// Returns the full path to the temporary directory containing the generated chart if succeeded.
Chartify(release, dirOrChart string, opts ...chartify.ChartifyOption) (string, error)
}
// PrepareCharts creates temporary directories of charts. // PrepareCharts creates temporary directories of charts.
// //
// Each resulting "chart" can be one of the followings: // Each resulting "chart" can be one of the followings:
@ -1233,7 +1223,9 @@ type Chartifier interface {
// Otherwise, if a chart is not a helm chart, it will call "chartify" to turn it into a chart. // Otherwise, if a chart is not a helm chart, it will call "chartify" to turn it into a chart.
// //
// If exists, it will also patch resources by json patches, strategic-merge patches, and injectors. // If exists, it will also patch resources by json patches, strategic-merge patches, and injectors.
func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifier, dir string, concurrency int, helmfileCommand string, opts ChartPrepareOptions) (map[PrepareChartKey]string, []error) { //
//nolint:gocognit // High complexity due to orchestration; refactoring is out of scope here.
func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurrency int, helmfileCommand string, opts ChartPrepareOptions) (map[PrepareChartKey]string, []error) {
if !opts.SkipResolve { if !opts.SkipResolve {
updated, err := st.ResolveDeps() updated, err := st.ResolveDeps()
if err != nil { if err != nil {
@ -1327,6 +1319,13 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifie
skipDeps := (!isLocal && !chartFetchedByGoGetter) || skipDepsGlobal || skipDepsRelease || skipDepsDefault skipDeps := (!isLocal && !chartFetchedByGoGetter) || skipDepsGlobal || skipDepsRelease || skipDepsDefault
if chartification != nil && helmfileCommand != "pull" { if chartification != nil && helmfileCommand != "pull" {
c := chartify.New(
chartify.HelmBin(st.DefaultHelmBinary),
chartify.KustomizeBin(st.DefaultKustomizeBinary),
chartify.UseHelm3(true),
chartify.WithLogf(st.logger.Debugf),
)
chartifyOpts := chartification.Opts chartifyOpts := chartification.Opts
if skipDeps { if skipDeps {
@ -1341,8 +1340,23 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifie
chartifyOpts.Validate = opts.Validate chartifyOpts.Validate = opts.Validate
if (helmfileCommand == "template" || helmfileCommand == "apply") && opts.TemplateArgs != "" { // Ensure chartify's internal helm template uses the correct kube context for lookup to work
chartifyOpts.TemplateArgs = opts.TemplateArgs if kc := st.kubeConnectionFlags(release); len(kc) > 0 {
if chartifyOpts.TemplateArgs != "" {
chartifyOpts.TemplateArgs = strings.TrimSpace(chartifyOpts.TemplateArgs + " " + strings.Join(kc, " "))
} else {
chartifyOpts.TemplateArgs = strings.Join(kc, " ")
}
}
// If the current command provided extra template args (e.g., --dry-run=server for `helmfile template`),
// pass them through to the chartify helm template as well to make lookup behavior consistent.
if opts.TemplateArgs != "" {
extra := strings.Join(argparser.CollectArgs(opts.TemplateArgs), " ")
if chartifyOpts.TemplateArgs != "" {
chartifyOpts.TemplateArgs = strings.TrimSpace(chartifyOpts.TemplateArgs + " " + extra)
} else {
chartifyOpts.TemplateArgs = extra
}
} }
chartifyOpts.KubeVersion = st.getKubeVersion(release, opts.KubeVersion) chartifyOpts.KubeVersion = st.getKubeVersion(release, opts.KubeVersion)
@ -1360,7 +1374,7 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifie
} }
chartifyOpts.SetFlags = append(chartifyOpts.SetFlags, flags...) chartifyOpts.SetFlags = append(chartifyOpts.SetFlags, flags...)
out, err := chartifier.Chartify(release.Name, chartPath, chartify.WithChartifyOpts(chartifyOpts)) out, err := c.Chartify(release.Name, chartPath, chartify.WithChartifyOpts(chartifyOpts))
if err != nil { if err != nil {
results <- &chartPrepareResult{err: err} results <- &chartPrepareResult{err: err}
return return
@ -1551,7 +1565,8 @@ type TemplateOpts struct {
ShowOnly []string ShowOnly []string
// Propagate '--skip-schema-validation' to helmv3 template and helm install // Propagate '--skip-schema-validation' to helmv3 template and helm install
SkipSchemaValidation bool SkipSchemaValidation bool
TemplateArgs string // TemplateArgs are extra args appended to "helm template" (e.g., "--dry-run=server")
TemplateArgs string
} }
type TemplateOpt interface{ Apply(*TemplateOpts) } type TemplateOpt interface{ Apply(*TemplateOpts) }
@ -2932,6 +2947,9 @@ func (st *HelmState) flagsForTemplate(helm helmexec.Interface, release *ReleaseS
flags = st.appendChartDownloadFlags(flags, release) flags = st.appendChartDownloadFlags(flags, release)
flags = st.appendShowOnlyFlags(flags, showOnly) flags = st.appendShowOnlyFlags(flags, showOnly)
flags = st.appendSkipSchemaValidationFlags(flags, release, skipSchemaValidation) flags = st.appendSkipSchemaValidationFlags(flags, release, skipSchemaValidation)
if opt != nil && opt.TemplateArgs != "" {
flags = append(flags, argparser.CollectArgs(opt.TemplateArgs)...)
}
common, files, err := st.namespaceAndValuesFlags(helm, release, workerIndex) common, files, err := st.namespaceAndValuesFlags(helm, release, workerIndex)
if err != nil { if err != nil {

View File

@ -4,13 +4,11 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"path"
"path/filepath" "path/filepath"
"reflect" "reflect"
"testing" "testing"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/helmfile/chartify"
"github.com/helmfile/vals" "github.com/helmfile/vals"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -2976,107 +2974,6 @@ func TestDiffpareSyncReleases(t *testing.T) {
} }
} }
// capturingChartifier implements state.Chartifier for tests.
type capturingChartifier struct {
mChartify func(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error)
capturedArgs []chartifyArgs
}
type chartifyArgs struct {
release string
dirOrChart string
opts []chartify.ChartifyOption
}
func (c *capturingChartifier) Chartify(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) {
c.capturedArgs = append(c.capturedArgs, chartifyArgs{release: release, dirOrChart: dirOrChart, opts: opts})
return c.mChartify(release, dirOrChart, opts...)
}
func TestPrepareCharts_invokesChartifierWithTemplateArgs(t *testing.T) {
tests := []struct {
name string
chartifier *capturingChartifier
dir string
concurrency int
command string
opts ChartPrepareOptions
expectedArgs []chartifyArgs
helmDefaults *HelmSpec
}{
{
name: "template command",
chartifier: &capturingChartifier{
mChartify: func(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) {
return "someTempDir", nil
},
},
dir: "someChartPath",
concurrency: 1,
command: "template",
opts: ChartPrepareOptions{
SkipDeps: true,
TemplateArgs: "someArgs",
},
helmDefaults: &HelmSpec{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "test-prepare-charts-*")
if err != nil {
t.Fatalf("setup temp test dir: %v", err)
}
defer os.RemoveAll(tmpDir)
err = os.Mkdir(path.Join(tmpDir, tt.dir), 0755)
if err != nil {
t.Fatalf("setup chart dir: %v", err)
}
release := ReleaseSpec{
Name: tt.name,
}
releases := []ReleaseSpec{
release,
}
state := &HelmState{
basePath: tmpDir,
ReleaseSetSpec: ReleaseSetSpec{
Releases: releases,
HelmDefaults: *tt.helmDefaults,
},
logger: logger,
valsRuntime: valsRuntime,
fs: filesystem.DefaultFileSystem(),
RenderedValues: map[string]any{},
}
helm := &exectest.Helm{
Lists: map[exectest.ListKey]string{},
Helm3: true,
}
_, errs := state.PrepareCharts(helm, tt.chartifier, path.Join(tmpDir, tt.dir), tt.concurrency, tt.command, tt.opts)
require.Len(t, errs, 0)
require.Len(t, tt.chartifier.capturedArgs, 1)
appliedChartifyOpts := &chartify.ChartifyOpts{}
for _, o := range tt.chartifier.capturedArgs[0].opts {
err = o.SetChartifyOption(appliedChartifyOpts)
if err != nil {
t.Fatalf("set captured chartify options: %v", err)
}
}
require.Equal(t, tt.opts.TemplateArgs, appliedChartifyOpts.TemplateArgs)
})
}
}
func TestPrepareSyncReleases(t *testing.T) { func TestPrepareSyncReleases(t *testing.T) {
tests := []struct { tests := []struct {
name string name string

View File

@ -3,22 +3,22 @@
declare -i tests_total=0 declare -i tests_total=0
function info () { function info () {
tput bold; tput setaf 4; echo -n "INFO: "; tput sgr0; echo "${@}" tput bold >/dev/null 2>&1 || true; tput setaf 4 >/dev/null 2>&1 || true; echo -n "INFO: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}"
} }
function warn () { function warn () {
tput bold; tput setaf 3; echo -n "WARN: "; tput sgr0; echo "${@}" tput bold >/dev/null 2>&1 || true; tput setaf 3 >/dev/null 2>&1 || true; echo -n "WARN: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}"
} }
function fail () { function fail () {
tput bold; tput setaf 1; echo -n "FAIL: "; tput sgr0; echo "${@}" tput bold >/dev/null 2>&1 || true; tput setaf 1 >/dev/null 2>&1 || true; echo -n "FAIL: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}"
exit 1 exit 1
} }
function test_start () { function test_start () {
tput bold; tput setaf 6; echo -n "TEST: "; tput sgr0; echo "${@}" tput bold >/dev/null 2>&1 || true; tput setaf 6 >/dev/null 2>&1 || true; echo -n "TEST: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}"
} }
function test_pass () { function test_pass () {
tests_total=$((tests_total+1)) tests_total=$((tests_total+1))
tput bold; tput setaf 2; echo -n "PASS: "; tput sgr0; echo "${@}" tput bold >/dev/null 2>&1 || true; tput setaf 2 >/dev/null 2>&1 || true; echo -n "PASS: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}"
} }
function all_tests_passed () { function all_tests_passed () {
tput bold; tput setaf 2; echo -n "PASS: "; tput sgr0; echo "${tests_total} tests passed" tput bold >/dev/null 2>&1 || true; tput setaf 2 >/dev/null 2>&1 || true; echo -n "PASS: "; tput sgr0 >/dev/null 2>&1 || true; echo "${tests_total} tests passed"
} }

View File

@ -103,6 +103,7 @@ ${kubectl} create namespace ${test_ns} || fail "Could not create namespace ${tes
. ${dir}/test-cases/issue-1749.sh . ${dir}/test-cases/issue-1749.sh
. ${dir}/test-cases/issue-1893.sh . ${dir}/test-cases/issue-1893.sh
. ${dir}/test-cases/state-values-set-cli-args-in-environments.sh . ${dir}/test-cases/state-values-set-cli-args-in-environments.sh
. ${dir}/test-cases/lookup.sh
# ALL DONE ----------------------------------------------------------------------------------------------------------- # ALL DONE -----------------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,62 @@
#!/usr/bin/env bash
# Verify Helm `lookup` works under helmfile for both chartify and non-chartify scenarios.
#
# Assumptions (prepared by test/integration/run.sh):
# - A minikube cluster is running, context=minikube
# - Namespace ${test_ns} is created
# - Variables ${helmfile}, ${kubectl}, and ${cases_dir} are defined
set -euo pipefail
reset_live_secret() {
info "Resetting live secret to key=init"
${kubectl} delete secret my-secret -n ${test_ns} >/dev/null 2>&1 || true
init_hf="${cases_dir}/lookup/input-init/helmfile.yaml.gotmpl"
${helmfile} -f "${init_hf}" sync -q
}
assert_template_outputs() {
reset_live_secret
local hf_file="$1"
info "Templating ${hf_file} with --template-args=\"--dry-run=server\""
out=$(mktemp)
${helmfile} -f "${hf_file}" template --template-args="--dry-run=server" >"${out}"
grep -q "key: init" "${out}" || fail "template output did not contain 'key: init'"
rm -f "${out}"
}
assert_cluster_key_is_init() {
v=$(${kubectl} get secret my-secret -o jsonpath='{.data.key}' | base64 -d)
[ "${v}" = "init" ] || fail "expected live secret key to be 'init', got '${v}'"
}
assert_apply() {
local hf_file="$1"
reset_live_secret
info "Applying ${hf_file}"
${helmfile} -f "${hf_file}" apply -q || fail "apply failed"
assert_cluster_key_is_init
}
assert_sync() {
local hf_file="$1"
reset_live_secret
info "Syncing ${hf_file}"
${helmfile} -f "${hf_file}" sync -q || fail "sync failed"
assert_cluster_key_is_init
}
# Non-chartify scenario
plain_hf="${cases_dir}/lookup/input-plain/helmfile.yaml.gotmpl"
assert_template_outputs "${plain_hf}"
assert_apply "${plain_hf}"
assert_sync "${plain_hf}"
test_pass "lookup without chartify"
# Chartify scenario (e.g. forceNamespace triggers chartify)
chartify_hf="${cases_dir}/lookup/input-chartify/helmfile.yaml.gotmpl"
assert_template_outputs "${chartify_hf}"
assert_apply "${chartify_hf}"
assert_sync "${chartify_hf}"
test_pass "lookup with chartify"

View File

@ -0,0 +1,17 @@
releases:
- name: lookup-test
chart: ../../../charts/raw
namespace: {{ .Namespace }}
# forceNamespace triggers chartify
forceNamespace: {{ .Namespace }}
values:
- templates:
- |
apiVersion: v1
kind: Secret
metadata:
name: lookup-result
type: Opaque
stringData:
# When lookup can reach the cluster, this resolves to the current live value (init)
key: {{`{{ index (index (lookup "v1" "Secret" .Release.Namespace "my-secret") "data") "key" | b64dec | default "overwritten" }}`}}

View File

@ -0,0 +1,14 @@
releases:
- name: setup-init
chart: ../../../charts/raw
namespace: {{ .Namespace }}
values:
- templates:
- |
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
stringData:
key: "init"

View File

@ -0,0 +1,15 @@
releases:
- name: lookup-test
chart: ../../../charts/raw
namespace: {{ .Namespace }}
forceNamespace: {{ .Namespace }}
values:
- templates:
- |
apiVersion: v1
kind: Secret
metadata:
name: lookup-result
type: Opaque
stringData:
key: {{`{{ index (index (lookup "v1" "Secret" .Release.Namespace "my-secret") "data") "key" | b64dec | default "overwritten" }}`}}