diff --git a/pkg/chartutil/files.go b/pkg/chartutil/files.go new file mode 100644 index 0000000000000000000000000000000000000000..45598de3a1cec84fa447b00a8e2649bbde736ee1 --- /dev/null +++ b/pkg/chartutil/files.go @@ -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)) +} diff --git a/pkg/chartutil/files_test.go b/pkg/chartutil/files_test.go new file mode 100644 index 0000000000000000000000000000000000000000..97eb4ee0529f8866399e6e1e0011c17f0cb30216 --- /dev/null +++ b/pkg/chartutil/files_test.go @@ -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) + } + } +} diff --git a/pkg/chartutil/values.go b/pkg/chartutil/values.go index 6585fce8dae2576d285df3cc57aa0821848bd27c..3166ce3fa18d898cc8a5c33eedf6f8a0ee171a7d 100644 --- a/pkg/chartutil/values.go +++ b/pkg/chartutil/values.go @@ -299,6 +299,7 @@ type ReleaseOptions struct { // 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) { + top := map[string]interface{}{ "Release": map[string]interface{}{ "Name": options.Name, @@ -307,6 +308,7 @@ func ToRenderValues(chrt *chart.Chart, chrtVals *chart.Config, options ReleaseOp "Service": "Tiller", }, "Chart": chrt.Metadata, + "Files": NewFiles(chrt.Files), } vals, err := CoalesceValues(chrt, chrtVals) diff --git a/pkg/chartutil/values_test.go b/pkg/chartutil/values_test.go index 3b58277b80ca0740004f38f10ce1c070e2be5287..33f0854a83c2e9e630dd663e0590712dd837f91f 100644 --- a/pkg/chartutil/values_test.go +++ b/pkg/chartutil/values_test.go @@ -23,6 +23,7 @@ import ( "testing" "text/template" + "github.com/golang/protobuf/ptypes/any" "k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/timeconv" ) @@ -93,6 +94,9 @@ where: Values: &chart.Config{Raw: ""}, }, }, + Files: []*any.Any{ + {TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")}, + }, } v := &chart.Config{Raw: overideValues} @@ -106,6 +110,18 @@ where: if err != nil { 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 vals = res["Values"].(Values) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 9349177014a21ffe60d3759b8f6cd0bde889afa4..cb88088e6e448aeb6499fd210735ac2f2f3a1db4 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -170,6 +170,7 @@ func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals char "Values": newVals, "Release": parentVals["Release"], "Chart": c.Metadata, + "Files": chartutil.NewFiles(c.Files), } } diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index a61d5de37b2330c506de1c36ef93c0b25a1ad3fe..03ee083dc1ff5f13e74d16a9565e51e9d0d9b2d6 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -23,6 +23,8 @@ import ( "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/proto/hapi/chart" + + "github.com/golang/protobuf/ptypes/any" ) func TestEngine(t *testing.T) { @@ -310,9 +312,14 @@ func TestRenderBuiltinValues(t *testing.T) { Metadata: &chart.Metadata{Name: "Latium"}, Templates: []*chart.Template{ {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: ``}, Dependencies: []*chart.Chart{}, + Files: []*any.Any{ + {TypeUrl: "author", Value: []byte("Virgil")}, + {TypeUrl: "book/title.txt", Value: []byte("Aeneid")}, + }, } outer := &chart.Chart{ @@ -342,6 +349,7 @@ func TestRenderBuiltinValues(t *testing.T) { expects := map[string]string{ "Troy/charts/Latium/Lavinia": "Troy/charts/Latium/LaviniaLatiumAeneid", "Troy/Aeneas": "Troy/AeneasTroyAeneid", + "Troy/charts/Latium/From": "Virgil Aeneid", } for file, expect := range expects { if out[file] != expect {