diff --git a/pkg/chartutil/chartfile.go b/pkg/chartutil/chartfile.go new file mode 100644 index 000000000..cd5efbc7b --- /dev/null +++ b/pkg/chartutil/chartfile.go @@ -0,0 +1,26 @@ +package chartutil + +import ( + "io/ioutil" + + "github.com/ghodss/yaml" + "github.com/kubernetes/helm/pkg/proto/hapi/chart" +) + +func UnmarshalChartfile(data []byte) (*chart.Metadata, error) { + y := &chart.Metadata{} + err := yaml.Unmarshal(data, y) + if err != nil { + return nil, err + } + return y, nil +} + +// LoadChartfile loads a Chart.yaml file into a *chart.Metadata. +func LoadChartfile(filename string) (*chart.Metadata, error) { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + return UnmarshalChartfile(b) +} diff --git a/pkg/chartutil/chartfile_test.go b/pkg/chartutil/chartfile_test.go new file mode 100644 index 000000000..4d6dbf6e1 --- /dev/null +++ b/pkg/chartutil/chartfile_test.go @@ -0,0 +1,69 @@ +package chartutil + +import ( + "testing" + + "github.com/kubernetes/helm/pkg/proto/hapi/chart" +) + +const testfile = "testdata/chartfiletest.yaml" + +func TestLoadChartfile(t *testing.T) { + f, err := LoadChartfile(testfile) + if err != nil { + t.Errorf("Failed to open %s: %s", testfile, err) + return + } + verifyChartfile(t, f) +} + +func verifyChartfile(t *testing.T, f *chart.Metadata) { + + if f.Name != "frobnitz" { + t.Errorf("Expected frobnitz, got %s", f.Name) + } + + if f.Description != "This is a frobnitz." { + t.Errorf("Unexpected description %q", f.Description) + } + + if f.Version != "1.2.3" { + t.Errorf("Unexpected version %q", f.Version) + } + + if len(f.Maintainers) != 2 { + t.Errorf("Expected 2 maintainers, got %d", len(f.Maintainers)) + } + + if f.Maintainers[0].Name != "The Helm Team" { + t.Errorf("Unexpected maintainer name.") + } + + if f.Maintainers[1].Email != "nobody@example.com" { + t.Errorf("Unexpected maintainer email.") + } + + if len(f.Sources) != 1 { + t.Fatalf("Unexpected number of sources") + } + + if f.Sources[0] != "https://example.com/foo/bar" { + t.Errorf("Expected https://example.com/foo/bar, got %s", f.Sources) + } + + if f.Home != "http://example.com" { + t.Error("Unexpected home.") + } + + if len(f.Keywords) != 3 { + t.Error("Unexpected keywords") + } + + kk := []string{"frobnitz", "sprocket", "dodad"} + for i, k := range f.Keywords { + if kk[i] != k { + t.Errorf("Expected %q, got %q", kk[i], k) + } + } + +} diff --git a/pkg/chartutil/doc.go b/pkg/chartutil/doc.go new file mode 100644 index 000000000..0191c3800 --- /dev/null +++ b/pkg/chartutil/doc.go @@ -0,0 +1,28 @@ +/*Package chartutil contains tools for working with charts. + +Charts are described in the protocol buffer definition (pkg/proto/hapi/charts). +This packe provides utilities for serializing and deserializing charts. + +A chart can be represented on the file system in one of two ways: + + - As a directory that contains a Chart.yaml file and other chart things. + - As a tarred gzipped file containing a directory that then contains a + Chart.yaml file. + +This package provides utilitites for working with those file formats. + +The preferred way of loading a chart is using 'chartutil.Load`: + + chart, err := chartutil.Load(filename) + +This will attempt to discover whether the file at 'filename' is a directory or +a chart archive. It will then load accordingly. + +For accepting raw compressed tar file data from an io.Reader, the +'chartutil.LoadArchive()' will read in the data, uncompress it, and unpack it +into a Chart. + +When creating charts in memory, use the 'github.com/kubernetes/helm/pkg/proto/happy/chart' +package directly. +*/ +package chartutil diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go new file mode 100644 index 000000000..00ca9489e --- /dev/null +++ b/pkg/chartutil/load.go @@ -0,0 +1,274 @@ +package chartutil + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/golang/protobuf/ptypes/any" + "github.com/kubernetes/helm/pkg/proto/hapi/chart" +) + +// Load takes a string name, tries to resolve it to a file or directory, and then loads it. +// +// This is the preferred way to load a chart. It will discover the chart encoding +// and hand off to the appropriate chart reader. +func Load(name string) (*chart.Chart, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if fi.IsDir() { + return LoadDir(name) + } + return LoadFile(name) +} + +// subchart is an intermediate representation of a dependency. +// +// It is used to temporarily store a dependency while we process the outer +// file. +type subchart []*afile + +func newSubchart() subchart { + return []*afile{} +} + +func (s subchart) add(name string, data []byte, arch bool) subchart { + s = append(s, &afile{name, data, arch}) + return s +} + +// afile represents an archive file buffered for later processing. +type afile struct { + name string + data []byte + archive bool +} + +// LoadArchive loads from a reader containing a compressed tar archive. +func LoadArchive(in io.Reader) (*chart.Chart, error) { + sc := map[string]subchart{} + unzipped, err := gzip.NewReader(in) + if err != nil { + return nil, err + } + defer unzipped.Close() + + c := &chart.Chart{} + b := bytes.NewBuffer(nil) + + tr := tar.NewReader(unzipped) + for { + hd, err := tr.Next() + if err == io.EOF { + // We're done with the reader. Now add subcharts and exit. + e := addSubcharts(c, sc) + return c, e + } + if err != nil { + return c, err + } + + if hd.FileInfo().IsDir() { + // Use this instead of hd.Typeflag because we don't have to do any + // inference chasing. + continue + } + + parts := strings.Split(hd.Name, "/") + n := strings.Join(parts[1:], "/") + + if _, err := io.Copy(b, tr); err != nil { + return c, err + } + + if strings.HasPrefix(n, "charts/") { + // If there are subcharts, we put those into a temporary holding + // array for later processing. + fmt.Printf("Appending %s to chart %s:\n%s\n", n, c.Metadata.Name, b.String()) + appendSubchart(sc, n, b.Bytes()) + b.Reset() + continue + } + + addToChart(c, n, b.Bytes()) + b.Reset() + } + +} + +// LoadFile loads from an archive file. +func LoadFile(name string) (*chart.Chart, error) { + if fi, err := os.Stat(name); err != nil { + return nil, err + } else if fi.IsDir() { + return nil, errors.New("cannot load a directory") + } + + raw, err := os.Open(name) + if err != nil { + return nil, err + } + defer raw.Close() + + return LoadArchive(raw) +} + +// LoadDir loads from a directory. +// +// This loads charts only from directories. +func LoadDir(dir string) (*chart.Chart, error) { + topdir, err := filepath.Abs(dir) + if err != nil { + return nil, err + } + + topdir += string(filepath.Separator) + sc := map[string]subchart{} + c := &chart.Chart{} + err = filepath.Walk(topdir, func(name string, fi os.FileInfo, err error) error { + n := strings.TrimPrefix(name, topdir) + if err != nil { + return err + } + if fi.IsDir() { + return nil + } + + data, err := ioutil.ReadFile(name) + if err != nil { + return fmt.Errorf("error reading %s: %s", n, err) + } + + if strings.HasPrefix(n, "charts/") { + appendSubchart(sc, n, data) + return nil + } + + return addToChart(c, n, data) + }) + if err != nil { + return c, err + } + + // Ensure that we had a Chart.yaml file + if c.Metadata == nil || c.Metadata.Name == "" { + return c, errors.New("chart metadata (Chart.yaml) missing") + } + + err = addSubcharts(c, sc) + return c, err +} + +func addToChart(c *chart.Chart, n string, data []byte) error { + fmt.Printf("--> Scanning %s\n", n) + if n == "Chart.yaml" { + md, err := UnmarshalChartfile(data) + if err != nil { + return err + } + if md.Name == "" { + fmt.Printf("Chart:\n%s\n", string(data)) + } + fmt.Printf("--> Adding %s as Chart.yaml\n", md.Name) + c.Metadata = md + } else if n == "values.toml" { + c.Values = &chart.Config{Raw: string(data)} + fmt.Printf("--> Adding to values:\n%s\n", string(data)) + } else if strings.HasPrefix(n, "charts/") { + // SKIP THESE. These are handled elsewhere, because they need context + // to process. + return nil + } else if strings.HasPrefix(n, "templates/") { + c.Templates = append(c.Templates, &chart.Template{Name: n, Data: data}) + } else { + c.Files = append(c.Files, &any.Any{TypeUrl: n, Value: data}) + } + return nil +} + +func addSubcharts(c *chart.Chart, s map[string]subchart) error { + for n, sc := range s { + fmt.Printf("===> Unpacking %s\n", n) + if err := addSubchart(c, sc); err != nil { + return fmt.Errorf("error adding %q: %s", n, err) + } + } + return nil +} + +// addSubchart transforms a subchart to a new chart, and then embeds it into the given chart. +func addSubchart(c *chart.Chart, sc subchart) error { + nc := &chart.Chart{} + deps := map[string]subchart{} + + // The sc paths are all relative to the sc itself. + for _, sub := range sc { + if sub.archive { + b := bytes.NewBuffer(sub.data) + var err error + nc, err = LoadArchive(b) + if err != nil { + fmt.Printf("Bad data in %s: %q", sub.name, string(sub.data)) + return err + } + break + } else if strings.HasPrefix(sub.name, "charts/") { + appendSubchart(deps, sub.name, sub.data) + } else { + fmt.Printf("Adding %s to subchart in %s\n", sub.name, c.Metadata.Name) + addToChart(nc, sub.name, sub.data) + } + } + + if nc.Metadata == nil || nc.Metadata.Name == "" { + return errors.New("embedded chart is not well-formed") + } + + fmt.Printf("Added dependency: %q\n", nc.Metadata.Name) + c.Dependencies = append(c.Dependencies, nc) + return nil +} + +func appendSubchart(sc map[string]subchart, n string, b []byte) { + fmt.Printf("Append subchart %s\n", n) + // TODO: Do we need to filter out 0 byte files? + // TODO: If this finds a dependency that is a tarball, we need to untar it, + // and express it as a subchart. + parts := strings.SplitN(n, "/", 3) + lp := len(parts) + switch lp { + case 2: + if filepath.Ext(parts[1]) == ".tgz" { + fmt.Printf("--> Adding archive %s\n", n) + // Basically, we delay expanding tar files until the last minute, + // which helps (a little) keep memory usage down. + bn := strings.TrimSuffix(parts[1], ".tgz") + cc := newSubchart() + sc[bn] = cc.add(parts[1], b, true) + return + } else { + // Skip directory entries and non-charts. + return + } + case 3: + if _, ok := sc[parts[1]]; !ok { + sc[parts[1]] = newSubchart() + } + //fmt.Printf("Adding file %q to %s\n", parts[2], parts[1]) + sc[parts[1]] = sc[parts[1]].add(parts[2], b, false) + return + default: + // Skip 1 or 0. + return + } + +} diff --git a/pkg/chartutil/load_test.go b/pkg/chartutil/load_test.go new file mode 100644 index 000000000..dae3ee438 --- /dev/null +++ b/pkg/chartutil/load_test.go @@ -0,0 +1,81 @@ +package chartutil + +import ( + "testing" + + "github.com/kubernetes/helm/pkg/proto/hapi/chart" +) + +func TestLoadDir(t *testing.T) { + c, err := Load("testdata/frobnitz") + if err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } + verifyFrobnitz(t, c) + verifyChart(t, c) +} + +func TestLoadFile(t *testing.T) { + c, err := Load("testdata/frobnitz-1.2.3.tgz") + if err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } + verifyFrobnitz(t, c) + verifyChart(t, c) +} + +func verifyChart(t *testing.T, c *chart.Chart) { + if len(c.Templates) != 1 { + t.Errorf("Expected 1 template, got %d", len(c.Templates)) + } + + if len(c.Files) != 5 { + t.Errorf("Expected 5 extra files, got %d", len(c.Files)) + for _, n := range c.Files { + t.Logf("\t%s", n.TypeUrl) + } + } + + if len(c.Dependencies) != 2 { + t.Errorf("Expected 2 dependencies, got %d (%v)", len(c.Dependencies), c.Dependencies) + for _, d := range c.Dependencies { + t.Logf("\tSubchart: %s\n", d.Metadata.Name) + } + } + + expect := map[string]map[string]string{ + "alpine": map[string]string{ + "version": "0.1.0", + }, + "mariner": map[string]string{ + "version": "4.3.2", + }, + } + + for _, dep := range c.Dependencies { + exp, ok := expect[dep.Metadata.Name] + if !ok { + t.Fatalf("Unknown dependency %s", dep.Metadata.Name) + } + if exp["version"] != dep.Metadata.Version { + t.Errorf("Expected %s version %s, got %s", dep.Metadata.Name, exp["version"], dep.Metadata.Version) + } + } + +} + +func verifyFrobnitz(t *testing.T, c *chart.Chart) { + verifyChartfile(t, c.Metadata) + + if len(c.Templates) != 1 { + t.Fatalf("Expected 1 template, got %d", len(c.Templates)) + } + + if c.Templates[0].Name != "templates/template.tpl" { + t.Errorf("Unexpected template: %s", c.Templates[0].Name) + } + + if len(c.Templates[0].Data) == 0 { + t.Error("No template data.") + } +} diff --git a/pkg/chartutil/testdata/albatross/Chart.yaml b/pkg/chartutil/testdata/albatross/Chart.yaml new file mode 100644 index 000000000..eeef737ff --- /dev/null +++ b/pkg/chartutil/testdata/albatross/Chart.yaml @@ -0,0 +1,4 @@ +name: albatross +description: A Helm chart for Kubernetes +version: 0.1.0 +home: "" diff --git a/pkg/chartutil/testdata/albatross/values.toml b/pkg/chartutil/testdata/albatross/values.toml new file mode 100644 index 000000000..0ef7eb2f9 --- /dev/null +++ b/pkg/chartutil/testdata/albatross/values.toml @@ -0,0 +1 @@ +albatross = "true" diff --git a/pkg/chartutil/testdata/chartfiletest.yaml b/pkg/chartutil/testdata/chartfiletest.yaml new file mode 100644 index 000000000..9f255b9bd --- /dev/null +++ b/pkg/chartutil/testdata/chartfiletest.yaml @@ -0,0 +1,15 @@ +name: frobnitz +description: This is a frobnitz. +version: "1.2.3" +keywords: + - frobnitz + - sprocket + - dodad +maintainers: + - name: The Helm Team + email: helm@example.com + - name: Someone Else + email: nobody@example.com +sources: + - https://example.com/foo/bar +home: http://example.com diff --git a/pkg/chartutil/testdata/frobnitz-1.2.3.tgz b/pkg/chartutil/testdata/frobnitz-1.2.3.tgz new file mode 100644 index 000000000..c908b2264 Binary files /dev/null and b/pkg/chartutil/testdata/frobnitz-1.2.3.tgz differ diff --git a/pkg/chartutil/testdata/frobnitz/Chart.yaml b/pkg/chartutil/testdata/frobnitz/Chart.yaml new file mode 100644 index 000000000..9f255b9bd --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/Chart.yaml @@ -0,0 +1,15 @@ +name: frobnitz +description: This is a frobnitz. +version: "1.2.3" +keywords: + - frobnitz + - sprocket + - dodad +maintainers: + - name: The Helm Team + email: helm@example.com + - name: Someone Else + email: nobody@example.com +sources: + - https://example.com/foo/bar +home: http://example.com diff --git a/pkg/chartutil/testdata/frobnitz/INSTALL.txt b/pkg/chartutil/testdata/frobnitz/INSTALL.txt new file mode 100644 index 000000000..2010438c2 --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/INSTALL.txt @@ -0,0 +1 @@ +This is an install document. The client may display this. diff --git a/pkg/chartutil/testdata/frobnitz/LICENSE b/pkg/chartutil/testdata/frobnitz/LICENSE new file mode 100644 index 000000000..6121943b1 --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/LICENSE @@ -0,0 +1 @@ +LICENSE placeholder. diff --git a/pkg/chartutil/testdata/frobnitz/README.md b/pkg/chartutil/testdata/frobnitz/README.md new file mode 100644 index 000000000..8cf4cc3d7 --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/README.md @@ -0,0 +1,11 @@ +# Frobnitz + +This is an example chart. + +## Usage + +This is an example. It has no usage. + +## Development + +For developer info, see the top-level repository. diff --git a/pkg/chartutil/testdata/frobnitz/charts/alpine/Chart.yaml b/pkg/chartutil/testdata/frobnitz/charts/alpine/Chart.yaml new file mode 100644 index 000000000..cab858d0a --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/charts/alpine/Chart.yaml @@ -0,0 +1,4 @@ +name: alpine +description: Deploy a basic Alpine Linux pod +version: 0.1.0 +home: https://github.com/kubernetes/helm diff --git a/pkg/chartutil/testdata/frobnitz/charts/alpine/README.md b/pkg/chartutil/testdata/frobnitz/charts/alpine/README.md new file mode 100644 index 000000000..a7c84fc41 --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/charts/alpine/README.md @@ -0,0 +1,9 @@ +This example was generated using the command `helm create alpine`. + +The `templates/` directory contains a very simple pod resource with a +couple of parameters. + +The `values.toml` file contains the default values for the +`alpine-pod.yaml` template. + +You can install this example using `helm install docs/examples/alpine`. diff --git a/pkg/chartutil/testdata/frobnitz/charts/alpine/charts/mast1/Chart.yaml b/pkg/chartutil/testdata/frobnitz/charts/alpine/charts/mast1/Chart.yaml new file mode 100644 index 000000000..171e36156 --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/charts/alpine/charts/mast1/Chart.yaml @@ -0,0 +1,4 @@ +name: mast1 +description: A Helm chart for Kubernetes +version: 0.1.0 +home: "" diff --git a/pkg/chartutil/testdata/frobnitz/charts/alpine/charts/mast1/values.toml b/pkg/chartutil/testdata/frobnitz/charts/alpine/charts/mast1/values.toml new file mode 100644 index 000000000..f0cab9e08 --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/charts/alpine/charts/mast1/values.toml @@ -0,0 +1,4 @@ +# Default values for mast1. +# This is a TOML-formatted file. https://github.com/toml-lang/toml +# Declare name/value pairs to be passed into your templates. +# name = "value" diff --git a/pkg/chartutil/testdata/frobnitz/charts/alpine/charts/mast2-0.1.0.tgz b/pkg/chartutil/testdata/frobnitz/charts/alpine/charts/mast2-0.1.0.tgz new file mode 100644 index 000000000..232322a26 Binary files /dev/null and b/pkg/chartutil/testdata/frobnitz/charts/alpine/charts/mast2-0.1.0.tgz differ diff --git a/pkg/chartutil/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml new file mode 100644 index 000000000..08cf3c2c1 --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: {{.Release.Name}}-{{.Chart.Name}} + labels: + heritage: {{.Release.Service}} + chartName: {{.Chart.Name}} + chartVersion: {{.Chart.Version | quote}} + annotations: + "helm.sh/created": "{{.Release.Time.Seconds}}" +spec: + restartPolicy: {{default "Never" .restart_policy}} + containers: + - name: waiter + image: "alpine:3.3" + command: ["/bin/sleep","9000"] diff --git a/pkg/chartutil/testdata/frobnitz/charts/alpine/values.toml b/pkg/chartutil/testdata/frobnitz/charts/alpine/values.toml new file mode 100644 index 000000000..504e6e1be --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/charts/alpine/values.toml @@ -0,0 +1,2 @@ +# The pod name +name = "my-alpine" diff --git a/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz b/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz new file mode 100644 index 000000000..d4f19e624 Binary files /dev/null and b/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz differ diff --git a/pkg/chartutil/testdata/frobnitz/docs/README.md b/pkg/chartutil/testdata/frobnitz/docs/README.md new file mode 100644 index 000000000..d40747caf --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/docs/README.md @@ -0,0 +1 @@ +This is a placeholder for documentation. diff --git a/pkg/chartutil/testdata/frobnitz/icon.svg b/pkg/chartutil/testdata/frobnitz/icon.svg new file mode 100644 index 000000000..892130606 --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/icon.svg @@ -0,0 +1,8 @@ + + + Example icon + + + diff --git a/pkg/chartutil/testdata/frobnitz/templates/template.tpl b/pkg/chartutil/testdata/frobnitz/templates/template.tpl new file mode 100644 index 000000000..c651ee6a0 --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/templates/template.tpl @@ -0,0 +1 @@ +Hello {{.Name | default "world"}} diff --git a/pkg/chartutil/testdata/frobnitz/values.toml b/pkg/chartutil/testdata/frobnitz/values.toml new file mode 100644 index 000000000..6fc24051f --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/values.toml @@ -0,0 +1,6 @@ +# A values file contains configuration. + +name = "Some Name" + +[section] +name = "Name in a section" diff --git a/pkg/chartutil/testdata/genfrob.sh b/pkg/chartutil/testdata/genfrob.sh new file mode 100755 index 000000000..38fc1b22c --- /dev/null +++ b/pkg/chartutil/testdata/genfrob.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# Pack the albatross chart into the mariner chart. +echo "Packing albatross into mariner" +tar -zcvf mariner/charts/albatross-0.1.0.tgz albatross + +echo "Packing mariner into frobnitz" +tar -zcvf frobnitz/charts/mariner-4.3.2.tgz mariner + +# Pack the frobnitz chart. +echo "Packing frobnitz" +tar -zcvf frobnitz-1.2.3.tgz frobnitz diff --git a/pkg/chartutil/testdata/mariner/Chart.yaml b/pkg/chartutil/testdata/mariner/Chart.yaml new file mode 100644 index 000000000..4d52794c6 --- /dev/null +++ b/pkg/chartutil/testdata/mariner/Chart.yaml @@ -0,0 +1,4 @@ +name: mariner +description: A Helm chart for Kubernetes +version: 4.3.2 +home: "" diff --git a/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz b/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz new file mode 100644 index 000000000..ed3c1aee9 Binary files /dev/null and b/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz differ diff --git a/pkg/chartutil/testdata/mariner/templates/placeholder.tpl b/pkg/chartutil/testdata/mariner/templates/placeholder.tpl new file mode 100644 index 000000000..29c11843a --- /dev/null +++ b/pkg/chartutil/testdata/mariner/templates/placeholder.tpl @@ -0,0 +1 @@ +# This is a placeholder. diff --git a/pkg/chartutil/testdata/mariner/values.toml b/pkg/chartutil/testdata/mariner/values.toml new file mode 100644 index 000000000..4a7bbf8e4 --- /dev/null +++ b/pkg/chartutil/testdata/mariner/values.toml @@ -0,0 +1,4 @@ +# Default values for mariner. +# This is a TOML-formatted file. https://github.com/toml-lang/toml +# Declare name/value pairs to be passed into your templates. +# name = "value"