Merge pull request #793 from technosophos/feat/values-yaml

feat(chartutil): Update to use YAML instead of TOML for values files.
pull/798/head
Matt Butcher 9 years ago
commit c570363e5b

@ -16,7 +16,7 @@ option go_package = "services";
// config. At any given time a release has one // config. At any given time a release has one
// chart and one config. // chart and one config.
// //
// Config: A config is a TOML file that supplies values // Config: A config is a YAML file that supplies values
// to the parametrizable templates of a chart. // to the parametrizable templates of a chart.
// //
// Chart: A chart is a helm package that contains // Chart: A chart is a helm package that contains
@ -150,7 +150,7 @@ message UpdateReleaseResponse {
message InstallReleaseRequest { message InstallReleaseRequest {
// Chart is the protobuf representation of a chart. // Chart is the protobuf representation of a chart.
hapi.chart.Chart chart = 1; hapi.chart.Chart chart = 1;
// Values is a string containing (unparsed) TOML values. // Values is a string containing (unparsed) YAML values.
hapi.chart.Config values = 2; hapi.chart.Config values = 2;
// DryRun, if true, will run through the release logic, but neither create // DryRun, if true, will run through the release logic, but neither create
// a release object nor deploy to Kubernetes. The release object returned // a release object nor deploy to Kubernetes. The release object returned

@ -5,8 +5,8 @@ import (
"path/filepath" "path/filepath"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/proto/hapi/chart"
) )
const createDesc = ` const createDesc = `
@ -19,7 +19,7 @@ something like this:
foo/ foo/
|- Chart.yaml # Information about your chart |- Chart.yaml # Information about your chart
| |
|- values.toml # The default values for your templates |- values.yaml # The default values for your templates
| |
|- charts/ # Charts that this chart depends on |- charts/ # Charts that this chart depends on
| |
@ -36,8 +36,8 @@ func init() {
} }
var createCmd = &cobra.Command{ var createCmd = &cobra.Command{
Use: "create [PATH]", Use: "create NAME",
Short: "Create a new chart at the location specified.", Short: "Create a new chart with the given name.",
Long: createDesc, Long: createDesc,
RunE: runCreate, RunE: runCreate,
} }
@ -50,12 +50,12 @@ func runCreate(cmd *cobra.Command, args []string) error {
cmd.Printf("Creating %s\n", cname) cmd.Printf("Creating %s\n", cname)
chartname := filepath.Base(cname) chartname := filepath.Base(cname)
cfile := chart.Chartfile{ cfile := &chart.Metadata{
Name: chartname, Name: chartname,
Description: "A Helm chart for Kubernetes", Description: "A Helm chart for Kubernetes",
Version: "0.1.0", Version: "0.1.0",
} }
_, err := chart.Create(&cfile, filepath.Dir(cname)) _, err := chartutil.Create(cfile, filepath.Dir(cname))
return err return err
} }

