diff --git a/cmd/helm/create.go b/cmd/helm/create.go
index 6e63fd305..5569a8e1c 100644
--- a/cmd/helm/create.go
+++ b/cmd/helm/create.go
@@ -24,8 +24,8 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
)
const createDesc = `
@@ -80,7 +80,7 @@ func (o *createOptions) run(out io.Writer) error {
Description: "A Helm chart for Kubernetes",
Version: "0.1.0",
AppVersion: "1.0",
- APIVersion: chartutil.APIVersionv1,
+ APIVersion: chart.APIVersionv1,
}
if o.starter != "" {
diff --git a/cmd/helm/create_test.go b/cmd/helm/create_test.go
index 5ec69f678..47fc88520 100644
--- a/cmd/helm/create_test.go
+++ b/cmd/helm/create_test.go
@@ -23,8 +23,9 @@ import (
"path/filepath"
"testing"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
)
func TestCreateCmd(t *testing.T) {
@@ -46,15 +47,15 @@ func TestCreateCmd(t *testing.T) {
t.Fatalf("chart is not directory")
}
- c, err := chartutil.LoadDir(cname)
+ c, err := loader.LoadDir(cname)
if err != nil {
t.Fatal(err)
}
- if c.Metadata.Name != cname {
- t.Errorf("Expected %q name, got %q", cname, c.Metadata.Name)
+ if c.Name() != cname {
+ t.Errorf("Expected %q name, got %q", cname, c.Name())
}
- if c.Metadata.APIVersion != chartutil.APIVersionv1 {
+ if c.Metadata.APIVersion != chart.APIVersionv1 {
t.Errorf("Wrong API version: %q", c.Metadata.APIVersion)
}
}
@@ -97,15 +98,15 @@ func TestCreateStarterCmd(t *testing.T) {
t.Fatalf("chart is not directory")
}
- c, err := chartutil.LoadDir(cname)
+ c, err := loader.LoadDir(cname)
if err != nil {
t.Fatal(err)
}
- if c.Metadata.Name != cname {
- t.Errorf("Expected %q name, got %q", cname, c.Metadata.Name)
+ if c.Name() != cname {
+ t.Errorf("Expected %q name, got %q", cname, c.Name())
}
- if c.Metadata.APIVersion != chartutil.APIVersionv1 {
+ if c.Metadata.APIVersion != chart.APIVersionv1 {
t.Errorf("Wrong API version: %q", c.Metadata.APIVersion)
}
diff --git a/cmd/helm/dependency.go b/cmd/helm/dependency.go
index e31c26000..d8eb41e77 100644
--- a/cmd/helm/dependency.go
+++ b/cmd/helm/dependency.go
@@ -26,7 +26,8 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
- "k8s.io/helm/pkg/chartutil"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
)
const dependencyDesc = `
@@ -130,27 +131,23 @@ func newDependencyListCmd(out io.Writer) *cobra.Command {
}
func (o *dependencyLisOptions) run(out io.Writer) error {
- c, err := chartutil.Load(o.chartpath)
+ c, err := loader.Load(o.chartpath)
if err != nil {
return err
}
- r, err := chartutil.LoadRequirements(c)
- if err != nil {
- if err == chartutil.ErrRequirementsNotFound {
- fmt.Fprintf(out, "WARNING: no requirements at %s/charts\n", o.chartpath)
- return nil
- }
- return err
+ if c.Requirements == nil {
+ fmt.Fprintf(out, "WARNING: no requirements at %s/charts\n", o.chartpath)
+ return nil
}
- o.printRequirements(out, r)
+ o.printRequirements(out, c.Requirements)
fmt.Fprintln(out)
- o.printMissing(out, r)
+ o.printMissing(out, c.Requirements)
return nil
}
-func (o *dependencyLisOptions) dependencyStatus(dep *chartutil.Dependency) string {
+func (o *dependencyLisOptions) dependencyStatus(dep *chart.Dependency) string {
filename := fmt.Sprintf("%s-%s.tgz", dep.Name, "*")
archives, err := filepath.Glob(filepath.Join(o.chartpath, "charts", filename))
if err != nil {
@@ -160,11 +157,11 @@ func (o *dependencyLisOptions) dependencyStatus(dep *chartutil.Dependency) strin
} else if len(archives) == 1 {
archive := archives[0]
if _, err := os.Stat(archive); err == nil {
- c, err := chartutil.Load(archive)
+ c, err := loader.Load(archive)
if err != nil {
return "corrupt"
}
- if c.Metadata.Name != dep.Name {
+ if c.Name() != dep.Name {
return "misnamed"
}
@@ -195,12 +192,12 @@ func (o *dependencyLisOptions) dependencyStatus(dep *chartutil.Dependency) strin
return "mispackaged"
}
- c, err := chartutil.Load(folder)
+ c, err := loader.Load(folder)
if err != nil {
return "corrupt"
}
- if c.Metadata.Name != dep.Name {
+ if c.Name() != dep.Name {
return "misnamed"
}
@@ -225,7 +222,7 @@ func (o *dependencyLisOptions) dependencyStatus(dep *chartutil.Dependency) strin
}
// printRequirements prints all of the requirements in the yaml file.
-func (o *dependencyLisOptions) printRequirements(out io.Writer, reqs *chartutil.Requirements) {
+func (o *dependencyLisOptions) printRequirements(out io.Writer, reqs *chart.Requirements) {
table := uitable.New()
table.MaxColWidth = 80
table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS")
@@ -236,7 +233,7 @@ func (o *dependencyLisOptions) printRequirements(out io.Writer, reqs *chartutil.
}
// printMissing prints warnings about charts that are present on disk, but are not in the requirements.
-func (o *dependencyLisOptions) printMissing(out io.Writer, reqs *chartutil.Requirements) {
+func (o *dependencyLisOptions) printMissing(out io.Writer, reqs *chart.Requirements) {
folder := filepath.Join(o.chartpath, "charts/*")
files, err := filepath.Glob(folder)
if err != nil {
@@ -253,14 +250,14 @@ func (o *dependencyLisOptions) printMissing(out io.Writer, reqs *chartutil.Requi
if !fi.IsDir() && filepath.Ext(f) != ".tgz" {
continue
}
- c, err := chartutil.Load(f)
+ c, err := loader.Load(f)
if err != nil {
fmt.Fprintf(out, "WARNING: %q is not a chart.\n", f)
continue
}
found := false
for _, d := range reqs.Dependencies {
- if d.Name == c.Metadata.Name {
+ if d.Name == c.Name() {
found = true
break
}
diff --git a/cmd/helm/dependency_update_test.go b/cmd/helm/dependency_update_test.go
index 212106af4..7401b7579 100644
--- a/cmd/helm/dependency_update_test.go
+++ b/cmd/helm/dependency_update_test.go
@@ -26,9 +26,8 @@ import (
"github.com/ghodss/yaml"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
- "k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/provenance"
"k8s.io/helm/pkg/repo"
"k8s.io/helm/pkg/repo/repotest"
@@ -88,8 +87,8 @@ func TestDependencyUpdateCmd(t *testing.T) {
// Now change the dependencies and update. This verifies that on update,
// old dependencies are cleansed and new dependencies are added.
- reqfile := &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ reqfile := &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "reqtest", Version: "0.1.0", Repository: srv.URL()},
{Name: "compressedchart", Version: "0.3.0", Repository: srv.URL()},
},
@@ -170,7 +169,7 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
out := bytes.NewBuffer(nil)
o := &dependencyUpdateOptions{}
- o.helmhome = helmpath.Home(hh)
+ o.helmhome = hh
o.chartpath = hh.Path(chartname)
if err := o.run(out); err != nil {
@@ -223,8 +222,8 @@ func createTestingChart(dest, name, baseURL string) error {
if err != nil {
return err
}
- req := &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ req := &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "reqtest", Version: "0.1.0", Repository: baseURL},
{Name: "compressedchart", Version: "0.1.0", Repository: baseURL},
},
@@ -232,7 +231,7 @@ func createTestingChart(dest, name, baseURL string) error {
return writeRequirements(dir, req)
}
-func writeRequirements(dir string, req *chartutil.Requirements) error {
+func writeRequirements(dir string, req *chart.Requirements) error {
data, err := yaml.Marshal(req)
if err != nil {
return err
diff --git a/cmd/helm/history.go b/cmd/helm/history.go
index 1139d9648..65eb75590 100644
--- a/cmd/helm/history.go
+++ b/cmd/helm/history.go
@@ -27,7 +27,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/hapi/release"
"k8s.io/helm/pkg/helm"
)
@@ -167,5 +167,5 @@ func formatChartname(c *chart.Chart) string {
// know how: https://github.com/kubernetes/helm/issues/1347
return "MISSING"
}
- return fmt.Sprintf("%s-%s", c.Metadata.Name, c.Metadata.Version)
+ return fmt.Sprintf("%s-%s", c.Name(), c.Metadata.Version)
}
diff --git a/cmd/helm/inspect.go b/cmd/helm/inspect.go
index 4f8327898..986273158 100644
--- a/cmd/helm/inspect.go
+++ b/cmd/helm/inspect.go
@@ -25,8 +25,8 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
- "k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
)
const inspectDesc = `
@@ -146,7 +146,7 @@ func newInspectCmd(out io.Writer) *cobra.Command {
}
func (i *inspectOptions) run(out io.Writer) error {
- chrt, err := chartutil.Load(i.chartpath)
+ chrt, err := loader.Load(i.chartpath)
if err != nil {
return err
}
diff --git a/cmd/helm/install.go b/cmd/helm/install.go
index e7910d57e..c953a2e46 100644
--- a/cmd/helm/install.go
+++ b/cmd/helm/install.go
@@ -28,10 +28,10 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
- "k8s.io/helm/pkg/chartutil"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/downloader"
"k8s.io/helm/pkg/getter"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/hapi/release"
"k8s.io/helm/pkg/helm"
)
@@ -176,12 +176,12 @@ func (o *installOptions) run(out io.Writer) error {
}
// Check chart requirements to make sure all dependencies are present in /charts
- chartRequested, err := chartutil.Load(o.chartPath)
+ chartRequested, err := loader.Load(o.chartPath)
if err != nil {
return err
}
- if req, err := chartutil.LoadRequirements(chartRequested); err == nil {
+ if req := chartRequested.Requirements; req != nil {
// If checkDependencies returns an error, we have unfulfilled dependencies.
// As of Helm 2.4.0, this is treated as a stopping condition:
// https://github.com/kubernetes/helm/issues/2209
@@ -203,8 +203,6 @@ func (o *installOptions) run(out io.Writer) error {
}
}
- } else if err != chartutil.ErrRequirementsNotFound {
- return errors.Wrap(err, "cannot load requirements")
}
rel, err := o.client.InstallReleaseFromChart(
@@ -272,7 +270,6 @@ func (o *installOptions) printRelease(out io.Writer, rel *release.Release) {
if rel == nil {
return
}
- // TODO: Switch to text/template like everything else.
fmt.Fprintf(out, "NAME: %s\n", rel.Name)
if settings.Debug {
printRelease(out, rel)
@@ -286,27 +283,20 @@ func generateName(nameTemplate string) (string, error) {
}
var b bytes.Buffer
err = t.Execute(&b, nil)
- if err != nil {
- return "", err
- }
- return b.String(), nil
+ return b.String(), err
}
-func checkDependencies(ch *chart.Chart, reqs *chartutil.Requirements) error {
- missing := []string{}
+func checkDependencies(ch *chart.Chart, reqs *chart.Requirements) error {
+ var missing []string
- deps := ch.Dependencies
+OUTER:
for _, r := range reqs.Dependencies {
- found := false
- for _, d := range deps {
- if d.Metadata.Name == r.Name {
- found = true
- break
+ for _, d := range ch.Dependencies() {
+ if d.Name() == r.Name {
+ continue OUTER
}
}
- if !found {
- missing = append(missing, r.Name)
- }
+ missing = append(missing, r.Name)
}
if len(missing) > 0 {
diff --git a/cmd/helm/package.go b/cmd/helm/package.go
index a41ee4f12..1e99b1eae 100644
--- a/cmd/helm/package.go
+++ b/cmd/helm/package.go
@@ -30,10 +30,11 @@ import (
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/downloader"
"k8s.io/helm/pkg/getter"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/provenance"
)
@@ -129,7 +130,7 @@ func (o *packageOptions) run(out io.Writer) error {
}
}
- ch, err := chartutil.LoadDir(path)
+ ch, err := loader.LoadDir(path)
if err != nil {
return err
}
@@ -161,18 +162,14 @@ func (o *packageOptions) run(out io.Writer) error {
debug("Setting appVersion to %s", o.appVersion)
}
- if filepath.Base(path) != ch.Metadata.Name {
- return errors.Errorf("directory name (%s) and Chart.yaml name (%s) must match", filepath.Base(path), ch.Metadata.Name)
+ if filepath.Base(path) != ch.Name() {
+ return errors.Errorf("directory name (%s) and Chart.yaml name (%s) must match", filepath.Base(path), ch.Name())
}
- if reqs, err := chartutil.LoadRequirements(ch); err == nil {
+ if reqs := ch.Requirements; reqs != nil {
if err := checkDependencies(ch, reqs); err != nil {
return err
}
- } else {
- if err != chartutil.ErrRequirementsNotFound {
- return err
- }
}
var dest string
diff --git a/cmd/helm/package_test.go b/cmd/helm/package_test.go
index d7f0e0f9d..b2a11eb98 100644
--- a/cmd/helm/package_test.go
+++ b/cmd/helm/package_test.go
@@ -26,8 +26,9 @@ import (
"github.com/spf13/cobra"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/helm/helmpath"
)
@@ -206,7 +207,7 @@ func TestSetAppVersion(t *testing.T) {
tmp := testTempDir(t)
hh := testHelmHome(t)
- settings.Home = helmpath.Home(hh)
+ settings.Home = hh
c := newPackageCmd(&bytes.Buffer{})
flags := map[string]string{
@@ -224,7 +225,7 @@ func TestSetAppVersion(t *testing.T) {
} else if fi.Size() == 0 {
t.Errorf("file %q has zero bytes.", chartPath)
}
- ch, err := chartutil.Load(chartPath)
+ ch, err := loader.Load(chartPath)
if err != nil {
t.Errorf("unexpected error loading packaged chart: %v", err)
}
@@ -332,7 +333,7 @@ func createValuesFile(t *testing.T, data string) string {
func getChartValues(chartPath string) (chartutil.Values, error) {
- chart, err := chartutil.Load(chartPath)
+ chart, err := loader.Load(chartPath)
if err != nil {
return nil, err
}
diff --git a/cmd/helm/repo_update_test.go b/cmd/helm/repo_update_test.go
index b84cd7a2d..b040bdc6e 100644
--- a/cmd/helm/repo_update_test.go
+++ b/cmd/helm/repo_update_test.go
@@ -45,7 +45,7 @@ func TestUpdateCmd(t *testing.T) {
}
o := &repoUpdateOptions{
update: updater,
- home: helmpath.Home(hh),
+ home: hh,
}
if err := o.run(out); err != nil {
t.Fatal(err)
diff --git a/cmd/helm/search/search_test.go b/cmd/helm/search/search_test.go
index 19568d9ca..92bf6c97d 100644
--- a/cmd/helm/search/search_test.go
+++ b/cmd/helm/search/search_test.go
@@ -20,7 +20,7 @@ import (
"strings"
"testing"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/repo"
)
diff --git a/cmd/helm/template.go b/cmd/helm/template.go
index a69cd6c6f..08682f2ff 100644
--- a/cmd/helm/template.go
+++ b/cmd/helm/template.go
@@ -31,12 +31,12 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/engine"
"k8s.io/helm/pkg/hapi/release"
util "k8s.io/helm/pkg/releaseutil"
"k8s.io/helm/pkg/tiller"
- tversion "k8s.io/helm/pkg/version"
)
const defaultDirectoryPermission = 0755
@@ -152,17 +152,15 @@ func (o *templateOptions) run(out io.Writer) error {
}
// Check chart requirements to make sure all dependencies are present in /charts
- c, err := chartutil.Load(o.chartPath)
+ c, err := loader.Load(o.chartPath)
if err != nil {
return err
}
- if req, err := chartutil.LoadRequirements(c); err == nil {
+ if req := c.Requirements; req != nil {
if err := checkDependencies(c, req); err != nil {
return err
}
- } else if err != chartutil.ErrRequirementsNotFound {
- return errors.Wrap(err, "cannot load requirements")
}
options := chartutil.ReleaseOptions{
Name: o.releaseName,
@@ -178,22 +176,18 @@ func (o *templateOptions) run(out io.Writer) error {
// Set up engine.
renderer := engine.New()
- caps := &chartutil.Capabilities{
- APIVersions: chartutil.DefaultVersionSet,
- KubeVersion: chartutil.DefaultKubeVersion,
- HelmVersion: tversion.GetBuildInfo(),
- }
-
// kubernetes version
kv, err := semver.NewVersion(o.kubeVersion)
if err != nil {
return errors.Wrap(err, "could not parse a kubernetes version")
}
+
+ caps := chartutil.DefaultCapabilities
caps.KubeVersion.Major = fmt.Sprint(kv.Major())
caps.KubeVersion.Minor = fmt.Sprint(kv.Minor())
caps.KubeVersion.GitVersion = fmt.Sprintf("v%d.%d.0", kv.Major(), kv.Minor())
- vals, err := chartutil.ToRenderValuesCaps(c, config, options, caps)
+ vals, err := chartutil.ToRenderValues(c, config, options, caps)
if err != nil {
return err
}
diff --git a/cmd/helm/testdata/output/upgrade-with-bad-dependencies.txt b/cmd/helm/testdata/output/upgrade-with-bad-dependencies.txt
index c77fba18b..a50915b9b 100644
--- a/cmd/helm/testdata/output/upgrade-with-bad-dependencies.txt
+++ b/cmd/helm/testdata/output/upgrade-with-bad-dependencies.txt
@@ -1 +1 @@
-Error: cannot load requirements: error converting YAML to JSON: yaml: line 2: did not find expected '-' indicator
+Error: cannot load requirements.yaml: error converting YAML to JSON: yaml: line 2: did not find expected '-' indicator
diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go
index 83e2bb24d..c7db6fb7e 100644
--- a/cmd/helm/upgrade.go
+++ b/cmd/helm/upgrade.go
@@ -25,7 +25,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
- "k8s.io/helm/pkg/chartutil"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/storage/driver"
)
@@ -150,17 +150,15 @@ func (o *upgradeOptions) run(out io.Writer) error {
}
// Check chart requirements to make sure all dependencies are present in /charts
- if ch, err := chartutil.Load(chartPath); err == nil {
- if req, err := chartutil.LoadRequirements(ch); err == nil {
- if err := checkDependencies(ch, req); err != nil {
- return err
- }
- } else if err != chartutil.ErrRequirementsNotFound {
- return errors.Wrap(err, "cannot load requirements")
- }
- } else {
+ ch, err := loader.Load(chartPath)
+ if err != nil {
return err
}
+ if req := ch.Requirements; req != nil {
+ if err := checkDependencies(ch, req); err != nil {
+ return err
+ }
+ }
resp, err := o.client.UpdateRelease(
o.release,
diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go
index c75b50b1a..904085725 100644
--- a/cmd/helm/upgrade_test.go
+++ b/cmd/helm/upgrade_test.go
@@ -19,8 +19,9 @@ package main
import (
"testing"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/hapi/release"
"k8s.io/helm/pkg/helm"
)
@@ -36,7 +37,7 @@ func TestUpgradeCmd(t *testing.T) {
if err != nil {
t.Fatalf("Error creating chart for upgrade: %v", err)
}
- ch, err := chartutil.Load(chartPath)
+ ch, err := loader.Load(chartPath)
if err != nil {
t.Fatalf("Error loading chart: %v", err)
}
@@ -56,7 +57,7 @@ func TestUpgradeCmd(t *testing.T) {
if err != nil {
t.Fatalf("Error creating chart: %v", err)
}
- ch, err = chartutil.Load(chartPath)
+ ch, err = loader.Load(chartPath)
if err != nil {
t.Fatalf("Error loading updated chart: %v", err)
}
@@ -73,7 +74,7 @@ func TestUpgradeCmd(t *testing.T) {
t.Fatalf("Error creating chart: %v", err)
}
var ch2 *chart.Chart
- ch2, err = chartutil.Load(chartPath)
+ ch2, err = loader.Load(chartPath)
if err != nil {
t.Fatalf("Error loading updated chart: %v", err)
}
diff --git a/docs/examples/nginx/charts/alpine/Chart.yaml b/docs/examples/nginx/charts/alpine/Chart.yaml
new file mode 100644
index 000000000..f4b660d4f
--- /dev/null
+++ b/docs/examples/nginx/charts/alpine/Chart.yaml
@@ -0,0 +1,7 @@
+name: alpine
+description: Deploy a basic Alpine Linux pod
+version: 0.1.0
+home: https://github.com/kubernetes/helm
+sources:
+ - https://github.com/kubernetes/helm
+appVersion: 3.3
diff --git a/docs/examples/nginx/charts/alpine/README.md b/docs/examples/nginx/charts/alpine/README.md
new file mode 100644
index 000000000..3e354724c
--- /dev/null
+++ b/docs/examples/nginx/charts/alpine/README.md
@@ -0,0 +1,11 @@
+# Alpine: A simple Helm chart
+
+Run a single pod of Alpine Linux.
+
+The `templates/` directory contains a very simple pod resource with a
+couple of parameters.
+
+The `values.yaml` 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/docs/examples/nginx/charts/alpine/templates/_helpers.tpl b/docs/examples/nginx/charts/alpine/templates/_helpers.tpl
new file mode 100644
index 000000000..3e9c25bed
--- /dev/null
+++ b/docs/examples/nginx/charts/alpine/templates/_helpers.tpl
@@ -0,0 +1,16 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "alpine.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+*/}}
+{{- define "alpine.fullname" -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
diff --git a/docs/examples/nginx/charts/alpine/templates/alpine-pod.yaml b/docs/examples/nginx/charts/alpine/templates/alpine-pod.yaml
new file mode 100644
index 000000000..da9caef78
--- /dev/null
+++ b/docs/examples/nginx/charts/alpine/templates/alpine-pod.yaml
@@ -0,0 +1,23 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: {{ template "alpine.fullname" . }}
+ labels:
+ # The "heritage" label is used to track which tool deployed a given chart.
+ # It is useful for admins who want to see what releases a particular tool
+ # is responsible for.
+ heritage: {{ .Release.Service }}
+ # The "release" convention makes it easy to tie a release to all of the
+ # Kubernetes resources that were created as part of that release.
+ release: {{ .Release.Name }}
+ # This makes it easy to audit chart usage.
+ chart: {{ .Chart.Name }}-{{ .Chart.Version }}
+ app: {{ template "alpine.name" . }}
+spec:
+ # This shows how to use a simple value. This will look for a passed-in value called restartPolicy.
+ restartPolicy: {{ .Values.restartPolicy }}
+ containers:
+ - name: waiter
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+ imagePullPolicy: {{ .Values.image.pullPolicy }}
+ command: ["/bin/sleep", "9000"]
diff --git a/docs/examples/nginx/charts/alpine/values.yaml b/docs/examples/nginx/charts/alpine/values.yaml
new file mode 100644
index 000000000..afe8cc6c0
--- /dev/null
+++ b/docs/examples/nginx/charts/alpine/values.yaml
@@ -0,0 +1,6 @@
+image:
+ repository: alpine
+ tag: 3.3
+ pullPolicy: IfNotPresent
+
+restartPolicy: Never
diff --git a/docs/examples/nginx/templates/NOTES.txt b/docs/examples/nginx/templates/NOTES.txt
new file mode 100644
index 000000000..4bdf443f6
--- /dev/null
+++ b/docs/examples/nginx/templates/NOTES.txt
@@ -0,0 +1 @@
+Sample notes for {{ .Chart.Name }}
\ No newline at end of file
diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go
new file mode 100644
index 000000000..b51bb5b90
--- /dev/null
+++ b/pkg/chart/chart.go
@@ -0,0 +1,95 @@
+/*
+Copyright 2018 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 chart
+
+// Chart is a helm package that contains metadata, a default config, zero or more
+// optionally parameterizable templates, and zero or more charts (dependencies).
+type Chart struct {
+ // Metadata is the contents of the Chartfile.
+ Metadata *Metadata
+ // Requirements is the contents of requirements.yaml.
+ Requirements *Requirements
+ // RequirementsLock is the contents of requirements.lock.
+ RequirementsLock *RequirementsLock
+ // Templates for this chart.
+ Templates []*File
+ // Values are default config for this template.
+ Values []byte
+ // Files are miscellaneous files in a chart archive,
+ // e.g. README, LICENSE, etc.
+ Files []*File
+
+ parent *Chart
+ dependencies []*Chart
+}
+
+// SetDependencies replaces the chart dependencies.
+func (ch *Chart) SetDependencies(charts ...*Chart) {
+ ch.dependencies = nil
+ ch.AddDependency(charts...)
+}
+
+// Name returns the name of the chart.
+func (ch *Chart) Name() string {
+ if ch.Metadata == nil {
+ return ""
+ }
+ return ch.Metadata.Name
+}
+
+// AddDependency determines if the chart is a subchart.
+func (ch *Chart) AddDependency(charts ...*Chart) {
+ for i, x := range charts {
+ charts[i].parent = ch
+ ch.dependencies = append(ch.dependencies, x)
+ }
+}
+
+// Root finds the root chart.
+func (ch *Chart) Root() *Chart {
+ if ch.IsRoot() {
+ return ch
+ }
+ return ch.Parent().Root()
+}
+
+// Dependencies are the charts that this chart depends on.
+func (ch *Chart) Dependencies() []*Chart { return ch.dependencies }
+
+// IsRoot determines if the chart is the root chart.
+func (ch *Chart) IsRoot() bool { return ch.parent == nil }
+
+// Parent returns a subchart's parent chart.
+func (ch *Chart) Parent() *Chart { return ch.parent }
+
+// Parent sets a subchart's parent chart.
+func (ch *Chart) SetParent(chart *Chart) { ch.parent = chart }
+
+// ChartPath returns the full path to this chart in dot notation.
+func (ch *Chart) ChartPath() string {
+ if !ch.IsRoot() {
+ return ch.Parent().ChartPath() + "." + ch.Name()
+ }
+ return ch.Name()
+}
+
+// ChartFullPath returns the full path to this chart.
+func (ch *Chart) ChartFullPath() string {
+ if !ch.IsRoot() {
+ return ch.Parent().ChartFullPath() + "/charts/" + ch.Name()
+ }
+ return ch.Name()
+}
diff --git a/pkg/chartutil/transform.go b/pkg/chart/chartfile.go
similarity index 56%
rename from pkg/chartutil/transform.go
rename to pkg/chart/chartfile.go
index f360e4fad..b669b781b 100644
--- a/pkg/chartutil/transform.go
+++ b/pkg/chart/chartfile.go
@@ -1,11 +1,10 @@
/*
-Copyright 2016 The Kubernetes Authors All rights reserved.
-
+Copyright 2018 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
+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,
@@ -14,12 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package chartutil
-
-import "strings"
+package chart
-// Transform performs a string replacement of the specified source for
-// a given key with the replacement string
-func Transform(src, key, replacement string) []byte {
- return []byte(strings.Replace(src, key, replacement, -1))
-}
+// APIVersionv1 is the API version number for version 1.
+const APIVersionv1 = "v1"
diff --git a/pkg/hapi/chart/file.go b/pkg/chart/file.go
similarity index 92%
rename from pkg/hapi/chart/file.go
rename to pkg/chart/file.go
index 90edd59f1..53ce89d3f 100644
--- a/pkg/hapi/chart/file.go
+++ b/pkg/chart/file.go
@@ -21,7 +21,7 @@ package chart
// base directory.
type File struct {
// Name is the path-like name of the template.
- Name string `json:"name,omitempty"`
+ Name string
// Data is the template as byte data.
- Data []byte `json:"data,omitempty"`
+ Data []byte
}
diff --git a/pkg/chart/loader/archive.go b/pkg/chart/loader/archive.go
new file mode 100644
index 000000000..dbdab98f9
--- /dev/null
+++ b/pkg/chart/loader/archive.go
@@ -0,0 +1,110 @@
+/*
+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 loader
+
+import (
+ "archive/tar"
+ "bytes"
+ "compress/gzip"
+ "io"
+ "os"
+ "strings"
+
+ "github.com/pkg/errors"
+
+ "k8s.io/helm/pkg/chart"
+)
+
+type FileLoader string
+
+func (l FileLoader) Load() (*chart.Chart, error) {
+ return LoadFile(string(l))
+}
+
+// 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)
+}
+
+// LoadArchive loads from a reader containing a compressed tar archive.
+func LoadArchive(in io.Reader) (*chart.Chart, error) {
+ unzipped, err := gzip.NewReader(in)
+ if err != nil {
+ return &chart.Chart{}, err
+ }
+ defer unzipped.Close()
+
+ files := []*BufferedFile{}
+ tr := tar.NewReader(unzipped)
+ for {
+ b := bytes.NewBuffer(nil)
+ hd, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return &chart.Chart{}, err
+ }
+
+ if hd.FileInfo().IsDir() {
+ // Use this instead of hd.Typeflag because we don't have to do any
+ // inference chasing.
+ continue
+ }
+
+ // Archive could contain \ if generated on Windows
+ delimiter := "/"
+ if strings.ContainsRune(hd.Name, '\\') {
+ delimiter = "\\"
+ }
+
+ parts := strings.Split(hd.Name, delimiter)
+ n := strings.Join(parts[1:], delimiter)
+
+ // Normalize the path to the / delimiter
+ n = strings.Replace(n, delimiter, "/", -1)
+
+ if parts[0] == "Chart.yaml" {
+ return nil, errors.New("chart yaml not in base directory")
+ }
+
+ if _, err := io.Copy(b, tr); err != nil {
+ return &chart.Chart{}, err
+ }
+
+ files = append(files, &BufferedFile{Name: n, Data: b.Bytes()})
+ b.Reset()
+ }
+
+ if len(files) == 0 {
+ return nil, errors.New("no files in chart archive")
+ }
+
+ return LoadFiles(files)
+}
diff --git a/pkg/chart/loader/directory.go b/pkg/chart/loader/directory.go
new file mode 100644
index 000000000..f51620cfb
--- /dev/null
+++ b/pkg/chart/loader/directory.go
@@ -0,0 +1,105 @@
+/*
+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 loader
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/pkg/errors"
+
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/ignore"
+ "k8s.io/helm/pkg/sympath"
+)
+
+type DirLoader string
+
+func (l DirLoader) Load() (*chart.Chart, error) {
+ return LoadDir(string(l))
+}
+
+// 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
+ }
+
+ // Just used for errors.
+ c := &chart.Chart{}
+
+ rules := ignore.Empty()
+ ifile := filepath.Join(topdir, ignore.HelmIgnore)
+ if _, err := os.Stat(ifile); err == nil {
+ r, err := ignore.ParseFile(ifile)
+ if err != nil {
+ return c, err
+ }
+ rules = r
+ }
+ rules.AddDefaults()
+
+ files := []*BufferedFile{}
+ topdir += string(filepath.Separator)
+
+ walk := func(name string, fi os.FileInfo, err error) error {
+ n := strings.TrimPrefix(name, topdir)
+ if n == "" {
+ // No need to process top level. Avoid bug with helmignore .* matching
+ // empty names. See issue 1779.
+ return nil
+ }
+
+ // Normalize to / since it will also work on Windows
+ n = filepath.ToSlash(n)
+
+ if err != nil {
+ return err
+ }
+ if fi.IsDir() {
+ // Directory-based ignore rules should involve skipping the entire
+ // contents of that directory.
+ if rules.Ignore(n, fi) {
+ return filepath.SkipDir
+ }
+ return nil
+ }
+
+ // If a .helmignore file matches, skip this file.
+ if rules.Ignore(n, fi) {
+ return nil
+ }
+
+ data, err := ioutil.ReadFile(name)
+ if err != nil {
+ return errors.Wrapf(err, "error reading %s", n)
+ }
+
+ files = append(files, &BufferedFile{Name: n, Data: data})
+ return nil
+ }
+ if err = sympath.Walk(topdir, walk); err != nil {
+ return c, err
+ }
+
+ return LoadFiles(files)
+}
diff --git a/pkg/chart/loader/load.go b/pkg/chart/loader/load.go
new file mode 100644
index 000000000..bbc0cca63
--- /dev/null
+++ b/pkg/chart/loader/load.go
@@ -0,0 +1,151 @@
+/*
+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 loader
+
+import (
+ "bytes"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/ghodss/yaml"
+ "github.com/pkg/errors"
+
+ "k8s.io/helm/pkg/chart"
+)
+
+type ChartLoader interface {
+ Load() (*chart.Chart, error)
+}
+
+func Loader(name string) (ChartLoader, error) {
+ fi, err := os.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if fi.IsDir() {
+ return DirLoader(name), nil
+ }
+ return FileLoader(name), nil
+
+}
+
+// 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.
+//
+// If a .helmignore file is present, the directory loader will skip loading any files
+// matching it. But .helmignore is not evaluated when reading out of an archive.
+func Load(name string) (*chart.Chart, error) {
+ l, err := Loader(name)
+ if err != nil {
+ return nil, err
+ }
+ return l.Load()
+}
+
+// BufferedFile represents an archive file buffered for later processing.
+type BufferedFile struct {
+ Name string
+ Data []byte
+}
+
+// LoadFiles loads from in-memory files.
+func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
+ c := new(chart.Chart)
+ subcharts := make(map[string][]*BufferedFile)
+
+ for _, f := range files {
+ switch {
+ case f.Name == "Chart.yaml":
+ c.Metadata = new(chart.Metadata)
+ if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil {
+ return c, errors.Wrap(err, "cannot load Chart.yaml")
+ }
+ case f.Name == "requirements.yaml":
+ c.Requirements = new(chart.Requirements)
+ if err := yaml.Unmarshal(f.Data, c.Requirements); err != nil {
+ return c, errors.Wrap(err, "cannot load requirements.yaml")
+ }
+ case f.Name == "requirements.lock":
+ c.RequirementsLock = new(chart.RequirementsLock)
+ if err := yaml.Unmarshal(f.Data, &c.RequirementsLock); err != nil {
+ return c, errors.Wrap(err, "cannot load requirements.lock")
+ }
+ case f.Name == "values.yaml":
+ c.Values = f.Data
+ case strings.HasPrefix(f.Name, "templates/"):
+ c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data})
+ case strings.HasPrefix(f.Name, "charts/"):
+ if filepath.Ext(f.Name) == ".prov" {
+ c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
+ continue
+ }
+
+ fname := strings.TrimPrefix(f.Name, "charts/")
+ cname := strings.SplitN(fname, "/", 2)[0]
+ subcharts[cname] = append(subcharts[cname], &BufferedFile{Name: fname, Data: f.Data})
+ default:
+ c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
+ }
+ }
+
+ // Ensure that we got a Chart.yaml file
+ if c.Metadata == nil {
+ return c, errors.New("chart metadata (Chart.yaml) missing")
+ }
+ if c.Name() == "" {
+ return c, errors.New("invalid chart (Chart.yaml): name must not be empty")
+ }
+
+ for n, files := range subcharts {
+ var sc *chart.Chart
+ var err error
+ switch {
+ case strings.IndexAny(n, "_.") == 0:
+ continue
+ case filepath.Ext(n) == ".tgz":
+ file := files[0]
+ if file.Name != n {
+ return c, errors.Errorf("error unpacking tar in %s: expected %s, got %s", c.Name(), n, file.Name)
+ }
+ // Untar the chart and add to c.Dependencies
+ sc, err = LoadArchive(bytes.NewBuffer(file.Data))
+ default:
+ // We have to trim the prefix off of every file, and ignore any file
+ // that is in charts/, but isn't actually a chart.
+ buff := make([]*BufferedFile, 0, len(files))
+ for _, f := range files {
+ parts := strings.SplitN(f.Name, "/", 2)
+ if len(parts) < 2 {
+ continue
+ }
+ f.Name = parts[1]
+ buff = append(buff, f)
+ }
+ sc, err = LoadFiles(buff)
+ }
+
+ if err != nil {
+ return c, errors.Wrapf(err, "error unpacking %s in %s", n, c.Name())
+ }
+ c.AddDependency(sc)
+ }
+
+ return c, nil
+}
diff --git a/pkg/chartutil/load_test.go b/pkg/chart/loader/load_test.go
similarity index 63%
rename from pkg/chartutil/load_test.go
rename to pkg/chart/loader/load_test.go
index 36dc37185..aca222780 100644
--- a/pkg/chartutil/load_test.go
+++ b/pkg/chart/loader/load_test.go
@@ -14,27 +14,35 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package chartutil
+package loader
import (
- "path"
"testing"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
)
func TestLoadDir(t *testing.T) {
- c, err := Load("testdata/frobnitz")
+ l, err := Loader("testdata/frobnitz")
+ if err != nil {
+ t.Fatalf("Failed to load testdata: %s", err)
+ }
+ c, err := l.Load()
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
verifyFrobnitz(t, c)
verifyChart(t, c)
verifyRequirements(t, c)
+ verifyRequirementsLock(t, c)
}
func TestLoadFile(t *testing.T) {
- c, err := Load("testdata/frobnitz-1.2.3.tgz")
+ l, err := Loader("testdata/frobnitz-1.2.3.tgz")
+ if err != nil {
+ t.Fatalf("Failed to load testdata: %s", err)
+ }
+ c, err := l.Load()
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
@@ -46,7 +54,7 @@ func TestLoadFile(t *testing.T) {
func TestLoadFiles(t *testing.T) {
goodFiles := []*BufferedFile{
{
- Name: ChartfileName,
+ Name: "Chart.yaml",
Data: []byte(`apiVersion: v1
name: frobnitz
description: This is a frobnitz.
@@ -67,16 +75,16 @@ icon: https://example.com/64x64.png
`),
},
{
- Name: ValuesfileName,
- Data: []byte(defaultValues),
+ Name: "values.yaml",
+ Data: []byte("some values"),
},
{
- Name: path.Join("templates", DeploymentName),
- Data: []byte(defaultDeployment),
+ Name: "templates/deployment.yaml",
+ Data: []byte("some deployment"),
},
{
- Name: path.Join("templates", ServiceName),
- Data: []byte(defaultService),
+ Name: "templates/service.yaml",
+ Data: []byte("some service"),
},
}
@@ -85,11 +93,11 @@ icon: https://example.com/64x64.png
t.Errorf("Expected good files to be loaded, got %v", err)
}
- if c.Metadata.Name != "frobnitz" {
- t.Errorf("Expected chart name to be 'frobnitz', got %s", c.Metadata.Name)
+ if c.Name() != "frobnitz" {
+ t.Errorf("Expected chart name to be 'frobnitz', got %s", c.Name())
}
- if string(c.Values) != defaultValues {
+ if string(c.Values) != "some values" {
t.Error("Expected chart values to be populated with default values")
}
@@ -119,15 +127,16 @@ func TestLoadFileBackslash(t *testing.T) {
}
func verifyChart(t *testing.T, c *chart.Chart) {
- if c.Metadata.Name == "" {
+ t.Helper()
+ if c.Name() == "" {
t.Fatalf("No chart metadata found on %v", c)
}
- t.Logf("Verifying chart %s", c.Metadata.Name)
+ t.Logf("Verifying chart %s", c.Name())
if len(c.Templates) != 1 {
t.Errorf("Expected 1 template, got %d", len(c.Templates))
}
- numfiles := 8
+ numfiles := 6
if len(c.Files) != numfiles {
t.Errorf("Expected %d extra files, got %d", numfiles, len(c.Files))
for _, n := range c.Files {
@@ -135,10 +144,10 @@ func verifyChart(t *testing.T, c *chart.Chart) {
}
}
- 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)
+ 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.Name())
}
}
@@ -151,35 +160,31 @@ func verifyChart(t *testing.T, c *chart.Chart) {
},
}
- for _, dep := range c.Dependencies {
+ for _, dep := range c.Dependencies() {
if dep.Metadata == nil {
t.Fatalf("expected metadata on dependency: %v", dep)
}
- exp, ok := expect[dep.Metadata.Name]
+ exp, ok := expect[dep.Name()]
if !ok {
- t.Fatalf("Unknown dependency %s", dep.Metadata.Name)
+ t.Fatalf("Unknown dependency %s", dep.Name())
}
if exp["version"] != dep.Metadata.Version {
- t.Errorf("Expected %s version %s, got %s", dep.Metadata.Name, exp["version"], dep.Metadata.Version)
+ t.Errorf("Expected %s version %s, got %s", dep.Name(), exp["version"], dep.Metadata.Version)
}
}
}
func verifyRequirements(t *testing.T, c *chart.Chart) {
- r, err := LoadRequirements(c)
- if err != nil {
- t.Fatal(err)
- }
- if len(r.Dependencies) != 2 {
- t.Errorf("Expected 2 requirements, got %d", len(r.Dependencies))
+ if len(c.Requirements.Dependencies) != 2 {
+ t.Errorf("Expected 2 requirements, got %d", len(c.Requirements.Dependencies))
}
- tests := []*Dependency{
+ tests := []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"},
{Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"},
}
for i, tt := range tests {
- d := r.Dependencies[i]
+ d := c.Requirements.Dependencies[i]
if d.Name != tt.Name {
t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name)
}
@@ -191,20 +196,17 @@ func verifyRequirements(t *testing.T, c *chart.Chart) {
}
}
}
+
func verifyRequirementsLock(t *testing.T, c *chart.Chart) {
- r, err := LoadRequirementsLock(c)
- if err != nil {
- t.Fatal(err)
- }
- if len(r.Dependencies) != 2 {
- t.Errorf("Expected 2 requirements, got %d", len(r.Dependencies))
+ if len(c.Requirements.Dependencies) != 2 {
+ t.Errorf("Expected 2 requirements, got %d", len(c.Requirements.Dependencies))
}
- tests := []*Dependency{
+ tests := []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"},
{Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"},
}
for i, tt := range tests {
- d := r.Dependencies[i]
+ d := c.Requirements.Dependencies[i]
if d.Name != tt.Name {
t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name)
}
@@ -223,17 +225,55 @@ func verifyFrobnitz(t *testing.T, c *chart.Chart) {
func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) {
- verifyChartfile(t, c.Metadata, name)
-
+ if c.Metadata == nil {
+ t.Fatal("Metadata is nil")
+ }
+ if c.Name() != name {
+ t.Errorf("Expected %s, got %s", name, c.Name())
+ }
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.")
}
+ if len(c.Files) != 6 {
+ t.Fatalf("Expected 6 Files, got %d", len(c.Files))
+ }
+ if len(c.Dependencies()) != 2 {
+ t.Fatalf("Expected 2 Dependency, got %d", len(c.Dependencies()))
+ }
+ if len(c.Requirements.Dependencies) != 2 {
+ t.Fatalf("Expected 2 Requirements.Dependency, got %d", len(c.Requirements.Dependencies))
+ }
+ if len(c.RequirementsLock.Dependencies) != 2 {
+ t.Fatalf("Expected 2 RequirementsLock.Dependency, got %d", len(c.RequirementsLock.Dependencies))
+ }
+
+ for _, dep := range c.Dependencies() {
+ switch dep.Name() {
+ case "mariner":
+ case "alpine":
+ if len(dep.Templates) != 1 {
+ t.Fatalf("Expected 1 template, got %d", len(dep.Templates))
+ }
+ if dep.Templates[0].Name != "templates/alpine-pod.yaml" {
+ t.Errorf("Unexpected template: %s", dep.Templates[0].Name)
+ }
+ if len(dep.Templates[0].Data) == 0 {
+ t.Error("No template data.")
+ }
+ if len(dep.Files) != 1 {
+ t.Fatalf("Expected 1 Files, got %d", len(dep.Files))
+ }
+ if len(dep.Dependencies()) != 2 {
+ t.Fatalf("Expected 2 Dependency, got %d", len(dep.Dependencies()))
+ }
+ default:
+ t.Errorf("Unexpected dependeny %s", dep.Name())
+ }
+ }
}
diff --git a/pkg/chart/loader/testdata/frobnitz-1.2.3.tgz b/pkg/chart/loader/testdata/frobnitz-1.2.3.tgz
new file mode 100644
index 000000000..fb21cd08f
Binary files /dev/null and b/pkg/chart/loader/testdata/frobnitz-1.2.3.tgz differ
diff --git a/pkg/chart/loader/testdata/frobnitz/.helmignore b/pkg/chart/loader/testdata/frobnitz/.helmignore
new file mode 100644
index 000000000..9973a57b8
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/.helmignore
@@ -0,0 +1 @@
+ignore/
diff --git a/pkg/chart/loader/testdata/frobnitz/Chart.yaml b/pkg/chart/loader/testdata/frobnitz/Chart.yaml
new file mode 100644
index 000000000..134cd1109
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/Chart.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+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
+icon: https://example.com/64x64.png
+annotations:
+ extrakey: extravalue
+ anotherkey: anothervalue
diff --git a/pkg/chart/loader/testdata/frobnitz/INSTALL.txt b/pkg/chart/loader/testdata/frobnitz/INSTALL.txt
new file mode 100644
index 000000000..2010438c2
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/INSTALL.txt
@@ -0,0 +1 @@
+This is an install document. The client may display this.
diff --git a/pkg/chart/loader/testdata/frobnitz/LICENSE b/pkg/chart/loader/testdata/frobnitz/LICENSE
new file mode 100644
index 000000000..6121943b1
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/LICENSE
@@ -0,0 +1 @@
+LICENSE placeholder.
diff --git a/pkg/chart/loader/testdata/frobnitz/README.md b/pkg/chart/loader/testdata/frobnitz/README.md
new file mode 100644
index 000000000..8cf4cc3d7
--- /dev/null
+++ b/pkg/chart/loader/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/chart/loader/testdata/frobnitz/charts/_ignore_me b/pkg/chart/loader/testdata/frobnitz/charts/_ignore_me
new file mode 100644
index 000000000..2cecca682
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/charts/_ignore_me
@@ -0,0 +1 @@
+This should be ignored by the loader, but may be included in a chart.
diff --git a/pkg/chart/loader/testdata/frobnitz/charts/alpine/Chart.yaml b/pkg/chart/loader/testdata/frobnitz/charts/alpine/Chart.yaml
new file mode 100644
index 000000000..38a4aaa54
--- /dev/null
+++ b/pkg/chart/loader/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://k8s.io/helm
diff --git a/pkg/chart/loader/testdata/frobnitz/charts/alpine/README.md b/pkg/chart/loader/testdata/frobnitz/charts/alpine/README.md
new file mode 100644
index 000000000..a7c84fc41
--- /dev/null
+++ b/pkg/chart/loader/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/chart/loader/testdata/frobnitz/charts/alpine/charts/mast1/Chart.yaml b/pkg/chart/loader/testdata/frobnitz/charts/alpine/charts/mast1/Chart.yaml
new file mode 100644
index 000000000..171e36156
--- /dev/null
+++ b/pkg/chart/loader/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/chart/loader/testdata/frobnitz/charts/alpine/charts/mast1/values.yaml b/pkg/chart/loader/testdata/frobnitz/charts/alpine/charts/mast1/values.yaml
new file mode 100644
index 000000000..42c39c262
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/charts/alpine/charts/mast1/values.yaml
@@ -0,0 +1,4 @@
+# Default values for mast1.
+# This is a YAML-formatted file.
+# Declare name/value pairs to be passed into your templates.
+# name = "value"
diff --git a/pkg/chart/loader/testdata/frobnitz/charts/alpine/charts/mast2-0.1.0.tgz b/pkg/chart/loader/testdata/frobnitz/charts/alpine/charts/mast2-0.1.0.tgz
new file mode 100644
index 000000000..ced5a4a6a
Binary files /dev/null and b/pkg/chart/loader/testdata/frobnitz/charts/alpine/charts/mast2-0.1.0.tgz differ
diff --git a/pkg/chart/loader/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml b/pkg/chart/loader/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml
new file mode 100644
index 000000000..0c6980cf7
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/charts/alpine/templates/alpine-pod.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: {{.Release.Name}}-{{.Chart.Name}}
+ labels:
+ heritage: {{.Release.Service}}
+ chartName: {{.Chart.Name}}
+ chartVersion: {{.Chart.Version | quote}}
+spec:
+ restartPolicy: {{default "Never" .restart_policy}}
+ containers:
+ - name: waiter
+ image: "alpine:3.3"
+ command: ["/bin/sleep","9000"]
diff --git a/pkg/chart/loader/testdata/frobnitz/charts/alpine/values.yaml b/pkg/chart/loader/testdata/frobnitz/charts/alpine/values.yaml
new file mode 100644
index 000000000..6c2aab7ba
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/charts/alpine/values.yaml
@@ -0,0 +1,2 @@
+# The pod name
+name: "my-alpine"
diff --git a/pkg/chart/loader/testdata/frobnitz/charts/mariner-4.3.2.tgz b/pkg/chart/loader/testdata/frobnitz/charts/mariner-4.3.2.tgz
new file mode 100644
index 000000000..3af333e76
Binary files /dev/null and b/pkg/chart/loader/testdata/frobnitz/charts/mariner-4.3.2.tgz differ
diff --git a/pkg/chart/loader/testdata/frobnitz/docs/README.md b/pkg/chart/loader/testdata/frobnitz/docs/README.md
new file mode 100644
index 000000000..d40747caf
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/docs/README.md
@@ -0,0 +1 @@
+This is a placeholder for documentation.
diff --git a/pkg/chart/loader/testdata/frobnitz/icon.svg b/pkg/chart/loader/testdata/frobnitz/icon.svg
new file mode 100644
index 000000000..892130606
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/icon.svg
@@ -0,0 +1,8 @@
+
+
diff --git a/pkg/chart/loader/testdata/frobnitz/ignore/me.txt b/pkg/chart/loader/testdata/frobnitz/ignore/me.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/pkg/chart/loader/testdata/frobnitz/requirements.lock b/pkg/chart/loader/testdata/frobnitz/requirements.lock
new file mode 100644
index 000000000..6fcc2ed9f
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/requirements.lock
@@ -0,0 +1,8 @@
+dependencies:
+ - name: alpine
+ version: "0.1.0"
+ repository: https://example.com/charts
+ - name: mariner
+ version: "4.3.2"
+ repository: https://example.com/charts
+digest: invalid
diff --git a/pkg/chart/loader/testdata/frobnitz/requirements.yaml b/pkg/chart/loader/testdata/frobnitz/requirements.yaml
new file mode 100644
index 000000000..5eb0bc98b
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/requirements.yaml
@@ -0,0 +1,7 @@
+dependencies:
+ - name: alpine
+ version: "0.1.0"
+ repository: https://example.com/charts
+ - name: mariner
+ version: "4.3.2"
+ repository: https://example.com/charts
diff --git a/pkg/chart/loader/testdata/frobnitz/templates/template.tpl b/pkg/chart/loader/testdata/frobnitz/templates/template.tpl
new file mode 100644
index 000000000..c651ee6a0
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/templates/template.tpl
@@ -0,0 +1 @@
+Hello {{.Name | default "world"}}
diff --git a/pkg/chart/loader/testdata/frobnitz/values.yaml b/pkg/chart/loader/testdata/frobnitz/values.yaml
new file mode 100644
index 000000000..61f501258
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz/values.yaml
@@ -0,0 +1,6 @@
+# A values file contains configuration.
+
+name: "Some Name"
+
+section:
+ name: "Name in a section"
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash-1.2.3.tgz b/pkg/chart/loader/testdata/frobnitz_backslash-1.2.3.tgz
new file mode 100644
index 000000000..692dd6aba
Binary files /dev/null and b/pkg/chart/loader/testdata/frobnitz_backslash-1.2.3.tgz differ
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/.helmignore b/pkg/chart/loader/testdata/frobnitz_backslash/.helmignore
new file mode 100755
index 000000000..9973a57b8
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/.helmignore
@@ -0,0 +1 @@
+ignore/
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/Chart.yaml b/pkg/chart/loader/testdata/frobnitz_backslash/Chart.yaml
new file mode 100755
index 000000000..49df2a046
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/Chart.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+name: frobnitz_backslash
+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
+icon: https://example.com/64x64.png
+annotations:
+ extrakey: extravalue
+ anotherkey: anothervalue
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/INSTALL.txt b/pkg/chart/loader/testdata/frobnitz_backslash/INSTALL.txt
new file mode 100755
index 000000000..2010438c2
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/INSTALL.txt
@@ -0,0 +1 @@
+This is an install document. The client may display this.
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/LICENSE b/pkg/chart/loader/testdata/frobnitz_backslash/LICENSE
new file mode 100755
index 000000000..6121943b1
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/LICENSE
@@ -0,0 +1 @@
+LICENSE placeholder.
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/README.md b/pkg/chart/loader/testdata/frobnitz_backslash/README.md
new file mode 100755
index 000000000..8cf4cc3d7
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/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/chart/loader/testdata/frobnitz_backslash/charts/_ignore_me b/pkg/chart/loader/testdata/frobnitz_backslash/charts/_ignore_me
new file mode 100755
index 000000000..2cecca682
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/charts/_ignore_me
@@ -0,0 +1 @@
+This should be ignored by the loader, but may be included in a chart.
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/Chart.yaml b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/Chart.yaml
new file mode 100755
index 000000000..38a4aaa54
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/Chart.yaml
@@ -0,0 +1,4 @@
+name: alpine
+description: Deploy a basic Alpine Linux pod
+version: 0.1.0
+home: https://k8s.io/helm
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/README.md b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/README.md
new file mode 100755
index 000000000..a7c84fc41
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/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/chart/loader/testdata/frobnitz_backslash/charts/alpine/charts/mast1/Chart.yaml b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/charts/mast1/Chart.yaml
new file mode 100755
index 000000000..171e36156
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/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/chart/loader/testdata/frobnitz_backslash/charts/alpine/charts/mast1/values.yaml b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/charts/mast1/values.yaml
new file mode 100755
index 000000000..42c39c262
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/charts/mast1/values.yaml
@@ -0,0 +1,4 @@
+# Default values for mast1.
+# This is a YAML-formatted file.
+# Declare name/value pairs to be passed into your templates.
+# name = "value"
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/charts/mast2-0.1.0.tgz b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/charts/mast2-0.1.0.tgz
new file mode 100755
index 000000000..ced5a4a6a
Binary files /dev/null and b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/charts/mast2-0.1.0.tgz differ
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml
new file mode 100755
index 000000000..0c6980cf7
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: {{.Release.Name}}-{{.Chart.Name}}
+ labels:
+ heritage: {{.Release.Service}}
+ chartName: {{.Chart.Name}}
+ chartVersion: {{.Chart.Version | quote}}
+spec:
+ restartPolicy: {{default "Never" .restart_policy}}
+ containers:
+ - name: waiter
+ image: "alpine:3.3"
+ command: ["/bin/sleep","9000"]
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/values.yaml b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/values.yaml
new file mode 100755
index 000000000..6c2aab7ba
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/charts/alpine/values.yaml
@@ -0,0 +1,2 @@
+# The pod name
+name: "my-alpine"
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/charts/mariner-4.3.2.tgz b/pkg/chart/loader/testdata/frobnitz_backslash/charts/mariner-4.3.2.tgz
new file mode 100755
index 000000000..3af333e76
Binary files /dev/null and b/pkg/chart/loader/testdata/frobnitz_backslash/charts/mariner-4.3.2.tgz differ
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/docs/README.md b/pkg/chart/loader/testdata/frobnitz_backslash/docs/README.md
new file mode 100755
index 000000000..d40747caf
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/docs/README.md
@@ -0,0 +1 @@
+This is a placeholder for documentation.
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/icon.svg b/pkg/chart/loader/testdata/frobnitz_backslash/icon.svg
new file mode 100755
index 000000000..892130606
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/icon.svg
@@ -0,0 +1,8 @@
+
+
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/ignore/me.txt b/pkg/chart/loader/testdata/frobnitz_backslash/ignore/me.txt
new file mode 100755
index 000000000..e69de29bb
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/requirements.lock b/pkg/chart/loader/testdata/frobnitz_backslash/requirements.lock
new file mode 100755
index 000000000..6fcc2ed9f
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/requirements.lock
@@ -0,0 +1,8 @@
+dependencies:
+ - name: alpine
+ version: "0.1.0"
+ repository: https://example.com/charts
+ - name: mariner
+ version: "4.3.2"
+ repository: https://example.com/charts
+digest: invalid
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/requirements.yaml b/pkg/chart/loader/testdata/frobnitz_backslash/requirements.yaml
new file mode 100755
index 000000000..5eb0bc98b
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/requirements.yaml
@@ -0,0 +1,7 @@
+dependencies:
+ - name: alpine
+ version: "0.1.0"
+ repository: https://example.com/charts
+ - name: mariner
+ version: "4.3.2"
+ repository: https://example.com/charts
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/templates/template.tpl b/pkg/chart/loader/testdata/frobnitz_backslash/templates/template.tpl
new file mode 100755
index 000000000..c651ee6a0
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/templates/template.tpl
@@ -0,0 +1 @@
+Hello {{.Name | default "world"}}
diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/values.yaml b/pkg/chart/loader/testdata/frobnitz_backslash/values.yaml
new file mode 100755
index 000000000..61f501258
--- /dev/null
+++ b/pkg/chart/loader/testdata/frobnitz_backslash/values.yaml
@@ -0,0 +1,6 @@
+# A values file contains configuration.
+
+name: "Some Name"
+
+section:
+ name: "Name in a section"
diff --git a/pkg/hapi/chart/metadata.go b/pkg/chart/metadata.go
similarity index 100%
rename from pkg/hapi/chart/metadata.go
rename to pkg/chart/metadata.go
diff --git a/pkg/chart/requirements.go b/pkg/chart/requirements.go
new file mode 100644
index 000000000..76b8ea8ab
--- /dev/null
+++ b/pkg/chart/requirements.go
@@ -0,0 +1,70 @@
+/*
+Copyright 2018 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 chart
+
+import "time"
+
+// Dependency describes a chart upon which another chart depends.
+//
+// Dependencies can be used to express developer intent, or to capture the state
+// of a chart.
+type Dependency struct {
+ // Name is the name of the dependency.
+ //
+ // This must mach the name in the dependency's Chart.yaml.
+ Name string `json:"name"`
+ // Version is the version (range) of this chart.
+ //
+ // A lock file will always produce a single version, while a dependency
+ // may contain a semantic version range.
+ Version string `json:"version,omitempty"`
+ // The URL to the repository.
+ //
+ // Appending `index.yaml` to this string should result in a URL that can be
+ // used to fetch the repository index.
+ Repository string `json:"repository"`
+ // A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled )
+ Condition string `json:"condition,omitempty"`
+ // Tags can be used to group charts for enabling/disabling together
+ Tags []string `json:"tags,omitempty"`
+ // Enabled bool determines if chart should be loaded
+ Enabled bool `json:"enabled,omitempty"`
+ // ImportValues holds the mapping of source values to parent key to be imported. Each item can be a
+ // string or pair of child/parent sublist items.
+ ImportValues []interface{} `json:"import-values,omitempty"`
+ // Alias usable alias to be used for the chart
+ Alias string `json:"alias,omitempty"`
+}
+
+// Requirements is a list of requirements for a chart.
+//
+// Requirements are charts upon which this chart depends. This expresses
+// developer intent.
+type Requirements struct {
+ Dependencies []*Dependency `json:"dependencies"`
+}
+
+// RequirementsLock is a lock file for requirements.
+//
+// It represents the state that the dependencies should be in.
+type RequirementsLock struct {
+ // Genderated is the date the lock file was last generated.
+ Generated time.Time `json:"generated"`
+ // Digest is a hash of the requirements file used to generate it.
+ Digest string `json:"digest"`
+ // Dependencies is the list of dependencies that this lock file has locked.
+ Dependencies []*Dependency `json:"dependencies"`
+}
diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go
index 06c117315..fdba95d7d 100644
--- a/pkg/chartutil/capabilities.go
+++ b/pkg/chartutil/capabilities.go
@@ -20,13 +20,14 @@ import (
"runtime"
"k8s.io/apimachinery/pkg/version"
+ "k8s.io/client-go/kubernetes/scheme"
tversion "k8s.io/helm/pkg/version"
)
var (
// DefaultVersionSet is the default version set, which includes only Core V1 ("v1").
- DefaultVersionSet = NewVersionSet("v1")
+ DefaultVersionSet = allKnownVersions()
// DefaultKubeVersion is the default kubernetes version
DefaultKubeVersion = &version.Info{
@@ -37,6 +38,12 @@ var (
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
}
+
+ // DefaultCapabilities is the default set of capabilities.
+ DefaultCapabilities = &Capabilities{
+ APIVersions: DefaultVersionSet,
+ KubeVersion: DefaultKubeVersion,
+ }
)
// Capabilities describes the capabilities of the Kubernetes cluster that Tiller is attached to.
@@ -52,11 +59,11 @@ type Capabilities struct {
}
// VersionSet is a set of Kubernetes API versions.
-type VersionSet map[string]interface{}
+type VersionSet map[string]struct{}
// NewVersionSet creates a new version set from a list of strings.
func NewVersionSet(apiVersions ...string) VersionSet {
- vs := VersionSet{}
+ vs := make(VersionSet)
for _, v := range apiVersions {
vs[v] = struct{}{}
}
@@ -70,3 +77,11 @@ func (v VersionSet) Has(apiVersion string) bool {
_, ok := v[apiVersion]
return ok
}
+
+func allKnownVersions() VersionSet {
+ vs := make(VersionSet)
+ for gvk := range scheme.Scheme.AllKnownTypes() {
+ vs[gvk.GroupVersion().String()] = struct{}{}
+ }
+ return vs
+}
diff --git a/pkg/chartutil/capabilities_test.go b/pkg/chartutil/capabilities_test.go
index ac20f0038..385a866c9 100644
--- a/pkg/chartutil/capabilities_test.go
+++ b/pkg/chartutil/capabilities_test.go
@@ -38,9 +38,6 @@ func TestDefaultVersionSet(t *testing.T) {
if !DefaultVersionSet.Has("v1") {
t.Error("Expected core v1 version set")
}
- if d := len(DefaultVersionSet); d != 1 {
- t.Errorf("Expected only one version, got %d", d)
- }
}
func TestCapabilities(t *testing.T) {
diff --git a/pkg/chartutil/chartfile.go b/pkg/chartutil/chartfile.go
index 461e47357..e388496f7 100644
--- a/pkg/chartutil/chartfile.go
+++ b/pkg/chartutil/chartfile.go
@@ -24,29 +24,18 @@ import (
"github.com/ghodss/yaml"
"github.com/pkg/errors"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
)
-// APIVersionv1 is the API version number for version 1.
-const APIVersionv1 = "v1"
-
-// UnmarshalChartfile takes raw Chart.yaml data and unmarshals it.
-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)
+ y := new(chart.Metadata)
+ err = yaml.Unmarshal(b, y)
+ return y, err
}
// SaveChartfile saves the given metadata as a Chart.yaml file at the given path.
@@ -80,8 +69,8 @@ func IsChartDir(dirName string) (bool, error) {
return false, errors.Errorf("cannot read Chart.Yaml in directory %q", dirName)
}
- chartContent, err := UnmarshalChartfile(chartYamlContent)
- if err != nil {
+ chartContent := new(chart.Metadata)
+ if err := yaml.Unmarshal(chartYamlContent, &chartContent); err != nil {
return false, err
}
if chartContent == nil {
diff --git a/pkg/chartutil/chartfile_test.go b/pkg/chartutil/chartfile_test.go
index 49de60f65..35be0ab27 100644
--- a/pkg/chartutil/chartfile_test.go
+++ b/pkg/chartutil/chartfile_test.go
@@ -19,7 +19,7 @@ package chartutil
import (
"testing"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
)
const testfile = "testdata/chartfiletest.yaml"
@@ -40,8 +40,8 @@ func verifyChartfile(t *testing.T, f *chart.Metadata, name string) {
}
// Api instead of API because it was generated via protobuf.
- if f.APIVersion != APIVersionv1 {
- t.Errorf("Expected API Version %q, got %q", APIVersionv1, f.APIVersion)
+ if f.APIVersion != chart.APIVersionv1 {
+ t.Errorf("Expected API Version %q, got %q", chart.APIVersionv1, f.APIVersion)
}
if f.Name != name {
diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go
index a2e024047..8b27bd2f3 100644
--- a/pkg/chartutil/create.go
+++ b/pkg/chartutil/create.go
@@ -21,10 +21,12 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "strings"
"github.com/pkg/errors"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
)
const (
@@ -294,7 +296,7 @@ Create chart name and version as used by the chart label.
// CreateFrom creates a new chart, but scaffolds it from the src chart.
func CreateFrom(chartfile *chart.Metadata, dest, src string) error {
- schart, err := Load(src)
+ schart, err := loader.Load(src)
if err != nil {
return errors.Wrapf(err, "could not load %s", src)
}
@@ -304,12 +306,12 @@ func CreateFrom(chartfile *chart.Metadata, dest, src string) error {
var updatedTemplates []*chart.File
for _, template := range schart.Templates {
- newData := Transform(string(template.Data), "", schart.Metadata.Name)
+ newData := transform(string(template.Data), schart.Name())
updatedTemplates = append(updatedTemplates, &chart.File{Name: template.Name, Data: newData})
}
schart.Templates = updatedTemplates
- schart.Values = Transform(string(schart.Values), "", schart.Metadata.Name)
+ schart.Values = transform(string(schart.Values), schart.Name())
return SaveDir(schart, dest)
}
@@ -378,27 +380,27 @@ func Create(chartfile *chart.Metadata, dir string) (string, error) {
{
// ingress.yaml
path: filepath.Join(cdir, TemplatesDir, IngressFileName),
- content: Transform(defaultIngress, "", chartfile.Name),
+ content: transform(defaultIngress, chartfile.Name),
},
{
// deployment.yaml
path: filepath.Join(cdir, TemplatesDir, DeploymentName),
- content: Transform(defaultDeployment, "", chartfile.Name),
+ content: transform(defaultDeployment, chartfile.Name),
},
{
// service.yaml
path: filepath.Join(cdir, TemplatesDir, ServiceName),
- content: Transform(defaultService, "", chartfile.Name),
+ content: transform(defaultService, chartfile.Name),
},
{
// NOTES.txt
path: filepath.Join(cdir, TemplatesDir, NotesName),
- content: Transform(defaultNotes, "", chartfile.Name),
+ content: transform(defaultNotes, chartfile.Name),
},
{
// _helpers.tpl
path: filepath.Join(cdir, TemplatesDir, HelpersName),
- content: Transform(defaultHelpers, "", chartfile.Name),
+ content: transform(defaultHelpers, chartfile.Name),
},
}
@@ -413,3 +415,9 @@ func Create(chartfile *chart.Metadata, dir string) (string, error) {
}
return cdir, nil
}
+
+// transform performs a string replacement of the specified source for
+// a given key with the replacement string
+func transform(src, replacement string) []byte {
+ return []byte(strings.Replace(src, "", replacement, -1))
+}
diff --git a/pkg/chartutil/create_test.go b/pkg/chartutil/create_test.go
index 01f5902a9..d932c5d1e 100644
--- a/pkg/chartutil/create_test.go
+++ b/pkg/chartutil/create_test.go
@@ -23,7 +23,8 @@ import (
"strings"
"testing"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
)
func TestCreate(t *testing.T) {
@@ -42,13 +43,13 @@ func TestCreate(t *testing.T) {
dir := filepath.Join(tdir, "foo")
- mychart, err := LoadDir(c)
+ mychart, err := loader.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)
+ if mychart.Name() != "foo" {
+ t.Errorf("Expected name to be 'foo', got %q", mychart.Name())
}
for _, d := range []string{TemplatesDir, ChartsDir} {
@@ -94,13 +95,13 @@ func TestCreateFrom(t *testing.T) {
dir := filepath.Join(tdir, "foo")
c := filepath.Join(tdir, cf.Name)
- mychart, err := LoadDir(c)
+ mychart, err := loader.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)
+ if mychart.Name() != "foo" {
+ t.Errorf("Expected name to be 'foo', got %q", mychart.Name())
}
for _, d := range []string{TemplatesDir, ChartsDir} {
@@ -111,7 +112,7 @@ func TestCreateFrom(t *testing.T) {
}
}
- for _, f := range []string{ChartfileName, ValuesfileName, "requirements.yaml"} {
+ 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() {
diff --git a/pkg/chartutil/doc.go b/pkg/chartutil/doc.go
index 1190d968d..516f4c1cb 100644
--- a/pkg/chartutil/doc.go
+++ b/pkg/chartutil/doc.go
@@ -16,7 +16,7 @@ limitations under the License.
/*Package chartutil contains tools for working with charts.
-Charts are described in the protocol buffer definition (pkg/proto/hapi/charts).
+Charts are described in the protocol buffer definition (pkg/proto/charts).
This packe provides utilities for serializing and deserializing charts.
A chart can be represented on the file system in one of two ways:
@@ -27,18 +27,18 @@ A chart can be represented on the file system in one of two ways:
This package provides utilitites for working with those file formats.
-The preferred way of loading a chart is using 'chartutil.Load`:
+The preferred way of loading a chart is using 'loader.Load`:
- chart, err := chartutil.Load(filename)
+ chart, err := loader.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
+'loader.LoadArchive()' will read in the data, uncompress it, and unpack it
into a Chart.
-When creating charts in memory, use the 'k8s.io/helm/pkg/proto/hapi/chart'
+When creating charts in memory, use the 'k8s.io/helm/pkg/proto/chart'
package directly.
*/
package chartutil // import "k8s.io/helm/pkg/chartutil"
diff --git a/pkg/chartutil/expand.go b/pkg/chartutil/expand.go
index 126e14e80..7f4fc8bd5 100644
--- a/pkg/chartutil/expand.go
+++ b/pkg/chartutil/expand.go
@@ -40,8 +40,8 @@ func Expand(dir string, r io.Reader) error {
return err
}
- //split header name and create missing directories
- d, _ := filepath.Split(header.Name)
+ // split header name and create missing directories
+ d := filepath.Dir(header.Name)
fullDir := filepath.Join(dir, d)
_, err = os.Stat(fullDir)
if err != nil && d != "" {
@@ -63,8 +63,7 @@ func Expand(dir string, r io.Reader) error {
if err != nil {
return err
}
- _, err = io.Copy(file, tr)
- if err != nil {
+ if _, err = io.Copy(file, tr); err != nil {
file.Close()
return err
}
diff --git a/pkg/chartutil/files.go b/pkg/chartutil/files.go
index ca149a5e7..af61a24a9 100644
--- a/pkg/chartutil/files.go
+++ b/pkg/chartutil/files.go
@@ -26,7 +26,7 @@ import (
"github.com/ghodss/yaml"
"github.com/gobwas/glob"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
)
// Files is a map of files in a chart that can be accessed from a template.
@@ -35,7 +35,7 @@ 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 []*chart.File) Files {
- files := map[string][]byte{}
+ files := make(map[string][]byte)
for _, f := range from {
files[f.Name] = f.Data
}
@@ -50,11 +50,10 @@ func NewFiles(from []*chart.File) Files {
// This is intended to be accessed from within a template, so a missed key returns
// an empty []byte.
func (f Files) GetBytes(name string) []byte {
- v, ok := f[name]
- if !ok {
- return []byte{}
+ if v, ok := f[name]; ok {
+ return v
}
- return v
+ return []byte{}
}
// Get returns a string representation of the given file.
@@ -97,7 +96,7 @@ func (f Files) Glob(pattern string) Files {
// (regardless of path) should be unique.
//
// This is designed to be called from a template, and will return empty string
-// (via ToYaml function) if it cannot be serialized to YAML, or if the Files
+// (via ToYAML function) if it cannot be serialized to YAML, or if the Files
// object is nil.
//
// The output will not be indented, so you will want to pipe this to the
@@ -110,14 +109,14 @@ func (f Files) AsConfig() string {
return ""
}
- m := map[string]string{}
+ m := make(map[string]string)
// Explicitly convert to strings, and file names
for k, v := range f {
m[path.Base(k)] = string(v)
}
- return ToYaml(m)
+ return ToYAML(m)
}
// AsSecrets returns the base64-encoded value of a Files object suitable for
@@ -126,7 +125,7 @@ func (f Files) AsConfig() string {
// (regardless of path) should be unique.
//
// This is designed to be called from a template, and will return empty string
-// (via ToYaml function) if it cannot be serialized to YAML, or if the Files
+// (via ToYAML function) if it cannot be serialized to YAML, or if the Files
// object is nil.
//
// The output will not be indented, so you will want to pipe this to the
@@ -139,13 +138,13 @@ func (f Files) AsSecrets() string {
return ""
}
- m := map[string]string{}
+ m := make(map[string]string)
for k, v := range f {
m[path.Base(k)] = base64.StdEncoding.EncodeToString(v)
}
- return ToYaml(m)
+ return ToYAML(m)
}
// Lines returns each line of a named file (split by "\n") as a slice, so it can
@@ -163,11 +162,11 @@ func (f Files) Lines(path string) []string {
return strings.Split(string(f[path]), "\n")
}
-// ToYaml takes an interface, marshals it to yaml, and returns a string. It will
+// ToYAML takes an interface, marshals it to yaml, and returns a string. It will
// always return a string, even on marshal error (empty string).
//
// This is designed to be called from a template.
-func ToYaml(v interface{}) string {
+func ToYAML(v interface{}) string {
data, err := yaml.Marshal(v)
if err != nil {
// Swallow errors inside of a template.
@@ -176,13 +175,13 @@ func ToYaml(v interface{}) string {
return strings.TrimSuffix(string(data), "\n")
}
-// FromYaml converts a YAML document into a map[string]interface{}.
+// FromYAML converts a YAML document into a map[string]interface{}.
//
// This is not a general-purpose YAML parser, and will not parse all valid
// YAML documents. Additionally, because its intended use is within templates
// it tolerates errors. It will insert the returned error message string into
// m["Error"] in the returned map.
-func FromYaml(str string) map[string]interface{} {
+func FromYAML(str string) map[string]interface{} {
m := map[string]interface{}{}
if err := yaml.Unmarshal([]byte(str), &m); err != nil {
@@ -191,11 +190,11 @@ func FromYaml(str string) map[string]interface{} {
return m
}
-// ToToml takes an interface, marshals it to toml, and returns a string. It will
+// ToTOML takes an interface, marshals it to toml, and returns a string. It will
// always return a string, even on marshal error (empty string).
//
// This is designed to be called from a template.
-func ToToml(v interface{}) string {
+func ToTOML(v interface{}) string {
b := bytes.NewBuffer(nil)
e := toml.NewEncoder(b)
err := e.Encode(v)
@@ -205,11 +204,11 @@ func ToToml(v interface{}) string {
return b.String()
}
-// ToJson takes an interface, marshals it to json, and returns a string. It will
+// ToJSON takes an interface, marshals it to json, and returns a string. It will
// always return a string, even on marshal error (empty string).
//
// This is designed to be called from a template.
-func ToJson(v interface{}) string {
+func ToJSON(v interface{}) string {
data, err := json.Marshal(v)
if err != nil {
// Swallow errors inside of a template.
@@ -218,14 +217,14 @@ func ToJson(v interface{}) string {
return string(data)
}
-// FromJson converts a JSON document into a map[string]interface{}.
+// FromJSON converts a JSON document into a map[string]interface{}.
//
// This is not a general-purpose JSON parser, and will not parse all valid
// JSON documents. Additionally, because its intended use is within templates
// it tolerates errors. It will insert the returned error message string into
// m["Error"] in the returned map.
-func FromJson(str string) map[string]interface{} {
- m := map[string]interface{}{}
+func FromJSON(str string) map[string]interface{} {
+ m := make(map[string]interface{})
if err := json.Unmarshal([]byte(str), &m); err != nil {
m["Error"] = err.Error()
diff --git a/pkg/chartutil/files_test.go b/pkg/chartutil/files_test.go
index a6c9d1b65..d8174723d 100644
--- a/pkg/chartutil/files_test.go
+++ b/pkg/chartutil/files_test.go
@@ -97,7 +97,7 @@ func TestLines(t *testing.T) {
as.Equal("bar", out[0])
}
-func TestToYaml(t *testing.T) {
+func TestToYAML(t *testing.T) {
expect := "foo: bar"
v := struct {
Foo string `json:"foo"`
@@ -105,12 +105,12 @@ func TestToYaml(t *testing.T) {
Foo: "bar",
}
- if got := ToYaml(v); got != expect {
+ if got := ToYAML(v); got != expect {
t.Errorf("Expected %q, got %q", expect, got)
}
}
-func TestToToml(t *testing.T) {
+func TestToTOML(t *testing.T) {
expect := "foo = \"bar\"\n"
v := struct {
Foo string `toml:"foo"`
@@ -118,7 +118,7 @@ func TestToToml(t *testing.T) {
Foo: "bar",
}
- if got := ToToml(v); got != expect {
+ if got := ToTOML(v); got != expect {
t.Errorf("Expected %q, got %q", expect, got)
}
@@ -128,19 +128,19 @@ func TestToToml(t *testing.T) {
"sail": "white",
},
}
- got := ToToml(dict)
+ got := ToTOML(dict)
expect = "[mast]\n sail = \"white\"\n"
if got != expect {
t.Errorf("Expected:\n%s\nGot\n%s\n", expect, got)
}
}
-func TestFromYaml(t *testing.T) {
+func TestFromYAML(t *testing.T) {
doc := `hello: world
one:
two: three
`
- dict := FromYaml(doc)
+ dict := FromYAML(doc)
if err, ok := dict["Error"]; ok {
t.Fatalf("Parse error: %s", err)
}
@@ -160,13 +160,13 @@ one:
- two
- three
`
- dict = FromYaml(doc2)
+ dict = FromYAML(doc2)
if _, ok := dict["Error"]; !ok {
t.Fatal("Expected parser error")
}
}
-func TestToJson(t *testing.T) {
+func TestToJSON(t *testing.T) {
expect := `{"foo":"bar"}`
v := struct {
Foo string `json:"foo"`
@@ -174,12 +174,12 @@ func TestToJson(t *testing.T) {
Foo: "bar",
}
- if got := ToJson(v); got != expect {
+ if got := ToJSON(v); got != expect {
t.Errorf("Expected %q, got %q", expect, got)
}
}
-func TestFromJson(t *testing.T) {
+func TestFromJSON(t *testing.T) {
doc := `{
"hello": "world",
"one": {
@@ -187,7 +187,7 @@ func TestFromJson(t *testing.T) {
}
}
`
- dict := FromJson(doc)
+ dict := FromJSON(doc)
if err, ok := dict["Error"]; ok {
t.Fatalf("Parse error: %s", err)
}
@@ -209,7 +209,7 @@ func TestFromJson(t *testing.T) {
"three"
]
`
- dict = FromJson(doc2)
+ dict = FromJSON(doc2)
if _, ok := dict["Error"]; !ok {
t.Fatal("Expected parser error")
}
diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go
deleted file mode 100644
index 44bcbde03..000000000
--- a/pkg/chartutil/load.go
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
-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 (
- "archive/tar"
- "bytes"
- "compress/gzip"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/pkg/errors"
-
- "k8s.io/helm/pkg/hapi/chart"
- "k8s.io/helm/pkg/ignore"
- "k8s.io/helm/pkg/sympath"
-)
-
-// 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.
-//
-// If a .helmignore file is present, the directory loader will skip loading any files
-// matching it. But .helmignore is not evaluated when reading out of an archive.
-func Load(name string) (*chart.Chart, error) {
- fi, err := os.Stat(name)
- if err != nil {
- return nil, err
- }
- if fi.IsDir() {
- if validChart, err := IsChartDir(name); !validChart {
- return nil, err
- }
- return LoadDir(name)
- }
- return LoadFile(name)
-}
-
-// BufferedFile represents an archive file buffered for later processing.
-type BufferedFile struct {
- Name string
- Data []byte
-}
-
-// LoadArchive loads from a reader containing a compressed tar archive.
-func LoadArchive(in io.Reader) (*chart.Chart, error) {
- unzipped, err := gzip.NewReader(in)
- if err != nil {
- return &chart.Chart{}, err
- }
- defer unzipped.Close()
-
- files := []*BufferedFile{}
- tr := tar.NewReader(unzipped)
- for {
- b := bytes.NewBuffer(nil)
- hd, err := tr.Next()
- if err == io.EOF {
- break
- }
- if err != nil {
- return &chart.Chart{}, err
- }
-
- if hd.FileInfo().IsDir() {
- // Use this instead of hd.Typeflag because we don't have to do any
- // inference chasing.
- continue
- }
-
- // Archive could contain \ if generated on Windows
- delimiter := "/"
- if strings.ContainsRune(hd.Name, '\\') {
- delimiter = "\\"
- }
-
- parts := strings.Split(hd.Name, delimiter)
- n := strings.Join(parts[1:], delimiter)
-
- // Normalize the path to the / delimiter
- n = strings.Replace(n, delimiter, "/", -1)
-
- if parts[0] == "Chart.yaml" {
- return nil, errors.New("chart yaml not in base directory")
- }
-
- if _, err := io.Copy(b, tr); err != nil {
- return &chart.Chart{}, err
- }
-
- files = append(files, &BufferedFile{Name: n, Data: b.Bytes()})
- b.Reset()
- }
-
- if len(files) == 0 {
- return nil, errors.New("no files in chart archive")
- }
-
- return LoadFiles(files)
-}
-
-// LoadFiles loads from in-memory files.
-func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
- c := &chart.Chart{}
- subcharts := map[string][]*BufferedFile{}
-
- for _, f := range files {
- if f.Name == "Chart.yaml" {
- m, err := UnmarshalChartfile(f.Data)
- if err != nil {
- return c, err
- }
- c.Metadata = m
- } 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 = f.Data
- } else if strings.HasPrefix(f.Name, "templates/") {
- c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data})
- } else if strings.HasPrefix(f.Name, "charts/") {
- if filepath.Ext(f.Name) == ".prov" {
- c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
- continue
- }
- cname := strings.TrimPrefix(f.Name, "charts/")
- if strings.IndexAny(cname, "._") == 0 {
- // Ignore charts/ that start with . or _.
- continue
- }
- parts := strings.SplitN(cname, "/", 2)
- scname := parts[0]
- subcharts[scname] = append(subcharts[scname], &BufferedFile{Name: cname, Data: f.Data})
- } else {
- c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
- }
- }
-
- // Ensure that we got a Chart.yaml file
- if c.Metadata == nil {
- return c, errors.New("chart metadata (Chart.yaml) missing")
- }
- if c.Metadata.Name == "" {
- return c, errors.New("invalid chart (Chart.yaml): name must not be empty")
- }
-
- for n, files := range subcharts {
- var sc *chart.Chart
- var err error
- if strings.IndexAny(n, "_.") == 0 {
- continue
- } else if filepath.Ext(n) == ".tgz" {
- file := files[0]
- if file.Name != n {
- return c, errors.Errorf("error unpacking tar in %s: expected %s, got %s", c.Metadata.Name, n, file.Name)
- }
- // Untar the chart and add to c.Dependencies
- b := bytes.NewBuffer(file.Data)
- sc, err = LoadArchive(b)
- } else {
- // We have to trim the prefix off of every file, and ignore any file
- // that is in charts/, but isn't actually a chart.
- buff := make([]*BufferedFile, 0, len(files))
- for _, f := range files {
- parts := strings.SplitN(f.Name, "/", 2)
- if len(parts) < 2 {
- continue
- }
- f.Name = parts[1]
- buff = append(buff, f)
- }
- sc, err = LoadFiles(buff)
- }
-
- if err != nil {
- return c, errors.Wrapf(err, "error unpacking %s in %s", n, c.Metadata.Name)
- }
-
- c.Dependencies = append(c.Dependencies, sc)
- }
-
- return c, nil
-}
-
-// 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
- }
-
- // Just used for errors.
- c := &chart.Chart{}
-
- rules := ignore.Empty()
- ifile := filepath.Join(topdir, ignore.HelmIgnore)
- if _, err := os.Stat(ifile); err == nil {
- r, err := ignore.ParseFile(ifile)
- if err != nil {
- return c, err
- }
- rules = r
- }
- rules.AddDefaults()
-
- files := []*BufferedFile{}
- topdir += string(filepath.Separator)
-
- walk := func(name string, fi os.FileInfo, err error) error {
- n := strings.TrimPrefix(name, topdir)
- if n == "" {
- // No need to process top level. Avoid bug with helmignore .* matching
- // empty names. See issue 1779.
- return nil
- }
-
- // Normalize to / since it will also work on Windows
- n = filepath.ToSlash(n)
-
- if err != nil {
- return err
- }
- if fi.IsDir() {
- // Directory-based ignore rules should involve skipping the entire
- // contents of that directory.
- if rules.Ignore(n, fi) {
- return filepath.SkipDir
- }
- return nil
- }
-
- // If a .helmignore file matches, skip this file.
- if rules.Ignore(n, fi) {
- return nil
- }
-
- data, err := ioutil.ReadFile(name)
- if err != nil {
- return errors.Wrapf(err, "error reading %s", n)
- }
-
- files = append(files, &BufferedFile{Name: n, Data: data})
- return nil
- }
- if err = sympath.Walk(topdir, walk); err != nil {
- return c, err
- }
-
- return LoadFiles(files)
-}
diff --git a/pkg/chartutil/requirements.go b/pkg/chartutil/requirements.go
index e43c44e13..218457cab 100644
--- a/pkg/chartutil/requirements.go
+++ b/pkg/chartutil/requirements.go
@@ -18,209 +18,88 @@ package chartutil
import (
"log"
"strings"
- "time"
"github.com/ghodss/yaml"
- "github.com/pkg/errors"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/version"
)
-const (
- requirementsName = "requirements.yaml"
- lockfileName = "requirements.lock"
-)
-
-var (
- // ErrRequirementsNotFound indicates that a requirements.yaml is not found.
- ErrRequirementsNotFound = errors.New(requirementsName + " not found")
- // ErrLockfileNotFound indicates that a requirements.lock is not found.
- ErrLockfileNotFound = errors.New(lockfileName + " not found")
-)
-
-// Dependency describes a chart upon which another chart depends.
-//
-// Dependencies can be used to express developer intent, or to capture the state
-// of a chart.
-type Dependency struct {
- // Name is the name of the dependency.
- //
- // This must mach the name in the dependency's Chart.yaml.
- Name string `json:"name"`
- // Version is the version (range) of this chart.
- //
- // A lock file will always produce a single version, while a dependency
- // may contain a semantic version range.
- Version string `json:"version,omitempty"`
- // The URL to the repository.
- //
- // Appending `index.yaml` to this string should result in a URL that can be
- // used to fetch the repository index.
- Repository string `json:"repository"`
- // A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled )
- Condition string `json:"condition,omitempty"`
- // Tags can be used to group charts for enabling/disabling together
- Tags []string `json:"tags,omitempty"`
- // Enabled bool determines if chart should be loaded
- Enabled bool `json:"enabled,omitempty"`
- // ImportValues holds the mapping of source values to parent key to be imported. Each item can be a
- // string or pair of child/parent sublist items.
- ImportValues []interface{} `json:"import-values,omitempty"`
- // Alias usable alias to be used for the chart
- Alias string `json:"alias,omitempty"`
-}
-
-// ErrNoRequirementsFile to detect error condition
-type ErrNoRequirementsFile error
-
-// Requirements is a list of requirements for a chart.
-//
-// Requirements are charts upon which this chart depends. This expresses
-// developer intent.
-type Requirements struct {
- Dependencies []*Dependency `json:"dependencies"`
-}
-
-// RequirementsLock is a lock file for requirements.
-//
-// It represents the state that the dependencies should be in.
-type RequirementsLock struct {
- // Genderated is the date the lock file was last generated.
- Generated time.Time `json:"generated"`
- // Digest is a hash of the requirements file used to generate it.
- Digest string `json:"digest"`
- // Dependencies is the list of dependencies that this lock file has locked.
- Dependencies []*Dependency `json:"dependencies"`
-}
-
-// LoadRequirements loads a requirements file from an in-memory chart.
-func LoadRequirements(c *chart.Chart) (*Requirements, error) {
- var data []byte
- for _, f := range c.Files {
- if f.Name == requirementsName {
- data = f.Data
- }
- }
- if len(data) == 0 {
- return nil, ErrRequirementsNotFound
- }
- r := &Requirements{}
- return r, yaml.Unmarshal(data, r)
-}
-
-// LoadRequirementsLock loads a requirements lock file.
-func LoadRequirementsLock(c *chart.Chart) (*RequirementsLock, error) {
- var data []byte
- for _, f := range c.Files {
- if f.Name == lockfileName {
- data = f.Data
- }
- }
- if len(data) == 0 {
- return nil, ErrLockfileNotFound
- }
- r := &RequirementsLock{}
- return r, yaml.Unmarshal(data, r)
-}
-
// ProcessRequirementsConditions disables charts based on condition path value in values
-func ProcessRequirementsConditions(reqs *Requirements, cvals Values) {
- var cond string
- var conds []string
- if reqs == nil || len(reqs.Dependencies) == 0 {
+func ProcessRequirementsConditions(reqs *chart.Requirements, cvals Values) {
+ if reqs == nil {
return
}
for _, r := range reqs.Dependencies {
var hasTrue, hasFalse bool
- cond = r.Condition
- // check for list
- if len(cond) > 0 {
- if strings.Contains(cond, ",") {
- conds = strings.Split(strings.TrimSpace(cond), ",")
- } else {
- conds = []string{strings.TrimSpace(cond)}
- }
- for _, c := range conds {
- if len(c) > 0 {
- // retrieve value
- vv, err := cvals.PathValue(c)
- if err == nil {
- // if not bool, warn
- if bv, ok := vv.(bool); ok {
- if bv {
- hasTrue = true
- } else {
- hasFalse = true
- }
+ for _, c := range strings.Split(strings.TrimSpace(r.Condition), ",") {
+ if len(c) > 0 {
+ // retrieve value
+ vv, err := cvals.PathValue(c)
+ if err == nil {
+ // if not bool, warn
+ if bv, ok := vv.(bool); ok {
+ if bv {
+ hasTrue = true
} else {
- log.Printf("Warning: Condition path '%s' for chart %s returned non-bool value", c, r.Name)
+ hasFalse = true
}
- } else if _, ok := err.(ErrNoValue); !ok {
- // this is a real error
- log.Printf("Warning: PathValue returned error %v", err)
-
- }
- if vv != nil {
- // got first value, break loop
- break
+ } else {
+ log.Printf("Warning: Condition path '%s' for chart %s returned non-bool value", c, r.Name)
}
+ } else if _, ok := err.(ErrNoValue); !ok {
+ // this is a real error
+ log.Printf("Warning: PathValue returned error %v", err)
+ }
+ if vv != nil {
+ // got first value, break loop
+ break
}
- }
- if !hasTrue && hasFalse {
- r.Enabled = false
- } else if hasTrue {
- r.Enabled = true
-
}
}
+ if !hasTrue && hasFalse {
+ r.Enabled = false
+ } else if hasTrue {
+ r.Enabled = true
+ }
}
-
}
// ProcessRequirementsTags disables charts based on tags in values
-func ProcessRequirementsTags(reqs *Requirements, cvals Values) {
- vt, err := cvals.Table("tags")
- if err != nil {
+func ProcessRequirementsTags(reqs *chart.Requirements, cvals Values) {
+ if reqs == nil {
return
-
}
- if reqs == nil || len(reqs.Dependencies) == 0 {
+ vt, err := cvals.Table("tags")
+ if err != nil {
return
}
for _, r := range reqs.Dependencies {
- if len(r.Tags) > 0 {
- tags := r.Tags
-
- var hasTrue, hasFalse bool
- for _, k := range tags {
- if b, ok := vt[k]; ok {
- // if not bool, warn
- if bv, ok := b.(bool); ok {
- if bv {
- hasTrue = true
- } else {
- hasFalse = true
- }
+ var hasTrue, hasFalse bool
+ for _, k := range r.Tags {
+ if b, ok := vt[k]; ok {
+ // if not bool, warn
+ if bv, ok := b.(bool); ok {
+ if bv {
+ hasTrue = true
} else {
- log.Printf("Warning: Tag '%s' for chart %s returned non-bool value", k, r.Name)
+ hasFalse = true
}
+ } else {
+ log.Printf("Warning: Tag '%s' for chart %s returned non-bool value", k, r.Name)
}
}
- if !hasTrue && hasFalse {
- r.Enabled = false
- } else if hasTrue || !hasTrue && !hasFalse {
- r.Enabled = true
-
- }
-
+ }
+ if !hasTrue && hasFalse {
+ r.Enabled = false
+ } else if hasTrue || !hasTrue && !hasFalse {
+ r.Enabled = true
}
}
-
}
-func getAliasDependency(charts []*chart.Chart, aliasChart *Dependency) *chart.Chart {
+func getAliasDependency(charts []*chart.Chart, aliasChart *chart.Dependency) *chart.Chart {
var chartFound chart.Chart
for _, existingChart := range charts {
if existingChart == nil {
@@ -248,14 +127,7 @@ func getAliasDependency(charts []*chart.Chart, aliasChart *Dependency) *chart.Ch
// ProcessRequirementsEnabled removes disabled charts from dependencies
func ProcessRequirementsEnabled(c *chart.Chart, v []byte) error {
- reqs, err := LoadRequirements(c)
- if err != nil {
- // if not just missing requirements file, return error
- if nerr, ok := err.(ErrNoRequirementsFile); !ok {
- return nerr
- }
-
- // no requirements to process
+ if c.Requirements == nil {
return nil
}
@@ -265,9 +137,9 @@ func ProcessRequirementsEnabled(c *chart.Chart, v []byte) error {
// However, if the dependency is already specified in requirements.yaml
// we should not add it, as it would be anyways processed from requirements.yaml
- for _, existingDependency := range c.Dependencies {
+ for _, existingDependency := range c.Dependencies() {
var dependencyFound bool
- for _, req := range reqs.Dependencies {
+ for _, req := range c.Requirements.Dependencies {
if existingDependency.Metadata.Name == req.Name && version.IsCompatibleRange(req.Version, existingDependency.Metadata.Version) {
dependencyFound = true
break
@@ -278,18 +150,18 @@ func ProcessRequirementsEnabled(c *chart.Chart, v []byte) error {
}
}
- for _, req := range reqs.Dependencies {
- if chartDependency := getAliasDependency(c.Dependencies, req); chartDependency != nil {
+ for _, req := range c.Requirements.Dependencies {
+ if chartDependency := getAliasDependency(c.Dependencies(), req); chartDependency != nil {
chartDependencies = append(chartDependencies, chartDependency)
}
if req.Alias != "" {
req.Name = req.Alias
}
}
- c.Dependencies = chartDependencies
+ c.SetDependencies(chartDependencies...)
// set all to true
- for _, lr := range reqs.Dependencies {
+ for _, lr := range c.Requirements.Dependencies {
lr.Enabled = true
}
cvals, err := CoalesceValues(c, v)
@@ -302,34 +174,32 @@ func ProcessRequirementsEnabled(c *chart.Chart, v []byte) error {
return err
}
// flag dependencies as enabled/disabled
- ProcessRequirementsTags(reqs, cvals)
- ProcessRequirementsConditions(reqs, cvals)
+ ProcessRequirementsTags(c.Requirements, cvals)
+ ProcessRequirementsConditions(c.Requirements, cvals)
// make a map of charts to remove
- rm := map[string]bool{}
- for _, r := range reqs.Dependencies {
+ rm := map[string]struct{}{}
+ for _, r := range c.Requirements.Dependencies {
if !r.Enabled {
// remove disabled chart
- rm[r.Name] = true
+ rm[r.Name] = struct{}{}
}
}
// don't keep disabled charts in new slice
cd := []*chart.Chart{}
- copy(cd, c.Dependencies[:0])
- for _, n := range c.Dependencies {
+ copy(cd, c.Dependencies()[:0])
+ for _, n := range c.Dependencies() {
if _, ok := rm[n.Metadata.Name]; !ok {
cd = append(cd, n)
}
-
}
+
// recursively call self to process sub dependencies
for _, t := range cd {
- err := ProcessRequirementsEnabled(t, yvals)
- // if its not just missing requirements file, return error
- if nerr, ok := err.(ErrNoRequirementsFile); !ok && err != nil {
- return nerr
+ if err := ProcessRequirementsEnabled(t, yvals); err != nil {
+ return err
}
}
- c.Dependencies = cd
+ c.SetDependencies(cd...)
return nil
}
@@ -361,30 +231,13 @@ func pathToMap(path string, data map[string]interface{}) map[string]interface{}
n[i][k] = n[z]
}
}
-
return n[0]
}
-// getParents returns a slice of parent charts in reverse order.
-func getParents(c *chart.Chart, out []*chart.Chart) []*chart.Chart {
- if len(out) == 0 {
- out = []*chart.Chart{c}
- }
- for _, ch := range c.Dependencies {
- if len(ch.Dependencies) > 0 {
- out = append(out, ch)
- out = getParents(ch, out)
- }
- }
-
- return out
-}
-
// processImportValues merges values from child to parent based on the chart's dependencies' ImportValues field.
func processImportValues(c *chart.Chart) error {
- reqs, err := LoadRequirements(c)
- if err != nil {
- return err
+ if c.Requirements == nil {
+ return nil
}
// combine chart values and empty config to get Values
cvals, err := CoalesceValues(c, []byte{})
@@ -393,45 +246,41 @@ func processImportValues(c *chart.Chart) error {
}
b := make(map[string]interface{})
// import values from each dependency if specified in import-values
- for _, r := range reqs.Dependencies {
- if len(r.ImportValues) > 0 {
- var outiv []interface{}
- for _, riv := range r.ImportValues {
- switch iv := riv.(type) {
- case map[string]interface{}:
- nm := map[string]string{
- "child": iv["child"].(string),
- "parent": iv["parent"].(string),
- }
- outiv = append(outiv, nm)
- s := r.Name + "." + nm["child"]
- // get child table
- vv, err := cvals.Table(s)
- if err != nil {
- log.Printf("Warning: ImportValues missing table: %v", err)
- continue
- }
- // create value map from child to be merged into parent
- vm := pathToMap(nm["parent"], vv.AsMap())
- b = coalesceTables(cvals, vm)
- case string:
- nm := map[string]string{
- "child": "exports." + iv,
- "parent": ".",
- }
- outiv = append(outiv, nm)
- s := r.Name + "." + nm["child"]
- vm, err := cvals.Table(s)
- if err != nil {
- log.Printf("Warning: ImportValues missing table: %v", err)
- continue
- }
- b = coalesceTables(b, vm.AsMap())
+ for _, r := range c.Requirements.Dependencies {
+ var outiv []interface{}
+ for _, riv := range r.ImportValues {
+ switch iv := riv.(type) {
+ case map[string]interface{}:
+ nm := map[string]string{
+ "child": iv["child"].(string),
+ "parent": iv["parent"].(string),
+ }
+ outiv = append(outiv, nm)
+ // get child table
+ vv, err := cvals.Table(r.Name + "." + nm["child"])
+ if err != nil {
+ log.Printf("Warning: ImportValues missing table: %v", err)
+ continue
+ }
+ // create value map from child to be merged into parent
+ vm := pathToMap(nm["parent"], vv.AsMap())
+ b = coalesceTables(cvals, vm)
+ case string:
+ nm := map[string]string{
+ "child": "exports." + iv,
+ "parent": ".",
}
+ outiv = append(outiv, nm)
+ vm, err := cvals.Table(r.Name + "." + nm["child"])
+ if err != nil {
+ log.Printf("Warning: ImportValues missing table: %v", err)
+ continue
+ }
+ b = coalesceTables(b, vm.AsMap())
}
- // set our formatted import values
- r.ImportValues = outiv
}
+ // set our formatted import values
+ r.ImportValues = outiv
}
b = coalesceTables(b, cvals)
y, err := yaml.Marshal(b)
@@ -447,10 +296,11 @@ func processImportValues(c *chart.Chart) error {
// ProcessRequirementsImportValues imports specified chart values from child to parent.
func ProcessRequirementsImportValues(c *chart.Chart) error {
- pc := getParents(c, nil)
- for i := len(pc) - 1; i >= 0; i-- {
- processImportValues(pc[i])
+ for _, d := range c.Dependencies() {
+ // recurse
+ if err := ProcessRequirementsImportValues(d); err != nil {
+ return err
+ }
}
-
- return nil
+ return processImportValues(c)
}
diff --git a/pkg/chartutil/requirements_test.go b/pkg/chartutil/requirements_test.go
index 0206f0d2f..f5425e8f7 100644
--- a/pkg/chartutil/requirements_test.go
+++ b/pkg/chartutil/requirements_test.go
@@ -20,12 +20,13 @@ import (
"strconv"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/version"
)
func TestLoadRequirements(t *testing.T) {
- c, err := Load("testdata/frobnitz")
+ c, err := loader.Load("testdata/frobnitz")
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
@@ -33,158 +34,89 @@ func TestLoadRequirements(t *testing.T) {
}
func TestLoadRequirementsLock(t *testing.T) {
- c, err := Load("testdata/frobnitz")
+ c, err := loader.Load("testdata/frobnitz")
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
verifyRequirementsLock(t, c)
}
-func TestRequirementsTagsNonValue(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // tags with no effect
- v := []byte("tags:\n nothinguseful: false\n\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart", "subchart1", "subcharta", "subchartb"}
-
- verifyRequirementsEnabled(t, c, v, e)
-}
-func TestRequirementsTagsDisabledL1(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // tags disabling a group
- v := []byte("tags:\n front-end: false\n\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart"}
-
- verifyRequirementsEnabled(t, c, v, e)
-}
-func TestRequirementsTagsEnabledL1(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // tags disabling a group and enabling a different group
- v := []byte("tags:\n front-end: false\n\n back-end: true\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart", "subchart2", "subchartb", "subchartc"}
-
- verifyRequirementsEnabled(t, c, v, e)
-}
-
-func TestRequirementsTagsDisabledL2(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // tags disabling only children, children still enabled since tag front-end=true in values.yaml
- v := []byte("tags:\n subcharta: false\n\n subchartb: false\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart", "subchart1", "subcharta", "subchartb"}
-
- verifyRequirementsEnabled(t, c, v, e)
-}
-func TestRequirementsTagsDisabledL1Mixed(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // tags disabling all parents/children with additional tag re-enabling a parent
- v := []byte("tags:\n front-end: false\n\n subchart1: true\n\n back-end: false\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart", "subchart1"}
-
- verifyRequirementsEnabled(t, c, v, e)
-}
-func TestRequirementsConditionsNonValue(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // tags with no effect
- v := []byte("subchart1:\n nothinguseful: false\n\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart", "subchart1", "subcharta", "subchartb"}
-
- verifyRequirementsEnabled(t, c, v, e)
-}
-func TestRequirementsConditionsEnabledL1Both(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // conditions enabling the parent charts, but back-end (b, c) is still disabled via values.yaml
- v := []byte("subchart1:\n enabled: true\nsubchart2:\n enabled: true\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart", "subchart1", "subchart2", "subcharta", "subchartb"}
-
- verifyRequirementsEnabled(t, c, v, e)
-}
-func TestRequirementsConditionsDisabledL1Both(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // conditions disabling the parent charts, effectively disabling children
- v := []byte("subchart1:\n enabled: false\nsubchart2:\n enabled: false\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart"}
-
- verifyRequirementsEnabled(t, c, v, e)
-}
-
-func TestRequirementsConditionsSecond(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // conditions a child using the second condition path of child's condition
- v := []byte("subchart1:\n subcharta:\n enabled: false\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart", "subchart1", "subchartb"}
-
- verifyRequirementsEnabled(t, c, v, e)
-}
-func TestRequirementsCombinedDisabledL2(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
- }
- // tags enabling a parent/child group with condition disabling one child
- v := []byte("subchartc:\n enabled: false\ntags:\n back-end: true\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart", "subchart1", "subchart2", "subcharta", "subchartb", "subchartb"}
- verifyRequirementsEnabled(t, c, v, e)
-}
-func TestRequirementsCombinedDisabledL1(t *testing.T) {
- c, err := Load("testdata/subpop")
- if err != nil {
- t.Fatalf("Failed to load testdata: %s", err)
+func TestRequirementsEnabled(t *testing.T) {
+ tests := []struct {
+ name string
+ v []byte
+ e []string // expected charts including duplicates in alphanumeric order
+ }{{
+ "tags with no effect",
+ []byte("tags:\n nothinguseful: false\n\n"),
+ []string{"parentchart", "subchart1", "subcharta", "subchartb"},
+ }, {
+ "tags with no effect",
+ []byte("tags:\n nothinguseful: false\n\n"),
+ []string{"parentchart", "subchart1", "subcharta", "subchartb"},
+ }, {
+ "tags disabling a group",
+ []byte("tags:\n front-end: false\n\n"),
+ []string{"parentchart"},
+ }, {
+ "tags disabling a group and enabling a different group",
+ []byte("tags:\n front-end: false\n\n back-end: true\n"),
+ []string{"parentchart", "subchart2", "subchartb", "subchartc"},
+ }, {
+ "tags disabling only children, children still enabled since tag front-end=true in values.yaml",
+ []byte("tags:\n subcharta: false\n\n subchartb: false\n"),
+ []string{"parentchart", "subchart1", "subcharta", "subchartb"},
+ }, {
+ "tags disabling all parents/children with additional tag re-enabling a parent",
+ []byte("tags:\n front-end: false\n\n subchart1: true\n\n back-end: false\n"),
+ []string{"parentchart", "subchart1"},
+ }, {
+ "tags with no effect",
+ []byte("subchart1:\n nothinguseful: false\n\n"),
+ []string{"parentchart", "subchart1", "subcharta", "subchartb"},
+ }, {
+ "conditions enabling the parent charts, but back-end (b, c) is still disabled via values.yaml",
+ []byte("subchart1:\n enabled: true\nsubchart2:\n enabled: true\n"),
+ []string{"parentchart", "subchart1", "subchart2", "subcharta", "subchartb"},
+ }, {
+ "conditions disabling the parent charts, effectively disabling children",
+ []byte("subchart1:\n enabled: false\nsubchart2:\n enabled: false\n"),
+ []string{"parentchart"},
+ }, {
+ "conditions a child using the second condition path of child's condition",
+ []byte("subchart1:\n subcharta:\n enabled: false\n"),
+ []string{"parentchart", "subchart1", "subchartb"},
+ }, {
+ "tags enabling a parent/child group with condition disabling one child",
+ []byte("subchartc:\n enabled: false\ntags:\n back-end: true\n"),
+ []string{"parentchart", "subchart1", "subchart2", "subcharta", "subchartb", "subchartb"},
+ }, {
+ "tags will not enable a child if parent is explicitly disabled with condition",
+ []byte("subchart1:\n enabled: false\ntags:\n front-end: true\n"),
+ []string{"parentchart"},
+ }}
+
+ for _, tc := range tests {
+ c, err := loader.Load("testdata/subpop")
+ if err != nil {
+ t.Fatalf("Failed to load testdata: %s", err)
+ }
+ t.Run(tc.name, func(t *testing.T) {
+ verifyRequirementsEnabled(t, c, tc.v, tc.e)
+ })
}
- // tags will not enable a child if parent is explicitly disabled with condition
- v := []byte("subchart1:\n enabled: false\ntags:\n front-end: true\n")
- // expected charts including duplicates in alphanumeric order
- e := []string{"parentchart"}
-
- verifyRequirementsEnabled(t, c, v, e)
}
func verifyRequirementsEnabled(t *testing.T, c *chart.Chart, v []byte, e []string) {
- out := []*chart.Chart{}
- err := ProcessRequirementsEnabled(c, v)
- if err != nil {
+ if err := ProcessRequirementsEnabled(c, v); err != nil {
t.Errorf("Error processing enabled requirements %v", err)
}
- out = extractCharts(c, out)
+
+ out := extractCharts(c, nil)
// build list of chart names
- p := []string{}
+ var p []string
for _, r := range out {
- p = append(p, r.Metadata.Name)
+ p = append(p, r.Name())
}
//sort alphanumeric and compare to expectations
sort.Strings(p)
@@ -201,23 +133,21 @@ func verifyRequirementsEnabled(t *testing.T, c *chart.Chart, v []byte, e []strin
// extractCharts recursively searches chart dependencies returning all charts found
func extractCharts(c *chart.Chart, out []*chart.Chart) []*chart.Chart {
-
- if len(c.Metadata.Name) > 0 {
+ if len(c.Name()) > 0 {
out = append(out, c)
}
- for _, d := range c.Dependencies {
+ for _, d := range c.Dependencies() {
out = extractCharts(d, out)
}
return out
}
+
func TestProcessRequirementsImportValues(t *testing.T) {
- c, err := Load("testdata/subpop")
+ c, err := loader.Load("testdata/subpop")
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
- v := []byte{}
-
e := make(map[string]string)
e["imported-chart1.SC1bool"] = "true"
@@ -279,17 +209,16 @@ func TestProcessRequirementsImportValues(t *testing.T) {
e["SCBexported2A"] = "blaster"
e["global.SC1exported2.all.SC1exported3"] = "SC1expstr"
- verifyRequirementsImportValues(t, c, v, e)
+ verifyRequirementsImportValues(t, c, e)
}
-func verifyRequirementsImportValues(t *testing.T, c *chart.Chart, v []byte, e map[string]string) {
- err := ProcessRequirementsImportValues(c)
- if err != nil {
- t.Errorf("Error processing import values requirements %v", err)
+func verifyRequirementsImportValues(t *testing.T, c *chart.Chart, e map[string]string) {
+ if err := ProcessRequirementsImportValues(c); err != nil {
+ t.Fatalf("Error processing import values requirements %v", err)
}
cc, err := ReadValues(c.Values)
if err != nil {
- t.Errorf("Error reading import values %v", err)
+ t.Fatalf("Error reading import values %v", err)
}
for kk, vv := range e {
pv, err := cc.PathValue(kk)
@@ -317,182 +246,203 @@ func verifyRequirementsImportValues(t *testing.T, c *chart.Chart, v []byte, e ma
return
}
}
-
}
}
func TestGetAliasDependency(t *testing.T) {
- c, err := Load("testdata/frobnitz")
+ c, err := loader.Load("testdata/frobnitz")
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
- req, err := LoadRequirements(c)
- if err != nil {
- t.Fatalf("Failed to load requirement for testdata: %s", err)
- }
+
+ req := c.Requirements
+
if len(req.Dependencies) == 0 {
t.Fatalf("There are no requirements to test")
}
// Success case
- aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0])
+ aliasChart := getAliasDependency(c.Dependencies(), req.Dependencies[0])
if aliasChart == nil {
t.Fatalf("Failed to get dependency chart for alias %s", req.Dependencies[0].Name)
}
if req.Dependencies[0].Alias != "" {
- if aliasChart.Metadata.Name != req.Dependencies[0].Alias {
- t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Alias, aliasChart.Metadata.Name)
+ if aliasChart.Name() != req.Dependencies[0].Alias {
+ t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Alias, aliasChart.Name())
}
- } else if aliasChart.Metadata.Name != req.Dependencies[0].Name {
- t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Name, aliasChart.Metadata.Name)
+ } else if aliasChart.Name() != req.Dependencies[0].Name {
+ t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Name, aliasChart.Name())
}
if req.Dependencies[0].Version != "" {
if !version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) {
t.Fatalf("Dependency chart version is not in the compatible range")
}
-
}
// Failure case
req.Dependencies[0].Name = "something-else"
- if aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]); aliasChart != nil {
- t.Fatalf("expected no chart but got %s", aliasChart.Metadata.Name)
+ if aliasChart := getAliasDependency(c.Dependencies(), req.Dependencies[0]); aliasChart != nil {
+ t.Fatalf("expected no chart but got %s", aliasChart.Name())
}
req.Dependencies[0].Version = "something else which is not in the compatible range"
if version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) {
t.Fatalf("Dependency chart version which is not in the compatible range should cause a failure other than a success ")
}
-
}
func TestDependentChartAliases(t *testing.T) {
- c, err := Load("testdata/dependent-chart-alias")
+ c, err := loader.Load("testdata/dependent-chart-alias")
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
- if len(c.Dependencies) == 0 {
+ if len(c.Dependencies()) == 0 {
t.Fatal("There are no dependencies to run this test")
}
- origLength := len(c.Dependencies)
+ origLength := len(c.Dependencies())
if err := ProcessRequirementsEnabled(c, c.Values); err != nil {
t.Fatalf("Expected no errors but got %q", err)
}
- if len(c.Dependencies) == origLength {
+ if len(c.Dependencies()) == origLength {
t.Fatal("Expected alias dependencies to be added, but did not got that")
}
- reqmts, err := LoadRequirements(c)
- if err != nil {
- t.Fatalf("Cannot load requirements for test chart, %v", err)
- }
-
- if len(c.Dependencies) != len(reqmts.Dependencies) {
- t.Fatalf("Expected number of chart dependencies %d, but got %d", len(reqmts.Dependencies), len(c.Dependencies))
+ if len(c.Dependencies()) != len(c.Requirements.Dependencies) {
+ t.Fatalf("Expected number of chart dependencies %d, but got %d", len(c.Requirements.Dependencies), len(c.Dependencies()))
}
-
}
func TestDependentChartWithSubChartsAbsentInRequirements(t *testing.T) {
- c, err := Load("testdata/dependent-chart-no-requirements-yaml")
+ c, err := loader.Load("testdata/dependent-chart-no-requirements-yaml")
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
- if len(c.Dependencies) != 2 {
- t.Fatalf("Expected 2 dependencies for this chart, but got %d", len(c.Dependencies))
+ if len(c.Dependencies()) != 2 {
+ t.Fatalf("Expected 2 dependencies for this chart, but got %d", len(c.Dependencies()))
}
- origLength := len(c.Dependencies)
+ origLength := len(c.Dependencies())
if err := ProcessRequirementsEnabled(c, c.Values); err != nil {
t.Fatalf("Expected no errors but got %q", err)
}
- if len(c.Dependencies) != origLength {
+ if len(c.Dependencies()) != origLength {
t.Fatal("Expected no changes in dependencies to be, but did something got changed")
}
-
}
func TestDependentChartWithSubChartsHelmignore(t *testing.T) {
- if _, err := Load("testdata/dependent-chart-helmignore"); err != nil {
+ if _, err := loader.Load("testdata/dependent-chart-helmignore"); err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
}
func TestDependentChartsWithSubChartsSymlink(t *testing.T) {
- c, err := Load("testdata/joonix")
+ c, err := loader.Load("testdata/joonix")
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
- if c.Metadata.Name != "joonix" {
- t.Fatalf("Unexpected chart name: %s", c.Metadata.Name)
+ if c.Name() != "joonix" {
+ t.Fatalf("Unexpected chart name: %s", c.Name())
}
- if n := len(c.Dependencies); n != 1 {
+ if n := len(c.Dependencies()); n != 1 {
t.Fatalf("Expected 1 dependency for this chart, but got %d", n)
}
}
func TestDependentChartsWithSubchartsAllSpecifiedInRequirements(t *testing.T) {
- c, err := Load("testdata/dependent-chart-with-all-in-requirements-yaml")
+ c, err := loader.Load("testdata/dependent-chart-with-all-in-requirements-yaml")
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
- if len(c.Dependencies) == 0 {
+ if len(c.Dependencies()) == 0 {
t.Fatal("There are no dependencies to run this test")
}
- origLength := len(c.Dependencies)
+ origLength := len(c.Dependencies())
if err := ProcessRequirementsEnabled(c, c.Values); err != nil {
t.Fatalf("Expected no errors but got %q", err)
}
- if len(c.Dependencies) != origLength {
+ if len(c.Dependencies()) != origLength {
t.Fatal("Expected no changes in dependencies to be, but did something got changed")
}
- reqmts, err := LoadRequirements(c)
- if err != nil {
- t.Fatalf("Cannot load requirements for test chart, %v", err)
- }
-
- if len(c.Dependencies) != len(reqmts.Dependencies) {
- t.Fatalf("Expected number of chart dependencies %d, but got %d", len(reqmts.Dependencies), len(c.Dependencies))
+ if len(c.Dependencies()) != len(c.Requirements.Dependencies) {
+ t.Fatalf("Expected number of chart dependencies %d, but got %d", len(c.Requirements.Dependencies), len(c.Dependencies()))
}
-
}
func TestDependentChartsWithSomeSubchartsSpecifiedInRequirements(t *testing.T) {
- c, err := Load("testdata/dependent-chart-with-mixed-requirements-yaml")
+ c, err := loader.Load("testdata/dependent-chart-with-mixed-requirements-yaml")
if err != nil {
t.Fatalf("Failed to load testdata: %s", err)
}
- if len(c.Dependencies) == 0 {
+ if len(c.Dependencies()) == 0 {
t.Fatal("There are no dependencies to run this test")
}
- origLength := len(c.Dependencies)
+ origLength := len(c.Dependencies())
if err := ProcessRequirementsEnabled(c, c.Values); err != nil {
t.Fatalf("Expected no errors but got %q", err)
}
- if len(c.Dependencies) != origLength {
+ if len(c.Dependencies()) != origLength {
t.Fatal("Expected no changes in dependencies to be, but did something got changed")
}
- reqmts, err := LoadRequirements(c)
- if err != nil {
- t.Fatalf("Cannot load requirements for test chart, %v", err)
+ if len(c.Dependencies()) <= len(c.Requirements.Dependencies) {
+ t.Fatalf("Expected more dependencies than specified in requirements.yaml(%d), but got %d", len(c.Requirements.Dependencies), len(c.Dependencies()))
}
+}
- if len(c.Dependencies) <= len(reqmts.Dependencies) {
- t.Fatalf("Expected more dependencies than specified in requirements.yaml(%d), but got %d", len(reqmts.Dependencies), len(c.Dependencies))
+func verifyRequirements(t *testing.T, c *chart.Chart) {
+ if len(c.Requirements.Dependencies) != 2 {
+ t.Errorf("Expected 2 requirements, got %d", len(c.Requirements.Dependencies))
+ }
+ tests := []*chart.Dependency{
+ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"},
+ {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"},
}
+ for i, tt := range tests {
+ d := c.Requirements.Dependencies[i]
+ if d.Name != tt.Name {
+ t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name)
+ }
+ if d.Version != tt.Version {
+ t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version)
+ }
+ if d.Repository != tt.Repository {
+ t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository)
+ }
+ }
+}
+func verifyRequirementsLock(t *testing.T, c *chart.Chart) {
+ if len(c.Requirements.Dependencies) != 2 {
+ t.Errorf("Expected 2 requirements, got %d", len(c.Requirements.Dependencies))
+ }
+ tests := []*chart.Dependency{
+ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"},
+ {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"},
+ }
+ for i, tt := range tests {
+ d := c.Requirements.Dependencies[i]
+ if d.Name != tt.Name {
+ t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name)
+ }
+ if d.Version != tt.Version {
+ t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version)
+ }
+ if d.Repository != tt.Repository {
+ t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository)
+ }
+ }
}
diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go
index 610f0aca0..aac6ab1d4 100644
--- a/pkg/chartutil/save.go
+++ b/pkg/chartutil/save.go
@@ -27,7 +27,7 @@ import (
"github.com/ghodss/yaml"
"github.com/pkg/errors"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
)
var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")
@@ -35,7 +35,7 @@ var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")
// SaveDir saves a chart as files in a directory.
func SaveDir(c *chart.Chart, dest string) error {
// Create the chart directory
- outdir := filepath.Join(dest, c.Metadata.Name)
+ outdir := filepath.Join(dest, c.Name())
if err := os.Mkdir(outdir, 0755); err != nil {
return err
}
@@ -83,7 +83,7 @@ func SaveDir(c *chart.Chart, dest string) error {
// Save dependencies
base := filepath.Join(outdir, ChartsDir)
- for _, dep := range c.Dependencies {
+ for _, dep := range c.Dependencies() {
// Here, we write each dependency as a tar file.
if _, err := Save(dep, base); err != nil {
return err
@@ -158,7 +158,7 @@ func Save(c *chart.Chart, outDir string) (string, error) {
}
func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
- base := filepath.Join(prefix, c.Metadata.Name)
+ base := filepath.Join(prefix, c.Name())
// Save Chart.yaml
cdata, err := yaml.Marshal(c.Metadata)
@@ -193,7 +193,7 @@ func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
}
// Save dependencies
- for _, dep := range c.Dependencies {
+ for _, dep := range c.Dependencies() {
if err := writeTarContents(out, dep, base+"/charts"); err != nil {
return err
}
@@ -212,8 +212,6 @@ func writeToTar(out *tar.Writer, name string, body []byte) error {
if err := out.WriteHeader(h); err != nil {
return err
}
- if _, err := out.Write(body); err != nil {
- return err
- }
- return nil
+ _, err := out.Write(body)
+ return err
}
diff --git a/pkg/chartutil/save_test.go b/pkg/chartutil/save_test.go
index 04db9cf80..e1760dad5 100644
--- a/pkg/chartutil/save_test.go
+++ b/pkg/chartutil/save_test.go
@@ -23,7 +23,8 @@ import (
"strings"
"testing"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
)
func TestSave(t *testing.T) {
@@ -55,13 +56,13 @@ func TestSave(t *testing.T) {
t.Fatalf("Expected %q to end with .tgz", where)
}
- c2, err := LoadFile(where)
+ c2, err := loader.LoadFile(where)
if err != nil {
t.Fatal(err)
}
- if c2.Metadata.Name != c.Metadata.Name {
- t.Fatalf("Expected chart archive to have %q, got %q", c.Metadata.Name, c2.Metadata.Name)
+ if c2.Name() != c.Name() {
+ t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name())
}
if !bytes.Equal(c2.Values, c.Values) {
t.Fatal("Values data did not match")
@@ -93,13 +94,13 @@ func TestSaveDir(t *testing.T) {
t.Fatalf("Failed to save: %s", err)
}
- c2, err := LoadDir(tmp + "/ahab")
+ c2, err := loader.LoadDir(tmp + "/ahab")
if err != nil {
t.Fatal(err)
}
- if c2.Metadata.Name != c.Metadata.Name {
- t.Fatalf("Expected chart archive to have %q, got %q", c.Metadata.Name, c2.Metadata.Name)
+ if c2.Name() != c.Name() {
+ t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name())
}
if !bytes.Equal(c2.Values, c.Values) {
t.Fatal("Values data did not match")
diff --git a/pkg/chartutil/values.go b/pkg/chartutil/values.go
index ad499b687..a9195c9f0 100644
--- a/pkg/chartutil/values.go
+++ b/pkg/chartutil/values.go
@@ -25,7 +25,7 @@ import (
"github.com/ghodss/yaml"
"github.com/pkg/errors"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
)
// ErrNoTable indicates that a chart does not have a matching table.
@@ -59,11 +59,10 @@ func (v Values) YAML() (string, error) {
//
// 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 {
+ for _, n := range strings.Split(name, ".") {
table, err = tableLookup(table, n)
if err != nil {
return table, err
@@ -110,7 +109,7 @@ func tableLookup(v Values, simple string) (Values, error) {
}
var e ErrNoTable = errors.Errorf("no table named %q", simple)
- return map[string]interface{}{}, e
+ return Values{}, e
}
// ReadValues will parse YAML byte data into a Values.
@@ -141,23 +140,23 @@ func ReadValuesFile(filename string) (Values, error) {
// - A chart has access to all of the variables for it, as well as all of
// the values destined for its dependencies.
func CoalesceValues(chrt *chart.Chart, vals []byte) (Values, error) {
+ var err error
cvals := Values{}
// Parse values if not nil. We merge these at the top level because
// the passed-in values are in the same namespace as the parent chart.
if vals != nil {
- evals, err := ReadValues(vals)
- if err != nil {
- return cvals, err
- }
- cvals, err = coalesce(chrt, evals)
+ cvals, err = ReadValues(vals)
if err != nil {
return cvals, err
}
}
- var err error
- cvals, err = coalesceDeps(chrt, cvals)
- return cvals, err
+ cvals, err = coalesce(chrt, cvals)
+ if err != nil {
+ return cvals, err
+ }
+
+ return coalesceDeps(chrt, cvals)
}
// coalesce coalesces the dest values and the chart values, giving priority to the dest values.
@@ -175,14 +174,14 @@ func coalesce(ch *chart.Chart, dest map[string]interface{}) (map[string]interfac
// coalesceDeps coalesces the dependencies of the given chart.
func coalesceDeps(chrt *chart.Chart, dest map[string]interface{}) (map[string]interface{}, error) {
- for _, subchart := range chrt.Dependencies {
- if c, ok := dest[subchart.Metadata.Name]; !ok {
+ for _, subchart := range chrt.Dependencies() {
+ if c, ok := dest[subchart.Name()]; !ok {
// If dest doesn't already have the key, create it.
- dest[subchart.Metadata.Name] = map[string]interface{}{}
+ dest[subchart.Name()] = make(map[string]interface{})
} else if !istable(c) {
- return dest, errors.Errorf("type mismatch on %s: %t", subchart.Metadata.Name, c)
+ return dest, errors.Errorf("type mismatch on %s: %t", subchart.Name(), c)
}
- if dv, ok := dest[subchart.Metadata.Name]; ok {
+ if dv, ok := dest[subchart.Name()]; ok {
dvmap := dv.(map[string]interface{})
// Get globals out of dest and merge them into dvmap.
@@ -190,7 +189,7 @@ func coalesceDeps(chrt *chart.Chart, dest map[string]interface{}) (map[string]in
var err error
// Now coalesce the rest of the values.
- dest[subchart.Metadata.Name], err = coalesce(subchart, dvmap)
+ dest[subchart.Name()], err = coalesce(subchart, dvmap)
if err != nil {
return dest, err
}
@@ -206,14 +205,14 @@ func coalesceGlobals(dest, src map[string]interface{}) map[string]interface{} {
var dg, sg map[string]interface{}
if destglob, ok := dest[GlobalKey]; !ok {
- dg = map[string]interface{}{}
+ dg = make(map[string]interface{})
} else if dg, ok = destglob.(map[string]interface{}); !ok {
log.Printf("warning: skipping globals because destination %s is not a table.", GlobalKey)
return dg
}
if srcglob, ok := src[GlobalKey]; !ok {
- sg = map[string]interface{}{}
+ sg = make(map[string]interface{})
} else if sg, ok = srcglob.(map[string]interface{}); !ok {
log.Printf("warning: skipping globals because source %s is not a table.", GlobalKey)
return dg
@@ -340,19 +339,8 @@ type ReleaseOptions struct {
// ToRenderValues composes the struct from the data coming from the Releases, Charts and Values files
//
-// WARNING: This function is deprecated for Helm > 2.1.99 Use ToRenderValuesCaps() instead. It will
-// remain in the codebase to stay SemVer compliant.
-//
-// In Helm 3.0, this will be changed to accept Capabilities as a fourth parameter.
-func ToRenderValues(chrt *chart.Chart, chrtVals []byte, options ReleaseOptions) (Values, error) {
- caps := &Capabilities{APIVersions: DefaultVersionSet}
- return ToRenderValuesCaps(chrt, chrtVals, options, caps)
-}
-
-// ToRenderValuesCaps composes the struct from the data coming from the Releases, Charts and Values files
-//
// This takes both ReleaseOptions and Capabilities to merge into the render values.
-func ToRenderValuesCaps(chrt *chart.Chart, chrtVals []byte, options ReleaseOptions, caps *Capabilities) (Values, error) {
+func ToRenderValues(chrt *chart.Chart, chrtVals []byte, options ReleaseOptions, caps *Capabilities) (Values, error) {
top := map[string]interface{}{
"Release": map[string]interface{}{
diff --git a/pkg/chartutil/values_test.go b/pkg/chartutil/values_test.go
index 8fe1b3be5..907dba575 100644
--- a/pkg/chartutil/values_test.go
+++ b/pkg/chartutil/values_test.go
@@ -25,7 +25,8 @@ import (
kversion "k8s.io/apimachinery/pkg/version"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/version"
)
@@ -89,16 +90,14 @@ where:
Metadata: &chart.Metadata{Name: "test"},
Templates: []*chart.File{},
Values: []byte(chartValues),
- Dependencies: []*chart.Chart{
- {
- Metadata: &chart.Metadata{Name: "where"},
- Values: []byte{},
- },
- },
Files: []*chart.File{
{Name: "scheherazade/shahryar.txt", Data: []byte("1,001 Nights")},
},
}
+ c.AddDependency(&chart.Chart{
+ Metadata: &chart.Metadata{Name: "where"},
+ Values: []byte{},
+ })
v := []byte(overideValues)
o := ReleaseOptions{
@@ -112,7 +111,7 @@ where:
KubeVersion: &kversion.Info{Major: "1"},
}
- res, err := ToRenderValuesCaps(c, v, o, caps)
+ res, err := ToRenderValues(c, v, o, caps)
if err != nil {
t.Fatal(err)
}
@@ -259,10 +258,8 @@ func matchValues(t *testing.T, data map[string]interface{}) {
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
+ err := tt.Execute(&b, v)
+ return b.String(), err
}
// ref: http://www.yaml.org/spec/1.2/spec.html#id2803362
@@ -293,7 +290,7 @@ pequod:
func TestCoalesceValues(t *testing.T) {
tchart := "testdata/moby"
- c, err := LoadDir(tchart)
+ c, err := loader.LoadDir(tchart)
if err != nil {
t.Fatal(err)
}
diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go
index a59e7dc0d..d085966dc 100644
--- a/pkg/downloader/manager.go
+++ b/pkg/downloader/manager.go
@@ -30,9 +30,10 @@ import (
"github.com/ghodss/yaml"
"github.com/pkg/errors"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/getter"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/repo"
"k8s.io/helm/pkg/resolver"
@@ -72,16 +73,13 @@ func (m *Manager) Build() error {
// If a lock file is found, run a build from that. Otherwise, just do
// an update.
- lock, err := chartutil.LoadRequirementsLock(c)
- if err != nil {
+ lock := c.RequirementsLock
+ if lock == nil {
return m.Update()
}
// A lock must accompany a requirements.yaml file.
- req, err := chartutil.LoadRequirements(c)
- if err != nil {
- return errors.Wrap(err, "requirements.yaml cannot be opened")
- }
+ req := c.Requirements
if sum, err := resolver.HashReq(req); err != nil || sum != lock.Digest {
return errors.New("requirements.lock is out of sync with requirements.yaml")
}
@@ -119,13 +117,9 @@ func (m *Manager) Update() error {
// If no requirements file is found, we consider this a successful
// completion.
- req, err := chartutil.LoadRequirements(c)
- if err != nil {
- if err == chartutil.ErrRequirementsNotFound {
- fmt.Fprintf(m.Out, "No requirements found in %s/charts.\n", m.ChartPath)
- return nil
- }
- return err
+ req := c.Requirements
+ if req == nil {
+ return nil
}
// Hash requirements.yaml
@@ -161,8 +155,8 @@ func (m *Manager) Update() error {
}
// If the lock file hasn't changed, don't write a new one.
- oldLock, err := chartutil.LoadRequirementsLock(c)
- if err == nil && oldLock.Digest == lock.Digest {
+ oldLock := c.RequirementsLock
+ if oldLock != nil && oldLock.Digest == lock.Digest {
return nil
}
@@ -176,13 +170,13 @@ func (m *Manager) loadChartDir() (*chart.Chart, error) {
} else if !fi.IsDir() {
return nil, errors.New("only unpacked charts can be updated")
}
- return chartutil.LoadDir(m.ChartPath)
+ return loader.LoadDir(m.ChartPath)
}
// resolve takes a list of requirements and translates them into an exact version to download.
//
// This returns a lock file, which has all of the requirements normalized to a specific version.
-func (m *Manager) resolve(req *chartutil.Requirements, repoNames map[string]string, hash string) (*chartutil.RequirementsLock, error) {
+func (m *Manager) resolve(req *chart.Requirements, repoNames map[string]string, hash string) (*chart.RequirementsLock, error) {
res := resolver.New(m.ChartPath, m.HelmHome)
return res.Resolve(req, repoNames, hash)
}
@@ -191,7 +185,7 @@ func (m *Manager) resolve(req *chartutil.Requirements, repoNames map[string]stri
//
// It will delete versions of the chart that exist on disk and might cause
// a conflict.
-func (m *Manager) downloadAll(deps []*chartutil.Dependency) error {
+func (m *Manager) downloadAll(deps []*chart.Dependency) error {
repos, err := m.loadChartRepositories()
if err != nil {
return err
@@ -307,12 +301,12 @@ func (m *Manager) safeDeleteDep(name, dir string) error {
return err
}
for _, fname := range files {
- ch, err := chartutil.LoadFile(fname)
+ ch, err := loader.LoadFile(fname)
if err != nil {
fmt.Fprintf(m.Out, "Could not verify %s for deletion: %s (Skipping)", fname, err)
continue
}
- if ch.Metadata.Name != name {
+ if ch.Name() != name {
// This is not the file you are looking for.
continue
}
@@ -325,7 +319,7 @@ func (m *Manager) safeDeleteDep(name, dir string) error {
}
// hasAllRepos ensures that all of the referenced deps are in the local repo cache.
-func (m *Manager) hasAllRepos(deps []*chartutil.Dependency) error {
+func (m *Manager) hasAllRepos(deps []*chart.Dependency) error {
rf, err := repo.LoadRepositoriesFile(m.HelmHome.RepositoryFile())
if err != nil {
return err
@@ -335,25 +329,22 @@ func (m *Manager) hasAllRepos(deps []*chartutil.Dependency) error {
// Verify that all repositories referenced in the deps are actually known
// by Helm.
missing := []string{}
+Loop:
for _, dd := range deps {
// If repo is from local path, continue
if strings.HasPrefix(dd.Repository, "file://") {
continue
}
- found := false
if dd.Repository == "" {
- found = true
- } else {
- for _, repo := range repos {
- if urlutil.Equal(repo.URL, strings.TrimSuffix(dd.Repository, "/")) {
- found = true
- }
- }
+ continue
}
- if !found {
- missing = append(missing, dd.Repository)
+ for _, repo := range repos {
+ if urlutil.Equal(repo.URL, strings.TrimSuffix(dd.Repository, "/")) {
+ continue Loop
+ }
}
+ missing = append(missing, dd.Repository)
}
if len(missing) > 0 {
return errors.Errorf("no repository definition for %s. Please add the missing repos via 'helm repo add'", strings.Join(missing, ", "))
@@ -362,7 +353,7 @@ func (m *Manager) hasAllRepos(deps []*chartutil.Dependency) error {
}
// getRepoNames returns the repo names of the referenced deps which can be used to fetch the cahced index file.
-func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string, error) {
+func (m *Manager) getRepoNames(deps []*chart.Dependency) (map[string]string, error) {
rf, err := repo.LoadRepositoriesFile(m.HelmHome.RepositoryFile())
if err != nil {
return nil, err
@@ -408,24 +399,22 @@ func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string,
}
}
if len(missing) > 0 {
- if len(missing) > 0 {
- errorMessage := fmt.Sprintf("no repository definition for %s. Please add them via 'helm repo add'", strings.Join(missing, ", "))
- // It is common for people to try to enter "stable" as a repository instead of the actual URL.
- // For this case, let's give them a suggestion.
- containsNonURL := false
- for _, repo := range missing {
- if !strings.Contains(repo, "//") && !strings.HasPrefix(repo, "@") && !strings.HasPrefix(repo, "alias:") {
- containsNonURL = true
- }
+ errorMessage := fmt.Sprintf("no repository definition for %s. Please add them via 'helm repo add'", strings.Join(missing, ", "))
+ // It is common for people to try to enter "stable" as a repository instead of the actual URL.
+ // For this case, let's give them a suggestion.
+ containsNonURL := false
+ for _, repo := range missing {
+ if !strings.Contains(repo, "//") && !strings.HasPrefix(repo, "@") && !strings.HasPrefix(repo, "alias:") {
+ containsNonURL = true
}
- if containsNonURL {
- errorMessage += `
+ }
+ if containsNonURL {
+ errorMessage += `
Note that repositories must be URLs or aliases. For example, to refer to the stable
repository, use "https://kubernetes-charts.storage.googleapis.com/" or "@stable" instead of
"stable". Don't forget to add the repo, too ('helm repo add').`
- }
- return nil, errors.New(errorMessage)
}
+ return nil, errors.New(errorMessage)
}
return reposMap, nil
}
@@ -596,7 +585,7 @@ func (m *Manager) loadChartRepositories() (map[string]*repo.ChartRepository, err
}
// writeLock writes a lockfile to disk
-func writeLock(chartpath string, lock *chartutil.RequirementsLock) error {
+func writeLock(chartpath string, lock *chart.RequirementsLock) error {
data, err := yaml.Marshal(lock)
if err != nil {
return err
@@ -618,7 +607,7 @@ func tarFromLocalDir(chartpath, name, repo, version string) (string, error) {
return "", err
}
- ch, err := chartutil.LoadDir(origPath)
+ ch, err := loader.LoadDir(origPath)
if err != nil {
return "", err
}
diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go
index 1ff2a9c17..f5a252d0b 100644
--- a/pkg/downloader/manager_test.go
+++ b/pkg/downloader/manager_test.go
@@ -20,7 +20,7 @@ import (
"reflect"
"testing"
- "k8s.io/helm/pkg/chartutil"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/helm/helmpath"
)
@@ -100,48 +100,48 @@ func TestGetRepoNames(t *testing.T) {
}
tests := []struct {
name string
- req []*chartutil.Dependency
+ req []*chart.Dependency
expect map[string]string
err bool
}{
{
name: "no repo definition failure",
- req: []*chartutil.Dependency{
+ req: []*chart.Dependency{
{Name: "oedipus-rex", Repository: "http://example.com/test"},
},
err: true,
},
{
name: "no repo definition failure -- stable repo",
- req: []*chartutil.Dependency{
+ req: []*chart.Dependency{
{Name: "oedipus-rex", Repository: "stable"},
},
err: true,
},
{
name: "no repo definition failure",
- req: []*chartutil.Dependency{
+ req: []*chart.Dependency{
{Name: "oedipus-rex", Repository: "http://example.com"},
},
expect: map[string]string{"oedipus-rex": "testing"},
},
{
name: "repo from local path",
- req: []*chartutil.Dependency{
+ req: []*chart.Dependency{
{Name: "local-dep", Repository: "file://./testdata/signtest"},
},
expect: map[string]string{"local-dep": "file://./testdata/signtest"},
},
{
name: "repo alias (alias:)",
- req: []*chartutil.Dependency{
+ req: []*chart.Dependency{
{Name: "oedipus-rex", Repository: "alias:testing"},
},
expect: map[string]string{"oedipus-rex": "testing"},
},
{
name: "repo alias (@)",
- req: []*chartutil.Dependency{
+ req: []*chart.Dependency{
{Name: "oedipus-rex", Repository: "@testing"},
},
expect: map[string]string{"oedipus-rex": "testing"},
diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go
index f09a8ec7c..2b330ecf3 100644
--- a/pkg/engine/engine.go
+++ b/pkg/engine/engine.go
@@ -17,7 +17,6 @@ limitations under the License.
package engine
import (
- "bytes"
"path"
"sort"
"strings"
@@ -26,19 +25,19 @@ import (
"github.com/Masterminds/sprig"
"github.com/pkg/errors"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
)
// Engine is an implementation of 'cmd/tiller/environment'.Engine that uses Go templates.
type Engine struct {
// FuncMap contains the template functions that will be passed to each
// render call. This may only be modified before the first call to Render.
- FuncMap template.FuncMap
+ funcMap template.FuncMap
// If strict is enabled, template rendering will fail if a template references
// a value that was not passed in.
Strict bool
- CurrentTemplates map[string]renderable
+ currentTemplates map[string]renderable
}
// New creates a new Go template Engine instance.
@@ -49,10 +48,7 @@ type Engine struct {
// The FuncMap sets all of the Sprig functions except for those that provide
// access to the underlying OS (env, expandenv).
func New() *Engine {
- f := FuncMap()
- return &Engine{
- FuncMap: f,
- }
+ return &Engine{funcMap: FuncMap()}
}
// FuncMap returns a mapping of all of the functions that Engine has.
@@ -76,11 +72,11 @@ func FuncMap() template.FuncMap {
// Add some extra functionality
extra := template.FuncMap{
- "toToml": chartutil.ToToml,
- "toYaml": chartutil.ToYaml,
- "fromYaml": chartutil.FromYaml,
- "toJson": chartutil.ToJson,
- "fromJson": chartutil.FromJson,
+ "toToml": chartutil.ToTOML,
+ "toYaml": chartutil.ToYAML,
+ "fromYaml": chartutil.FromYAML,
+ "toJson": chartutil.ToJSON,
+ "fromJson": chartutil.FromJSON,
// This is a placeholder for the "include" function, which is
// late-bound to a template. By declaring it here, we preserve the
@@ -119,8 +115,8 @@ func FuncMap() template.FuncMap {
func (e *Engine) Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, error) {
// Render the charts
tmap := allTemplates(chrt, values)
- e.CurrentTemplates = tmap
- return e.render(tmap)
+ e.currentTemplates = tmap
+ return e.render(chrt, tmap)
}
// renderable is an object that can be rendered.
@@ -138,18 +134,16 @@ type renderable struct {
// The resulting FuncMap is only valid for the passed-in template.
func (e *Engine) alterFuncMap(t *template.Template) template.FuncMap {
// Clone the func map because we are adding context-specific functions.
- var funcMap template.FuncMap = map[string]interface{}{}
- for k, v := range e.FuncMap {
+ funcMap := make(template.FuncMap)
+ for k, v := range e.funcMap {
funcMap[k] = v
}
// Add the 'include' function here so we can close over t.
funcMap["include"] = func(name string, data interface{}) (string, error) {
- buf := bytes.NewBuffer(nil)
- if err := t.ExecuteTemplate(buf, name, data); err != nil {
- return "", err
- }
- return buf.String(), nil
+ var buf strings.Builder
+ err := t.ExecuteTemplate(&buf, name, data)
+ return buf.String(), err
}
// Add the 'required' function here
@@ -177,15 +171,15 @@ func (e *Engine) alterFuncMap(t *template.Template) template.FuncMap {
basePath: basePath.(string),
}
- templates := map[string]renderable{}
templateName, err := vals.PathValue("Template.Name")
if err != nil {
return "", errors.Wrapf(err, "cannot retrieve Template.Name from values inside tpl function: %s", tpl)
}
+ templates := make(map[string]renderable)
templates[templateName.(string)] = r
- result, err := e.render(templates)
+ result, err := e.render(nil, templates)
if err != nil {
return "", errors.Wrapf(err, "error during tpl function execution for %q", tpl)
}
@@ -196,7 +190,7 @@ func (e *Engine) alterFuncMap(t *template.Template) template.FuncMap {
}
// render takes a map of templates/values and renders them.
-func (e *Engine) render(tpls map[string]renderable) (rendered map[string]string, err error) {
+func (e *Engine) render(ch *chart.Chart, tpls map[string]renderable) (rendered map[string]string, err error) {
// Basically, what we do here is start with an empty parent template and then
// build up a list of templates -- one for each file. Once all of the templates
// have been parsed, we loop through again and execute every template.
@@ -228,8 +222,7 @@ func (e *Engine) render(tpls map[string]renderable) (rendered map[string]string,
for _, fname := range keys {
r := tpls[fname]
- t = t.New(fname).Funcs(funcMap)
- if _, err := t.Parse(r.tpl); err != nil {
+ if _, err := t.New(fname).Funcs(funcMap).Parse(r.tpl); err != nil {
return map[string]string{}, errors.Wrapf(err, "parse error in %q", fname)
}
files = append(files, fname)
@@ -237,17 +230,15 @@ func (e *Engine) render(tpls map[string]renderable) (rendered map[string]string,
// Adding the engine's currentTemplates to the template context
// so they can be referenced in the tpl function
- for fname, r := range e.CurrentTemplates {
+ for fname, r := range e.currentTemplates {
if t.Lookup(fname) == nil {
- t = t.New(fname).Funcs(funcMap)
- if _, err := t.Parse(r.tpl); err != nil {
+ if _, err := t.New(fname).Funcs(funcMap).Parse(r.tpl); err != nil {
return map[string]string{}, errors.Wrapf(err, "parse error in %q", fname)
}
}
}
rendered = make(map[string]string, len(files))
- var buf bytes.Buffer
for _, file := range files {
// Don't render partials. We don't care out the direct output of partials.
// They are only included from other templates.
@@ -256,7 +247,8 @@ func (e *Engine) render(tpls map[string]renderable) (rendered map[string]string,
}
// At render time, add information about the template that is being rendered.
vals := tpls[file].vals
- vals["Template"] = map[string]interface{}{"Name": file, "BasePath": tpls[file].basePath}
+ vals["Template"] = chartutil.Values{"Name": file, "BasePath": tpls[file].basePath}
+ var buf strings.Builder
if err := t.ExecuteTemplate(&buf, file, vals); err != nil {
return map[string]string{}, errors.Wrapf(err, "render error in %q", file)
}
@@ -264,8 +256,14 @@ func (e *Engine) render(tpls map[string]renderable) (rendered map[string]string,
// Work around the issue where Go will emit "" even if Options(missing=zero)
// is set. Since missing=error will never get here, we do not need to handle
// the Strict case.
- rendered[file] = strings.Replace(buf.String(), "", "", -1)
- buf.Reset()
+ f := &chart.File{
+ Name: strings.Replace(file, "/templates", "/manifests", -1),
+ Data: []byte(strings.Replace(buf.String(), "", "", -1)),
+ }
+ rendered[file] = string(f.Data)
+ if ch != nil {
+ ch.Files = append(ch.Files, f)
+ }
}
return rendered, nil
@@ -299,8 +297,8 @@ func (p byPathLen) Less(i, j int) bool {
//
// As it goes, it also prepares the values in a scope-sensitive manner.
func allTemplates(c *chart.Chart, vals chartutil.Values) map[string]renderable {
- templates := map[string]renderable{}
- recAllTpls(c, templates, vals, true, "")
+ templates := make(map[string]renderable)
+ recAllTpls(c, templates, vals)
return templates
}
@@ -308,44 +306,32 @@ 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
// scope.
-func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals chartutil.Values, top bool, parentID string) {
+func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals chartutil.Values) {
// This should never evaluate to a nil map. That will cause problems when
// values are appended later.
- cvals := chartutil.Values{}
- if top {
- // If this is the top of the rendering tree, assume that parentVals
- // is already resolved to the authoritative values.
+ cvals := make(chartutil.Values)
+ if c.IsRoot() {
cvals = parentVals
- } else if c.Metadata != nil && c.Metadata.Name != "" {
- // If there is a {{.Values.ThisChart}} in the parent metadata,
- // copy that into the {{.Values}} for this template.
- newVals := chartutil.Values{}
- if vs, err := parentVals.Table("Values"); err == nil {
- if tmp, err := vs.Table(c.Metadata.Name); err == nil {
- newVals = tmp
- }
- }
-
+ } else if c.Name() != "" {
cvals = map[string]interface{}{
- "Values": newVals,
+ "Values": make(chartutil.Values),
"Release": parentVals["Release"],
"Chart": c.Metadata,
"Files": chartutil.NewFiles(c.Files),
"Capabilities": parentVals["Capabilities"],
}
+ // If there is a {{.Values.ThisChart}} in the parent metadata,
+ // copy that into the {{.Values}} for this template.
+ if vs, err := parentVals.Table("Values." + c.Name()); err == nil {
+ cvals["Values"] = vs
+ }
}
- 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() {
+ recAllTpls(child, templates, cvals)
}
- for _, child := range c.Dependencies {
- recAllTpls(child, templates, cvals, false, newParentID)
- }
+ newParentID := c.ChartFullPath()
for _, t := range c.Templates {
templates[path.Join(newParentID, t.Name)] = renderable{
tpl: string(t.Data),
diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go
index be9aaa448..3b1127d45 100644
--- a/pkg/engine/engine_test.go
+++ b/pkg/engine/engine_test.go
@@ -21,8 +21,8 @@ import (
"sync"
"testing"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
)
func TestSortTemplates(t *testing.T) {
@@ -62,7 +62,7 @@ func TestEngine(t *testing.T) {
// Forbidden because they allow access to the host OS.
forbidden := []string{"env", "expandenv"}
for _, f := range forbidden {
- if _, ok := e.FuncMap[f]; ok {
+ if _, ok := e.funcMap[f]; ok {
t.Errorf("Forbidden function %s exists in FuncMap.", f)
}
}
@@ -149,7 +149,7 @@ func TestRenderInternals(t *testing.T) {
"three": {tpl: `{{template "two" dict "Value" "three"}}`, vals: vals},
}
- out, err := e.render(tpls)
+ out, err := e.render(nil, tpls)
if err != nil {
t.Fatalf("Failed template rendering: %s", err)
}
@@ -182,7 +182,7 @@ func TestParallelRenderInternals(t *testing.T) {
tt := fmt.Sprintf("expect-%d", i)
v := chartutil.Values{"val": tt}
tpls := map[string]renderable{fname: {tpl: `{{.val}}`, vals: v}}
- out, err := e.render(tpls)
+ out, err := e.render(nil, tpls)
if err != nil {
t.Errorf("Failed to render %s: %s", tt, err)
}
@@ -202,22 +202,23 @@ func TestAllTemplates(t *testing.T) {
{Name: "templates/foo", Data: []byte("foo")},
{Name: "templates/bar", Data: []byte("bar")},
},
- Dependencies: []*chart.Chart{
- {
- Metadata: &chart.Metadata{Name: "laboratory mice"},
- Templates: []*chart.File{
- {Name: "templates/pinky", Data: []byte("pinky")},
- {Name: "templates/brain", Data: []byte("brain")},
- },
- Dependencies: []*chart.Chart{{
- Metadata: &chart.Metadata{Name: "same thing we do every night"},
- Templates: []*chart.File{
- {Name: "templates/innermost", Data: []byte("innermost")},
- }},
- },
- },
+ }
+ dep1 := &chart.Chart{
+ Metadata: &chart.Metadata{Name: "laboratory mice"},
+ Templates: []*chart.File{
+ {Name: "templates/pinky", Data: []byte("pinky")},
+ {Name: "templates/brain", Data: []byte("brain")},
+ },
+ }
+ ch1.AddDependency(dep1)
+
+ dep2 := &chart.Chart{
+ Metadata: &chart.Metadata{Name: "same thing we do every night"},
+ Templates: []*chart.File{
+ {Name: "templates/innermost", Data: []byte("innermost")},
},
}
+ dep1.AddDependency(dep2)
var v chartutil.Values
tpls := allTemplates(ch1, v)
@@ -235,18 +236,15 @@ func TestRenderDependency(t *testing.T) {
Templates: []*chart.File{
{Name: "templates/outer", Data: []byte(toptpl)},
},
- Dependencies: []*chart.Chart{
- {
- Metadata: &chart.Metadata{Name: "innerchart"},
- Templates: []*chart.File{
- {Name: "templates/inner", Data: []byte(deptpl)},
- },
- },
- },
}
+ ch.AddDependency(&chart.Chart{
+ Metadata: &chart.Metadata{Name: "innerchart"},
+ Templates: []*chart.File{
+ {Name: "templates/inner", Data: []byte(deptpl)},
+ },
+ })
out, err := e.Render(ch, map[string]interface{}{})
-
if err != nil {
t.Fatalf("failed to render chart: %s", err)
}
@@ -285,9 +283,9 @@ func TestRenderNestedValues(t *testing.T) {
Templates: []*chart.File{
{Name: innerpath, Data: []byte(`Old {{.Values.who}} is still a-flyin'`)},
},
- Values: []byte(`who: "Robert"`),
- Dependencies: []*chart.Chart{deepest},
+ Values: []byte(`who: "Robert"`),
}
+ inner.AddDependency(deepest)
outer := &chart.Chart{
Metadata: &chart.Metadata{Name: "top"},
@@ -299,8 +297,8 @@ what: stinkweed
who: me
herrick:
who: time`),
- Dependencies: []*chart.Chart{inner},
}
+ outer.AddDependency(inner)
injValues := []byte(`
what: rosebuds
@@ -358,8 +356,6 @@ func TestRenderBuiltinValues(t *testing.T) {
{Name: "templates/Lavinia", Data: []byte(`{{.Template.Name}}{{.Chart.Name}}{{.Release.Name}}`)},
{Name: "templates/From", Data: []byte(`{{.Files.author | printf "%s"}} {{.Files.Get "book/title.txt"}}`)},
},
- Values: []byte{},
- Dependencies: []*chart.Chart{},
Files: []*chart.File{
{Name: "author", Data: []byte("Virgil")},
{Name: "book/title.txt", Data: []byte("Aeneid")},
@@ -371,9 +367,8 @@ func TestRenderBuiltinValues(t *testing.T) {
Templates: []*chart.File{
{Name: "templates/Aeneas", Data: []byte(`{{.Template.Name}}{{.Chart.Name}}{{.Release.Name}}`)},
},
- Values: []byte{},
- Dependencies: []*chart.Chart{inner},
}
+ outer.AddDependency(inner)
inject := chartutil.Values{
"Values": "",
@@ -403,15 +398,13 @@ func TestRenderBuiltinValues(t *testing.T) {
}
-func TestAlterFuncMap(t *testing.T) {
+func TestAlterFuncMap_include(t *testing.T) {
c := &chart.Chart{
Metadata: &chart.Metadata{Name: "conrad"},
Templates: []*chart.File{
{Name: "templates/quote", Data: []byte(`{{include "conrad/templates/_partial" . | indent 2}} dead.`)},
{Name: "templates/_partial", Data: []byte(`{{.Release.Name}} - he`)},
},
- Values: []byte{},
- Dependencies: []*chart.Chart{},
}
v := chartutil.Values{
@@ -431,127 +424,127 @@ func TestAlterFuncMap(t *testing.T) {
if got := out["conrad/templates/quote"]; got != expect {
t.Errorf("Expected %q, got %q (%v)", expect, got, out)
}
+}
- reqChart := &chart.Chart{
+func TestAlterFuncMap_require(t *testing.T) {
+ c := &chart.Chart{
Metadata: &chart.Metadata{Name: "conan"},
Templates: []*chart.File{
{Name: "templates/quote", Data: []byte(`All your base are belong to {{ required "A valid 'who' is required" .Values.who }}`)},
{Name: "templates/bases", Data: []byte(`All {{ required "A valid 'bases' is required" .Values.bases }} of them!`)},
},
- Values: []byte{},
- Dependencies: []*chart.Chart{},
}
- reqValues := chartutil.Values{
+ v := chartutil.Values{
"Values": chartutil.Values{
"who": "us",
"bases": 2,
},
- "Chart": reqChart.Metadata,
+ "Chart": c.Metadata,
"Release": chartutil.Values{
"Name": "That 90s meme",
},
}
- outReq, err := New().Render(reqChart, reqValues)
+ out, err := New().Render(c, v)
if err != nil {
t.Fatal(err)
}
expectStr := "All your base are belong to us"
- if gotStr := outReq["conan/templates/quote"]; gotStr != expectStr {
- t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, outReq)
+ if gotStr := out["conan/templates/quote"]; gotStr != expectStr {
+ t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out)
}
expectNum := "All 2 of them!"
- if gotNum := outReq["conan/templates/bases"]; gotNum != expectNum {
- t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, outReq)
+ if gotNum := out["conan/templates/bases"]; gotNum != expectNum {
+ t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, out)
}
+}
- tplChart := &chart.Chart{
+func TestAlterFuncMap_tpl(t *testing.T) {
+ c := &chart.Chart{
Metadata: &chart.Metadata{Name: "TplFunction"},
Templates: []*chart.File{
{Name: "templates/base", Data: []byte(`Evaluate tpl {{tpl "Value: {{ .Values.value}}" .}}`)},
},
- Values: []byte{},
- Dependencies: []*chart.Chart{},
}
- tplValues := chartutil.Values{
+ v := chartutil.Values{
"Values": chartutil.Values{
"value": "myvalue",
},
- "Chart": tplChart.Metadata,
+ "Chart": c.Metadata,
"Release": chartutil.Values{
"Name": "TestRelease",
},
}
- outTpl, err := New().Render(tplChart, tplValues)
+ out, err := New().Render(c, v)
if err != nil {
t.Fatal(err)
}
- expectTplStr := "Evaluate tpl Value: myvalue"
- if gotStrTpl := outTpl["TplFunction/templates/base"]; gotStrTpl != expectTplStr {
- t.Errorf("Expected %q, got %q (%v)", expectTplStr, gotStrTpl, outTpl)
+ expect := "Evaluate tpl Value: myvalue"
+ if got := out["TplFunction/templates/base"]; got != expect {
+ t.Errorf("Expected %q, got %q (%v)", expect, got, out)
}
+}
- tplChartWithFunction := &chart.Chart{
+func TestAlterFuncMap_tplfunc(t *testing.T) {
+ c := &chart.Chart{
Metadata: &chart.Metadata{Name: "TplFunction"},
Templates: []*chart.File{
{Name: "templates/base", Data: []byte(`Evaluate tpl {{tpl "Value: {{ .Values.value | quote}}" .}}`)},
},
- Values: []byte{},
- Dependencies: []*chart.Chart{},
}
- tplValuesWithFunction := chartutil.Values{
+ v := chartutil.Values{
"Values": chartutil.Values{
"value": "myvalue",
},
- "Chart": tplChartWithFunction.Metadata,
+ "Chart": c.Metadata,
"Release": chartutil.Values{
"Name": "TestRelease",
},
}
- outTplWithFunction, err := New().Render(tplChartWithFunction, tplValuesWithFunction)
+ out, err := New().Render(c, v)
if err != nil {
t.Fatal(err)
}
- expectTplStrWithFunction := "Evaluate tpl Value: \"myvalue\""
- if gotStrTplWithFunction := outTplWithFunction["TplFunction/templates/base"]; gotStrTplWithFunction != expectTplStrWithFunction {
- t.Errorf("Expected %q, got %q (%v)", expectTplStrWithFunction, gotStrTplWithFunction, outTplWithFunction)
+ expect := "Evaluate tpl Value: \"myvalue\""
+ if got := out["TplFunction/templates/base"]; got != expect {
+ t.Errorf("Expected %q, got %q (%v)", expect, got, out)
}
+}
- tplChartWithInclude := &chart.Chart{
+func TestAlterFuncMap_tplinclude(t *testing.T) {
+ c := &chart.Chart{
Metadata: &chart.Metadata{Name: "TplFunction"},
Templates: []*chart.File{
{Name: "templates/base", Data: []byte(`{{ tpl "{{include ` + "`" + `TplFunction/templates/_partial` + "`" + ` . | quote }}" .}}`)},
{Name: "templates/_partial", Data: []byte(`{{.Template.Name}}`)},
},
- Values: []byte{},
- Dependencies: []*chart.Chart{},
}
- tplValueWithInclude := chartutil.Values{
+ v := chartutil.Values{
"Values": chartutil.Values{
"value": "myvalue",
},
- "Chart": tplChartWithInclude.Metadata,
+ "Chart": c.Metadata,
"Release": chartutil.Values{
"Name": "TestRelease",
},
}
- outTplWithInclude, err := New().Render(tplChartWithInclude, tplValueWithInclude)
+ out, err := New().Render(c, v)
if err != nil {
t.Fatal(err)
}
- expectedTplStrWithInclude := "\"TplFunction/templates/base\""
- if gotStrTplWithInclude := outTplWithInclude["TplFunction/templates/base"]; gotStrTplWithInclude != expectedTplStrWithInclude {
- t.Errorf("Expected %q, got %q (%v)", expectedTplStrWithInclude, gotStrTplWithInclude, outTplWithInclude)
+ expect := "\"TplFunction/templates/base\""
+ if got := out["TplFunction/templates/base"]; got != expect {
+ t.Errorf("Expected %q, got %q (%v)", expect, got, out)
}
}
diff --git a/pkg/hapi/chart/chart.go b/pkg/hapi/chart/chart.go
deleted file mode 100644
index 711bee61d..000000000
--- a/pkg/hapi/chart/chart.go
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-Copyright 2018 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 chart
-
-// Chart is a helm package that contains metadata, a default config, zero or more
-// optionally parameterizable templates, and zero or more charts (dependencies).
-type Chart struct {
- // Metadata is the contents of the Chartfile.
- Metadata *Metadata `json:"metadata,omitempty"`
- // Templates for this chart.
- Templates []*File `json:"templates,omitempty"`
- // Dependencies are the charts that this chart depends on.
- Dependencies []*Chart `json:"dependencies,omitempty"`
- // Values are default config for this template.
- Values []byte `json:"values,omitempty"`
- // Files are miscellaneous files in a chart archive,
- // e.g. README, LICENSE, etc.
- Files []*File `json:"files,omitempty"`
-}
diff --git a/pkg/hapi/release/release.go b/pkg/hapi/release/release.go
index f8b739468..b850f74a6 100644
--- a/pkg/hapi/release/release.go
+++ b/pkg/hapi/release/release.go
@@ -15,7 +15,7 @@ limitations under the License.
package release
-import "k8s.io/helm/pkg/hapi/chart"
+import "k8s.io/helm/pkg/chart"
// Release describes a deployment of a chart, together with the chart
// and the variables used to deploy that chart.
diff --git a/pkg/hapi/tiller.go b/pkg/hapi/tiller.go
index ee30f5619..f0fc89a1f 100644
--- a/pkg/hapi/tiller.go
+++ b/pkg/hapi/tiller.go
@@ -16,7 +16,7 @@ limitations under the License.
package hapi
import (
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/hapi/release"
)
diff --git a/pkg/helm/client.go b/pkg/helm/client.go
index 8925b6043..83b3c8e49 100644
--- a/pkg/helm/client.go
+++ b/pkg/helm/client.go
@@ -17,13 +17,13 @@ limitations under the License.
package helm // import "k8s.io/helm/pkg/helm"
import (
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/hapi"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/hapi/release"
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/tiller"
- "k8s.io/helm/pkg/tiller/environment"
)
// Client manages client side of the Helm-Tiller protocol.
@@ -39,8 +39,7 @@ func NewClient(opts ...Option) *Client {
}
func (c *Client) init() *Client {
- env := environment.New()
- c.tiller = tiller.NewReleaseServer(env, c.opts.discovery, c.opts.kubeClient)
+ c.tiller = tiller.NewReleaseServer(c.opts.discovery, c.opts.kubeClient)
c.tiller.Releases = storage.Init(c.opts.driver)
return c
}
@@ -69,7 +68,7 @@ func (c *Client) ListReleases(opts ...ReleaseListOption) ([]*release.Release, er
// InstallRelease loads a chart from chstr, installs it, and returns the release response.
func (c *Client) InstallRelease(chstr, ns string, opts ...InstallOption) (*release.Release, error) {
// load the chart to install
- chart, err := chartutil.Load(chstr)
+ chart, err := loader.Load(chstr)
if err != nil {
return nil, err
}
@@ -136,7 +135,7 @@ func (c *Client) UninstallRelease(rlsName string, opts ...UninstallOption) (*hap
// UpdateRelease loads a chart from chstr and updates a release to a new/different chart.
func (c *Client) UpdateRelease(rlsName, chstr string, opts ...UpdateOption) (*release.Release, error) {
// load the chart to update
- chart, err := chartutil.Load(chstr)
+ chart, err := loader.Load(chstr)
if err != nil {
return nil, err
}
diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go
index d7f5e01fd..03f374700 100644
--- a/pkg/helm/fake.go
+++ b/pkg/helm/fake.go
@@ -23,8 +23,8 @@ import (
"github.com/pkg/errors"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/hapi"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/hapi/release"
)
diff --git a/pkg/helm/fake_test.go b/pkg/helm/fake_test.go
index 12114328a..97f127507 100644
--- a/pkg/helm/fake_test.go
+++ b/pkg/helm/fake_test.go
@@ -20,8 +20,8 @@ import (
"reflect"
"testing"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/hapi"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/hapi/release"
)
diff --git a/pkg/helm/helm_test.go b/pkg/helm/helm_test.go
index 94207077f..d2a369488 100644
--- a/pkg/helm/helm_test.go
+++ b/pkg/helm/helm_test.go
@@ -23,9 +23,9 @@ import (
"github.com/pkg/errors"
- "k8s.io/helm/pkg/chartutil"
+ cpb "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/hapi"
- cpb "k8s.io/helm/pkg/hapi/chart"
rls "k8s.io/helm/pkg/hapi/release"
)
@@ -349,7 +349,7 @@ func assert(t *testing.T, expect, actual interface{}) {
}
func loadChart(t *testing.T, name string) *cpb.Chart {
- c, err := chartutil.Load(filepath.Join(chartsDir, name))
+ c, err := loader.Load(filepath.Join(chartsDir, name))
if err != nil {
t.Fatalf("failed to load test chart (%q): %s\n", name, err)
}
diff --git a/pkg/helm/interface.go b/pkg/helm/interface.go
index 25b96a0a8..fff653fba 100644
--- a/pkg/helm/interface.go
+++ b/pkg/helm/interface.go
@@ -17,8 +17,8 @@ limitations under the License.
package helm
import (
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/hapi"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/hapi/release"
)
diff --git a/pkg/kube/converter.go b/pkg/kube/converter.go
new file mode 100644
index 000000000..b1093a737
--- /dev/null
+++ b/pkg/kube/converter.go
@@ -0,0 +1,40 @@
+/*
+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 kube // import "k8s.io/helm/pkg/kube"
+
+import (
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/kubernetes/pkg/api/legacyscheme"
+)
+
+// AsDefaultVersionedOrOriginal returns the object as a Go object in the external form if possible (matching the
+// group version kind of the mapping if provided, a best guess based on serialization if not provided, or obj if it cannot be converted.
+// TODO update call sites to specify the scheme they want on their builder.
+func AsDefaultVersionedOrOriginal(obj runtime.Object, mapping *meta.RESTMapping) runtime.Object {
+ converter := runtime.ObjectConvertor(legacyscheme.Scheme)
+ groupVersioner := runtime.GroupVersioner(schema.GroupVersions(legacyscheme.Scheme.PrioritizedVersionsAllGroups()))
+ if mapping != nil {
+ groupVersioner = mapping.GroupVersionKind.GroupVersion()
+ }
+
+ if obj, err := converter.ConvertToVersion(obj, groupVersioner); err == nil {
+ return obj
+ }
+ return obj
+}
diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go
index 30691c500..9f39253e8 100644
--- a/pkg/lint/rules/chartfile.go
+++ b/pkg/lint/rules/chartfile.go
@@ -24,8 +24,8 @@ import (
"github.com/asaskevich/govalidator"
"github.com/pkg/errors"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/lint/support"
)
diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go
index 4af73422e..a2bf8c0fa 100644
--- a/pkg/lint/rules/chartfile_test.go
+++ b/pkg/lint/rules/chartfile_test.go
@@ -24,8 +24,8 @@ import (
"github.com/pkg/errors"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/lint/support"
)
diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go
index 6b2a75027..fe1168ccd 100644
--- a/pkg/lint/rules/template.go
+++ b/pkg/lint/rules/template.go
@@ -23,10 +23,10 @@ import (
"github.com/ghodss/yaml"
"github.com/pkg/errors"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/engine"
"k8s.io/helm/pkg/lint/support"
- tversion "k8s.io/helm/pkg/version"
)
// Templates lints the templates in the Linter.
@@ -42,7 +42,7 @@ func Templates(linter *support.Linter, values []byte, namespace string, strict b
}
// Load chart and parse templates, based on tiller/release_server
- chart, err := chartutil.Load(linter.ChartDir)
+ chart, err := loader.Load(linter.ChartDir)
chartLoaded := linter.RunLinterRule(support.ErrorSev, path, err)
@@ -51,11 +51,7 @@ func Templates(linter *support.Linter, values []byte, namespace string, strict b
}
options := chartutil.ReleaseOptions{Name: "testRelease"}
- caps := &chartutil.Capabilities{
- APIVersions: chartutil.DefaultVersionSet,
- KubeVersion: chartutil.DefaultKubeVersion,
- HelmVersion: tversion.GetBuildInfo(),
- }
+
cvals, err := chartutil.CoalesceValues(chart, values)
if err != nil {
return
@@ -65,7 +61,8 @@ func Templates(linter *support.Linter, values []byte, namespace string, strict b
if err != nil {
return
}
- valuesToRender, err := chartutil.ToRenderValuesCaps(chart, yvals, options, caps)
+ caps := chartutil.DefaultCapabilities
+ valuesToRender, err := chartutil.ToRenderValues(chart, yvals, options, caps)
if err != nil {
// FIXME: This seems to generate a duplicate, but I can't find where the first
// error is coming from.
@@ -109,7 +106,7 @@ func Templates(linter *support.Linter, values []byte, namespace string, strict b
// NOTE: disabled for now, Refs https://github.com/kubernetes/helm/issues/1037
// linter.RunLinterRule(support.WarningSev, path, validateQuotes(string(preExecutedTemplate)))
- renderedContent := renderedContentMap[filepath.Join(chart.Metadata.Name, fileName)]
+ renderedContent := renderedContentMap[filepath.Join(chart.Name(), fileName)]
var yamlStruct K8sYamlStruct
// Even though K8sYamlStruct only defines Metadata namespace, an error in any other
// key will be raised as well
diff --git a/pkg/provenance/sign.go b/pkg/provenance/sign.go
index 4d1803454..62e9462c1 100644
--- a/pkg/provenance/sign.go
+++ b/pkg/provenance/sign.go
@@ -31,8 +31,8 @@ import (
"golang.org/x/crypto/openpgp/clearsign"
"golang.org/x/crypto/openpgp/packet"
- "k8s.io/helm/pkg/chartutil"
- hapi "k8s.io/helm/pkg/hapi/chart"
+ hapi "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
)
var defaultPGPConfig = packet.Config{
@@ -317,7 +317,7 @@ func messageBlock(chartpath string) (*bytes.Buffer, error) {
}
// Load the archive into memory.
- chart, err := chartutil.LoadFile(chartpath)
+ chart, err := loader.LoadFile(chartpath)
if err != nil {
return b, err
}
diff --git a/pkg/releaseutil/manifest.go b/pkg/releaseutil/manifest.go
index a0449cc55..d233fc106 100644
--- a/pkg/releaseutil/manifest.go
+++ b/pkg/releaseutil/manifest.go
@@ -46,7 +46,6 @@ func SplitManifests(bigFile string) map[string]string {
docs := sep.Split(bigFileTmp, -1)
var count int
for _, d := range docs {
-
if d == "" {
continue
}
diff --git a/pkg/releaseutil/sorter.go b/pkg/releaseutil/sorter.go
index cd90e5816..31f8367dd 100644
--- a/pkg/releaseutil/sorter.go
+++ b/pkg/releaseutil/sorter.go
@@ -22,14 +22,28 @@ import (
rspb "k8s.io/helm/pkg/hapi/release"
)
-type sorter struct {
- list []*rspb.Release
- less func(int, int) bool
+type list []*rspb.Release
+
+func (s list) Len() int { return len(s) }
+func (s list) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+type ByName struct{ list }
+
+func (s ByName) Less(i, j int) bool { return s.list[i].Name < s.list[j].Name }
+
+type ByDate struct{ list }
+
+func (s ByDate) Less(i, j int) bool {
+ ti := s.list[i].Info.LastDeployed.Second()
+ tj := s.list[j].Info.LastDeployed.Second()
+ return ti < tj
}
-func (s *sorter) Len() int { return len(s.list) }
-func (s *sorter) Less(i, j int) bool { return s.less(i, j) }
-func (s *sorter) Swap(i, j int) { s.list[i], s.list[j] = s.list[j], s.list[i] }
+type ByRevision struct{ list }
+
+func (s ByRevision) Less(i, j int) bool {
+ return s.list[i].Version < s.list[j].Version
+}
// Reverse reverses the list of releases sorted by the sort func.
func Reverse(list []*rspb.Release, sortFn func([]*rspb.Release)) {
@@ -42,36 +56,17 @@ func Reverse(list []*rspb.Release, sortFn func([]*rspb.Release)) {
// SortByName returns the list of releases sorted
// in lexicographical order.
func SortByName(list []*rspb.Release) {
- s := &sorter{list: list}
- s.less = func(i, j int) bool {
- ni := s.list[i].Name
- nj := s.list[j].Name
- return ni < nj
- }
- sort.Sort(s)
+ sort.Sort(ByName{list})
}
// SortByDate returns the list of releases sorted by a
// release's last deployed time (in seconds).
func SortByDate(list []*rspb.Release) {
- s := &sorter{list: list}
-
- s.less = func(i, j int) bool {
- ti := s.list[i].Info.LastDeployed.Second()
- tj := s.list[j].Info.LastDeployed.Second()
- return ti < tj
- }
- sort.Sort(s)
+ sort.Sort(ByDate{list})
}
// SortByRevision returns the list of releases sorted by a
// release's revision number (release.Version).
func SortByRevision(list []*rspb.Release) {
- s := &sorter{list: list}
- s.less = func(i, j int) bool {
- vi := s.list[i].Version
- vj := s.list[j].Version
- return vi < vj
- }
- sort.Sort(s)
+ sort.Sort(ByRevision{list})
}
diff --git a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go
index 708b15043..03d89fe2f 100644
--- a/pkg/repo/chartrepo.go
+++ b/pkg/repo/chartrepo.go
@@ -27,7 +27,7 @@ import (
"github.com/ghodss/yaml"
"github.com/pkg/errors"
- "k8s.io/helm/pkg/chartutil"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/provenance"
)
@@ -172,7 +172,7 @@ func (r *ChartRepository) saveIndexFile() error {
func (r *ChartRepository) generateIndex() error {
for _, path := range r.ChartPaths {
- ch, err := chartutil.Load(path)
+ ch, err := loader.Load(path)
if err != nil {
return err
}
@@ -182,7 +182,7 @@ func (r *ChartRepository) generateIndex() error {
return err
}
- if !r.IndexFile.Has(ch.Metadata.Name, ch.Metadata.Version) {
+ if !r.IndexFile.Has(ch.Name(), ch.Metadata.Version) {
r.IndexFile.Add(ch.Metadata, path, r.Config.URL, digest)
}
// TODO: If a chart exists, but has a different Digest, should we error?
diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go
index b1c066ced..01563a31e 100644
--- a/pkg/repo/chartrepo_test.go
+++ b/pkg/repo/chartrepo_test.go
@@ -27,8 +27,8 @@ import (
"testing"
"time"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/getter"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/helm/environment"
)
diff --git a/pkg/repo/index.go b/pkg/repo/index.go
index 9cd6159fc..d64b065b8 100644
--- a/pkg/repo/index.go
+++ b/pkg/repo/index.go
@@ -30,8 +30,8 @@ import (
"github.com/ghodss/yaml"
"github.com/pkg/errors"
- "k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/provenance"
"k8s.io/helm/pkg/urlutil"
)
@@ -251,7 +251,7 @@ func IndexDirectory(dir, baseURL string) (*IndexFile, error) {
parentURL = filepath.Join(baseURL, parentDir)
}
- c, err := chartutil.Load(arch)
+ c, err := loader.Load(arch)
if err != nil {
// Assume this is not a chart.
continue
diff --git a/pkg/repo/index_test.go b/pkg/repo/index_test.go
index c3199290a..68f8c7176 100644
--- a/pkg/repo/index_test.go
+++ b/pkg/repo/index_test.go
@@ -22,8 +22,8 @@ import (
"path/filepath"
"testing"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/getter"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/helm/environment"
)
diff --git a/pkg/resolver/resolver.go b/pkg/resolver/resolver.go
index 2d2fba018..4df51181a 100644
--- a/pkg/resolver/resolver.go
+++ b/pkg/resolver/resolver.go
@@ -26,7 +26,7 @@ import (
"github.com/Masterminds/semver"
"github.com/pkg/errors"
- "k8s.io/helm/pkg/chartutil"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/provenance"
"k8s.io/helm/pkg/repo"
@@ -47,10 +47,10 @@ func New(chartpath string, helmhome helmpath.Home) *Resolver {
}
// Resolve resolves dependencies and returns a lock file with the resolution.
-func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]string, d string) (*chartutil.RequirementsLock, error) {
+func (r *Resolver) Resolve(reqs *chart.Requirements, repoNames map[string]string, d string) (*chart.RequirementsLock, error) {
// Now we clone the dependencies, locking as we go.
- locked := make([]*chartutil.Dependency, len(reqs.Dependencies))
+ locked := make([]*chart.Dependency, len(reqs.Dependencies))
missing := []string{}
for i, d := range reqs.Dependencies {
if strings.HasPrefix(d.Repository, "file://") {
@@ -59,7 +59,7 @@ func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]st
return nil, err
}
- locked[i] = &chartutil.Dependency{
+ locked[i] = &chart.Dependency{
Name: d.Name,
Repository: d.Repository,
Version: d.Version,
@@ -81,7 +81,7 @@ func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]st
return nil, errors.Errorf("%s chart not found in repo %s", d.Name, d.Repository)
}
- locked[i] = &chartutil.Dependency{
+ locked[i] = &chart.Dependency{
Name: d.Name,
Repository: d.Repository,
}
@@ -107,7 +107,7 @@ func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]st
if len(missing) > 0 {
return nil, errors.Errorf("can't get a valid version for repositories %s. Try changing the version constraint in requirements.yaml", strings.Join(missing, ", "))
}
- return &chartutil.RequirementsLock{
+ return &chart.RequirementsLock{
Generated: time.Now(),
Digest: d,
Dependencies: locked,
@@ -118,7 +118,7 @@ func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]st
//
// This should be used only to compare against another hash generated by this
// function.
-func HashReq(req *chartutil.Requirements) (string, error) {
+func HashReq(req *chart.Requirements) (string, error) {
data, err := json.Marshal(req)
if err != nil {
return "", err
diff --git a/pkg/resolver/resolver_test.go b/pkg/resolver/resolver_test.go
index 78a0bc46c..decf3b59a 100644
--- a/pkg/resolver/resolver_test.go
+++ b/pkg/resolver/resolver_test.go
@@ -18,20 +18,20 @@ package resolver
import (
"testing"
- "k8s.io/helm/pkg/chartutil"
+ "k8s.io/helm/pkg/chart"
)
func TestResolve(t *testing.T) {
tests := []struct {
name string
- req *chartutil.Requirements
- expect *chartutil.RequirementsLock
+ req *chart.Requirements
+ expect *chart.RequirementsLock
err bool
}{
{
name: "version failure",
- req: &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ req: &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "oedipus-rex", Repository: "http://example.com", Version: ">a1"},
},
},
@@ -39,8 +39,8 @@ func TestResolve(t *testing.T) {
},
{
name: "cache index failure",
- req: &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ req: &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "oedipus-rex", Repository: "http://example.com", Version: "1.0.0"},
},
},
@@ -48,8 +48,8 @@ func TestResolve(t *testing.T) {
},
{
name: "chart not found failure",
- req: &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ req: &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "redis", Repository: "http://example.com", Version: "1.0.0"},
},
},
@@ -57,8 +57,8 @@ func TestResolve(t *testing.T) {
},
{
name: "constraint not satisfied failure",
- req: &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ req: &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "alpine", Repository: "http://example.com", Version: ">=1.0.0"},
},
},
@@ -66,34 +66,34 @@ func TestResolve(t *testing.T) {
},
{
name: "valid lock",
- req: &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ req: &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "alpine", Repository: "http://example.com", Version: ">=0.1.0"},
},
},
- expect: &chartutil.RequirementsLock{
- Dependencies: []*chartutil.Dependency{
+ expect: &chart.RequirementsLock{
+ Dependencies: []*chart.Dependency{
{Name: "alpine", Repository: "http://example.com", Version: "0.2.0"},
},
},
},
{
name: "repo from valid local path",
- req: &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ req: &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "signtest", Repository: "file://../../../../cmd/helm/testdata/testcharts/signtest", Version: "0.1.0"},
},
},
- expect: &chartutil.RequirementsLock{
- Dependencies: []*chartutil.Dependency{
+ expect: &chart.RequirementsLock{
+ Dependencies: []*chart.Dependency{
{Name: "signtest", Repository: "file://../../../../cmd/helm/testdata/testcharts/signtest", Version: "0.1.0"},
},
},
},
{
name: "repo from invalid local path",
- req: &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ req: &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "notexist", Repository: "file://../testdata/notexist", Version: "0.1.0"},
},
},
@@ -147,8 +147,8 @@ func TestResolve(t *testing.T) {
func TestHashReq(t *testing.T) {
expect := "sha256:e70e41f8922e19558a8bf62f591a8b70c8e4622e3c03e5415f09aba881f13885"
- req := &chartutil.Requirements{
- Dependencies: []*chartutil.Dependency{
+ req := &chart.Requirements{
+ Dependencies: []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "http://localhost:8879/charts"},
},
}
@@ -160,7 +160,7 @@ func TestHashReq(t *testing.T) {
t.Errorf("Expected %q, got %q", expect, h)
}
- req = &chartutil.Requirements{Dependencies: []*chartutil.Dependency{}}
+ req = &chart.Requirements{Dependencies: []*chart.Dependency{}}
h, err = HashReq(req)
if err != nil {
t.Fatal(err)
diff --git a/pkg/tiller/engine.go b/pkg/tiller/engine.go
new file mode 100644
index 000000000..06e27c53f
--- /dev/null
+++ b/pkg/tiller/engine.go
@@ -0,0 +1,40 @@
+/*
+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 tiller
+
+import (
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/chartutil"
+)
+
+// Engine represents a template engine that can render templates.
+//
+// For some engines, "rendering" includes both compiling and executing. (Other
+// engines do not distinguish between phases.)
+//
+// The engine returns a map where the key is the named output entity (usually
+// a file name) and the value is the rendered content of the template.
+//
+// An Engine must be capable of executing multiple concurrent requests, but
+// without tainting one request's environment with data from another request.
+type Engine interface {
+ // Render renders a chart.
+ //
+ // It receives a chart, a config, and a map of overrides to the config.
+ // Overrides are assumed to be passed from the system, not the user.
+ Render(*chart.Chart, chartutil.Values) (map[string]string, error)
+}
diff --git a/pkg/tiller/environment/environment.go b/pkg/tiller/environment/environment.go
index fb2293789..8815b2d2d 100644
--- a/pkg/tiller/environment/environment.go
+++ b/pkg/tiller/environment/environment.go
@@ -29,64 +29,9 @@ import (
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
- "k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/engine"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/kube"
)
-// GoTplEngine is the name of the Go template engine, as registered in the EngineYard.
-const GoTplEngine = "gotpl"
-
-// DefaultEngine points to the engine that the EngineYard should treat as the
-// default. A chart that does not specify an engine may be run through the
-// default engine.
-var DefaultEngine = GoTplEngine
-
-// EngineYard maps engine names to engine implementations.
-type EngineYard map[string]Engine
-
-// Get retrieves a template engine by name.
-//
-// If no matching template engine is found, the second return value will
-// be false.
-func (y EngineYard) Get(k string) (Engine, bool) {
- e, ok := y[k]
- return e, ok
-}
-
-// Default returns the default template engine.
-//
-// The default is specified by DefaultEngine.
-//
-// If the default template engine cannot be found, this panics.
-func (y EngineYard) Default() Engine {
- d, ok := y[DefaultEngine]
- if !ok {
- // This is a developer error!
- panic("Default template engine does not exist")
- }
- return d
-}
-
-// Engine represents a template engine that can render templates.
-//
-// For some engines, "rendering" includes both compiling and executing. (Other
-// engines do not distinguish between phases.)
-//
-// The engine returns a map where the key is the named output entity (usually
-// a file name) and the value is the rendered content of the template.
-//
-// An Engine must be capable of executing multiple concurrent requests, but
-// without tainting one request's environment with data from another request.
-type Engine interface {
- // Render renders a chart.
- //
- // It receives a chart, a config, and a map of overrides to the config.
- // Overrides are assumed to be passed from the system, not the user.
- Render(*chart.Chart, chartutil.Values) (map[string]string, error)
-}
-
// KubeClient represents a client capable of communicating with the Kubernetes API.
//
// A KubeClient must be concurrency safe.
@@ -193,25 +138,3 @@ func (p *PrintingKubeClient) WaitAndGetCompletedPodPhase(namespace string, reade
_, err := io.Copy(p.Out, reader)
return core.PodUnknown, err
}
-
-// Environment provides the context for executing a client request.
-//
-// All services in a context are concurrency safe.
-type Environment struct {
- // EngineYard provides access to the known template engines.
- EngineYard EngineYard
-}
-
-// New returns an environment initialized with the defaults.
-func New() *Environment {
- e := engine.New()
- var ey EngineYard = map[string]Engine{
- // Currently, the only template engine we support is the GoTpl one. But
- // we can easily add some here.
- GoTplEngine: e,
- }
-
- return &Environment{
- EngineYard: ey,
- }
-}
diff --git a/pkg/tiller/environment/environment_test.go b/pkg/tiller/environment/environment_test.go
index 616163e4c..47299c6b6 100644
--- a/pkg/tiller/environment/environment_test.go
+++ b/pkg/tiller/environment/environment_test.go
@@ -25,19 +25,9 @@ import (
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
- "k8s.io/helm/pkg/chartutil"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/kube"
)
-type mockEngine struct {
- out map[string]string
-}
-
-func (e *mockEngine) Render(chrt *chart.Chart, v chartutil.Values) (map[string]string, error) {
- return e.out, nil
-}
-
type mockKubeClient struct{}
func (k *mockKubeClient) Create(ns string, r io.Reader, timeout int64, shouldWait bool) error {
@@ -69,25 +59,9 @@ func (k *mockKubeClient) WaitAndGetCompletedPodStatus(namespace string, reader i
return "", nil
}
-var _ Engine = &mockEngine{}
var _ KubeClient = &mockKubeClient{}
var _ KubeClient = &PrintingKubeClient{}
-func TestEngine(t *testing.T) {
- eng := &mockEngine{out: map[string]string{"albatross": "test"}}
-
- env := New()
- env.EngineYard = EngineYard(map[string]Engine{"test": eng})
-
- if engine, ok := env.EngineYard.Get("test"); !ok {
- t.Errorf("failed to get engine from EngineYard")
- } else if out, err := engine.Render(&chart.Chart{}, map[string]interface{}{}); err != nil {
- t.Errorf("unexpected template error: %s", err)
- } else if out["albatross"] != "test" {
- t.Errorf("expected 'test', got %q", out["albatross"])
- }
-}
-
func TestKubeClient(t *testing.T) {
kc := &mockKubeClient{}
diff --git a/pkg/tiller/hook_sorter.go b/pkg/tiller/hook_sorter.go
index cc6e7e992..4643dc439 100644
--- a/pkg/tiller/hook_sorter.go
+++ b/pkg/tiller/hook_sorter.go
@@ -17,37 +17,16 @@ limitations under the License.
package tiller
import (
- "sort"
-
"k8s.io/helm/pkg/hapi/release"
)
-// sortByHookWeight does an in-place sort of hooks by their supplied weight.
-func sortByHookWeight(hooks []*release.Hook) []*release.Hook {
- hs := newHookWeightSorter(hooks)
- sort.Sort(hs)
- return hs.hooks
-}
-
-type hookWeightSorter struct {
- hooks []*release.Hook
-}
-
-func newHookWeightSorter(h []*release.Hook) *hookWeightSorter {
- return &hookWeightSorter{
- hooks: h,
- }
-}
-
-func (hs *hookWeightSorter) Len() int { return len(hs.hooks) }
-
-func (hs *hookWeightSorter) Swap(i, j int) {
- hs.hooks[i], hs.hooks[j] = hs.hooks[j], hs.hooks[i]
-}
+type hookByWeight []*release.Hook
-func (hs *hookWeightSorter) Less(i, j int) bool {
- if hs.hooks[i].Weight == hs.hooks[j].Weight {
- return hs.hooks[i].Name < hs.hooks[j].Name
+func (x hookByWeight) Len() int { return len(x) }
+func (x hookByWeight) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x hookByWeight) Less(i, j int) bool {
+ if x[i].Weight == x[j].Weight {
+ return x[i].Name < x[j].Name
}
- return hs.hooks[i].Weight < hs.hooks[j].Weight
+ return x[i].Weight < x[j].Weight
}
diff --git a/pkg/tiller/hook_sorter_test.go b/pkg/tiller/hook_sorter_test.go
index 4e33bdad4..3360fcbd1 100644
--- a/pkg/tiller/hook_sorter_test.go
+++ b/pkg/tiller/hook_sorter_test.go
@@ -17,6 +17,7 @@ limitations under the License.
package tiller
import (
+ "sort"
"testing"
"k8s.io/helm/pkg/hapi/release"
@@ -61,10 +62,10 @@ func TestHookSorter(t *testing.T) {
},
}
- res := sortByHookWeight(hooks)
+ sort.Sort(hookByWeight(hooks))
got := ""
expect := "abcdefg"
- for _, r := range res {
+ for _, r := range hooks {
got += r.Name
}
if got != expect {
diff --git a/pkg/tiller/hooks.go b/pkg/tiller/hooks.go
index 29c311509..55e748a66 100644
--- a/pkg/tiller/hooks.go
+++ b/pkg/tiller/hooks.go
@@ -78,7 +78,7 @@ type manifestFile struct {
//
// Files that do not parse into the expected format are simply placed into a map and
// returned.
-func sortManifests(files map[string]string, apis chartutil.VersionSet, sort SortOrder) ([]*release.Hook, []Manifest, error) {
+func SortManifests(files map[string]string, apis chartutil.VersionSet, sort SortOrder) ([]*release.Hook, []Manifest, error) {
result := &result{}
for filePath, c := range files {
diff --git a/pkg/tiller/hooks_test.go b/pkg/tiller/hooks_test.go
index 694c1cab1..ef0fdbd40 100644
--- a/pkg/tiller/hooks_test.go
+++ b/pkg/tiller/hooks_test.go
@@ -140,7 +140,7 @@ metadata:
manifests[o.path] = o.manifest
}
- hs, generic, err := sortManifests(manifests, chartutil.NewVersionSet("v1", "v1beta1"), InstallOrder)
+ hs, generic, err := SortManifests(manifests, chartutil.NewVersionSet("v1", "v1beta1"), InstallOrder)
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
diff --git a/pkg/tiller/release_content_test.go b/pkg/tiller/release_content_test.go
index b5947fc57..71b5a3e02 100644
--- a/pkg/tiller/release_content_test.go
+++ b/pkg/tiller/release_content_test.go
@@ -34,7 +34,7 @@ func TestGetReleaseContent(t *testing.T) {
t.Errorf("Error getting release content: %s", err)
}
- if res.Chart.Metadata.Name != rel.Chart.Metadata.Name {
- t.Errorf("Expected %q, got %q", rel.Chart.Metadata.Name, res.Chart.Metadata.Name)
+ if res.Chart.Name() != rel.Chart.Name() {
+ t.Errorf("Expected %q, got %q", rel.Chart.Name(), res.Chart.Name())
}
}
diff --git a/pkg/tiller/release_install.go b/pkg/tiller/release_install.go
index db07249f5..c9087ffd7 100644
--- a/pkg/tiller/release_install.go
+++ b/pkg/tiller/release_install.go
@@ -66,16 +66,16 @@ func (s *ReleaseServer) prepareRelease(req *hapi.InstallReleaseRequest) (*releas
}
revision := 1
- ts := time.Now()
options := chartutil.ReleaseOptions{
Name: name,
IsInstall: true,
}
- valuesToRender, err := chartutil.ToRenderValuesCaps(req.Chart, req.Values, options, caps)
+ valuesToRender, err := chartutil.ToRenderValues(req.Chart, req.Values, options, caps)
if err != nil {
return nil, err
}
+ ts := time.Now()
hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions)
if err != nil {
// Return a release with partial data so that client can show debugging
diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go
index a6201489e..511babb71 100644
--- a/pkg/tiller/release_server.go
+++ b/pkg/tiller/release_server.go
@@ -20,6 +20,7 @@ import (
"bytes"
"path"
"regexp"
+ "sort"
"strings"
"time"
@@ -29,9 +30,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chartutil"
+ "k8s.io/helm/pkg/engine"
"k8s.io/helm/pkg/hapi"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/hapi/release"
"k8s.io/helm/pkg/hooks"
relutil "k8s.io/helm/pkg/releaseutil"
@@ -78,7 +80,7 @@ var ValidName = regexp.MustCompile("^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+
// ReleaseServer implements the server-side gRPC endpoint for the HAPI services.
type ReleaseServer struct {
- env *environment.Environment
+ engine Engine
discovery discovery.DiscoveryInterface
// Releases stores records of releases.
@@ -90,9 +92,9 @@ type ReleaseServer struct {
}
// NewReleaseServer creates a new release server.
-func NewReleaseServer(env *environment.Environment, discovery discovery.DiscoveryInterface, kubeClient environment.KubeClient) *ReleaseServer {
+func NewReleaseServer(discovery discovery.DiscoveryInterface, kubeClient environment.KubeClient) *ReleaseServer {
return &ReleaseServer{
- env: env,
+ engine: engine.New(),
discovery: discovery,
Releases: storage.Init(driver.NewMemory()),
KubeClient: kubeClient,
@@ -204,18 +206,6 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) {
return "ERROR", errors.New("no available release name found")
}
-func (s *ReleaseServer) engine(ch *chart.Chart) environment.Engine {
- renderer := s.env.EngineYard.Default()
- if ch.Metadata.Engine != "" {
- if r, ok := s.env.EngineYard.Get(ch.Metadata.Engine); ok {
- renderer = r
- } else {
- s.Log("warning: %s requested non-existent template engine %s", ch.Metadata.Name, ch.Metadata.Engine)
- }
- }
- return renderer
-}
-
// capabilities builds a Capabilities from discovery information.
func capabilities(disc discovery.DiscoveryInterface) (*chartutil.Capabilities, error) {
sv, err := disc.ServerVersion()
@@ -269,9 +259,8 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values
}
}
- s.Log("rendering %s chart using values", ch.Metadata.Name)
- renderer := s.engine(ch)
- files, err := renderer.Render(ch, values)
+ s.Log("rendering %s chart using values", ch.Name())
+ files, err := s.engine.Render(ch, values)
if err != nil {
return nil, nil, "", err
}
@@ -286,7 +275,7 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values
if strings.HasSuffix(k, notesFileSuffix) {
// Only apply the notes if it belongs to the parent chart
// Note: Do not use filePath.Join since it creates a path with \ which is not expected
- if k == path.Join(ch.Metadata.Name, "templates", notesFileSuffix) {
+ if k == path.Join(ch.Name(), "templates", notesFileSuffix) {
notes = v
}
delete(files, k)
@@ -296,7 +285,7 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values
// Sort hooks, manifests, and partials. Only hooks and manifests are returned,
// as partials are not used after renderer.Render. Empty manifests are also
// removed here.
- hooks, manifests, err := sortManifests(files, vs, InstallOrder)
+ hooks, manifests, err := SortManifests(files, vs, InstallOrder)
if err != nil {
// By catching parse errors here, we can prevent bogus releases from going
// to Kubernetes.
@@ -351,7 +340,7 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
}
}
- executingHooks = sortByHookWeight(executingHooks)
+ sort.Sort(hookByWeight(executingHooks))
for _, h := range executingHooks {
if err := s.deleteHookIfShouldBeDeletedByDeletePolicy(h, hooks.BeforeHookCreation, name, namespace, hook, s.KubeClient); err != nil {
diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go
index 9840c4731..97b4b19f9 100644
--- a/pkg/tiller/release_server_test.go
+++ b/pkg/tiller/release_server_test.go
@@ -32,8 +32,9 @@ import (
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
+ "k8s.io/helm/pkg/chart"
+ "k8s.io/helm/pkg/engine"
"k8s.io/helm/pkg/hapi"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/hapi/release"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/kube"
@@ -93,10 +94,9 @@ data:
func rsFixture(t *testing.T) *ReleaseServer {
t.Helper()
- env := environment.New()
dc := fake.NewSimpleClientset().Discovery()
kc := &environment.PrintingKubeClient{Out: ioutil.Discard}
- rs := NewReleaseServer(env, dc, kc)
+ rs := NewReleaseServer(dc, kc)
rs.Log = func(format string, v ...interface{}) {
t.Helper()
if *verbose {
@@ -142,7 +142,7 @@ func withKube(version string) chartOption {
func withDependency(dependencyOpts ...chartOption) chartOption {
return func(opts *chartOptions) {
- opts.Dependencies = append(opts.Dependencies, buildChart(dependencyOpts...))
+ opts.AddDependency(buildChart(dependencyOpts...))
}
}
@@ -483,26 +483,23 @@ func (kc *mockHooksKubeClient) WatchUntilReady(ns string, r io.Reader, timeout i
return nil
}
-func (kc *mockHooksKubeClient) Update(ns string, currentReader, modifiedReader io.Reader, force, recreate bool, timeout int64, shouldWait bool) error {
+func (kc *mockHooksKubeClient) Update(_ string, _, _ io.Reader, _, _ bool, _ int64, _ bool) error {
return nil
}
-func (kc *mockHooksKubeClient) Build(ns string, reader io.Reader) (kube.Result, error) {
+func (kc *mockHooksKubeClient) Build(_ string, _ io.Reader) (kube.Result, error) {
return []*resource.Info{}, nil
}
-func (kc *mockHooksKubeClient) BuildUnstructured(ns string, reader io.Reader) (kube.Result, error) {
+func (kc *mockHooksKubeClient) BuildUnstructured(_ string, _ io.Reader) (kube.Result, error) {
return []*resource.Info{}, nil
}
-func (kc *mockHooksKubeClient) WaitAndGetCompletedPodPhase(namespace string, reader io.Reader, timeout time.Duration) (core.PodPhase, error) {
+func (kc *mockHooksKubeClient) WaitAndGetCompletedPodPhase(_ string, _ io.Reader, _ time.Duration) (core.PodPhase, error) {
return core.PodUnknown, nil
}
func deletePolicyStub(kubeClient *mockHooksKubeClient) *ReleaseServer {
- e := environment.New()
-
- dc := fake.NewSimpleClientset().Discovery()
return &ReleaseServer{
- env: e,
- discovery: dc,
+ engine: engine.New(),
+ discovery: fake.NewSimpleClientset().Discovery(),
KubeClient: kubeClient,
Log: func(_ string, _ ...interface{}) {},
}
diff --git a/pkg/tiller/release_uninstall.go b/pkg/tiller/release_uninstall.go
index 9abb7559c..b39e9a2b6 100644
--- a/pkg/tiller/release_uninstall.go
+++ b/pkg/tiller/release_uninstall.go
@@ -132,7 +132,7 @@ func (s *ReleaseServer) deleteRelease(rel *release.Release) (kept string, errs [
}
manifests := relutil.SplitManifests(rel.Manifest)
- _, files, err := sortManifests(manifests, vs, UninstallOrder)
+ _, files, err := SortManifests(manifests, vs, UninstallOrder)
if err != nil {
// We could instead just delete everything in no particular order.
// FIXME: One way to delete at this point would be to try a label-based
diff --git a/pkg/tiller/release_update.go b/pkg/tiller/release_update.go
index 763c49bfb..2d86b65b0 100644
--- a/pkg/tiller/release_update.go
+++ b/pkg/tiller/release_update.go
@@ -105,7 +105,7 @@ func (s *ReleaseServer) prepareUpdate(req *hapi.UpdateReleaseRequest) (*release.
if err != nil {
return nil, nil, err
}
- valuesToRender, err := chartutil.ToRenderValuesCaps(req.Chart, req.Values, options, caps)
+ valuesToRender, err := chartutil.ToRenderValues(req.Chart, req.Values, options, caps)
if err != nil {
return nil, nil, err
}
diff --git a/pkg/tiller/release_update_test.go b/pkg/tiller/release_update_test.go
index 08a119ff2..15c367311 100644
--- a/pkg/tiller/release_update_test.go
+++ b/pkg/tiller/release_update_test.go
@@ -22,8 +22,8 @@ import (
"strings"
"testing"
+ "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/hapi"
- "k8s.io/helm/pkg/hapi/chart"
"k8s.io/helm/pkg/hapi/release"
)