fix(#507): support assign --post-renderer within helmfile flags and helmdefault or release config

1. only implement post-renderer flags this patch
2. As mumoshu advise, add helmfile flags `--post-render` and add the
   postRenderer  config in helmDefaults and release. the priority is
   helmfile flags > release > helmDefaults.
3. fix the test case in state_test.go and some other tests.

Signed-off-by: guofutan <guofutan@tencent.com>
Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
guofutan 2022-12-12 17:44:18 +08:00 committed by yxxhero
parent 1f0f7ec8d6
commit 0a953731b0
18 changed files with 320 additions and 102 deletions

View File

@ -60,6 +60,7 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&applyOptions.Wait, "wait", false, `Override helmDefaults.wait setting "helm upgrade --install --wait"`) f.BoolVar(&applyOptions.Wait, "wait", false, `Override helmDefaults.wait setting "helm upgrade --install --wait"`)
f.BoolVar(&applyOptions.WaitForJobs, "wait-for-jobs", false, `Override helmDefaults.waitForJobs setting "helm upgrade --install --wait-for-jobs"`) f.BoolVar(&applyOptions.WaitForJobs, "wait-for-jobs", false, `Override helmDefaults.waitForJobs setting "helm upgrade --install --wait-for-jobs"`)
f.BoolVar(&applyOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reuse-values"`) f.BoolVar(&applyOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reuse-values"`)
f.StringVar(&applyOptions.PostRenderer, "post-renderer", "", `pass post-renderer to "helm template" or "helm upgrade --install"`)
return cmd return cmd
} }

View File

@ -44,6 +44,7 @@ func NewSyncCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&syncOptions.Wait, "wait", false, `Override helmDefaults.wait setting "helm upgrade --install --wait"`) f.BoolVar(&syncOptions.Wait, "wait", false, `Override helmDefaults.wait setting "helm upgrade --install --wait"`)
f.BoolVar(&syncOptions.WaitForJobs, "wait-for-jobs", false, `Override helmDefaults.waitForJobs setting "helm upgrade --install --wait-for-jobs"`) f.BoolVar(&syncOptions.WaitForJobs, "wait-for-jobs", false, `Override helmDefaults.waitForJobs setting "helm upgrade --install --wait-for-jobs"`)
f.BoolVar(&syncOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reuse-values"`) f.BoolVar(&syncOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reuse-values"`)
f.StringVar(&syncOptions.PostRenderer, "post-renderer", "", `pass post-renderer to "helm template" or "helm upgrade --install"`)
return cmd return cmd
} }

View File

@ -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.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.SkipDeps, "skip-deps", false, `skip running "helm repo update" and "helm dependency build"`) f.BoolVar(&templateOptions.SkipDeps, "skip-deps", false, `skip running "helm repo update" and "helm dependency build"`)
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.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"`)
return cmd return cmd
} }

View File