@ -9,8 +9,7 @@ import (
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
@ -56,7 +55,7 @@ func fetch(cmd *cobra.Command, args []string) error {
defer resp.Body.Close() defer resp.Body.Close()
if untarFile { if untarFile {
return chart.Expand(untarDir, resp.Body) return chartutil.Expand(untarDir, resp.Body)
} }
p := strings.Split(u.String(), "/") p := strings.Split(u.String(), "/")
return saveChartFile(p[len(p)-1], resp.Body) return saveChartFile(p[len(p)-1], resp.Body)

@ -42,7 +42,7 @@ var installCmd = &cobra.Command{
func init() { func init() {
f := installCmd.Flags() f := installCmd.Flags()
f.StringVarP(&installValues, "values", "f", "", "path to a values TOML file") f.StringVarP(&installValues, "values", "f", "", "path to a values YAML file")
f.StringVarP(&installRelName, "name", "n", "", "the release name. If unspecified, it will autogenerate one for you.") f.StringVarP(&installRelName, "name", "n", "", "the release name. If unspecified, it will autogenerate one for you.")
f.BoolVar(&installDryRun, "dry-run", false, "simulate an install") f.BoolVar(&installDryRun, "dry-run", false, "simulate an install")

@ -6,8 +6,7 @@ import (
"path/filepath" "path/filepath"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
@ -50,7 +49,7 @@ func runPackage(cmd *cobra.Command, args []string) error {
return err return err
} }
ch, err := chart.LoadDir(path) ch, err := chartutil.LoadDir(path)
if err != nil { if err != nil {
return err return err
} }
@ -60,7 +59,7 @@ func runPackage(cmd *cobra.Command, args []string) error {
if err != nil { if err != nil {
return err return err
} }
name, err := chart.Save(ch, cwd) name, err := chartutil.Save(ch, cwd)
if err == nil && flagDebug { if err == nil && flagDebug {
cmd.Printf("Saved %s to current directory\n", name) cmd.Printf("Saved %s to current directory\n", name)
} }

@ -25,7 +25,7 @@ wordpress/
Chart.yaml # A YAML file containing information about the chart Chart.yaml # A YAML file containing information about the chart
LICENSE # OPTIONAL: A plain text file containing the license for the chart LICENSE # OPTIONAL: A plain text file containing the license for the chart
README.md # OPTIONAL: A human-readable README file README.md # OPTIONAL: A human-readable README file
values.toml # The default configuration values for this chart values.yaml # The default configuration values for this chart
charts/ # A directory containing any charts upon which this chart depends. charts/ # A directory containing any charts upon which this chart depends.
templates/ # A directory of templates that, when combined with values, templates/ # A directory of templates that, when combined with values,
# will generate valid Kubernetes manifest files. # will generate valid Kubernetes manifest files.
@ -133,13 +133,13 @@ Helm renders the charts, it will pass every file in that directory
through the template engine. through the template engine.
Values for the templates are supplied two ways: Values for the templates are supplied two ways:
- Chart developers may supply a file called `values.toml` inside of a - Chart developers may supply a file called `values.yaml` inside of a
chart. This file can contain default values. chart. This file can contain default values.
- Chart users may supply a TOML file that contains values. This can be - Chart users may supply a YAML file that contains values. This can be
provided on the command line with `helm install`. provided on the command line with `helm install`.
When a user supplies custom values, these values will override the When a user supplies custom values, these values will override the
values in the chart's `values.toml` file. values in the chart's `values.yaml` file.
### Template Files ### Template Files
Template files follow the standard conventions for writing Go templates. Template files follow the standard conventions for writing Go templates.
@ -207,36 +207,36 @@ used to pass arbitrarily structured data into the template.
### Values files ### Values files
Considering the template in the previous section, a `values.toml` file Considering the template in the previous section, a `values.yaml` file
that supplies the necessary values would look like this: that supplies the necessary values would look like this:
```toml ```yaml
imageRegistry = "quay.io/deis" imageRegistry = "quay.io/deis"
dockerTag = "latest" dockerTag = "latest"
pullPolicy = "alwaysPull" pullPolicy = "alwaysPull"
storage = "s3" storage = "s3"
``` ```
A values file is formatted in TOML. A chart may include a default A values file is formatted in YAML. A chart may include a default
`values.toml` file. The Helm install command allows a user to override `values.yaml` file. The Helm install command allows a user to override
values by supplying additional TOML values: values by supplying additional YAML values:
```console ```console
$ helm install --values=myvals.toml wordpress $ helm install --values=myvals.yaml wordpress
``` ```
When values are passed in this way, they will be merged into the default When values are passed in this way, they will be merged into the default
values file. For example, consider a `myvals.toml` file that looks like values file. For example, consider a `myvals.yaml` file that looks like
this: this:
```toml ```yaml
storage = "gcs" storage = "gcs"
``` ```
When this is merged with the `values.toml` in the chart, the resulting When this is merged with the `values.yaml` in the chart, the resulting
generated content will be: generated content will be:
```toml ```yaml
imageRegistry = "quay.io/deis" imageRegistry = "quay.io/deis"
dockerTag = "latest" dockerTag = "latest"
pullPolicy = "alwaysPull" pullPolicy = "alwaysPull"
@ -246,7 +246,7 @@ storage = "gcs"
Note that only the last field was overridden. Note that only the last field was overridden.
**NOTE:** The default values file included inside of a chart _must_ be named **NOTE:** The default values file included inside of a chart _must_ be named
`values.toml`. But files specified on the command line can be named `values.yaml`. But files specified on the command line can be named
anything. anything.
### Scope, Dependencies, and Values ### Scope, Dependencies, and Values
@ -259,7 +259,7 @@ demonstration Wordpress chart above has both `mysql` and `apache` as
dependencies. The values file could supply values to all of these dependencies. The values file could supply values to all of these
components: components:
```toml ```yaml
title = "My Wordpress Site" # Sent to the Wordpress template title = "My Wordpress Site" # Sent to the Wordpress template
[mysql] [mysql]
@ -289,7 +289,7 @@ standard references that will help you out.
- [Go templates](https://godoc.org/text/template) - [Go templates](https://godoc.org/text/template)
- [Extra template functions](https://godoc.org/github.com/Masterminds/sprig) - [Extra template functions](https://godoc.org/github.com/Masterminds/sprig)
- [The TOML format](https://github.com/toml-lang/toml) - [The YAML format]()
## Using Helm to Manage Charts ## Using Helm to Manage Charts

@ -3,7 +3,7 @@ This example was generated using the command `helm create alpine`.
The `templates/` directory contains a very simple pod resource with a The `templates/` directory contains a very simple pod resource with a
couple of parameters. couple of parameters.
The `values.toml` file contains the default values for the The `values.yaml` file contains the default values for the
`alpine-pod.yaml` template. `alpine-pod.yaml` template.
You can install this example using `helm install docs/examples/alpine`. You can install this example using `helm install docs/examples/alpine`.

@ -1,2 +0,0 @@
# The pod name
name = "my-alpine"

@ -0,0 +1,2 @@
# The pod name
name: my-alpine

@ -26,3 +26,14 @@ func LoadChartfile(filename string) (*chart.Metadata, error) {
} }
return UnmarshalChartfile(b) return UnmarshalChartfile(b)
} }
// SaveChartfile saves the given metadata as a Chart.yaml file at the given path.
//
// 'filename' should be the complete path and filename ('foo/Chart.yaml')
func SaveChartfile(filename string, cf *chart.Metadata) error {
out, err := yaml.Marshal(cf)
if err != nil {
return err
}
return ioutil.WriteFile(filename, out, 0755)
}

@ -0,0 +1,78 @@
package chartutil
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"k8s.io/helm/pkg/proto/hapi/chart"
)
const (
// ChartfileName is the default Chart file name.
ChartfileName = "Chart.yaml"
// ValuesfileName is the default values file name.
ValuesfileName = "values.yaml"
// TemplatesDir is the relative directory name for templates.
TemplatesDir = "templates"
// ChartsDir is the relative directory name for charts dependencies.
ChartsDir = "charts"
)
const defaultValues = `# Default values for %s.
# This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates.
# name: value
`
// Create creates a new chart in a directory.
//
// Inside of dir, this will create a directory based on the name of
// chartfile.Name. It will then write the Chart.yaml into this directory and
// create the (empty) appropriate directories.
//
// The returned string will point to the newly created directory. It will be
// an absolute path, even if the provided base directory was relative.
//
// If dir does not exist, this will return an error.
// If Chart.yaml or any directories cannot be created, this will return an
// error. In such a case, this will attempt to clean up by removing the
// new chart directory.
func Create(chartfile *chart.Metadata, dir string) (string, error) {
path, err := filepath.Abs(dir)
if err != nil {
return path, err
}
if fi, err := os.Stat(path); err != nil {
return path, err
} else if !fi.IsDir() {
return path, fmt.Errorf("no such directory %s", path)
}
n := chartfile.Name
cdir := filepath.Join(path, n)
if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
return cdir, fmt.Errorf("file %s already exists and is not a directory", cdir)
}
if err := os.MkdirAll(cdir, 0755); err != nil {
return cdir, err
}
if err := SaveChartfile(filepath.Join(cdir, ChartfileName), chartfile); err != nil {
return cdir, err
}
val := []byte(fmt.Sprintf(defaultValues, chartfile.Name))
if err := ioutil.WriteFile(filepath.Join(cdir, ValuesfileName), val, 0644); err != nil {
return cdir, err
}
for _, d := range []string{TemplatesDir, ChartsDir} {
if err := os.MkdirAll(filepath.Join(cdir, d), 0755); err != nil {
return cdir, err
}
}
return cdir, nil
}

@ -0,0 +1,53 @@
package chartutil
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"k8s.io/helm/pkg/proto/hapi/chart"
)
func TestCreate(t *testing.T) {
tdir, err := ioutil.TempDir("", "helm-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tdir)
cf := &chart.Metadata{Name: "foo"}
c, err := Create(cf, tdir)
if err != nil {
t.Fatal(err)
}
dir := filepath.Join(tdir, "foo")
mychart, err := LoadDir(c)
if err != nil {
t.Fatalf("Failed to load newly created chart %q: %s", c, err)
}
if mychart.Metadata.Name != "foo" {
t.Errorf("Expected name to be 'foo', got %q", mychart.Metadata.Name)
}
for _, d := range []string{TemplatesDir, ChartsDir} {
if fi, err := os.Stat(filepath.Join(dir, d)); err != nil {
t.Errorf("Expected %s dir: %s", d, err)
} else if !fi.IsDir() {
t.Errorf("Expected %s to be a directory.", d)
}
}
for _, f := range []string{ChartfileName, ValuesfileName} {
if fi, err := os.Stat(filepath.Join(dir, f)); err != nil {
t.Errorf("Expected %s file: %s", f, err)
} else if fi.IsDir() {
t.Errorf("Expected %s to be a fle.", f)
}
}
}

@ -0,0 +1,47 @@
package chartutil
import (
"archive/tar"
"compress/gzip"
"io"
"os"
"path/filepath"
)
// Expand uncompresses and extracts a chart into the specified directory.
func Expand(dir string, r io.Reader) error {
gr, err := gzip.NewReader(r)
if err != nil {
return err
}
defer gr.Close()
tr := tar.NewReader(gr)
for {
header, err := tr.Next()
if err == io.EOF {
break
} else if err != nil {
return err
}
path := filepath.Clean(filepath.Join(dir, header.Name))
info := header.FileInfo()
if info.IsDir() {
if err = os.MkdirAll(path, info.Mode()); err != nil {
return err
}
continue
}
file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, tr)
if err != nil {
return err
}
}
return nil
}

@ -93,7 +93,9 @@ func loadFiles(files []*afile) (*chart.Chart, error) {
return c, err return c, err
} }
c.Metadata = m c.Metadata = m
} else if f.name == "values.toml" || f.name == "values.yaml" { } else if f.name == "values.toml" {
return c, errors.New("values.toml is illegal as of 2.0.0-alpha.2")
} else if f.name == "values.yaml" {
c.Values = &chart.Config{Raw: string(f.data)} c.Values = &chart.Config{Raw: string(f.data)}
} else if strings.HasPrefix(f.name, "templates/") { } else if strings.HasPrefix(f.name, "templates/") {
c.Templates = append(c.Templates, &chart.Template{Name: f.name, Data: f.data}) c.Templates = append(c.Templates, &chart.Template{Name: f.name, Data: f.data})

@ -1 +0,0 @@
albatross = "true"

@ -0,0 +1 @@
albatross: "true"

@ -0,0 +1,12 @@
poet: "Coleridge"
title: "Rime of the Ancient Mariner"
stanza: ["at", "length", "did", "cross", "an", "Albatross"]
mariner:
with: "crossbow"
shot: "ALBATROSS"
water:
water:
where: "everywhere"
nor: "any drop to drink"

Binary file not shown.

@ -1,4 +1,4 @@
# Default values for mast1. # Default values for mast1.
# This is a TOML-formatted file. https://github.com/toml-lang/toml # This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates. # Declare name/value pairs to be passed into your templates.
# name = "value" # name = "value"

@ -1,2 +0,0 @@
# The pod name
name = "my-alpine"

@ -0,0 +1,2 @@
# The pod name
name: "my-alpine"

@ -1,6 +0,0 @@
# A values file contains configuration.
name = "Some Name"
[section]
name = "Name in a section"

@ -0,0 +1,6 @@
# A values file contains configuration.
name: "Some Name"
section:
name: "Name in a section"

@ -1,4 +1,4 @@
# Default values for mariner. # Default values for mariner.
# This is a TOML-formatted file. https://github.com/toml-lang/toml # This is a YAML-formatted file. https://github.com/toml-lang/toml
# Declare name/value pairs to be passed into your templates. # Declare name/value pairs to be passed into your templates.
# name = "value" # name: "value"

@ -0,0 +1,81 @@
package chartutil
import (
"errors"
"io"
"io/ioutil"
"strings"
"github.com/ghodss/yaml"
)
// ErrNoTable indicates that a chart does not have a matching table.
var ErrNoTable = errors.New("no table")
// Values represents a collection of chart values.
type Values map[string]interface{}
// Table gets a table (YAML subsection) from a Values object.
//
// The table is returned as a Values.
//
// Compound table names may be specified with dots:
//
// foo.bar
//
// The above will be evaluated as "The table bar inside the table
// foo".
//
// An ErrNoTable is returned if the table does not exist.
func (v Values) Table(name string) (Values, error) {
names := strings.Split(name, ".")
table := v
var err error
for _, n := range names {
table, err = tableLookup(table, n)
if err != nil {
return table, err
}
}
return table, err
}
// Encode writes serialized Values information to the given io.Writer.
func (v Values) Encode(w io.Writer) error {
//return yaml.NewEncoder(w).Encode(v)
out, err := yaml.Marshal(v)
if err != nil {
return err
}
_, err = w.Write(out)
return err
}
func tableLookup(v Values, simple string) (Values, error) {
v2, ok := v[simple]
if !ok {
return v, ErrNoTable
}
vv, ok := v2.(map[string]interface{})
if !ok {
return vv, ErrNoTable
}
return vv, nil
}
// ReadValues will parse YAML byte data into a Values.
func ReadValues(data []byte) (Values, error) {
out := map[string]interface{}{}
err := yaml.Unmarshal(data, &out)
return out, err
}
// ReadValuesFile will parse a YAML file into a Values.
func ReadValuesFile(filename string) (Values, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return map[string]interface{}{}, err
}
return ReadValues(data)
}

@ -0,0 +1,141 @@
package chartutil
import (
"bytes"
"fmt"
"testing"
"text/template"
)
func TestReadValues(t *testing.T) {
doc := `# Test YAML parse
poet: "Coleridge"
title: "Rime of the Ancient Mariner"
stanza:
- "at"
- "length"
- "did"
- cross
- an
- Albatross
mariner:
with: "crossbow"
shot: "ALBATROSS"
water:
water:
where: "everywhere"
nor: "any drop to drink"
`
data, err := ReadValues([]byte(doc))
if err != nil {
t.Fatalf("Error parsing bytes: %s", err)
}
matchValues(t, data)
}
func TestReadValuesFile(t *testing.T) {
data, err := ReadValuesFile("./testdata/coleridge.yaml")
if err != nil {
t.Fatalf("Error reading YAML file: %s", err)
}
matchValues(t, data)
}
func ExampleValues() {
doc := `
title: "Moby Dick"
chapter:
one:
title: "Loomings"
two:
title: "The Carpet-Bag"
three:
title: "The Spouter Inn"
`
d, err := ReadValues([]byte(doc))
if err != nil {
panic(err)
}
ch1, err := d.Table("chapter.one")
if err != nil {
panic("could not find chapter one")
}
fmt.Print(ch1["title"])
// Output:
// Loomings
}
func TestTable(t *testing.T) {
doc := `
title: "Moby Dick"
chapter:
one:
title: "Loomings"
two:
title: "The Carpet-Bag"
three:
title: "The Spouter Inn"
`
d, err := ReadValues([]byte(doc))
if err != nil {
t.Fatalf("Failed to parse the White Whale: %s", err)
}
if _, err := d.Table("title"); err == nil {
t.Fatalf("Title is not a table.")
}
if _, err := d.Table("chapter"); err != nil {
t.Fatalf("Failed to get the chapter table: %s\n%v", err, d)
}
if v, err := d.Table("chapter.one"); err != nil {
t.Errorf("Failed to get chapter.one: %s", err)
} else if v["title"] != "Loomings" {
t.Errorf("Unexpected title: %s", v["title"])
}
if _, err := d.Table("chapter.three"); err != nil {
t.Errorf("Chapter three is missing: %s\n%v", err, d)
}
if _, err := d.Table("chapter.OneHundredThirtySix"); err == nil {
t.Errorf("I think you mean 'Epilogue'")
}
}
func matchValues(t *testing.T, data map[string]interface{}) {
if data["poet"] != "Coleridge" {
t.Errorf("Unexpected poet: %s", data["poet"])
}
if o, err := ttpl("{{len .stanza}}", data); err != nil {
t.Errorf("len stanza: %s", err)
} else if o != "6" {
t.Errorf("Expected 6, got %s", o)
}
if o, err := ttpl("{{.mariner.shot}}", data); err != nil {
t.Errorf(".mariner.shot: %s", err)
} else if o != "ALBATROSS" {
t.Errorf("Expected that mariner shot ALBATROSS")
}
if o, err := ttpl("{{.water.water.where}}", data); err != nil {
t.Errorf(".water.water.where: %s", err)
} else if o != "everywhere" {
t.Errorf("Expected water water everywhere")
}
}
func ttpl(tpl string, v map[string]interface{}) (string, error) {
var b bytes.Buffer
tt := template.Must(template.New("t").Parse(tpl))
if err := tt.Execute(&b, v); err != nil {
return "", err
}
return b.String(), nil
}

@ -7,8 +7,7 @@ import (
"text/template" "text/template"
"github.com/Masterminds/sprig" "github.com/Masterminds/sprig"
"k8s.io/helm/pkg/chartutil"
chartutil "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
) )
@ -177,7 +176,7 @@ func coalesceValues(c *chart.Chart, v chartutil.Values) chartutil.Values {
nv, err := chartutil.ReadValues([]byte(c.Values.Raw)) nv, err := chartutil.ReadValues([]byte(c.Values.Raw))
if err != nil { if err != nil {
// On error, we return just the overridden values. // On error, we return just the overridden values.
// FIXME: We should log this error. It indicates that the TOML data // FIXME: We should log this error. It indicates that the YAML data
// did not parse. // did not parse.
log.Printf("error reading default values: %s", err) log.Printf("error reading default values: %s", err)
return v return v
@ -226,7 +225,7 @@ func coalesceTables(dst, src map[string]interface{}) {
} }
} }
// istable is a special-purpose function to see if the present thing matches the definition of a TOML table. // istable is a special-purpose function to see if the present thing matches the definition of a YAML table.
func istable(v interface{}) bool { func istable(v interface{}) bool {
_, ok := v.(map[string]interface{}) _, ok := v.(map[string]interface{})
return ok return ok

@ -5,7 +5,7 @@ import (
"sync" "sync"
"testing" "testing"
chartutil "k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
) )
@ -31,13 +31,12 @@ func TestRender(t *testing.T) {
{Name: "test1", Data: []byte("{{.outer | title }} {{.inner | title}}")}, {Name: "test1", Data: []byte("{{.outer | title }} {{.inner | title}}")},
}, },
Values: &chart.Config{ Values: &chart.Config{
Raw: `outer = "DEFAULT"\ninner= "DEFAULT"\n`, Raw: "outer: DEFAULT\ninner: DEFAULT",
}, },
} }
vals := &chart.Config{ vals := &chart.Config{
Raw: `outer = "BAD" Raw: "outer: BAD\ninner: inn",
inner= "inn"`,
} }
overrides := map[string]interface{}{ overrides := map[string]interface{}{
@ -207,18 +206,20 @@ func TestRenderNestedValues(t *testing.T) {
{Name: outerpath, Data: []byte(`Gather ye {{.what}} while ye may`)}, {Name: outerpath, Data: []byte(`Gather ye {{.what}} while ye may`)},
}, },
Values: &chart.Config{ Values: &chart.Config{
Raw: `what = "stinkweed" Raw: `
[herrick] what: stinkweed
who = "time" herrick:
`}, who: time`,
},
Dependencies: []*chart.Chart{inner}, Dependencies: []*chart.Chart{inner},
} }
inject := chart.Config{ inject := chart.Config{
Raw: ` Raw: `
what = "rosebuds" what: rosebuds
[herrick.deepest] herrick:
what = "flower"`, deepest:
what: flower`,
} }
out, err := e.Render(outer, &inject, map[string]interface{}{}) out, err := e.Render(outer, &inject, map[string]interface{}{})

