pull/12775/merge
Michael Lee 1 year ago committed by GitHub
commit 5833a0925f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -37,9 +37,11 @@ import (
)
const (
outputFlag = "output"
postRenderFlag = "post-renderer"
postRenderArgsFlag = "post-renderer-args"
outputFlag = "output"
postRenderMainFlag = "post-renderer"
postRenderMainArgsFlag = "post-renderer-args"
postRenderHooksFlag = "post-renderer-hooks"
postRenderHooksArgsFlag = "post-renderer-hooks-args"
)
func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) {
@ -115,10 +117,14 @@ func (o *outputValue) Set(s string) error {
return nil
}
func bindPostRenderFlag(cmd *cobra.Command, varRef *postrender.PostRenderer) {
p := &postRendererOptions{varRef, "", []string{}}
cmd.Flags().Var(&postRendererString{p}, postRenderFlag, "the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path")
cmd.Flags().Var(&postRendererArgsSlice{p}, postRenderArgsFlag, "an argument to the post-renderer (can specify multiple)")
func bindPostRenderFlag(cmd *cobra.Command, mainRef *postrender.PostRenderer, hooksRef *postrender.PostRenderer) {
mainOptions := &postRendererOptions{mainRef, "", []string{}}
cmd.Flags().Var(&postRendererString{mainOptions}, postRenderMainFlag, "the path to an executable to be used for post rendering CRDs and manifests. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path")
cmd.Flags().Var(&postRendererArgsSlice{mainOptions}, postRenderMainArgsFlag, "an argument to the main post-renderer (can specify multiple)")
hooksOptions := &postRendererOptions{hooksRef, "", []string{}}
cmd.Flags().Var(&postRendererString{hooksOptions}, postRenderHooksFlag, "the path to an executable to be used for post rendering hooks. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path")
cmd.Flags().Var(&postRendererArgsSlice{hooksOptions}, postRenderHooksArgsFlag, "an argument to the hooks post-renderer (can specify multiple)")
}
type postRendererOptions struct {

@ -168,7 +168,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f := cmd.Flags()
f.BoolVar(&client.HideSecret, "hide-secret", false, "hide Kubernetes Secrets when also using the --dry-run flag")
bindOutputFlag(cmd, &outfmt)
bindPostRenderFlag(cmd, &client.PostRenderer)
bindPostRenderFlag(cmd, &client.PostRenderer, &client.PostRendererHooks)
return cmd
}

@ -200,7 +200,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.StringVar(&kubeVersion, "kube-version", "", "Kubernetes version used for Capabilities.KubeVersion")
f.StringSliceVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions")
f.BoolVar(&client.UseReleaseName, "release-name", false, "use release name in the output-dir path.")
bindPostRenderFlag(cmd, &client.PostRenderer)
bindPostRenderFlag(cmd, &client.PostRenderer, &client.PostRendererHooks)
return cmd
}

@ -142,6 +142,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
instClient.Namespace = client.Namespace
instClient.Atomic = client.Atomic
instClient.PostRenderer = client.PostRenderer
instClient.PostRendererHooks = client.PostRendererHooks
instClient.DisableOpenAPIValidation = client.DisableOpenAPIValidation
instClient.SubNotes = client.SubNotes
instClient.HideNotes = client.HideNotes
@ -281,7 +282,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
addChartPathOptionsFlags(f, &client.ChartPathOptions)
addValueOptionsFlags(f, valueOpts)
bindOutputFlag(cmd, &outfmt)
bindPostRenderFlag(cmd, &client.PostRenderer)
bindPostRenderFlag(cmd, &client.PostRenderer, &client.PostRendererHooks)
err := cmd.RegisterFlagCompletionFunc("version", func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 2 {

@ -103,7 +103,20 @@ type Configuration struct {
// TODO: As part of the refactor the duplicate code in cmd/helm/template.go should be removed
//
// This code has to do with writing files to disk.
func (cfg *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string, subNotes, useReleaseName, includeCrds bool, pr postrender.PostRenderer, interactWithRemote, enableDNS, hideSecret bool) ([]*release.Hook, *bytes.Buffer, string, error) {
func (cfg *Configuration) renderResources(
ch *chart.Chart,
values chartutil.Values,
releaseName,
outputDir string,
subNotes,
useReleaseName,
includeCrds bool,
mainPostRenderer postrender.PostRenderer,
hooksPostRenderer postrender.PostRenderer,
interactWithRemote,
enableDNS,
hideSecret bool,
) ([]*release.Hook, *bytes.Buffer, string, error) {
hs := []*release.Hook{}
b := bytes.NewBuffer(nil)
@ -222,13 +235,27 @@ func (cfg *Configuration) renderResources(ch *chart.Chart, values chartutil.Valu
}
}
if pr != nil {
b, err = pr.Run(b)
if mainPostRenderer != nil {
b, err = mainPostRenderer.Run(b)
if err != nil {
return hs, b, notes, errors.Wrap(err, "error while running post render on files")
}
}
// Post-rendering hooks is disabled by default for backwards compat.
// See note above about outputDir.
if hooksPostRenderer != nil && outputDir == "" {
for _, hook := range hs {
hookBuffer := bytes.NewBuffer(nil)
fmt.Fprintf(hookBuffer, "# Source: %s\n%s\n", hook.Name, hook.Manifest)
newManifest, err := hooksPostRenderer.Run(hookBuffer)
if err != nil {
return hs, b, notes, errors.Wrapf(err, "error while running post render on hook %v", hook.Name)
}
hook.Manifest = newManifest.String()
}
}
return hs, b, notes, nil
}

@ -108,8 +108,9 @@ type Install struct {
EnableDNS bool
// Used by helm template to add the release as part of OutputDir path
// OutputDir/<ReleaseName>
UseReleaseName bool
PostRenderer postrender.PostRenderer
UseReleaseName bool
PostRenderer postrender.PostRenderer
PostRendererHooks postrender.PostRenderer
// Lock to control raceconditions when the process receives a SIGTERM
Lock sync.Mutex
}
@ -310,7 +311,20 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma
rel := i.createRelease(chrt, vals, i.Labels)
var manifestDoc *bytes.Buffer
rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.PostRenderer, interactWithRemote, i.EnableDNS, i.HideSecret)
rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(
chrt,
valuesToRender,
i.ReleaseName,
i.OutputDir,
i.SubNotes,
i.UseReleaseName,
i.IncludeCRDs,
i.PostRenderer,
i.PostRendererHooks,
interactWithRemote,
i.EnableDNS,
i.HideSecret,
)
// Even for errors, attach this if available
if manifestDoc != nil {
rel.Manifest = manifestDoc.String()

@ -17,6 +17,7 @@ limitations under the License.
package action
import (
"bytes"
"context"
"fmt"
"io"
@ -528,6 +529,51 @@ func TestInstallRelease_Atomic_Interrupted(t *testing.T) {
is.Equal(err, driver.ErrReleaseNotFound)
}
type testPostRenderer struct {
injectedStr string
}
func (p *testPostRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) {
out := bytes.NewBuffer(nil)
out.WriteString(fmt.Sprintf("# %v\n", p.injectedStr))
out.Write(renderedManifests.Bytes())
return out, nil
}
func TestInstallRelease_WithPostRenderer_EnabledForMain(t *testing.T) {
injectedStr := "Added by post-renderer"
is := assert.New(t)
instAction := installAction(t)
instAction.PostRenderer = &testPostRenderer{injectedStr}
res, err := instAction.Run(buildChart(), map[string]interface{}{})
if err != nil {
t.Fatalf("Failed install: %s", err)
}
is.Contains(res.Manifest, injectedStr)
for _, hook := range res.Hooks {
is.NotContains(hook.Manifest, injectedStr)
}
}
func TestInstallRelease_WithPostRenderer_EnabledAll(t *testing.T) {
mainInjectedStr := "Added by main post-renderer"
hooksInjectedStr := "Added by hooks post-renderer"
is := assert.New(t)
instAction := installAction(t)
instAction.PostRenderer = &testPostRenderer{mainInjectedStr}
instAction.PostRendererHooks = &testPostRenderer{hooksInjectedStr}
res, err := instAction.Run(buildChart(), map[string]interface{}{})
if err != nil {
t.Fatalf("Failed install: %s", err)
}
is.Contains(res.Manifest, mainInjectedStr)
for _, hook := range res.Hooks {
is.Contains(hook.Manifest, hooksInjectedStr)
}
}
func TestNameTemplate(t *testing.T) {
testCases := []nameTemplateTestCase{
// Just a straight up nop please

@ -102,11 +102,13 @@ type Upgrade struct {
// Description is the description of this operation
Description string
Labels map[string]string
// PostRender is an optional post-renderer
// PostRender is an optional post-renderer that runs on manifests and CRDs.
//
// If this is non-nil, then after templates are rendered, they will be sent to the
// post renderer before sending to the Kubernetes API server.
PostRenderer postrender.PostRenderer
// PostRendererHooks is similar to PostRenderer, except it runs only on hooks.
PostRendererHooks postrender.PostRenderer
// DisableOpenAPIValidation controls whether OpenAPI validation is enforced.
DisableOpenAPIValidation bool
// Get missing dependencies
@ -269,7 +271,20 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin
interactWithRemote = true
}
hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false, u.PostRenderer, interactWithRemote, u.EnableDNS, u.HideSecret)
hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(
chart,
valuesToRender,
"",
"",
u.SubNotes,
false,
false,
u.PostRenderer,
u.PostRendererHooks,
interactWithRemote,
u.EnableDNS,
u.HideSecret,
)
if err != nil {
return nil, nil, err
}

Loading…
Cancel
Save