@ -1392,6 +1392,7 @@ Do you really want to apply?
} }
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...) r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
r.helm.SetPostRenderer(c.PostRenderer())
// We deleted releases by traversing the DAG in reverse order // We deleted releases by traversing the DAG in reverse order
if len(releasesToBeDeleted) > 0 { if len(releasesToBeDeleted) > 0 {
@ -1774,6 +1775,7 @@ Do you really want to sync?
var errs []error var errs []error
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...) r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
r.helm.SetPostRenderer(c.PostRenderer())
// Traverse DAG of all the releases so that we don't suffer from false-positive missing dependencies // Traverse DAG of all the releases so that we don't suffer from false-positive missing dependencies
st.Releases = selectedAndNeededReleases st.Releases = selectedAndNeededReleases

View File

@ -2304,6 +2304,10 @@ func (c configImpl) SkipCharts() bool {
return c.skipCharts return c.skipCharts
} }
func (c configImpl) PostRenderer() string {
return ""
}
type applyConfig struct { type applyConfig struct {
args string args string
values []string values []string
@ -2334,6 +2338,7 @@ type applyConfig struct {
wait bool wait bool
waitForJobs bool waitForJobs bool
reuseValues bool reuseValues bool
postRenderer string
// template-only options // template-only options
includeCRDs, skipTests bool includeCRDs, skipTests bool
@ -2473,6 +2478,10 @@ func (a applyConfig) ReuseValues() bool {
return a.reuseValues return a.reuseValues
} }
func (a applyConfig) PostRenderer() string {
return a.postRenderer
}
type depsConfig struct { type depsConfig struct {
skipRepos bool skipRepos bool
includeTransitiveNeeds bool includeTransitiveNeeds bool
@ -2555,6 +2564,11 @@ func (helm *mockHelmExec) SetHelmBinary(bin string) {
} }
func (helm *mockHelmExec) SetEnableLiveOutput(enableLiveOutput bool) { func (helm *mockHelmExec) SetEnableLiveOutput(enableLiveOutput bool) {
} }
func (helm *mockHelmExec) SetPostRenderer(postRenderer string) {
}
func (helm *mockHelmExec) GetPostRenderer() string {
return ""
}
func (helm *mockHelmExec) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error { func (helm *mockHelmExec) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error {
helm.repos = append(helm.repos, mockRepo{Name: name}) helm.repos = append(helm.repos, mockRepo{Name: name})
return nil return nil

View File

@ -42,6 +42,7 @@ type ReposConfigProvider interface {
type ApplyConfigProvider interface { type ApplyConfigProvider interface {
Args() string Args() string
PostRenderer() string
Values() []string Values() []string
Set() []string Set() []string
@ -80,6 +81,7 @@ type ApplyConfigProvider interface {
type SyncConfigProvider interface { type SyncConfigProvider interface {
Args() string Args() string
PostRenderer() string
Values() []string Values() []string
Set() []string Set() []string
@ -186,6 +188,7 @@ type FetchConfigProvider interface {
type TemplateConfigProvider interface { type TemplateConfigProvider interface {
Args() string Args() string
PostRenderer() string
Values() []string Values() []string
Set() []string Set() []string

View File

@ -53,6 +53,12 @@ func (helm *noCallHelmExec) SetHelmBinary(bin string) {
func (helm *noCallHelmExec) SetEnableLiveOutput(enableLiveOutput bool) { func (helm *noCallHelmExec) SetEnableLiveOutput(enableLiveOutput bool) {
helm.doPanic() helm.doPanic()
} }
func (helm *noCallHelmExec) SetPostRenderer(postRenderer string) {
}
func (helm *noCallHelmExec) GetPostRenderer() string {
return ""
}
func (helm *noCallHelmExec) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error { func (helm *noCallHelmExec) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error {
helm.doPanic() helm.doPanic()
return nil return nil

View File

@ -112,13 +112,6 @@ func GetArgs(args string, state *state.HelmState) []string {
} }
} }
if len(state.HelmDefaults.PostRenderer) > 0 {
argArr = append(argArr, fmt.Sprintf("--post-renderer=\"%s\"", state.HelmDefaults.PostRenderer))
}
for _, arg := range state.HelmDefaults.PostRendererArgs {
argArr = append(argArr, fmt.Sprintf("--post-renderer-args=\"%s\"", arg))
}
state.HelmDefaults.Args = argArr state.HelmDefaults.Args = argArr
return state.HelmDefaults.Args return state.HelmDefaults.Args

View File

@ -35,14 +35,6 @@ func TestGetArgs(t *testing.T) {
defaultArgs: []string{"--recreate-pods", "--force"}, defaultArgs: []string{"--recreate-pods", "--force"},
expected: "--timeout=3600 --set app1.bootstrap=true --set app2.bootstrap=false,app3.bootstrap=true --tiller-namespace ns --recreate-pods --force", expected: "--timeout=3600 --set app1.bootstrap=true --set app2.bootstrap=false,app3.bootstrap=true --tiller-namespace ns --recreate-pods --force",
}, },
{
args: "--post-renderer=aaa --post-renderer-args=bbb",
expected: "--post-renderer=aaa --post-renderer-args=bbb",
},
{
args: "--post-renderer aaa --post-renderer-args bbb",
expected: "--post-renderer aaa --post-renderer-args bbb",
},
} }
for _, test := range tests { for _, test := range tests {
Helmdefaults := state.HelmSpec{KubeContext: "test", TillerNamespace: "test-namespace", Args: test.defaultArgs} Helmdefaults := state.HelmSpec{KubeContext: "test", TillerNamespace: "test-namespace", Args: test.defaultArgs}
@ -57,38 +49,6 @@ func TestGetArgs(t *testing.T) {
} }
} }
func TestGetArgs_PostRenderer(t *testing.T) {
tests := []struct {
postRenderer string
PostRendererArgs []string
expected string
}{
{
postRenderer: "sed",
PostRendererArgs: []string{"-i", "s/aaa/bb/g"},
expected: "--post-renderer=\"sed\" --post-renderer-args=\"-i\" --post-renderer-args=\"s/aaa/bb/g\"",
},
{
postRenderer: "sed",
PostRendererArgs: []string{"-i", "s/aa a/b b/g"},
expected: "--post-renderer=\"sed\" --post-renderer-args=\"-i\" --post-renderer-args=\"s/aa a/b b/g\"",
},
}
for _, test := range tests {
Helmdefaults := state.HelmSpec{KubeContext: "test", TillerNamespace: "test-namespace", PostRenderer: test.postRenderer, PostRendererArgs: test.PostRendererArgs}
testState := &state.HelmState{
ReleaseSetSpec: state.ReleaseSetSpec{
HelmDefaults: Helmdefaults,
},
}
receivedArgs := GetArgs("", testState)
require.Equalf(t, test.expected, strings.Join(receivedArgs, " "), "expected args %s, received args %s", test.expected, strings.Join(receivedArgs, " "))
}
}
// TestIsNewFlag tests the isNewFlag function // TestIsNewFlag tests the isNewFlag function
func TestIsNewFlag(t *testing.T) { func TestIsNewFlag(t *testing.T) {
tests := []struct { tests := []struct {

View File

@ -50,6 +50,8 @@ type ApplyOptions struct {
WaitForJobs bool WaitForJobs bool
// ReuseValues is true if the helm command should reuse the values // ReuseValues is true if the helm command should reuse the values
ReuseValues bool ReuseValues bool
// Propagate '--postRenderer' to helmv3 template and helm install
PostRenderer string
} }
// NewApply creates a new Apply // NewApply creates a new Apply
@ -193,3 +195,8 @@ func (a *ApplyImpl) WaitForJobs() bool {
func (a *ApplyImpl) ReuseValues() bool { func (a *ApplyImpl) ReuseValues() bool {
return a.ApplyOptions.ReuseValues return a.ApplyOptions.ReuseValues
} }
// PostRenderer returns the PostRenderer.
func (a *ApplyImpl) PostRenderer() string {
return a.ApplyOptions.PostRenderer
}

View File

@ -26,6 +26,8 @@ type SyncOptions struct {
WaitForJobs bool WaitForJobs bool
// ReuseValues is true if the helm command should reuse the values // ReuseValues is true if the helm command should reuse the values
ReuseValues bool ReuseValues bool
// Propagate '--postRenderer' to helmv3 template and helm install
PostRenderer string
} }
// NewSyncOptions creates a new Apply // NewSyncOptions creates a new Apply
@ -110,3 +112,8 @@ func (t *SyncImpl) WaitForJobs() bool {
func (t *SyncImpl) ReuseValues() bool { func (t *SyncImpl) ReuseValues() bool {
return t.SyncOptions.ReuseValues return t.SyncOptions.ReuseValues
} }
// PostRenderer returns the PostRenderer.
func (t *SyncImpl) PostRenderer() string {
return t.SyncOptions.PostRenderer
}

View File

@ -34,6 +34,8 @@ type TemplateOptions struct {
SkipDeps bool SkipDeps bool
// SkipCleanup is the skip cleanup flag // SkipCleanup is the skip cleanup flag
SkipCleanup bool SkipCleanup bool
// Propagate '--postRenderer' to helmv3 template and helm install
PostRenderer string
} }
// NewTemplateOptions creates a new Apply // NewTemplateOptions creates a new Apply
@ -123,3 +125,8 @@ func (t *TemplateImpl) Validate() bool {
func (t *TemplateImpl) Values() []string { func (t *TemplateImpl) Values() []string {
return t.TemplateOptions.Values return t.TemplateOptions.Values
} }
// PostRenderer returns the PostRenderer.
func (t *TemplateImpl) PostRenderer() string {
return t.TemplateOptions.PostRenderer
}

View File

@ -92,6 +92,11 @@ func (helm *Helm) SetHelmBinary(bin string) {
} }
func (helm *Helm) SetEnableLiveOutput(enableLiveOutput bool) { func (helm *Helm) SetEnableLiveOutput(enableLiveOutput bool) {
} }
func (helm *Helm) SetPostRenderer(postRenderer string) {
}
func (helm *Helm) GetPostRenderer() string {
return ""
}
func (helm *Helm) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error { func (helm *Helm) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error {
helm.Repo = []string{name, repository, cafile, certfile, keyfile, username, password, managed, passCredentials, skipTLSVerify} helm.Repo = []string{name, repository, cafile, certfile, keyfile, username, password, managed, passCredentials, skipTLSVerify}
return nil return nil
@ -200,7 +205,10 @@ func (helm *Helm) ChartExport(chart string, path string, flags ...string) error
return nil return nil
} }
func (helm *Helm) IsHelm3() bool { func (helm *Helm) IsHelm3() bool {
if helm.Version == nil {
return helm.Helm3 return helm.Helm3
}
return helm.Version.Major() == 3
} }
func (helm *Helm) GetVersion() helmexec.Version { func (helm *Helm) GetVersion() helmexec.Version {

View File

@ -36,7 +36,7 @@ type execer struct {
logger *zap.SugaredLogger logger *zap.SugaredLogger
kubeContext string kubeContext string
extra []string extra []string
postRenderers []string postRenderer string
decryptedSecretMutex sync.Mutex decryptedSecretMutex sync.Mutex
decryptedSecrets map[string]*decryptedSecret decryptedSecrets map[string]*decryptedSecret
writeTempFile func([]byte) (string, error) writeTempFile func([]byte) (string, error)
@ -132,23 +132,7 @@ func New(helmBinary string, enableLiveOutput bool, logger *zap.SugaredLogger, ku
} }
func (helm *execer) SetExtraArgs(args ...string) { func (helm *execer) SetExtraArgs(args ...string) {
var extraArgs []string helm.extra = args
var renderArgs []string
// reset the postRenderers and filter --post-renderer=xx or --post-renderer xxx from args and put into helm.postRenderers
for i := 0; i < len(args); i++ {
if strings.HasPrefix(args[i], "--post-renderer=") || strings.HasPrefix(args[i], "--post-renderer-args=") {
renderArgs = append(renderArgs, args[i])
} else if (args[i] == "--post-renderer" || args[i] == "--post-renderer-args") && i < len(args)-1 {
renderArgs = append(renderArgs, args[i])
renderArgs = append(renderArgs, args[i+1])
i++
} else {
extraArgs = append(extraArgs, args[i])
}
}
helm.extra = extraArgs
helm.postRenderers = renderArgs
} }
func (helm *execer) SetHelmBinary(bin string) { func (helm *execer) SetHelmBinary(bin string) {
@ -159,6 +143,14 @@ func (helm *execer) SetEnableLiveOutput(enableLiveOutput bool) {
helm.enableLiveOutput = enableLiveOutput helm.enableLiveOutput = enableLiveOutput
} }
func (helm *execer) SetPostRenderer(postRenderer string) {
helm.postRenderer = postRenderer
}
func (helm *execer) GetPostRenderer() string {
return helm.postRenderer
}
func (helm *execer) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error { func (helm *execer) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error {
var args []string var args []string
var out []byte var out []byte
@ -268,8 +260,8 @@ func (helm *execer) SyncRelease(context HelmContext, name, chart string, flags .
env["HELM_TILLER_HISTORY_MAX"] = strconv.Itoa(context.HistoryMax) env["HELM_TILLER_HISTORY_MAX"] = strconv.Itoa(context.HistoryMax)
} }
if helm.IsHelm3() { if helm.IsHelm3() && helm.postRenderer != "" {
flags = append(flags, helm.postRenderers...) flags = append(flags, "--post-renderer", helm.postRenderer)
} }
out, err := helm.exec(append(append(preArgs, "upgrade", "--install", name, chart), flags...), env, nil) out, err := helm.exec(append(append(preArgs, "upgrade", "--install", name, chart), flags...), env, nil)
@ -411,10 +403,9 @@ func (helm *execer) TemplateRelease(name string, chart string, flags ...string)
args = []string{"template", chart, "--name", name} args = []string{"template", chart, "--name", name}
} }
if helm.IsHelm3() { if helm.IsHelm3() && helm.postRenderer != "" {
flags = append(flags, helm.postRenderers...) flags = append(flags, "--post-renderer", helm.postRenderer)
} }
out, err := helm.exec(append(args, flags...), map[string]string{}, nil) out, err := helm.exec(append(args, flags...), map[string]string{}, nil)
var outputToFile bool var outputToFile bool

View File

@ -69,29 +69,6 @@ func Test_SetExtraArgs(t *testing.T) {
if !reflect.DeepEqual(helm.extra, []string{"alpha", "beta"}) { if !reflect.DeepEqual(helm.extra, []string{"alpha", "beta"}) {
t.Error("helmexec.SetExtraArgs() - two extra arguments missing (overwriting the previous value)") t.Error("helmexec.SetExtraArgs() - two extra arguments missing (overwriting the previous value)")
} }
helm.SetExtraArgs("--post-renderer=aaa")
fmt.Println(helm.postRenderers)
if !reflect.DeepEqual(helm.postRenderers, []string{"--post-renderer=aaa"}) {
t.Error("helmexec.SetExtraArgs() - post-renderer assign arguments missing ")
}
helm.SetExtraArgs("--post-renderer", "aaa")
fmt.Println(helm.postRenderers)
if !reflect.DeepEqual(helm.postRenderers, []string{"--post-renderer", "aaa"}) {
t.Error("helmexec.SetExtraArgs() - post-renderer blank arguments missing ")
}
helm.SetExtraArgs("--post-renderer-args=bbb")
fmt.Println(helm.postRenderers)
if !reflect.DeepEqual(helm.postRenderers, []string{"--post-renderer-args=bbb"}) {
t.Error("helmexec.SetExtraArgs() - post-renderer-args assign arguments missing")
}
helm.SetExtraArgs("--post-renderer", "aaa", "--post-renderer-args=bbb")
if !reflect.DeepEqual(helm.postRenderers, []string{"--post-renderer", "aaa", "--post-renderer-args=bbb"}) {
t.Error("helmexec.SetExtraArgs() - post-renderer arguments not be set correct")
}
} }
func Test_SetHelmBinary(t *testing.T) { func Test_SetHelmBinary(t *testing.T) {
@ -116,6 +93,30 @@ func Test_SetEnableLiveOutput(t *testing.T) {
} }
} }
func Test_SetPostRenderer(t *testing.T) {
helm := MockExecer(NewLogger(os.Stdout, "info"), "dev")
if helm.enableLiveOutput {
t.Error("helmexec.enableLiveOutput should not be enabled by default")
}
postRendererFoo := "/bin/rewrite-repo.sh"
helm.SetPostRenderer(postRendererFoo)
if helm.postRenderer != postRendererFoo {
t.Errorf("helmexec.SetPostRenderer() - actual = %s expect = %s", helm.postRenderer, postRendererFoo)
}
}
func Test_GetPostRenderer(t *testing.T) {
helm := MockExecer(NewLogger(os.Stdout, "info"), "dev")
if helm.enableLiveOutput {
t.Error("helmexec.enableLiveOutput should not be enabled by default")
}
postRendererFoo := "/bin/rewrite-repo.sh"
helm.SetPostRenderer(postRendererFoo)
if helm.GetPostRenderer() != postRendererFoo {
t.Errorf("helmexec.GetPostRenderer() - actual = %s expect = %s", helm.GetPostRenderer(), postRendererFoo)
}
}
func Test_AddRepo_Helm_3_3_2(t *testing.T) { func Test_AddRepo_Helm_3_3_2(t *testing.T) {
var buffer bytes.Buffer var buffer bytes.Buffer
logger := NewLogger(&buffer, "debug") logger := NewLogger(&buffer, "debug")

View File

@ -14,6 +14,8 @@ type Interface interface {
SetExtraArgs(args ...string) SetExtraArgs(args ...string)
SetHelmBinary(bin string) SetHelmBinary(bin string)
SetEnableLiveOutput(enableLiveOutput bool) SetEnableLiveOutput(enableLiveOutput bool)
SetPostRenderer(postRenderer string)
GetPostRenderer() string
AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error
UpdateRepo() error UpdateRepo() error

View File

@ -125,8 +125,6 @@ type HelmSpec struct {
TillerNamespace string `yaml:"tillerNamespace,omitempty"` TillerNamespace string `yaml:"tillerNamespace,omitempty"`
Tillerless bool `yaml:"tillerless"` Tillerless bool `yaml:"tillerless"`
Args []string `yaml:"args,omitempty"` Args []string `yaml:"args,omitempty"`
PostRenderer string `yaml:"postRenderer,omitempty"`
PostRendererArgs []string `yaml:"postRendererArgs,omitempty"`
Verify bool `yaml:"verify"` Verify bool `yaml:"verify"`
// Devel, when set to true, use development versions, too. Equivalent to version '>0.0.0-0' // Devel, when set to true, use development versions, too. Equivalent to version '>0.0.0-0'
Devel bool `yaml:"devel"` Devel bool `yaml:"devel"`
@ -154,6 +152,8 @@ type HelmSpec struct {
SkipDeps bool `yaml:"skipDeps"` SkipDeps bool `yaml:"skipDeps"`
// on helm upgrade/diff, reuse values currently set in the release and merge them with the ones defined within helmfile // on helm upgrade/diff, reuse values currently set in the release and merge them with the ones defined within helmfile
ReuseValues bool `yaml:"reuseValues"` ReuseValues bool `yaml:"reuseValues"`
// Propagate '--postRenderer' to helmv3 template and helm install
PostRenderer *string `yaml:"postRenderer,omitempty"`
TLS bool `yaml:"tls"` TLS bool `yaml:"tls"`
TLSCACert string `yaml:"tlsCACert,omitempty"` TLSCACert string `yaml:"tlsCACert,omitempty"`
@ -317,6 +317,9 @@ type ReleaseSpec struct {
// This is relevant only when your release uses a local chart or a directory containing K8s manifests or a Kustomization // This is relevant only when your release uses a local chart or a directory containing K8s manifests or a Kustomization
// as a Helm chart. // as a Helm chart.
SkipDeps *bool `yaml:"skipDeps,omitempty"` SkipDeps *bool `yaml:"skipDeps,omitempty"`
// Propagate '--postRenderer' to helmv3 template and helm install
PostRenderer *string `yaml:"postRenderer,omitempty"`
} }
// ChartPathOrName returns ChartPath if it is non-empty, and returns Chart otherwise. // ChartPathOrName returns ChartPath if it is non-empty, and returns Chart otherwise.
@ -2515,6 +2518,14 @@ func (st *HelmState) flagsForUpgrade(helm helmexec.Interface, release *ReleaseSp
return nil, nil, err return nil, nil, err
} }
if helm.IsHelm3() && helm.GetPostRenderer() == "" {
if release.PostRenderer != nil && *release.PostRenderer != "" {
flags = append(flags, "--post-renderer", *release.PostRenderer)
} else if st.HelmDefaults.PostRenderer != nil && *st.HelmDefaults.PostRenderer != "" {
flags = append(flags, "--post-renderer", *st.HelmDefaults.PostRenderer)
}
}
common, clean, err := st.namespaceAndValuesFlags(helm, release, workerIndex) common, clean, err := st.namespaceAndValuesFlags(helm, release, workerIndex)
if err != nil { if err != nil {
return nil, clean, err return nil, clean, err
@ -2542,6 +2553,14 @@ func (st *HelmState) flagsForTemplate(helm helmexec.Interface, release *ReleaseS
flags = st.appendApiVersionsFlags(flags, release) flags = st.appendApiVersionsFlags(flags, release)
if helm.IsHelm3() && helm.GetPostRenderer() == "" {
if release.PostRenderer != nil && *release.PostRenderer != "" {
flags = append(flags, "--post-renderer", *release.PostRenderer)
} else if st.HelmDefaults.PostRenderer != nil && *st.HelmDefaults.PostRenderer != "" {
flags = append(flags, "--post-renderer", *st.HelmDefaults.PostRenderer)
}
}
common, files, err := st.namespaceAndValuesFlags(helm, release, workerIndex) common, files, err := st.namespaceAndValuesFlags(helm, release, workerIndex)
if err != nil { if err != nil {
return nil, files, err return nil, files, err

View File

@ -161,7 +161,8 @@ func boolValue(v bool) *bool {
func TestHelmState_flagsForUpgrade(t *testing.T) { func TestHelmState_flagsForUpgrade(t *testing.T) {
enable := true enable := true
disable := false disable := false
postRendererDefault := "foo-default.sh"
postRendererRelease := "foo-release.sh"
some := func(v int) *int { some := func(v int) *int {
return &v return &v
} }
@ -693,6 +694,73 @@ func TestHelmState_flagsForUpgrade(t *testing.T) {
}, },
wantErr: "releases[].createNamespace requires Helm 3.2.0 or greater", wantErr: "releases[].createNamespace requires Helm 3.2.0 or greater",
}, },
{
name: "post-renderer-flags-use-helmdefault",
defaults: HelmSpec{
Verify: false,
CreateNamespace: &enable,
PostRenderer: &postRendererDefault,
},
version: semver.MustParse("3.10.0"),
release: &ReleaseSpec{
Chart: "test/chart",
Version: "0.1",
Verify: &disable,
Name: "test-charts",
Namespace: "test-namespace",
CreateNamespace: &disable,
},
want: []string{
"--version", "0.1",
"--post-renderer", postRendererDefault,
"--namespace", "test-namespace",
},
},
{
name: "post-renderer-flags-use-release",
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,
PostRenderer: &postRendererRelease,
},
want: []string{
"--version", "0.1",
"--post-renderer", postRendererRelease,
"--namespace", "test-namespace",
},
},
{
name: "post-renderer-flags-use-release-prior-helmdefault",
defaults: HelmSpec{
Verify: false,
CreateNamespace: &enable,
PostRenderer: &postRendererDefault,
},
version: semver.MustParse("3.10.0"),
release: &ReleaseSpec{
Chart: "test/chart",
Version: "0.1",
Verify: &disable,
Name: "test-charts",
Namespace: "test-namespace",
CreateNamespace: &disable,
PostRenderer: &postRendererRelease,
},
want: []string{
"--version", "0.1",
"--post-renderer", postRendererRelease,
"--namespace", "test-namespace",
},
},
} }
for i := range tests { for i := range tests {
tt := tests[i] tt := tests[i]
@ -724,6 +792,118 @@ func TestHelmState_flagsForUpgrade(t *testing.T) {
} }
} }
func TestHelmState_flagsForTemplate(t *testing.T) {
enable := true
disable := false
postRendererDefault := "foo-default.sh"
postRendererRelease := "foo-release.sh"
tests := []struct {
name string
version *semver.Version
defaults HelmSpec
release *ReleaseSpec
want []string
wantErr string
}{
{
name: "post-renderer-flags-use-helmdefault",
defaults: HelmSpec{
Verify: false,
CreateNamespace: &enable,
PostRenderer: &postRendererDefault,
},
version: semver.MustParse("3.10.0"),
release: &ReleaseSpec{
Chart: "test/chart",
Version: "0.1",
Verify: &disable,
Name: "test-charts",
Namespace: "test-namespace",
CreateNamespace: &disable,
},
want: []string{
"--version", "0.1",
"--post-renderer", postRendererDefault,
"--namespace", "test-namespace",
},
},
{
name: "post-renderer-flags-use-release",
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,
PostRenderer: &postRendererRelease,
},
want: []string{
"--version", "0.1",
"--post-renderer", postRendererRelease,
"--namespace", "test-namespace",
},
},
{
name: "post-renderer-flags-use-release-prior-helmdefault",
defaults: HelmSpec{
Verify: false,
CreateNamespace: &enable,
PostRenderer: &postRendererDefault,
},
version: semver.MustParse("3.10.0"),
release: &ReleaseSpec{
Chart: "test/chart",
Version: "0.1",
Verify: &disable,
Name: "test-charts",
Namespace: "test-namespace",
CreateNamespace: &disable,
PostRenderer: &postRendererRelease,
},
want: []string{
"--version", "0.1",
"--post-renderer", postRendererRelease,
"--namespace", "test-namespace",
},
},
}
for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
state := &HelmState{
basePath: "./",
ReleaseSetSpec: ReleaseSetSpec{
DeprecatedContext: "default",
Releases: []ReleaseSpec{*tt.release},
HelmDefaults: tt.defaults,
},
valsRuntime: valsRuntime,
}
helm := &exectest.Helm{
Version: tt.version,
}
args, _, err := state.flagsForTemplate(helm, tt.release, 0)
if err != nil && tt.wantErr == "" {
t.Errorf("unexpected error flagsForUpgrade: %v", err)
}
if tt.wantErr != "" && (err == nil || err.Error() != tt.wantErr) {
t.Errorf("expected error '%v'; got '%v'", err, tt.wantErr)
}
if !reflect.DeepEqual(args, tt.want) {
t.Errorf("flagsForUpgrade returned = %v, want %v", args, tt.want)
}
})
}
}
func Test_isLocalChart(t *testing.T) { func Test_isLocalChart(t *testing.T) {
type args struct { type args struct {
chart string chart string
@ -1054,6 +1234,7 @@ func TestHelmState_SyncRepos(t *testing.T) {
} }
func TestHelmState_SyncReleases(t *testing.T) { func TestHelmState_SyncReleases(t *testing.T) {
postRenderer := "foo.sh"
tests := []struct { tests := []struct {
name string name string
releases []ReleaseSpec releases []ReleaseSpec
@ -1150,6 +1331,20 @@ func TestHelmState_SyncReleases(t *testing.T) {
helm: &exectest.Helm{}, helm: &exectest.Helm{},
wantReleases: []exectest.Release{{Name: "releaseName", Flags: []string{"--set", "foo.bar[0]={A,B}", "--reset-values"}}}, wantReleases: []exectest.Release{{Name: "releaseName", Flags: []string{"--set", "foo.bar[0]={A,B}", "--reset-values"}}},
}, },
{
name: "post renderer",
releases: []ReleaseSpec{
{
Name: "releaseName",
Chart: "foo",
PostRenderer: &postRenderer,
},
},
helm: &exectest.Helm{
Helm3: true,
},
wantReleases: []exectest.Release{{Name: "releaseName", Flags: []string{"--post-renderer", postRenderer, "--reset-values"}}},
},
} }
for i := range tests { for i := range tests {
tt := tests[i] tt := tests[i]