@ -9,7 +9,7 @@ const (
ErrMissingTpls = Error("missing chart templates") ErrMissingTpls = Error("missing chart templates")
// ErrMissingChart indicates that the Chart.yaml data is missing. // ErrMissingChart indicates that the Chart.yaml data is missing.
ErrMissingChart = Error("missing chart metadata") ErrMissingChart = Error("missing chart metadata")
// ErrMissingValues indicates that the config values.toml data is missing. // ErrMissingValues indicates that the config values.yaml data is missing.
ErrMissingValues = Error("missing chart values") ErrMissingValues = Error("missing chart values")
) )

@ -4,7 +4,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
chartutil "k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/chartutil"
) )
// Chartfile checks the Chart.yaml file for errors and warnings. // Chartfile checks the Chart.yaml file for errors and warnings.

@ -53,8 +53,8 @@ func TestBadValues(t *testing.T) {
if len(m) != 1 { if len(m) != 1 {
t.Errorf("All didn't fail with expected errors, got %#v", m) t.Errorf("All didn't fail with expected errors, got %#v", m)
} }
if !strings.Contains(m[0].Text, "Bare keys cannot contain ':'") { if !strings.Contains(m[0].Text, "cannot unmarshal") {
t.Errorf("All didn't have the error for invalid key format") t.Errorf("All didn't have the error for invalid key format: %s", m[0].Text)
} }
} }

