Commit 73a28902 authored by Matt Butcher's avatar Matt Butcher
Browse files

fix(engine): change template naming

Template paths were relative to the chart that contained them, which
meant that all templates were named 'template/SOMETHING'. This made it
trivially easy to hit namespace collisions as in #933.

Template path names are essentially opaque strings so this patch simply
changes them to be qualified by parent chart.
parent b080e944
main Release add-codeql dependabot/go_modules/github.com/docker/distribution-2.8.2incompatible dependabot/go_modules/github.com/lib/pq-1.10.9 dependabot/go_modules/github.com/rubenv/sql-migrate-1.4.0 dependabot/go_modules/golang.org/x/crypto-0.9.0 dependabot/go_modules/golang.org/x/term-0.8.0 dependabot/go_modules/k8s.io/klog/v2-2.100.1 dev-v2 feat-v3/event-emitter-lua kube-update-test release-2.0 release-2.1 release-2.10 release-2.11 release-2.12 release-2.13 release-2.14 release-2.15 release-2.16 release-2.17 release-2.2 release-2.3 release-2.4 release-2.5 release-2.6 release-2.7 release-2.8 release-2.9 release-3.0 release-3.1 release-3.10 release-3.11 release-3.12 release-3.2 release-3.3 release-3.4 release-3.5 release-3.6 release-3.6.1 release-3.6.2 release-3.7 release-3.8 release-3.9 release-v3.0.0-beta.4 v3.12.0 v3.12.0-rc.1 v3.12.0-dev.1 v3.11.3 v3.11.2 v3.11.1 v3.11.0 v3.11.0-rc.2 v3.11.0-rc.1 v3.10.3 v3.10.2 v3.10.1 v3.10.0 v3.10.0-rc.1 v3.9.4 v3.9.3 v3.9.2 v3.9.1 v3.9.0 v3.9.0-rc.1 v3.8.2 v3.8.1 v3.8.0 v3.8.0-rc.2 v3.8.0-rc.1 v3.7.2 v3.7.1 v3.7.0 v3.7.0-rc.3 v3.7.0-rc.2 v3.7.0-rc.1 v3.6.3 v3.6.2 v3.6.1 v3.6.0 v3.6.0-rc.1 v3.5.4 v3.5.3 v3.5.2 v3.5.1 v3.5.0 v3.5.0-rc.2 v3.5.0-rc.1 v3.4.2 v3.4.1 v3.4.0 v3.4.0-rc.1 v3.3.4 v3.3.3 v3.3.2 v3.3.1 v3.3.0 v3.3.0-rc.2 v3.3.0-rc.1 v3.2.4 v3.2.3 v3.2.2 v3.2.1 v3.2.0 v3.2.0-rc.1 v3.1.3 v3.1.2 v3.1.1 v3.1.0 v3.1.0-rc.3 v3.1.0-rc.2 v3.1.0-rc.1 v3.0.3 v3.0.2 v3.0.1 v3.0.0 v3.0.0-rc.4 v3.0.0-rc.3 v3.0.0-rc.2 v3.0.0-rc.1 v3.0.0-beta.5 v3.0.0-beta.4 v3.0.0-beta.3 v3.0.0-beta.2 v3.0.0-beta.1 v3.0.0-alpha.2 v3.0.0-alpha.1 v2.17.0 v2.17.0-rc.1 v2.16.12 v2.16.11 v2.16.10 v2.16.9 v2.16.8 v2.16.7 v2.16.6 v2.16.5 v2.16.4 v2.16.3 v2.16.2 v2.16.1 v2.16.0 v2.16.0-rc.2 v2.16.0-rc.1 v2.15.2 v2.15.1 v2.15.0 v2.15.0-rc.2 v2.15.0-rc.1 v2.14.3 v2.14.2 v2.14.1 v2.14.0 v2.14.0-rc.2 v2.14.0-rc.1 v2.13.1 v2.13.1-rc.1 v2.13.0 v2.13.0-rc.2 v2.13.0-rc.1 v2.12.3 v2.12.2 v2.12.1 v2.12.0 v2.12.0-rc.2 v2.12.0-rc.1 v2.11.0 v2.11.0-rc.4 v2.11.0-rc.3 v2.11.0-rc.2 v2.11.0-rc.1 v2.10.0 v2.10.0-rc.3 v2.10.0-rc.2 v2.10.0-rc.1 v2.9.1 v2.9.0 v2.9.0-rc5 v2.9.0-rc4 v2.9.0-rc3 v2.9.0-rc2 v2.9.0-rc1 v2.8.2 v2.8.2-rc1 v2.8.1 v2.8.0 v2.8.0-rc.1 v2.7.2 v2.7.1 v2.7.0 v2.7.0-rc1 v2.6.2 v2.6.1 v2.6.0 v2.5.1 v2.5.0 v2.4.2 v2.4.1 v2.4.0 v2.3.1 v2.3.0 v2.2.3 v2.2.2 v2.2.1 v2.2.0 v2.1.3 v2.1.2 v2.1.1 v2.1.0 v2.0.2 v2.0.1 v2.0.0 v2.0.0-rc.2 v2.0.0-rc.1 v2.0.0-beta.2 v2.0.0-beta.1 v2.0.0-alpha.5 v2.0.0-alpha.4 v2.0.0-alpha.3
No related merge requests found
Showing with 37 additions and 23 deletions
+37 -23
...@@ -134,7 +134,7 @@ func TestInstallRelease(t *testing.T) { ...@@ -134,7 +134,7 @@ func TestInstallRelease(t *testing.T) {
t.Errorf("Expected manifest in %v", res) t.Errorf("Expected manifest in %v", res)
} }
if !strings.Contains(rel.Manifest, "---\n# Source: hello\nhello: world") { if !strings.Contains(rel.Manifest, "---\n# Source: hello/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Manifest) t.Errorf("unexpected output: %s", rel.Manifest)
} }
} }
...@@ -150,8 +150,8 @@ func TestInstallReleaseDryRun(t *testing.T) { ...@@ -150,8 +150,8 @@ func TestInstallReleaseDryRun(t *testing.T) {
{Name: "hello", Data: []byte("hello: world")}, {Name: "hello", Data: []byte("hello: world")},
{Name: "goodbye", Data: []byte("goodbye: world")}, {Name: "goodbye", Data: []byte("goodbye: world")},
{Name: "empty", Data: []byte("")}, {Name: "empty", Data: []byte("")},
{Name: "with-partials", Data: []byte("hello: {{ template \"partials/_planet\" . }}")}, {Name: "with-partials", Data: []byte(`hello: {{ template "_planet" . }}`)},
{Name: "partials/_planet", Data: []byte("Earth")}, {Name: "partials/_planet", Data: []byte(`{{define "_planet"}}Earth{{end}}`)},
{Name: "hooks", Data: []byte(manifestWithHook)}, {Name: "hooks", Data: []byte(manifestWithHook)},
}, },
}, },
...@@ -165,11 +165,11 @@ func TestInstallReleaseDryRun(t *testing.T) { ...@@ -165,11 +165,11 @@ func TestInstallReleaseDryRun(t *testing.T) {
t.Errorf("Expected release name.") t.Errorf("Expected release name.")
} }
if !strings.Contains(res.Release.Manifest, "---\n# Source: hello\nhello: world") { if !strings.Contains(res.Release.Manifest, "---\n# Source: hello/hello\nhello: world") {
t.Errorf("unexpected output: %s", res.Release.Manifest) t.Errorf("unexpected output: %s", res.Release.Manifest)
} }
if !strings.Contains(res.Release.Manifest, "---\n# Source: goodbye\ngoodbye: world") { if !strings.Contains(res.Release.Manifest, "---\n# Source: hello/goodbye\ngoodbye: world") {
t.Errorf("unexpected output: %s", res.Release.Manifest) t.Errorf("unexpected output: %s", res.Release.Manifest)
} }
...@@ -177,7 +177,7 @@ func TestInstallReleaseDryRun(t *testing.T) { ...@@ -177,7 +177,7 @@ func TestInstallReleaseDryRun(t *testing.T) {
t.Errorf("Should contain partial content. %s", res.Release.Manifest) t.Errorf("Should contain partial content. %s", res.Release.Manifest)
} }
if strings.Contains(res.Release.Manifest, "hello: {{ template \"partials/_planet\" . }}") { if strings.Contains(res.Release.Manifest, "hello: {{ template \"_planet\" . }}") {
t.Errorf("Should not contain partial templates itself. %s", res.Release.Manifest) t.Errorf("Should not contain partial templates itself. %s", res.Release.Manifest)
} }
......
...@@ -19,6 +19,8 @@ package engine ...@@ -19,6 +19,8 @@ package engine
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"log"
"path"
"strings" "strings"
"text/template" "text/template"
...@@ -105,6 +107,7 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) { ...@@ -105,6 +107,7 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
} }
files := []string{} files := []string{}
for fname, r := range tpls { for fname, r := range tpls {
log.Printf("Preparing template %s", fname)
t = t.New(fname).Funcs(e.FuncMap) t = t.New(fname).Funcs(e.FuncMap)
if _, err := t.Parse(r.tpl); err != nil { if _, err := t.Parse(r.tpl); err != nil {
return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err) return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
...@@ -137,7 +140,7 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) { ...@@ -137,7 +140,7 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
// As it goes, it also prepares the values in a scope-sensitive manner. // As it goes, it also prepares the values in a scope-sensitive manner.
func allTemplates(c *chart.Chart, vals chartutil.Values) map[string]renderable { func allTemplates(c *chart.Chart, vals chartutil.Values) map[string]renderable {
templates := map[string]renderable{} templates := map[string]renderable{}
recAllTpls(c, templates, vals, true) recAllTpls(c, templates, vals, true, "")
return templates return templates
} }
...@@ -145,7 +148,7 @@ func allTemplates(c *chart.Chart, vals chartutil.Values) map[string]renderable { ...@@ -145,7 +148,7 @@ func allTemplates(c *chart.Chart, vals chartutil.Values) map[string]renderable {
// //
// As it recurses, it also sets the values to be appropriate for the template // As it recurses, it also sets the values to be appropriate for the template
// scope. // scope.
func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals chartutil.Values, top bool) { func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals chartutil.Values, top bool, parentID string) {
// This should never evaluate to a nil map. That will cause problems when // This should never evaluate to a nil map. That will cause problems when
// values are appended later. // values are appended later.
cvals := chartutil.Values{} cvals := chartutil.Values{}
...@@ -170,11 +173,19 @@ func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals char ...@@ -170,11 +173,19 @@ func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals char
} }
} }
newParentID := c.Metadata.Name
if parentID != "" {
// We artificially reconstruct the chart path to child templates. This
// creates a namespaced filename that can be used to track down the source
// of a particular template declaration.
newParentID = path.Join(parentID, "charts", newParentID)
}
for _, child := range c.Dependencies { for _, child := range c.Dependencies {
recAllTpls(child, templates, cvals, false) recAllTpls(child, templates, cvals, false, newParentID)
} }
for _, t := range c.Templates { for _, t := range c.Templates {
templates[t.Name] = renderable{ templates[path.Join(newParentID, t.Name)] = renderable{
tpl: string(t.Data), tpl: string(t.Data),
vals: cvals, vals: cvals,
} }
......
...@@ -75,16 +75,16 @@ func TestRender(t *testing.T) { ...@@ -75,16 +75,16 @@ func TestRender(t *testing.T) {
} }
expect := "Spouter Inn" expect := "Spouter Inn"
if out["test1"] != expect { if out["moby/test1"] != expect {
t.Errorf("Expected %q, got %q", expect, out["test1"]) t.Errorf("Expected %q, got %q", expect, out["test1"])
} }
expect = "ishmael" expect = "ishmael"
if out["test2"] != expect { if out["moby/test2"] != expect {
t.Errorf("Expected %q, got %q", expect, out["test2"]) t.Errorf("Expected %q, got %q", expect, out["test2"])
} }
expect = "" expect = ""
if out["test3"] != expect { if out["moby/test3"] != expect {
t.Errorf("Expected %q, got %q", expect, out["test3"]) t.Errorf("Expected %q, got %q", expect, out["test3"])
} }
...@@ -188,11 +188,13 @@ func TestRenderDependency(t *testing.T) { ...@@ -188,11 +188,13 @@ func TestRenderDependency(t *testing.T) {
deptpl := `{{define "myblock"}}World{{end}}` deptpl := `{{define "myblock"}}World{{end}}`
toptpl := `Hello {{template "myblock"}}` toptpl := `Hello {{template "myblock"}}`
ch := &chart.Chart{ ch := &chart.Chart{
Metadata: &chart.Metadata{Name: "outerchart"},
Templates: []*chart.Template{ Templates: []*chart.Template{
{Name: "outer", Data: []byte(toptpl)}, {Name: "outer", Data: []byte(toptpl)},
}, },
Dependencies: []*chart.Chart{ Dependencies: []*chart.Chart{
{ {
Metadata: &chart.Metadata{Name: "innerchart"},
Templates: []*chart.Template{ Templates: []*chart.Template{
{Name: "inner", Data: []byte(deptpl)}, {Name: "inner", Data: []byte(deptpl)},
}, },
...@@ -211,7 +213,7 @@ func TestRenderDependency(t *testing.T) { ...@@ -211,7 +213,7 @@ func TestRenderDependency(t *testing.T) {
} }
expect := "Hello World" expect := "Hello World"
if out["outer"] != expect { if out["outerchart/outer"] != expect {
t.Errorf("Expected %q, got %q", expect, out["outer"]) t.Errorf("Expected %q, got %q", expect, out["outer"])
} }
...@@ -220,10 +222,11 @@ func TestRenderDependency(t *testing.T) { ...@@ -220,10 +222,11 @@ func TestRenderDependency(t *testing.T) {
func TestRenderNestedValues(t *testing.T) { func TestRenderNestedValues(t *testing.T) {
e := New() e := New()
innerpath := "charts/inner/templates/inner.tpl" innerpath := "templates/inner.tpl"
outerpath := "templates/outer.tpl" outerpath := "templates/outer.tpl"
deepestpath := "charts/inner/charts/deepest/templates/deepest.tpl" // Ensure namespacing rules are working.
checkrelease := "charts/inner/charts/deepest/templates/release.tpl" deepestpath := "templates/inner.tpl"
checkrelease := "templates/release.tpl"
deepest := &chart.Chart{ deepest := &chart.Chart{
Metadata: &chart.Metadata{Name: "deepest"}, Metadata: &chart.Metadata{Name: "deepest"},
...@@ -288,19 +291,19 @@ global: ...@@ -288,19 +291,19 @@ global:
t.Fatalf("failed to render templates: %s", err) t.Fatalf("failed to render templates: %s", err)
} }
if out[outerpath] != "Gather ye rosebuds while ye may" { if out["top/"+outerpath] != "Gather ye rosebuds while ye may" {
t.Errorf("Unexpected outer: %q", out[outerpath]) t.Errorf("Unexpected outer: %q", out[outerpath])
} }
if out[innerpath] != "Old time is still a-flyin'" { if out["top/charts/herrick/"+innerpath] != "Old time is still a-flyin'" {
t.Errorf("Unexpected inner: %q", out[innerpath]) t.Errorf("Unexpected inner: %q", out[innerpath])
} }
if out[deepestpath] != "And this same flower that smiles to-day" { if out["top/charts/herrick/charts/deepest/"+deepestpath] != "And this same flower that smiles to-day" {
t.Errorf("Unexpected deepest: %q", out[deepestpath]) t.Errorf("Unexpected deepest: %q", out[deepestpath])
} }
if out[checkrelease] != "Tomorrow will be dyin" { if out["top/charts/herrick/charts/deepest/"+checkrelease] != "Tomorrow will be dyin" {
t.Errorf("Unexpected release: %q", out[checkrelease]) t.Errorf("Unexpected release: %q", out[checkrelease])
} }
} }
...@@ -340,8 +343,8 @@ func TestRenderBuiltinValues(t *testing.T) { ...@@ -340,8 +343,8 @@ func TestRenderBuiltinValues(t *testing.T) {
} }
expects := map[string]string{ expects := map[string]string{
"Lavinia": "LaviniaLatiumAeneid", "Troy/charts/Latium/Lavinia": "Troy/charts/Latium/LaviniaLatiumAeneid",
"Aeneas": "AeneasTroyAeneid", "Troy/Aeneas": "Troy/AeneasTroyAeneid",
} }
for file, expect := range expects { for file, expect := range expects {
if out[file] != expect { if out[file] != expect {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment