feat(tiller): add Files map to templates

Templates can now access the non-template files in a chart by using
the '{{.Files}}' map inside of a template.

Relates to #950
pull/994/head
Matt Butcher 9 years ago
parent bd5a9753a7
commit 033dbfe75e

@ -0,0 +1,53 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package chartutil
import (
"github.com/golang/protobuf/ptypes/any"
)
// Files is a map of files in a chart that can be accessed from a template.
type Files map[string][]byte
// NewFiles creates a new Files from chart files.
// Given an []*any.Any (the format for files in a chart.Chart), extract a map of files.
func NewFiles(from []*any.Any) Files {
files := map[string][]byte{}
for _, f := range from {
files[f.TypeUrl] = f.Value
}
return files
}
// Get a file by path.
//
// This is intended to be accessed from within a template, so a missed key returns
// an empty []byte.
func (f Files) Get(name string) []byte {
v, ok := f[name]
if !ok {
return []byte{}
}
return v
}
// GetString returns a string representation of the given file.
//
// This is a convenience for the otherwise cumbersome template logic
// for '{{.Files.Get "foo" | printf "%s"}}'.
func (f Files) GetString(name string) string {
return string(f.Get(name))
}

@ -0,0 +1,53 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package chartutil
import (
"testing"
"github.com/golang/protobuf/ptypes/any"
)
func TestNewFiles(t *testing.T) {
cases := []struct {
path, data string
}{
{"ship/captain.txt", "The Captain"},
{"ship/stowaway.txt", "Legatt"},
{"story/name.txt", "The Secret Sharer"},
{"story/author.txt", "Joseph Conrad"},
}
a := []*any.Any{}
for _, c := range cases {
a = append(a, &any.Any{TypeUrl: c.path, Value: []byte(c.data)})
}
files := NewFiles(a)
if len(files) != len(cases) {
t.Errorf("Expected len() = %d, got %d", len(cases), len(files))
}
for i, f := range cases {
if got := string(files.Get(f.path)); got != f.data {
t.Errorf("%d: expected %q, got %q", i, f.data, got)
}
if got := files.GetString(f.path); got != f.data {
t.Errorf("%d: expected %q, got %q", i, f.data, got)
}
}
}

@ -299,6 +299,7 @@ type ReleaseOptions struct {
// ToRenderValues composes the struct from the data coming from the Releases, Charts and Values files // ToRenderValues composes the struct from the data coming from the Releases, Charts and Values files
func ToRenderValues(chrt *chart.Chart, chrtVals *chart.Config, options ReleaseOptions) (Values, error) { func ToRenderValues(chrt *chart.Chart, chrtVals *chart.Config, options ReleaseOptions) (Values, error) {
top := map[string]interface{}{ top := map[string]interface{}{
"Release": map[string]interface{}{ "Release": map[string]interface{}{
"Name": options.Name, "Name": options.Name,
@ -307,6 +308,7 @@ func ToRenderValues(chrt *chart.Chart, chrtVals *chart.Config, options ReleaseOp
"Service": "Tiller", "Service": "Tiller",
}, },
"Chart": chrt.Metadata, "Chart": chrt.Metadata,
"Files": NewFiles(chrt.Files),
} }
vals, err := CoalesceValues(chrt, chrtVals) vals, err := CoalesceValues(chrt, chrtVals)

@ -23,6 +23,7 @@ import (
"testing" "testing"
"text/template" "text/template"
"github.com/golang/protobuf/ptypes/any"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/timeconv" "k8s.io/helm/pkg/timeconv"
) )
@ -93,6 +94,9 @@ where:
Values: &chart.Config{Raw: ""}, Values: &chart.Config{Raw: ""},
}, },
}, },
Files: []*any.Any{
{TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")},
},
} }
v := &chart.Config{Raw: overideValues} v := &chart.Config{Raw: overideValues}
@ -106,6 +110,18 @@ where:
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Ensure that the top-level values are all set.
if name := res["Chart"].(*chart.Metadata).Name; name != "test" {
t.Errorf("Expected chart name 'test', got %q", name)
}
if name := res["Release"].(map[string]interface{})["Name"]; fmt.Sprint(name) != "Seven Voyages" {
t.Errorf("Expected release name 'Seven Voyages', got %q", name)
}
if data := res["Files"].(Files)["scheherazade/shahryar.txt"]; string(data) != "1,001 Nights" {
t.Errorf("Expected file '1,001 Nights', got %q", string(data))
}
var vals Values var vals Values
vals = res["Values"].(Values) vals = res["Values"].(Values)

@ -170,6 +170,7 @@ func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals char
"Values": newVals, "Values": newVals,
"Release": parentVals["Release"], "Release": parentVals["Release"],
"Chart": c.Metadata, "Chart": c.Metadata,
"Files": chartutil.NewFiles(c.Files),
} }
} }

@ -23,6 +23,8 @@ import (
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
"github.com/golang/protobuf/ptypes/any"
) )
func TestEngine(t *testing.T) { func TestEngine(t *testing.T) {
@ -310,9 +312,14 @@ func TestRenderBuiltinValues(t *testing.T) {
Metadata: &chart.Metadata{Name: "Latium"}, Metadata: &chart.Metadata{Name: "Latium"},
Templates: []*chart.Template{ Templates: []*chart.Template{
{Name: "Lavinia", Data: []byte(`{{.Template.Name}}{{.Chart.Name}}{{.Release.Name}}`)}, {Name: "Lavinia", Data: []byte(`{{.Template.Name}}{{.Chart.Name}}{{.Release.Name}}`)},
{Name: "From", Data: []byte(`{{.Files.author | printf "%s"}} {{.Files.GetString "book/title.txt"}}`)},
}, },
Values: &chart.Config{Raw: ``}, Values: &chart.Config{Raw: ``},
Dependencies: []*chart.Chart{}, Dependencies: []*chart.Chart{},
Files: []*any.Any{
{TypeUrl: "author", Value: []byte("Virgil")},
{TypeUrl: "book/title.txt", Value: []byte("Aeneid")},
},
} }
outer := &chart.Chart{ outer := &chart.Chart{
@ -342,6 +349,7 @@ func TestRenderBuiltinValues(t *testing.T) {
expects := map[string]string{ expects := map[string]string{
"Troy/charts/Latium/Lavinia": "Troy/charts/Latium/LaviniaLatiumAeneid", "Troy/charts/Latium/Lavinia": "Troy/charts/Latium/LaviniaLatiumAeneid",
"Troy/Aeneas": "Troy/AeneasTroyAeneid", "Troy/Aeneas": "Troy/AeneasTroyAeneid",
"Troy/charts/Latium/From": "Virgil Aeneid",
} }
for file, expect := range expects { for file, expect := range expects {
if out[file] != expect { if out[file] != expect {

Loading…
Cancel
Save