pull/13537/merge
Raymond Augé 9 months ago committed by GitHub
commit 2742b2846f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -17,6 +17,11 @@ package chart
import "time"
type PostRendererOptions struct {
Command string `json:"command" yaml:"command"`
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
}
// Dependency describes a chart upon which another chart depends.
//
// Dependencies can be used to express developer intent, or to capture the state
@ -47,6 +52,8 @@ type Dependency struct {
ImportValues []interface{} `json:"import-values,omitempty" yaml:"import-values,omitempty"`
// Alias usable alias to be used for the chart
Alias string `json:"alias,omitempty" yaml:"alias,omitempty"`
// A post rendering operation that will be applied to the rendered outputs of this dependency
PostRenderer *PostRendererOptions `json:"postRenderer,omitempty" yaml:"postRenderer,omitempty"`
}
// Validate checks for common problems with the dependency datastructure in

@ -17,6 +17,7 @@ limitations under the License.
package engine
import (
"bytes"
"fmt"
"log"
"path"
@ -31,6 +32,7 @@ import (
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/postrender"
)
// Engine is an implementation of the Helm rendering implementation for templates.
@ -75,7 +77,11 @@ func New(config *rest.Config) Engine {
// bar chart during render time.
func (e Engine) Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, error) {
tmap := allTemplates(chrt, values)
return e.render(tmap)
rendered, err := e.render(tmap)
if err != nil {
return nil, err
}
return postRenderDependency(nil, chrt, rendered)
}
// Render takes a chart, optional values, and value overrides, and attempts to
@ -307,6 +313,77 @@ func (e Engine) render(tpls map[string]renderable) (rendered map[string]string,
return rendered, nil
}
func postRenderDependency(parent *chart.Chart, chrt *chart.Chart, rendered map[string]string) (map[string]string, error) {
for _, c := range chrt.Dependencies() {
_, err := postRenderDependency(chrt, c, rendered)
if err != nil {
return nil, err
}
}
// Skip root chart since it has it's own post-render mechanism
if chrt.IsRoot() || parent == nil {
return rendered, nil
}
var postRenderOptions *chart.PostRendererOptions
for _, depMetadata := range parent.Metadata.Dependencies {
if depMetadata.Name == chrt.Name() {
postRenderOptions = depMetadata.PostRenderer
break
}
}
if postRenderOptions == nil {
return rendered, nil
}
postRenderer, err := postrender.NewExec(postRenderOptions.Command, postRenderOptions.Args...)
if err != nil {
errorMessage := err.Error()
if strings.HasPrefix(errorMessage, "unable to find binary at ") {
log.Printf("[INFO] Skipping dependency post render operation because: %s", errorMessage)
return rendered, nil
}
return nil, err
}
fullChartPath := chrt.ChartFullPath()
for k, renderedContent := range rendered {
if len(strings.TrimSpace(renderedContent)) == 0 || strings.HasSuffix(k, "/templates/NOTES.txt") {
continue
}
if strings.HasPrefix(k, fullChartPath+"/templates/") {
result, err := postRender(postRenderer, renderedContent)
if err != nil {
return nil, err
}
rendered[k] = result
}
}
return rendered, nil
}
func postRender(postRenderer postrender.PostRenderer, renderedContent string) (string, error) {
var buffer bytes.Buffer
buffer.WriteString(renderedContent)
newBuffer, err := postRenderer.Run(&buffer)
if err != nil {
return "", err
}
return newBuffer.String(), nil
}
func cleanupParseError(filename string, err error) error {
tokens := strings.Split(err.Error(), ": ")
if len(tokens) == 1 {

@ -18,12 +18,14 @@ package engine
import (
"fmt"
"os"
"path"
"strings"
"sync"
"testing"
"text/template"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -1300,3 +1302,76 @@ func TestRenderTplMissingKeyString(t *testing.T) {
t.Fatal(err)
}
}
func TestRenderDependencyPostRenderer(t *testing.T) {
dep := &chart.Chart{
Metadata: &chart.Metadata{
Name: "foo",
},
Templates: []*chart.File{
{Name: "templates/foo1", Data: []byte("value: {{ add .Values.bar 2 }}\n")},
{Name: "templates/NOTES.txt", Data: []byte("SOME TEXT")},
{Name: "templates/empty", Data: []byte("")},
},
Values: map[string]interface{}{},
}
cwd, _ := os.Getwd()
c := &chart.Chart{
Metadata: &chart.Metadata{
Name: "moby",
Version: "1.2.3",
Dependencies: []*chart.Dependency{
{
Name: "foo",
PostRenderer: &chart.PostRendererOptions{
Command: cwd + "/../../testdata/postrender.sh",
},
},
},
},
Templates: []*chart.File{
{Name: "templates/test1", Data: []byte("name: {{ .Chart.Name }}")},
},
Values: map[string]interface{}{},
}
c.SetDependencies(dep)
vals := map[string]interface{}{
"Values": map[string]any{
"foo": map[string]any{
"bar": 3,
},
},
}
v, err := chartutil.CoalesceValues(c, vals)
if err != nil {
t.Fatalf("Failed to coalesce values: %s", err)
}
var e Engine
out, err := e.Render(c, v)
if err != nil {
t.Errorf("Failed to render templates: %s", err)
return
}
assert.Equal(t, len(out), 4)
expected := "name: moby"
fp := path.Join(c.ChartFullPath(), "templates/test1")
if out[fp] != expected {
t.Errorf("Expected %q, got %q", expected, out[fp])
}
expected = "value: 25\n"
fp = path.Join(dep.ChartFullPath(), "templates/foo1")
if out[fp] != expected {
t.Errorf("Expected %q, got %q", expected, out[fp])
}
}

@ -0,0 +1,5 @@
#!/bin/sh
s=$(tee | sed 's/5/25/')
echo "${s}"
Loading…
Cancel
Save