From b74fee715ee1d660be8fea8bf35942fc447a6a7e Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Wed, 13 Mar 2019 11:44:41 +0000 Subject: [PATCH 01/12] Add capability for application charts to be used as library charts Signed-off-by: Martin Hickey --- cmd/helm/template_test.go | 10 + ...te-chart-with-template-lib-archive-dep.txt | 62 ++ .../template-chart-with-template-lib-dep.txt | 62 ++ .../.helmignore | 21 + .../Chart.yaml | 6 + .../charts/common-0.0.5.tgz | Bin 0 -> 8446 bytes .../templates/NOTES.txt | 19 + .../templates/_helpers.tpl | 32 + .../templates/deployment.yaml | 51 ++ .../templates/ingress.yaml | 38 + .../templates/service.yaml | 10 + .../values.yaml | 48 + .../chart-with-template-lib-dep/.helmignore | 21 + .../chart-with-template-lib-dep/Chart.yaml | 6 + .../charts/common/.helmignore | 21 + .../charts/common/Chart.yaml | 12 + .../charts/common/README.md | 831 ++++++++++++++++++ .../charts/common/templates/_chartref.tpl | 14 + .../charts/common/templates/_configmap.yaml | 9 + .../charts/common/templates/_container.yaml | 15 + .../charts/common/templates/_deployment.yaml | 18 + .../charts/common/templates/_envvar.tpl | 31 + .../charts/common/templates/_fullname.tpl | 39 + .../charts/common/templates/_ingress.yaml | 27 + .../charts/common/templates/_metadata.yaml | 10 + .../templates/_metadata_annotations.tpl | 18 + .../common/templates/_metadata_labels.tpl | 28 + .../charts/common/templates/_name.tpl | 29 + .../templates/_persistentvolumeclaim.yaml | 24 + .../charts/common/templates/_secret.yaml | 10 + .../charts/common/templates/_service.yaml | 17 + .../charts/common/templates/_util.tpl | 15 + .../charts/common/templates/_volume.tpl | 22 + .../charts/common/templates/configmap.yaml | 6 + .../charts/common/values.yaml | 4 + .../templates/NOTES.txt | 19 + .../templates/_helpers.tpl | 32 + .../templates/deployment.yaml | 51 ++ .../templates/ingress.yaml | 38 + .../templates/service.yaml | 10 + .../chart-with-template-lib-dep/values.yaml | 48 + docs/charts.md | 4 + pkg/chart/loader/archive.go | 43 +- pkg/chart/loader/load.go | 57 +- pkg/registry/cache.go | 2 +- 45 files changed, 1883 insertions(+), 7 deletions(-) create mode 100644 cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt create mode 100644 cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/.helmignore create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/Chart.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/charts/common-0.0.5.tgz create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/templates/NOTES.txt create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/templates/_helpers.tpl create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/templates/deployment.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/templates/ingress.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/templates/service.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/values.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/.helmignore create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/Chart.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/.helmignore create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/Chart.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/README.md create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_chartref.tpl create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_configmap.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_container.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_deployment.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_envvar.tpl create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_fullname.tpl create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_ingress.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_metadata.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_metadata_annotations.tpl create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_metadata_labels.tpl create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_name.tpl create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_persistentvolumeclaim.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_secret.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_service.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_util.tpl create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/_volume.tpl create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/templates/configmap.yaml create mode 100755 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/values.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/templates/NOTES.txt create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/templates/_helpers.tpl create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/templates/deployment.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/templates/ingress.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/templates/service.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-template-lib-dep/values.yaml diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index 65586c394..d4131acd3 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -64,6 +64,16 @@ func TestTemplateCmd(t *testing.T) { wantError: true, golden: "output/install-chart-bad-type.txt", }, + { + name: "check chart with dependency which is an app chart acting as a library chart", + cmd: fmt.Sprintf("template '%s'", "testdata/testcharts/chart-with-template-lib-dep"), + golden: "output/template-chart-with-template-lib-dep.txt", + }, + { + name: "check chart with dependency which is an app chart archive acting as a library chart", + cmd: fmt.Sprintf("template '%s'", "testdata/testcharts/chart-with-template-lib-archive-dep"), + golden: "output/template-chart-with-template-lib-archive-dep.txt", + }, } runTestCmd(t, tests) } diff --git a/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt b/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt new file mode 100644 index 000000000..d92f71308 --- /dev/null +++ b/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt @@ -0,0 +1,62 @@ +--- +# Source: chart-with-template-lib-archive-dep/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app: chart-with-template-lib-archive-dep + chart: chart-with-template-lib-archive-dep-0.1.0 + heritage: Helm + release: RELEASE-NAME + name: release-name-chart-with-template-lib-archive-dep +spec: + ports: + - name: http + port: 80 + targetPort: http + selector: + app: chart-with-template-lib-archive-dep + release: RELEASE-NAME + type: ClusterIP +--- +# Source: chart-with-template-lib-archive-dep/templates/deployment.yaml +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: RELEASE-NAME-chart-with-template-lib-archive-dep + labels: + app: chart-with-template-lib-archive-dep + chart: chart-with-template-lib-archive-dep-0.1.0 + release: RELEASE-NAME + heritage: Helm +spec: + replicas: 1 + selector: + matchLabels: + app: chart-with-template-lib-archive-dep + release: RELEASE-NAME + template: + metadata: + labels: + app: chart-with-template-lib-archive-dep + release: RELEASE-NAME + spec: + containers: + - name: chart-with-template-lib-archive-dep + image: "nginx:stable" + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {} + diff --git a/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt b/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt new file mode 100644 index 000000000..64a6b305d --- /dev/null +++ b/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt @@ -0,0 +1,62 @@ +--- +# Source: chart-with-template-lib-dep/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app: chart-with-template-lib-dep + chart: chart-with-template-lib-dep-0.1.0 + heritage: Helm + release: RELEASE-NAME + name: release-name-chart-with-template-lib-dep +spec: + ports: + - name: http + port: 80 + targetPort: http + selector: + app: chart-with-template-lib-dep + release: RELEASE-NAME + type: ClusterIP +--- +# Source: chart-with-template-lib-dep/templates/deployment.yaml +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: RELEASE-NAME-chart-with-template-lib-dep + labels: + app: chart-with-template-lib-dep + chart: chart-with-template-lib-dep-0.1.0 + release: RELEASE-NAME + heritage: Helm +spec: + replicas: 1 + selector: + matchLabels: + app: chart-with-template-lib-dep + release: RELEASE-NAME + template: + metadata: + labels: + app: chart-with-template-lib-dep + release: RELEASE-NAME + spec: + containers: + - name: chart-with-template-lib-dep + image: "nginx:stable" + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {} + diff --git a/cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/.helmignore b/cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/Chart.yaml new file mode 100644 index 000000000..de53ce5e3 --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: chart-with-template-lib-archive-dep +type: application +version: 0.1.0 diff --git a/cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/charts/common-0.0.5.tgz b/cmd/helm/testdata/testcharts/chart-with-template-lib-archive-dep/charts/common-0.0.5.tgz new file mode 100644 index 0000000000000000000000000000000000000000..465517824e7a2e6492cede07e7233e7120506185 GIT binary patch literal 8446 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 Date: Fri, 29 Mar 2019 09:31:59 +0000 Subject: [PATCH 02/12] Fix test data Signed-off-by: Martin Hickey --- .../output/template-chart-with-template-lib-archive-dep.txt | 1 - .../testdata/output/template-chart-with-template-lib-dep.txt | 1 - 2 files changed, 2 deletions(-) diff --git a/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt b/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt index d92f71308..23a0b984c 100644 --- a/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt +++ b/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt @@ -59,4 +59,3 @@ spec: port: http resources: {} - diff --git a/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt b/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt index 64a6b305d..33147a73e 100644 --- a/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt +++ b/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt @@ -59,4 +59,3 @@ spec: port: http resources: {} - From 0b809dd07882501af7d4eaf2506aa8105f2e30df Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Wed, 1 May 2019 14:56:32 +0100 Subject: [PATCH 03/12] Validate library chart files after chart loaded Validate the library chart files after the chart and its depoendencies have been loaded. This is an update following review comment: - https://github.com/helm/helm/pull/5441#pullrequestreview-231339425 Signed-off-by: Martin Hickey --- pkg/chart/loader/archive.go | 43 +++------------------------- pkg/chart/loader/load.go | 57 ++----------------------------------- pkg/chartutil/chartfile.go | 16 +++++++++-- pkg/engine/engine.go | 4 +++ pkg/registry/cache.go | 2 +- 5 files changed, 25 insertions(+), 97 deletions(-) diff --git a/pkg/chart/loader/archive.go b/pkg/chart/loader/archive.go index 71a111235..a8dc3f17b 100644 --- a/pkg/chart/loader/archive.go +++ b/pkg/chart/loader/archive.go @@ -51,30 +51,11 @@ func LoadFile(name string) (*chart.Chart, error) { } defer raw.Close() - isLibChart, err := IsArchiveLibraryChart(raw) - if err != nil { - return nil, err - } - _, _ = raw.Seek(0, 0) - return LoadArchive(raw, isLibChart) -} - -// IsArchiveLibraryChart return true if it is a library chart -func IsArchiveLibraryChart(in io.Reader) (bool, error) { - var isLibChart = false - _, err := traverse(in, false, &isLibChart) - if err != nil { - return false, err - } - return isLibChart, nil + return LoadArchive(raw) } // LoadArchive loads from a reader containing a compressed tar archive. -func LoadArchive(in io.Reader, isLibChart bool) (*chart.Chart, error) { - return traverse(in, true, &isLibChart) -} - -func traverse(in io.Reader, loadFiles bool, isLibChart *bool) (*chart.Chart, error) { +func LoadArchive(in io.Reader) (*chart.Chart, error) { unzipped, err := gzip.NewReader(in) if err != nil { return &chart.Chart{}, err @@ -119,29 +100,13 @@ func traverse(in io.Reader, loadFiles bool, isLibChart *bool) (*chart.Chart, err return &chart.Chart{}, err } - if !loadFiles && n == "Chart.yaml" { - var err error - *isLibChart, err = IsLibraryChart(b.Bytes()) - if err != nil { - return nil, errors.Wrapf(err, "cannot load Chart.yaml") - } - return nil, nil - } - - if IsFileValid(n, *isLibChart) { - files = append(files, &BufferedFile{Name: n, Data: b.Bytes()}) - } - + files = append(files, &BufferedFile{Name: n, Data: b.Bytes()}) b.Reset() } - if loadFiles && len(files) == 0 { + if len(files) == 0 { return nil, errors.New("no files in chart archive") } - if !loadFiles { - return nil, errors.New("cannot find the chart type") - } - return LoadFiles(files) } diff --git a/pkg/chart/loader/load.go b/pkg/chart/loader/load.go index 6c78b7964..cd886d8c7 100644 --- a/pkg/chart/loader/load.go +++ b/pkg/chart/loader/load.go @@ -124,30 +124,8 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { 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 - var isLibChart bool - isLibChart, err = IsArchiveLibraryChart(bytes.NewBuffer(file.Data)) - if err == nil { - sc, err = LoadArchive(bytes.NewBuffer(file.Data), isLibChart) - } + sc, err = LoadArchive(bytes.NewBuffer(file.Data)) default: - // Need to ascertain if the subchart is a library chart as will parse files - // differently from a standard application chart - var isLibChart = false - for _, f := range files { - parts := strings.SplitN(f.Name, "/", 2) - if len(parts) < 2 { - continue - } - name := parts[1] - if name == "Chart.yaml" { - isLibChart, err = IsLibraryChart(f.Data) - if err != nil { - return c, errors.Wrapf(err, "cannot load Chart.yaml for %s in %s", n, c.Name()) - } - break - } - } - // 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)) @@ -157,12 +135,7 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { continue } f.Name = parts[1] - - // If the subchart is a library chart then will only want - // to render library and value files, and not any included template files - if IsFileValid(f.Name, isLibChart) { - buff = append(buff, f) - } + buff = append(buff, f) } sc, err = LoadFiles(buff) } @@ -170,34 +143,8 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { if err != nil { return c, errors.Wrapf(err, "error unpacking %s in %s", n, c.Name()) } - c.AddDependency(sc) } return c, nil } - -// IsLibraryChart return true if it is a library chart -func IsLibraryChart(data []byte) (bool, error) { - var isLibChart = false - metadata := new(chart.Metadata) - if err := yaml.Unmarshal(data, metadata); err != nil { - return false, errors.Wrapf(err, "cannot load data") - } - if strings.EqualFold(metadata.Type, "library") { - isLibChart = true - } - return isLibChart, nil -} - -// IsFileValid return true if this file is valid for library or -// application chart -func IsFileValid(filename string, isLibChart bool) bool { - if isLibChart { - if strings.HasPrefix(filepath.Base(filename), "_") || !strings.HasPrefix(filepath.Dir(filename), "template") { - return true - } - return false - } - return true -} diff --git a/pkg/chartutil/chartfile.go b/pkg/chartutil/chartfile.go index 17d6e2bb2..9caa3f87e 100644 --- a/pkg/chartutil/chartfile.go +++ b/pkg/chartutil/chartfile.go @@ -88,8 +88,7 @@ func IsChartDir(dirName string) (bool, error) { // // Application chart type is only installable func IsChartInstallable(chart *chart.Chart) (bool, error) { - chartType := chart.Metadata.Type - if strings.EqualFold(chartType, "library") { + if IsLibraryChart(chart) { return false, errors.New("Library charts are not installable") } validChartType, _ := IsValidChartType(chart) @@ -110,3 +109,16 @@ func IsValidChartType(chart *chart.Chart) (bool, error) { } return true, nil } + +// IsLibraryChart returns true if the chart is a library chart +func IsLibraryChart(c *chart.Chart) bool { + return strings.EqualFold(c.Metadata.Type, "library") +} + +// IsTemplateValid returns true if the template is valid for the chart type +func IsTemplateValid(templateName string, isLibChart bool) bool { + if isLibChart { + return strings.HasPrefix(filepath.Base(templateName), "_") + } + return true +} diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index b1bc93040..4d3e418bc 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -268,8 +268,12 @@ func recAllTpls(c *chart.Chart, templates map[string]renderable, vals chartutil. recAllTpls(child, templates, next) } + isLibChart := chartutil.IsLibraryChart(c) newParentID := c.ChartFullPath() for _, t := range c.Templates { + if !chartutil.IsTemplateValid(t.Name, isLibChart) { + continue + } templates[path.Join(newParentID, t.Name)] = renderable{ tpl: string(t.Data), vals: next, diff --git a/pkg/registry/cache.go b/pkg/registry/cache.go index cd5d0a203..39dec1467 100644 --- a/pkg/registry/cache.go +++ b/pkg/registry/cache.go @@ -85,7 +85,7 @@ func (cache *filesystemCache) LayersToChart(layers []ocispec.Descriptor) (*chart } // Construct chart object and attach metadata - ch, err := loader.LoadArchive(bytes.NewBuffer(contentRaw), false) + ch, err := loader.LoadArchive(bytes.NewBuffer(contentRaw)) if err != nil { return nil, err } From b960dea497f499e6fec0836dcfd4c874dc19c696 Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Thu, 9 May 2019 19:53:52 -0700 Subject: [PATCH 04/12] fix(cmd/helm): set 300s as default on timeout flags Signed-off-by: Adam Reese --- cmd/helm/install.go | 3 ++- cmd/helm/release_testing_run.go | 3 ++- cmd/helm/rollback.go | 3 ++- cmd/helm/uninstall.go | 3 ++- cmd/helm/upgrade.go | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 61ba90084..fefa18c05 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -18,6 +18,7 @@ package main import ( "io" + "time" "helm.sh/helm/pkg/release" @@ -121,7 +122,7 @@ func addInstallFlags(f *pflag.FlagSet, client *action.Install) { f.BoolVar(&client.DryRun, "dry-run", false, "simulate an install") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install") f.BoolVar(&client.Replace, "replace", false, "re-use the given name, even if that name is already used. This is unsafe in production") - f.DurationVar(&client.Timeout, "timeout", 300, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") + f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.BoolVarP(&client.GenerateName, "generate-name", "g", false, "generate the name (and omit the NAME parameter)") f.StringVar(&client.NameTemplate, "name-template", "", "specify template used to name the release") diff --git a/cmd/helm/release_testing_run.go b/cmd/helm/release_testing_run.go index 4a639c75e..9608ba374 100644 --- a/cmd/helm/release_testing_run.go +++ b/cmd/helm/release_testing_run.go @@ -18,6 +18,7 @@ package main import ( "fmt" "io" + "time" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -68,7 +69,7 @@ func newReleaseTestRunCmd(cfg *action.Configuration, out io.Writer) *cobra.Comma } f := cmd.Flags() - f.DurationVar(&client.Timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") + f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&client.Cleanup, "cleanup", false, "delete test pods upon completion") return cmd diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index a46ee8b9d..ff2236cfa 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -19,6 +19,7 @@ package main import ( "fmt" "io" + "time" "github.com/spf13/cobra" @@ -60,7 +61,7 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVar(&client.Recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") f.BoolVar(&client.Force, "force", false, "force resource update through delete/recreate if needed") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during rollback") - f.DurationVar(&client.Timeout, "timeout", 300, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") + f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") return cmd diff --git a/cmd/helm/uninstall.go b/cmd/helm/uninstall.go index 814237a55..0710a3c45 100644 --- a/cmd/helm/uninstall.go +++ b/cmd/helm/uninstall.go @@ -19,6 +19,7 @@ package main import ( "fmt" "io" + "time" "github.com/spf13/cobra" @@ -67,7 +68,7 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVar(&client.DryRun, "dry-run", false, "simulate a uninstall") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation") f.BoolVar(&client.KeepHistory, "keep-history", false, "remove all associated resources and mark the release as deleted, but retain the release history") - f.DurationVar(&client.Timeout, "timeout", 300, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") + f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") return cmd } diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index efc472d9e..4bbf46d4f 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -19,6 +19,7 @@ package main import ( "fmt" "io" + "time" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -142,7 +143,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVar(&client.Recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") f.BoolVar(&client.Force, "force", false, "force resource update through delete/recreate if needed") f.BoolVar(&client.DisableHooks, "no-hooks", false, "disable pre/post upgrade hooks") - f.DurationVar(&client.Timeout, "timeout", 300, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") + f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&client.ResetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") f.BoolVar(&client.ReuseValues, "reuse-values", false, "when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored.") f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") From 65ad58511eab0332c502d3f5ce4778618047a7b6 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Wed, 8 May 2019 10:10:34 -0400 Subject: [PATCH 05/12] Updating OWERS to remove outdated reviewers and to reflect current case Two changes in this: 1. Remove the reviewers. These are from when Helm was under Kubernetes and used its tools. That is no longer the case so this section has no use. 2. List fibonacci1729 with the maintainers. He has been a maintainer a long time. The original listing had to do with department locations within Deis rather than his work. He has been a maintainer since before Helm was a CNCF project. Fixes #5685 Signed-off-by: Matt Farina --- OWNERS | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/OWNERS b/OWNERS index 32b26efa2..fcc3606c2 100644 --- a/OWNERS +++ b/OWNERS @@ -1,24 +1,11 @@ maintainers: - - adamreese - - bacongobbler - - jascott1 - - mattfarina - - michelleN - - nebril - - prydonius - - SlickNik - - technosophos - - thomastaylor312 - - viglesiasce -reviewers: - adamreese - bacongobbler - fibonacci1729 + - hickeyma - jascott1 - mattfarina - michelleN - - migmartri - - nebril - prydonius - SlickNik - technosophos @@ -26,5 +13,7 @@ reviewers: - viglesiasce emeritus: - migmartri + - nebril - seh - vaikas-google + - rimusz From 22d0ba8b51563cbaf7bd180ccc89eff21cf97219 Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Fri, 10 May 2019 15:29:21 +0100 Subject: [PATCH 06/12] Print manifest output for dry-run option Signed-off-by: Martin Hickey --- pkg/action/printer.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/action/printer.go b/pkg/action/printer.go index 30f46b0ee..abc0ce243 100644 --- a/pkg/action/printer.go +++ b/pkg/action/printer.go @@ -56,6 +56,10 @@ func PrintRelease(out io.Writer, rel *release.Release) { formatTestResults(lastRun.Results)) } + if strings.EqualFold(rel.Info.Description, "Dry run complete") { + fmt.Fprintf(out, "MANIFEST:\n%s\n", rel.Manifest) + } + if len(rel.Info.Notes) > 0 { fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(rel.Info.Notes)) } From 041c347edbd8225f9361ecde63d93746b45851e9 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Fri, 10 May 2019 09:03:46 -0700 Subject: [PATCH 07/12] docs(faq): more information on what changed in Helm 3 Signed-off-by: Matthew Fisher --- docs/faq.md | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 148 insertions(+), 4 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index bcb5afc7e..08f565e65 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -10,12 +10,155 @@ send us a pull request. Here's an exhaustive list of all the major changes introduced in Helm 3. +### Removal of Tiller + +During the Helm 2 development cycle, we introduced Tiller. Tiller played an important role for teams working on a shared +cluster - it made it possible for multiple different operators to interact with the same set of releases. + +With role-based access controls (RBAC) enabled by default in Kubernetes 1.6, locking down Tiller for use in a production +scenario became more difficult to manage. Due to the vast number of possible security policies, our stance was to +provide a permissive default configuration. This allowed first-time users to start experimenting with Helm and +Kubernetes without having to dive headfirst into the security controls. Unfortunately, this permissive configuration +could grant a user a broad range of permissions they weren’t intended to have. DevOps and SREs had to learn additional +operational steps when installing Tiller into a multi-tenant cluster. + +After hearing how community members were using Helm in certain scenarios, we found that Tiller’s release management +system did not need to rely upon an in-cluster operator to maintain state or act as a central hub for Helm release +information. Instead, we could simply fetch information from the Kubernetes API server, render the Charts client-side, +and store a record of the installation in Kubernetes. + +Tiller’s primary goal could be accomplished without Tiller, so one of the first decisions we made regarding Helm 3 was +to completely remove Tiller. + +With Tiller gone, the security model for Helm is radically simplified. Helm 3 now supports all the modern security, +identity, and authorization features of modern Kubernetes. Helm’s permissions are evaluated using your [kubeconfig file](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/). +Cluster administrators can restrict user permissions at whatever granularity they see fit. Releases are still recorded +in-cluster, and the rest of Helm’s functionality remains. + +### Release Names are now scoped to the Namespace + +With the removal of Tiller, the information about each release had to go somewhere. In Helm 2, this was stored in the +same namespace as Tiller. In practice, this meant that once a name was used by a release, no other release could use +that same name, even if it was deployed in a different namespace. + +In Helm 3, release information about a particular release is now stored in the same namespace as the release itself. +This means that users can now `helm install wordpress stable/wordpress` in two separate namespaces, and each can be +referred with `helm list` by changing the current namespace context. + ### Go import path changes In Helm 3, Helm switched the Go import path over from `k8s.io/helm` to `helm.sh/helm`. If you intend to upgrade to the Helm 3 Go client libraries, make sure to change your import paths. -### Helm delete +### Capabilities + +The `.Capabilities` built-in object available during the rendering stage has been simplified. + +[Built-in Objects](chart_template_guide/builtin_objects.md) + +### Validating Chart Values with JSONSchema + +A JSON Schema can now be imposed upon chart values. This ensures that values provided by the user follow the schema +laid out by the chart maintainer, providing better error reporting when the user provides an incorrect set of values for +a chart. + +Validation occurs when any of the following commands are invoked: + +* `helm install` +* `helm upgrade` +* `helm template` +* `helm lint` + +See the documentation on [Schema files](charts.md#schema-files) for more information. + +### Consolidation of requirements.yaml into Chart.yaml + +The Chart dependency management system moved from requirements.yaml and requirements.lock to Chart.yaml and Chart.lock, +meaning that charts that relied on the `helm dependency` subcommands will need some tweaking to work in Helm 3. + +In Helm 2, this is how a requirements.yaml looked: + +``` +dependencies: +- name: mariadb + version: 5.x.x + repository: https://kubernetes-charts.storage.googleapis.com/ + condition: mariadb.enabled + tags: + - database +``` + +In Helm 3, the dependency is expressed the same way, but now from your Chart.yaml: + +``` +dependencies: +- name: mariadb + version: 5.x.x + repository: https://kubernetes-charts.storage.googleapis.com/ + condition: mariadb.enabled + tags: + - database +``` + +Charts are still downloaded and placed in the charts/ directory, so subcharts vendored into the charts/ directory will continue to work without modification. + +### Name (or --generate-name) is now required on install + +In Helm 2, if no name was provided, an auto-generated name would be given. In production, this proved to be more of a +nuisance than a helpful feature. In Helm 3, Helm will throw an error if no name is provided with `helm install`. + +For those who still wish to have a name auto-generated for you, you can use the `--generate-name` flag to create one for +you. + +### Pushing Charts to OCI Registries + +At a high level, a Chart Repository is a location where Charts can be stored and shared. The Helm client packs and ships +Helm Charts to a Chart Repository. Simply put, a Chart Repository is a basic HTTP server that houses an index.yaml file +and some packaged charts. + +While there are several benefits to the Chart Repository API meeting the most basic storage requirements, a few +drawbacks have started to show: + +- Chart Repositories have a very hard time abstracting most of the security implementations required in a production environment. Having a standard API for authentication and authorization is very important in production scenarios. +- Helm’s Chart provenance tools used for signing and verifying the integrity and origin of a chart are an optional piece of the Chart publishing process. +- In multi-tenant scenarios, the same Chart can be uploaded by another tenant, costing twice the storage cost to store the same content. Smarter chart repositories have been designed to handle this, but it’s not a part of the formal specification. +- Using a single index file for search, metadata information, and fetching Charts has made it difficult or clunky to design around in secure multi-tenant implementations. + +Docker’s Distribution project (also known as Docker Registry v2) is the successor to the Docker Registry project. Many +major cloud vendors have a product offering of the Distribution project, and with so many vendors offering the same +product, the Distribution project has benefited from many years of hardening, security best practices, and +battle-testing. + +Please have a look at `helm help chart` and `helm help registry` for more information on how to package a chart and +push it to a Docker registry. + +### Removal of helm serve + +`helm serve` ran a local Chart Repository on your machine for development purposes. However, it didn't receive much +uptake as a development tool and had numerous issues with its design. In the end, we decided to remove it and split it +out as a plugin. + +### Library chart support + +Helm 3 supports a class of chart called a “library chart”. This is a chart that is shared by other charts, but does not +create any release artifacts of its own. A library chart’s templates can only declare `define` elements. Globally scoped +non-`define` content is simply ignored. This allows users to re-use and share snippets of code that can be re-used across +many charts, avoiding redundancy and keeping charts [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself). + +Library charts are declared in the dependencies directive in Chart.yaml, and are installed and managed like any other +chart. + +``` +dependencies: + - name: mylib + version: 1.x.x + repository: quay.io +``` + +We’re very excited to see the use cases this feature opens up for chart developers, as well as any best practices that +arise from consuming library charts. + +### CLI Command Renames In order to better align the verbiage from other package managers, `helm delete` was re-named to `helm uninstall`. `helm delete` is still retained as an alias to `helm uninstall`, so either form @@ -25,11 +168,12 @@ In Helm 2, in order to purge the release ledger, the `--purge` flag had to be pr functionality is now enabled by default. To retain the previous behaviour, use `helm uninstall --keep-history`. -### Capabilities +Additionally, several other commands were re-named to accommodate the same conventions: -Capabilities built-in has been simplified. +- `helm inspect` -> `helm show` +- `helm fetch` -> `helm pull` -[Built-in Objects](chart_template_guide/builtin_objects.md) +These commands have also retained their older verbs as aliases, so you can continue to use them in either form. ## Installing From eb1ba03e2489580cea6ff89605204545dceeb9d0 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Fri, 10 May 2019 08:04:27 -0700 Subject: [PATCH 08/12] update links to get.helm.sh Signed-off-by: Matthew Fisher --- docs/install.md | 8 ++++---- docs/release_checklist.md | 39 +++++++-------------------------------- scripts/get | 2 +- 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/docs/install.md b/docs/install.md index cc684bf45..56d7171a2 100755 --- a/docs/install.md +++ b/docs/install.md @@ -65,12 +65,12 @@ the latest master branch. They are not official releases, and may not be stable. However, they offer the opportunity to test the cutting edge features. -Canary Helm binaries are stored in the [Kubernetes Helm GCS bucket](https://kubernetes-helm.storage.googleapis.com). +Canary Helm binaries are stored at [get.helm.sh](https://get.helm.sh). Here are links to the common builds: -- [Linux AMD64](https://kubernetes-helm.storage.googleapis.com/helm-canary-linux-amd64.tar.gz) -- [macOS AMD64](https://kubernetes-helm.storage.googleapis.com/helm-canary-darwin-amd64.tar.gz) -- [Experimental Windows AMD64](https://kubernetes-helm.storage.googleapis.com/helm-canary-windows-amd64.zip) +- [Linux AMD64](https://get.helm.sh/helm-canary-linux-amd64.tar.gz) +- [macOS AMD64](https://get.helm.sh/helm-canary-darwin-amd64.tar.gz) +- [Experimental Windows AMD64](https://get.helm.sh/helm-canary-windows-amd64.zip) ### From Source (Linux, macOS) diff --git a/docs/release_checklist.md b/docs/release_checklist.md index 8d3b78b23..56928a8b8 100644 --- a/docs/release_checklist.md +++ b/docs/release_checklist.md @@ -94,31 +94,6 @@ index 2109a0a..6f5a1a4 100644 BuildMetadata = "unreleased" ``` -The README stores links to the latest release for helm. We want to change the version to the first release candidate which we are releasing (more on that in step 5). - -```shell -$ git diff README.md -diff --git a/README.md b/README.md -index 022afd79..547839e2 100644 ---- a/README.md -+++ b/README.md -@@ -34,10 +34,10 @@ Think of it like apt/yum/homebrew for Kubernetes. - - Binary downloads of the Helm client can be found at the following links: - --- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-darwin-amd64.tar.gz) --- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz) --- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-386.tar.gz) --- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-windows-amd64.tar.gz) -+- [OSX](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-darwin-amd64.tar.gz) -+- [Linux](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-linux-amd64.tar.gz) -+- [Linux 32-bit](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-linux-386.tar.gz) -+- [Windows](https://kubernetes-helm.storage.googleapis.com/helm-v2.8.0-windows-amd64.tar.gz) - - Unpack the `helm` binary and add it to your PATH and you are good to go! - macOS/[homebrew](https://brew.sh/) users can also use `brew install kubernetes-helm`. -``` - For patch releases, the old version number will be the latest patch release, so just bump the patch number, incrementing Z by one. ```shell @@ -149,24 +124,24 @@ git push upstream $RELEASE_CANDIDATE_NAME CircleCI will automatically create a tagged release image and client binary to test with. -For testers, the process to start testing after CircleCI finishes building the artifacts involves the following steps to grab the client from Google Cloud Storage: +After CircleCI finishes building the artifacts, use the following commands to fetch the client for testing: linux/amd64, using /bin/bash: ```shell -wget https://kubernetes-helm.storage.googleapis.com/helm-$RELEASE_CANDIDATE_NAME-linux-amd64.tar.gz +wget https://get.helm.sh/helm-$RELEASE_CANDIDATE_NAME-linux-amd64.tar.gz ``` darwin/amd64, using Terminal.app: ```shell -wget https://kubernetes-helm.storage.googleapis.com/helm-$RELEASE_CANDIDATE_NAME-darwin-amd64.tar.gz +wget https://get.helm.sh/helm-$RELEASE_CANDIDATE_NAME-darwin-amd64.tar.gz ``` windows/amd64, using PowerShell: ```shell -PS C:\> Invoke-WebRequest -Uri "https://kubernetes-helm.storage.googleapis.com/helm-$RELEASE_CANDIDATE_NAME-windows-amd64.tar.gz" -OutFile "helm-$ReleaseCandidateName-windows-amd64.tar.gz" +PS C:\> Invoke-WebRequest -Uri "https://get.helm.sh/helm-$RELEASE_CANDIDATE_NAME-windows-amd64.tar.gz" -OutFile "helm-$ReleaseCandidateName-windows-amd64.tar.gz" ``` Then, unpack and move the binary to somewhere on your $PATH, or move it somewhere and add it to your $PATH (e.g. /usr/local/bin/helm for linux/macOS, C:\Program Files\helm\helm.exe for Windows). @@ -230,9 +205,9 @@ The community keeps growing, and we'd love to see you there. Download Helm X.Y. The common platform binaries are here: -- [OSX](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-darwin-amd64.tar.gz) -- [Linux](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-linux-amd64.tar.gz) -- [Windows](https://storage.googleapis.com/kubernetes-helm/helm-vX.Y.Z-windows-amd64.tar.gz) +- [OSX](https://get.helm.sh/helm-vX.Y.Z-darwin-amd64.tar.gz) +- [Linux](https://get.helm.sh/helm-vX.Y.Z-linux-amd64.tar.gz) +- [Windows](https://get.helm.sh/helm-vX.Y.Z-windows-amd64.tar.gz) The [Quickstart Guide](https://docs.helm.sh/using_helm/#quickstart-guide) will get you going from there. For **upgrade instructions** or detailed installation notes, check the [install guide](https://docs.helm.sh/using_helm/#installing-helm). You can also use a [script to install](https://raw.githubusercontent.com/helm/helm/master/scripts/get) on any system with `bash`. diff --git a/scripts/get b/scripts/get index 4981d81d3..e8dd25d99 100755 --- a/scripts/get +++ b/scripts/get @@ -109,7 +109,7 @@ checkHelmInstalledVersion() { # for that binary. downloadFile() { HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz" - DOWNLOAD_URL="https://kubernetes-helm.storage.googleapis.com/$HELM_DIST" + DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST" CHECKSUM_URL="$DOWNLOAD_URL.sha256" HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)" HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST" From 5367c6c296847ad2fc3645df0e3f189c10907c26 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 14 May 2019 11:00:20 -0700 Subject: [PATCH 09/12] fix(loader): assume apiVersion is v1 when loading charts In Helm 2, no chart validation was performed on v1 charts, so there are a few charts out there that never added an apiVersion to the Chart.yaml. To ensure those charts continue to work for Helm 3, we should assume that charts loaded without an apiVersion set should be assumed as v1. Signed-off-by: Matthew Fisher --- pkg/chart/loader/load.go | 6 ++++++ pkg/chart/loader/testdata/albatross/Chart.yaml | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/chart/loader/load.go b/pkg/chart/loader/load.go index cd886d8c7..2642d87b6 100644 --- a/pkg/chart/loader/load.go +++ b/pkg/chart/loader/load.go @@ -79,6 +79,12 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { return c, errors.Wrap(err, "cannot load Chart.yaml") } + // NOTE(bacongobbler): while the chart specification says that APIVersion must be set, + // Helm 2 accepted charts that did not provide an APIVersion in their chart metadata. + // Because of that, if APIVersion is unset, we should assume we're loading a v1 chart. + if c.Metadata.APIVersion == "" { + c.Metadata.APIVersion = chart.APIVersionV1 + } case f.Name == "Chart.lock": c.Lock = new(chart.Lock) if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { diff --git a/pkg/chart/loader/testdata/albatross/Chart.yaml b/pkg/chart/loader/testdata/albatross/Chart.yaml index b5188fde0..eeef737ff 100644 --- a/pkg/chart/loader/testdata/albatross/Chart.yaml +++ b/pkg/chart/loader/testdata/albatross/Chart.yaml @@ -1,4 +1,3 @@ -apiVersion: v1 name: albatross description: A Helm chart for Kubernetes version: 0.1.0 From 29842e040fd90b5d19d4393a5345a4709020252d Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Tue, 14 May 2019 14:12:47 -0400 Subject: [PATCH 10/12] Adding lint check for apiVersion which is a required field Fixes #5727 Signed-off-by: Matt Farina --- pkg/lint/lint_test.go | 10 +++++++--- pkg/lint/rules/chartfile.go | 13 +++++++++++++ pkg/lint/rules/chartfile_test.go | 14 +++++++++----- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index e4fc67152..326a02e69 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -35,12 +35,12 @@ const goodChartDir = "rules/testdata/goodone" func TestBadChart(t *testing.T) { m := All(badChartDir, values, namespace, strict).Messages - if len(m) != 5 { + if len(m) != 6 { t.Errorf("Number of errors %v", len(m)) t.Errorf("All didn't fail with expected errors, got %#v", m) } // There should be one INFO, 2 WARNINGs and one ERROR messages, check for them - var i, w, e, e2, e3 bool + var i, w, e, e2, e3, e4 bool for _, msg := range m { if msg.Severity == support.InfoSev { if strings.Contains(msg.Err.Error(), "icon is recommended") { @@ -62,9 +62,13 @@ func TestBadChart(t *testing.T) { if strings.Contains(msg.Err.Error(), "directory name (badchartfile) and chart name () must be the same") { e3 = true } + + if strings.Contains(msg.Err.Error(), "apiVersion is required") { + e4 = true + } } } - if !e || !e2 || !e3 || !w || !i { + if !e || !e2 || !e3 || !e4 || !w || !i { t.Errorf("Didn't find all the expected errors, got %#v", m) } } diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index f1abf55d4..2f9707884 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -48,6 +48,7 @@ func Chartfile(linter *support.Linter) { linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartNameDirMatch(linter.ChartDir, chartFile)) // Chart metadata + linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartApiVersion(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartVersion(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartMaintainer(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartSources(chartFile)) @@ -85,6 +86,18 @@ func validateChartNameDirMatch(chartDir string, cf *chart.Metadata) error { return nil } +func validateChartApiVersion(cf *chart.Metadata) error { + if cf.ApiVersion == "" { + return errors.New("apiVersion is required") + } + + if cf.ApiVersion != "v1" { + return fmt.Errorf("apiVersion '%s' is not valid. The value must be \"v1\"", cf.ApiVersion) + } + + return nil +} + func validateChartVersion(cf *chart.Metadata) error { if cf.Version == "" { return errors.New("version is required") diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go index e9ef3a29d..461616034 100644 --- a/pkg/lint/rules/chartfile_test.go +++ b/pkg/lint/rules/chartfile_test.go @@ -209,8 +209,8 @@ func TestChartfile(t *testing.T) { Chartfile(&linter) msgs := linter.Messages - if len(msgs) != 4 { - t.Errorf("Expected 3 errors, got %d", len(msgs)) + if len(msgs) != 5 { + t.Errorf("Expected 4 errors, got %d", len(msgs)) } if !strings.Contains(msgs[0].Err.Error(), "name is required") { @@ -221,12 +221,16 @@ func TestChartfile(t *testing.T) { t.Errorf("Unexpected message 1: %s", msgs[1].Err) } - if !strings.Contains(msgs[2].Err.Error(), "version 0.0.0 is less than or equal to 0") { + if !strings.Contains(msgs[2].Err.Error(), "apiVersion is required") { t.Errorf("Unexpected message 2: %s", msgs[2].Err) } - if !strings.Contains(msgs[3].Err.Error(), "icon is recommended") { - t.Errorf("Unexpected message 3: %s", msgs[3].Err) + if !strings.Contains(msgs[3].Err.Error(), "version 0.0.0 is less than or equal to 0") { + t.Errorf("Unexpected message 3: %s", msgs[2].Err) + } + + if !strings.Contains(msgs[4].Err.Error(), "icon is recommended") { + t.Errorf("Unexpected message 4: %s", msgs[3].Err) } } From 069eec9e425c727323d7eb866662c1cff67757e6 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Tue, 14 May 2019 14:46:40 -0400 Subject: [PATCH 11/12] Updatin gthe apiVersion linting for Helm v3 Signed-off-by: Matt Farina --- pkg/lint/rules/chartfile.go | 11 ++++++----- pkg/lint/rules/testdata/badchartfile/Chart.yaml | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index 2f9707884..24c8a6f44 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -17,6 +17,7 @@ limitations under the License. package rules // import "helm.sh/helm/pkg/lint/rules" import ( + "fmt" "os" "path/filepath" @@ -48,7 +49,7 @@ func Chartfile(linter *support.Linter) { linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartNameDirMatch(linter.ChartDir, chartFile)) // Chart metadata - linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartApiVersion(chartFile)) + linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartAPIVersion(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartVersion(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartMaintainer(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartSources(chartFile)) @@ -86,13 +87,13 @@ func validateChartNameDirMatch(chartDir string, cf *chart.Metadata) error { return nil } -func validateChartApiVersion(cf *chart.Metadata) error { - if cf.ApiVersion == "" { +func validateChartAPIVersion(cf *chart.Metadata) error { + if cf.APIVersion == "" { return errors.New("apiVersion is required") } - if cf.ApiVersion != "v1" { - return fmt.Errorf("apiVersion '%s' is not valid. The value must be \"v1\"", cf.ApiVersion) + if cf.APIVersion != "v1" && cf.APIVersion != "v2" { + return fmt.Errorf("apiVersion '%s' is not valid. The value must be either \"v1\" or \"v2\"", cf.APIVersion) } return nil diff --git a/pkg/lint/rules/testdata/badchartfile/Chart.yaml b/pkg/lint/rules/testdata/badchartfile/Chart.yaml index b64052eb9..dbb4a1501 100644 --- a/pkg/lint/rules/testdata/badchartfile/Chart.yaml +++ b/pkg/lint/rules/testdata/badchartfile/Chart.yaml @@ -1,4 +1,3 @@ -apiVersion: v1 description: A Helm chart for Kubernetes version: 0.0.0 home: "" From 50e06b14474b1acc204b7c05e85696cf69415f49 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Tue, 14 May 2019 16:14:52 -0400 Subject: [PATCH 12/12] Adding apiVersion guidance to the linting Signed-off-by: Matt Farina --- pkg/lint/lint_test.go | 2 +- pkg/lint/rules/chartfile.go | 2 +- pkg/lint/rules/chartfile_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index 326a02e69..962a9ca41 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -63,7 +63,7 @@ func TestBadChart(t *testing.T) { e3 = true } - if strings.Contains(msg.Err.Error(), "apiVersion is required") { + if strings.Contains(msg.Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") { e4 = true } } diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index 24c8a6f44..da0675868 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -89,7 +89,7 @@ func validateChartNameDirMatch(chartDir string, cf *chart.Metadata) error { func validateChartAPIVersion(cf *chart.Metadata) error { if cf.APIVersion == "" { - return errors.New("apiVersion is required") + return errors.New("apiVersion is required. The value must be either \"v1\" or \"v2\"") } if cf.APIVersion != "v1" && cf.APIVersion != "v2" { diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go index 461616034..4e71b860a 100644 --- a/pkg/lint/rules/chartfile_test.go +++ b/pkg/lint/rules/chartfile_test.go @@ -221,7 +221,7 @@ func TestChartfile(t *testing.T) { t.Errorf("Unexpected message 1: %s", msgs[1].Err) } - if !strings.Contains(msgs[2].Err.Error(), "apiVersion is required") { + if !strings.Contains(msgs[2].Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") { t.Errorf("Unexpected message 2: %s", msgs[2].Err) }