Skip to content

Commit

Permalink
Add RenderVerifier for templates (#1327)
Browse files Browse the repository at this point in the history
* Add package verifier that renders the template to detect invalid go template expressions

Signed-off-by: Andreas Neumann <aneumann@mesosphere.com>
  • Loading branch information
ANeumann82 committed Feb 7, 2020
1 parent 15b143a commit 2fb38e4
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 6 deletions.
6 changes: 3 additions & 3 deletions pkg/engine/renderer/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ func (e Engine) Template(name string) *template.Template {

// Render creates a fully rendered template based on a set of values. It parses these in strict mode,
// returning errors when keys are missing.
func (e *Engine) Render(tpl string, vals map[string]interface{}) (string, error) {
func (e *Engine) Render(tplName string, tpl string, vals map[string]interface{}) (string, error) {
var buf bytes.Buffer
t := e.Template("tpl")
t := e.Template(tplName)

if _, err := t.Parse(tpl); err != nil {
return "", fmt.Errorf("error parsing template: %s", err)
}

if err := t.ExecuteTemplate(&buf, "tpl", vals); err != nil {
if err := t.ExecuteTemplate(&buf, tplName, vals); err != nil {
return "", fmt.Errorf("error rendering template: %s", err)
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/engine/renderer/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestRender(t *testing.T) {
"Params": params,
}

rendered, err := engine.Render(test.template, vals)
rendered, err := engine.Render(test.name, test.template, vals)
if err != nil {
t.Errorf("error rendering template: %s", err)
}
Expand All @@ -54,7 +54,7 @@ func TestUnsafeFuncs(t *testing.T) {
unsafeFuncs := []string{"env", "expandenv", "base", "dir", "clean", "ext", "isAbs"}

for _, fun := range unsafeFuncs {
_, err := engine.Render(fmt.Sprintf("{{ \"foo\" | %s }}", fun), nil)
_, err := engine.Render("tpl", fmt.Sprintf("{{ \"foo\" | %s }}", fun), nil)

if err == nil {
t.Errorf("expected error for %s, got none", fun)
Expand Down
2 changes: 1 addition & 1 deletion pkg/engine/task/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func render(resourceNames []string, ctx Context) (map[string]string, error) {
return nil, fmt.Errorf("error finding resource named %s", rn)
}

rendered, err := engine.Render(resource, configs)
rendered, err := engine.Render(rn, resource, configs)
if err != nil {
return nil, fmt.Errorf("error expanding template %s: %w", rn, err)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/kudoctl/cmd/verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var verifiers = []verifier.PackageVerifier{
task.ReferenceVerifier{},
template.ParametersVerifier{},
template.ReferenceVerifier{},
template.RenderVerifier{},
}

// PackageFiles verifies operator package files
Expand Down
48 changes: 48 additions & 0 deletions pkg/kudoctl/packages/verifier/template/verify_render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package template

import (
"github.com/kudobuilder/kudo/pkg/engine/renderer"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages/verifier"
)

var _ verifier.PackageVerifier = &RenderVerifier{}

// RenderVerifier checks that all templates are compilable and contain valid golang template syntax
type RenderVerifier struct{}

func (RenderVerifier) Verify(pf *packages.Files) verifier.Result {
res := verifier.NewResult()
res.Merge(templateCompilable(pf))
return res
}

func templateCompilable(pf *packages.Files) verifier.Result {
params := make(map[string]string)
for _, p := range pf.Params.Parameters {
params[p.Name] = "default"
}

configs := make(map[string]interface{})
configs["OperatorName"] = "OperatorName"
configs["Name"] = "Name"
configs["Namespace"] = "Namespace"
configs["Params"] = params
configs["Pipes"] = make(map[string]string)
configs["PlanName"] = "PlanName"
configs["PhaseName"] = "PhaseName"
configs["StepName"] = "StepName"
configs["AppVersion"] = "AppVersion"

res := verifier.NewResult()

engine := renderer.New()
for k, v := range pf.Templates {
_, err := engine.Render(k, v, configs)
if err != nil {
res.AddErrors(err.Error())
}
}

return res
}
32 changes: 32 additions & 0 deletions pkg/kudoctl/packages/verifier/template/verify_render_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package template

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages"
)

func TestTemplateRenderVerifier(t *testing.T) {
params := make([]v1beta1.Parameter, 0)
paramFile := packages.ParamsFile{Parameters: params}
templates := make(map[string]string)
templates["foo.yaml"] = `
{{ if eq }}
{{ end }}
`
operator := packages.OperatorFile{}
pf := packages.Files{
Templates: templates,
Operator: &operator,
Params: &paramFile,
}
verifier := RenderVerifier{}
res := verifier.Verify(&pf)

assert.Equal(t, 0, len(res.Warnings))
assert.Equal(t, 1, len(res.Errors))
assert.Equal(t, `error rendering template: template: foo.yaml:2:6: executing "foo.yaml" at <eq>: wrong number of args for eq: want at least 1 got 0`, res.Errors[0])
}

0 comments on commit 2fb38e4

Please sign in to comment.