@ -8,7 +8,7 @@ type Severity int
const ( const (
// UnknownSev indicates that the severity of the error is unknown, and should not stop processing. // UnknownSev indicates that the severity of the error is unknown, and should not stop processing.
UnknownSev = iota UnknownSev = iota
// InfoSev indicates information, for example missing values.toml file // InfoSev indicates information, for example missing values.yaml file
InfoSev InfoSev
// WarningSev indicates that something does not meet code standards, but will likely function. // WarningSev indicates that something does not meet code standards, but will likely function.
WarningSev WarningSev

@ -1 +0,0 @@
name = "mariner"

@ -0,0 +1 @@
name: "mariner"

@ -1,4 +0,0 @@
# Default values for badchartfile.
# This is a TOML-formatted file. https://github.com/toml-lang/toml
# Declare name/value pairs to be passed into your templates.
# name = "value"

@ -0,0 +1 @@
# Default values for badchartfile.

@ -1,2 +1,2 @@
# Invalid value for badvaluesfile for testing lint fails with invalid toml format # Invalid value for badvaluesfile for testing lint fails with invalid yaml format
name: "value" name= "value"

@ -1 +0,0 @@
name = "goodone here"

@ -0,0 +1 @@
name: "goodone here"

@ -4,18 +4,18 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/chartutil"
) )
// Values lints a chart's values.toml file. // Values lints a chart's values.yaml file.
func Values(basepath string) (messages []Message) { func Values(basepath string) (messages []Message) {
vf := filepath.Join(basepath, "values.toml") vf := filepath.Join(basepath, "values.yaml")
messages = []Message{} messages = []Message{}
if _, err := os.Stat(vf); err != nil { if _, err := os.Stat(vf); err != nil {
messages = append(messages, Message{Severity: InfoSev, Text: "No values.toml file"}) messages = append(messages, Message{Severity: InfoSev, Text: "No values.yaml file"})
return return
} }
_, err := chart.ReadValuesFile(vf) _, err := chartutil.ReadValuesFile(vf)
if err != nil { if err != nil {
messages = append(messages, Message{Severity: ErrorSev, Text: err.Error()}) messages = append(messages, Message{Severity: ErrorSev, Text: err.Error()})
} }

@ -238,7 +238,7 @@ func (*UpdateReleaseResponse) Descriptor() ([]byte, []int) { return fileDescript
type InstallReleaseRequest struct { type InstallReleaseRequest struct {
// Chart is the protobuf representation of a chart. // Chart is the protobuf representation of a chart.
Chart *hapi_chart3.Chart `protobuf:"bytes,1,opt,name=chart" json:"chart,omitempty"` Chart *hapi_chart3.Chart `protobuf:"bytes,1,opt,name=chart" json:"chart,omitempty"`
// Values is a string containing (unparsed) TOML values. // Values is a string containing (unparsed) YAML values.
Values *hapi_chart.Config `protobuf:"bytes,2,opt,name=values" json:"values,omitempty"` Values *hapi_chart.Config `protobuf:"bytes,2,opt,name=values" json:"values,omitempty"`
// DryRun, if true, will run through the release logic, but neither create // DryRun, if true, will run through the release logic, but neither create
// a release object nor deploy to Kubernetes. The release object returned // a release object nor deploy to Kubernetes. The release object returned

@ -7,7 +7,7 @@ import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/proto/hapi/chart"
) )
var indexPath = "index.yaml" var indexPath = "index.yaml"
@ -24,7 +24,7 @@ type ChartRef struct {
Created string `yaml:"created,omitempty"` Created string `yaml:"created,omitempty"`
Removed bool `yaml:"removed,omitempty"` Removed bool `yaml:"removed,omitempty"`
Checksum string `yaml:"checksum,omitempty"` Checksum string `yaml:"checksum,omitempty"`
Chartfile chart.Chartfile `yaml:"chartfile"` Chartfile *chart.Metadata `yaml:"chartfile"`
} }
// DownloadIndexFile uses // DownloadIndexFile uses

@ -29,7 +29,12 @@ func TestDownloadIndexFile(t *testing.T) {
fmt.Fprintln(w, string(fileBytes)) fmt.Fprintln(w, string(fileBytes))
})) }))
dirName, err := ioutil.TempDir("testdata", "tmp") dirName, err := ioutil.TempDir("", "tmp")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dirName)
path := filepath.Join(dirName, testRepo+"-index.yaml") path := filepath.Join(dirName, testRepo+"-index.yaml")
if err := DownloadIndexFile(testRepo, ts.URL, path); err != nil { if err := DownloadIndexFile(testRepo, ts.URL, path); err != nil {
t.Errorf("%#v", err) t.Errorf("%#v", err)
@ -54,8 +59,6 @@ func TestDownloadIndexFile(t *testing.T) {
t.Errorf("Expected 2 entries in index file but got %v", numEntries) t.Errorf("Expected 2 entries in index file but got %v", numEntries)
} }
os.Remove(path) os.Remove(path)
os.Remove(dirName)
} }
func TestLoadIndexFile(t *testing.T) { func TestLoadIndexFile(t *testing.T) {

@ -7,7 +7,8 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/proto/hapi/chart"
) )
var localRepoPath string var localRepoPath string
@ -42,7 +43,7 @@ func serveFile(w http.ResponseWriter, r *http.Request, file string) {
// AddChartToLocalRepo saves a chart in the given path and then reindexes the index file // AddChartToLocalRepo saves a chart in the given path and then reindexes the index file
func AddChartToLocalRepo(ch *chart.Chart, path string) error { func AddChartToLocalRepo(ch *chart.Chart, path string) error {
_, err := chart.Save(ch, path) _, err := chartutil.Save(ch, path)
if err != nil { if err != nil {
return err return err
} }
@ -51,7 +52,7 @@ func AddChartToLocalRepo(ch *chart.Chart, path string) error {
// Reindex adds an entry to the index file at the given path // Reindex adds an entry to the index file at the given path
func Reindex(ch *chart.Chart, path string) error { func Reindex(ch *chart.Chart, path string) error {
name := ch.Chartfile().Name + "-" + ch.Chartfile().Version name := ch.Metadata.Name + "-" + ch.Metadata.Version
y, err := LoadIndexFile(path) y, err := LoadIndexFile(path)
if err != nil { if err != nil {
return err return err

@ -13,7 +13,7 @@ import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/chartutil"
) )
// ChartRepository represents a chart repository // ChartRepository represents a chart repository
@ -108,12 +108,12 @@ func (r *ChartRepository) Index() error {
} }
for _, path := range r.ChartPaths { for _, path := range r.ChartPaths {
ch, err := chart.Load(path) ch, err := chartutil.Load(path)
if err != nil { if err != nil {
return err return err
} }
chartfile := ch.Chartfile() chartfile := ch.Metadata
hash, err := generateChecksum(path) hash, err := generateChecksum(path)
if err != nil { if err != nil {
return err return err
@ -135,7 +135,7 @@ func (r *ChartRepository) Index() error {
url, _ := url.Parse(r.URL) url, _ := url.Parse(r.URL)
url.Path = filepath.Join(url.Path, key+".tgz") url.Path = filepath.Join(url.Path, key+".tgz")
entry := &ChartRef{Chartfile: *chartfile, Name: chartfile.Name, URL: url.String(), Created: created, Checksum: hash, Removed: false} entry := &ChartRef{Chartfile: chartfile, Name: chartfile.Name, URL: url.String(), Created: created, Checksum: hash, Removed: false}
r.IndexFile.Entries[key] = entry r.IndexFile.Entries[key] = entry

Binary file not shown.

Binary file not shown.
Loading…
Cancel
Save