From 22552cec77c8a1b390794d1401c41f05223c9caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Lambert?= Date: Thu, 3 Sep 2020 11:22:00 +0700 Subject: [PATCH] feat: add values templates to customize values with go-template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the 3rd and last PR splitted from #6876, and should be merged after #8677 and #8679 There have been many requests for a way to use templates for `values.yaml` (#2492, #2133, ...). The main reason being that it's currently impossible to derive the values of the subcharts from templates. However, having templates in `values.yaml` make them unparsable and create a "chicken or the egg" problem when rendering them. This PR offers an intuitive solution without such a problem: an optional `values/` directory which templates are rendered using `values.yaml`, and then merge them with it. Those `values/` templates are only required for specific cases, work the same way as `templates/` templates, and `values.yaml` will remain the main parsable source of value. Values evaluation is now made in 2 step. First the `values.yaml` file is read. Then the `values/***.yaml` files are rendered using those values (`values/_***.tpl` files ara still allowed as helpers), and are used to update the values. For each chart and subchart, the following steps are performed: 1. If the chart has a parent, parent sub-values and global values are retrieved. 2. The chart values are coalesced with the retrieved value, the chart values are not authoritative. 3. The chart `values/` templates are rendered, the same way `templates/` templates are. The values are not updated during this step. 4. The values are updated with the rendered `values/` templates, sorted by name. The `values/` templates are authoritative and can replace values from the chart `values.yaml` or the previous `values/` templates. 5. The dependencies conditions and tags are evaluated over the updated values, and disabled dependencies are removed. 6. The same process is performed on enabled dependencies. Once values are recursively updated, and once import values are treated on the enabled dependencies, those values are used for templates rendering. Signed-off-by: Aurélien Lambert --- cmd/helm/create.go | 5 +- ...hart-with-bad-subcharts-with-subcharts.txt | 6 +- .../output/lint-chart-with-bad-subcharts.txt | 3 +- pkg/chart/chart.go | 2 + pkg/chart/loader/load.go | 2 + pkg/chart/loader/load_test.go | 22 +- pkg/chart/loader/testdata/frobnitz-1.2.3.tgz | Bin 3482 -> 3526 bytes pkg/chart/loader/testdata/frobnitz.v1.tgz | Bin 3525 -> 3569 bytes .../testdata/frobnitz.v1/values/value.yaml | 1 + .../frobnitz.v2.reqs/values/value.yaml | 1 + .../testdata/frobnitz/values/value.yaml | 1 + .../testdata/frobnitz_backslash-1.2.3.tgz | Bin 3490 -> 3531 bytes .../frobnitz_backslash/values/value.yaml | 1 + .../loader/testdata/frobnitz_with_bom.tgz | Bin 3523 -> 3556 bytes .../frobnitz_with_bom/values/value.yaml | 1 + .../frobnitz_with_dev_null/values/value.yaml | 1 + .../frobnitz_with_symlink/values/value.yaml | 1 + pkg/chartutil/create.go | 27 ++- pkg/chartutil/create_test.go | 2 + pkg/chartutil/save.go | 12 +- pkg/chartutil/save_test.go | 7 + .../charts/mariner/values/placeholder.yaml | 1 + pkg/engine/engine.go | 51 ++++- pkg/engine/engine_test.go | 208 ++++++++++++++++++ .../charts/import_values/values/import.yaml | 5 + pkg/engine/testdata/dependencies/values.yaml | 10 +- .../dependencies/values/condition.yaml | 4 + .../testdata/dependencies/values/tags.yaml | 3 + .../testdata/values_templates/Chart.yaml | 4 + .../charts/subchart/Chart.yaml | 5 + .../charts/subchart/values.yaml | 13 ++ .../charts/subchart/values/coalesce.yaml | 5 + .../charts/subchart/values/global.yaml | 9 + .../charts/subchart/values/replaced.yaml | 4 + .../testdata/values_templates/values.yaml | 20 ++ .../values_templates/values/coalesce.yaml | 4 + .../values_templates/values/global.yaml | 3 + .../values_templates/values/release.yaml | 1 + .../values_templates/values/replaced1.yaml | 4 + .../values_templates/values/replaced2.yaml | 4 + .../values_templates/values/sub_replaced.yaml | 5 + pkg/lint/lint_test.go | 6 +- pkg/lint/rules/dependencies.go | 13 +- pkg/lint/rules/template.go | 70 +++--- 44 files changed, 483 insertions(+), 64 deletions(-) create mode 100644 pkg/chart/loader/testdata/frobnitz.v1/values/value.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz.v2.reqs/values/value.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz/values/value.yaml create mode 100755 pkg/chart/loader/testdata/frobnitz_backslash/values/value.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/values/value.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz_with_dev_null/values/value.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz_with_symlink/values/value.yaml create mode 100644 pkg/chartutil/testdata/frobnitz/charts/mariner/values/placeholder.yaml create mode 100644 pkg/engine/testdata/dependencies/charts/import_values/values/import.yaml create mode 100644 pkg/engine/testdata/dependencies/values/condition.yaml create mode 100644 pkg/engine/testdata/dependencies/values/tags.yaml create mode 100644 pkg/engine/testdata/values_templates/Chart.yaml create mode 100644 pkg/engine/testdata/values_templates/charts/subchart/Chart.yaml create mode 100644 pkg/engine/testdata/values_templates/charts/subchart/values.yaml create mode 100644 pkg/engine/testdata/values_templates/charts/subchart/values/coalesce.yaml create mode 100644 pkg/engine/testdata/values_templates/charts/subchart/values/global.yaml create mode 100644 pkg/engine/testdata/values_templates/charts/subchart/values/replaced.yaml create mode 100644 pkg/engine/testdata/values_templates/values.yaml create mode 100644 pkg/engine/testdata/values_templates/values/coalesce.yaml create mode 100644 pkg/engine/testdata/values_templates/values/global.yaml create mode 100644 pkg/engine/testdata/values_templates/values/release.yaml create mode 100644 pkg/engine/testdata/values_templates/values/replaced1.yaml create mode 100644 pkg/engine/testdata/values_templates/values/replaced2.yaml create mode 100644 pkg/engine/testdata/values_templates/values/sub_replaced.yaml diff --git a/cmd/helm/create.go b/cmd/helm/create.go index 21a7e026c..294f153d7 100644 --- a/cmd/helm/create.go +++ b/cmd/helm/create.go @@ -41,8 +41,9 @@ something like this: ├── Chart.yaml # Information about your chart ├── values.yaml # The default values for your templates ├── charts/ # Charts that this chart depends on - └── templates/ # The template files - └── tests/ # The test files + ├── templates/ # The template files + │ └── tests/ # The test files + └── values/ # The values template files 'helm create' takes a path for an argument. If directories in the given path do not exist, Helm will attempt to create them as it goes. If the given diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt index e77aa387f..29a30fbc2 100644 --- a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt +++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt @@ -1,8 +1,7 @@ ==> Linting testdata/testcharts/chart-with-bad-subcharts [INFO] Chart.yaml: icon is recommended [WARNING] templates/: directory not found -[ERROR] : unable to load chart - error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required +[ERROR] : error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required ==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart [ERROR] Chart.yaml: name is required @@ -10,8 +9,7 @@ [ERROR] Chart.yaml: version is required [INFO] Chart.yaml: icon is recommended [WARNING] templates/: directory not found -[ERROR] : unable to load chart - validation: chart.metadata.name is required +[ERROR] : validation: chart.metadata.name is required ==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart [INFO] Chart.yaml: icon is recommended diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt index 265e555f7..89cbbda20 100644 --- a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt +++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt @@ -1,7 +1,6 @@ ==> Linting testdata/testcharts/chart-with-bad-subcharts [INFO] Chart.yaml: icon is recommended [WARNING] templates/: directory not found -[ERROR] : unable to load chart - error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required +[ERROR] : error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required Error: 1 chart(s) linted, 1 chart(s) failed diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go index bd75375a4..9f56e2db4 100644 --- a/pkg/chart/chart.go +++ b/pkg/chart/chart.go @@ -40,6 +40,8 @@ type Chart struct { Lock *Lock `json:"lock"` // Templates for this chart. Templates []*File `json:"templates"` + // Values templates for this chart. + ValuesTemplates []*File `json:"valuesTemplates"` // Values are default config for this chart. Values map[string]interface{} `json:"values"` // Schema is an optional JSON schema for imposing structure on Values diff --git a/pkg/chart/loader/load.go b/pkg/chart/loader/load.go index dd4fd2dff..a9444cb0b 100644 --- a/pkg/chart/loader/load.go +++ b/pkg/chart/loader/load.go @@ -129,6 +129,8 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { case strings.HasPrefix(f.Name, "templates/"): c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data}) + case strings.HasPrefix(f.Name, "values/"): + c.ValuesTemplates = append(c.ValuesTemplates, &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}) diff --git a/pkg/chart/loader/load_test.go b/pkg/chart/loader/load_test.go index 16a94d4eb..15e94d96e 100644 --- a/pkg/chart/loader/load_test.go +++ b/pkg/chart/loader/load_test.go @@ -245,6 +245,10 @@ icon: https://example.com/64x64.png Name: "templates/service.yaml", Data: []byte("some service"), }, + { + Name: "values/test.yaml", + Data: []byte("some other values"), + }, } c, err := LoadFiles(goodFiles) @@ -260,7 +264,7 @@ icon: https://example.com/64x64.png t.Error("Expected chart values to be populated with default values") } - if len(c.Raw) != 5 { + if len(c.Raw) != 6 { t.Errorf("Expected %d files, got %d", 5, len(c.Raw)) } @@ -272,6 +276,10 @@ icon: https://example.com/64x64.png t.Errorf("Expected number of templates == 2, got %d", len(c.Templates)) } + if len(c.ValuesTemplates) != 1 { + t.Errorf("Expected number of values templates == 1, got %d", len(c.ValuesTemplates)) + } + if _, err = LoadFiles([]*BufferedFile{}); err == nil { t.Fatal("Expected err to be non-nil") } @@ -405,6 +413,9 @@ func verifyChart(t *testing.T, c *chart.Chart) { if len(c.Templates) != 1 { t.Errorf("Expected 1 template, got %d", len(c.Templates)) } + if len(c.ValuesTemplates) != 1 { + t.Errorf("Expected 1 values template, got %d", len(c.ValuesTemplates)) + } numfiles := 6 if len(c.Files) != numfiles { @@ -509,6 +520,15 @@ func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { if len(c.Templates[0].Data) == 0 { t.Error("No template data.") } + if len(c.ValuesTemplates) != 1 { + t.Fatalf("Expected 1 values template, got %d", len(c.ValuesTemplates)) + } + if c.ValuesTemplates[0].Name != "values/value.yaml" { + t.Errorf("Unexpected values template: %s", c.ValuesTemplates[0].Name) + } + if len(c.ValuesTemplates[0].Data) == 0 { + t.Error("No values template data.") + } if len(c.Files) != 6 { t.Fatalf("Expected 6 Files, got %d", len(c.Files)) } diff --git a/pkg/chart/loader/testdata/frobnitz-1.2.3.tgz b/pkg/chart/loader/testdata/frobnitz-1.2.3.tgz index b2b76a83c768f144f8b436a0deeb9da2c9a57bd1..1830f2d954a9616f3aa34b9ca2877015699997a9 100644 GIT binary patch literal 3526 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 AssI20 literal 3482 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 diff --git a/pkg/chart/loader/testdata/frobnitz.v1.tgz b/pkg/chart/loader/testdata/frobnitz.v1.tgz index 6282f9b73fb2877b76328adeaccdc8d94b1097c2..dde8753954df36338122153d08c15d0a2ef3a3b1 100644 GIT binary patch literal 3569 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 literal 3525 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 diff --git a/pkg/chart/loader/testdata/frobnitz.v1/values/value.yaml b/pkg/chart/loader/testdata/frobnitz.v1/values/value.yaml new file mode 100644 index 000000000..6c32007ff --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz.v1/values/value.yaml @@ -0,0 +1 @@ +name: "{{ .Values.name }} Too" diff --git a/pkg/chart/loader/testdata/frobnitz.v2.reqs/values/value.yaml b/pkg/chart/loader/testdata/frobnitz.v2.reqs/values/value.yaml new file mode 100644 index 000000000..6c32007ff --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz.v2.reqs/values/value.yaml @@ -0,0 +1 @@ +name: "{{ .Values.name }} Too" diff --git a/pkg/chart/loader/testdata/frobnitz/values/value.yaml b/pkg/chart/loader/testdata/frobnitz/values/value.yaml new file mode 100644 index 000000000..6c32007ff --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz/values/value.yaml @@ -0,0 +1 @@ +name: "{{ .Values.name }} Too" diff --git a/pkg/chart/loader/testdata/frobnitz_backslash-1.2.3.tgz b/pkg/chart/loader/testdata/frobnitz_backslash-1.2.3.tgz index a9d4c11d82bf1f3b49851053e6f0d9b6c1e9a2d4..f14eb8c0c2e59e5cf9d52d51714b645c7b0203b4 100644 GIT binary patch literal 3531 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 F0014c6_)@2 literal 3490 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 diff --git a/pkg/chart/loader/testdata/frobnitz_backslash/values/value.yaml b/pkg/chart/loader/testdata/frobnitz_backslash/values/value.yaml new file mode 100755 index 000000000..6c32007ff --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_backslash/values/value.yaml @@ -0,0 +1 @@ +name: "{{ .Values.name }} Too" diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom.tgz b/pkg/chart/loader/testdata/frobnitz_with_bom.tgz index be0cd027db34d392a875cf8151642f9922016dbd..d24775b1b720ee5e84cbd890e2a8bf952c7792f9 100644 GIT binary patch literal 3556 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 literal 3523 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 diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/values/value.yaml b/pkg/chart/loader/testdata/frobnitz_with_bom/values/value.yaml new file mode 100644 index 000000000..6c32007ff --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/values/value.yaml @@ -0,0 +1 @@ +name: "{{ .Values.name }} Too" diff --git a/pkg/chart/loader/testdata/frobnitz_with_dev_null/values/value.yaml b/pkg/chart/loader/testdata/frobnitz_with_dev_null/values/value.yaml new file mode 100644 index 000000000..6c32007ff --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_dev_null/values/value.yaml @@ -0,0 +1 @@ +name: "{{ .Values.name }} Too" diff --git a/pkg/chart/loader/testdata/frobnitz_with_symlink/values/value.yaml b/pkg/chart/loader/testdata/frobnitz_with_symlink/values/value.yaml new file mode 100644 index 000000000..6c32007ff --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_symlink/values/value.yaml @@ -0,0 +1 @@ +name: "{{ .Values.name }} Too" diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 8d8f48176..3edd05152 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -39,6 +39,8 @@ const ( SchemafileName = "values.schema.json" // TemplatesDir is the relative directory name for templates. TemplatesDir = "templates" + // ValuesTemplatesDir is the relative directory name for values templates. + ValuesTemplatesDir = "values" // ChartsDir is the relative directory name for charts dependencies. ChartsDir = "charts" // TemplatesTestsDir is the relative directory name for tests. @@ -482,7 +484,15 @@ func CreateFrom(chartfile *chart.Metadata, dest, src string) error { updatedTemplates = append(updatedTemplates, &chart.File{Name: template.Name, Data: newData}) } + var updatedValuesTemplates []*chart.File + + for _, template := range schart.ValuesTemplates { + newData := transform(string(template.Data), schart.Name()) + updatedValuesTemplates = append(updatedValuesTemplates, &chart.File{Name: template.Name, Data: newData}) + } + schart.Templates = updatedTemplates + schart.ValuesTemplates = updatedValuesTemplates b, err := yaml.Marshal(schart.Values) if err != nil { return errors.Wrap(err, "reading values file") @@ -606,10 +616,21 @@ func Create(name, dir string) (string, error) { return cdir, err } } - // Need to add the ChartsDir explicitly as it does not contain any file OOTB - if err := os.MkdirAll(filepath.Join(cdir, ChartsDir), 0755); err != nil { - return cdir, err + + // Need to add empty directories explicitly + edirs := []string{ + // values/ + filepath.Join(cdir, ValuesTemplatesDir), + // charts/ + filepath.Join(cdir, ChartsDir), + } + + for _, edir := range edirs { + if err := os.MkdirAll(edir, 0755); err != nil { + return cdir, err + } } + return cdir, nil } diff --git a/pkg/chartutil/create_test.go b/pkg/chartutil/create_test.go index a11c45140..83f8a0aa2 100644 --- a/pkg/chartutil/create_test.go +++ b/pkg/chartutil/create_test.go @@ -62,6 +62,7 @@ func TestCreate(t *testing.T) { TemplatesTestsDir, TestConnectionName, ValuesfileName, + ValuesTemplatesDir, } { if _, err := os.Stat(filepath.Join(dir, f)); err != nil { t.Errorf("Expected %s file: %s", f, err) @@ -102,6 +103,7 @@ func TestCreateFrom(t *testing.T) { ChartfileName, ValuesfileName, filepath.Join(TemplatesDir, "placeholder.tpl"), + filepath.Join(ValuesTemplatesDir, "placeholder.yaml"), } { if _, err := os.Stat(filepath.Join(dir, f)); err != nil { t.Errorf("Expected %s file: %s", f, err) diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go index 2ce4eddaf..0db42fc73 100644 --- a/pkg/chartutil/save.go +++ b/pkg/chartutil/save.go @@ -70,8 +70,8 @@ func SaveDir(c *chart.Chart, dest string) error { } } - // Save templates and files - for _, o := range [][]*chart.File{c.Templates, c.Files} { + // Save values templates, templates and files + for _, o := range [][]*chart.File{c.ValuesTemplates, c.Templates, c.Files} { for _, f := range o { n := filepath.Join(outdir, f.Name) if err := writeFile(n, f.Data); err != nil { @@ -202,6 +202,14 @@ func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error { } } + // Save values templates + for _, f := range c.ValuesTemplates { + n := filepath.Join(base, f.Name) + if err := writeToTar(out, n, f.Data); err != nil { + return err + } + } + // Save templates for _, f := range c.Templates { n := filepath.Join(base, f.Name) diff --git a/pkg/chartutil/save_test.go b/pkg/chartutil/save_test.go index 3a45b2992..c569a9417 100644 --- a/pkg/chartutil/save_test.go +++ b/pkg/chartutil/save_test.go @@ -221,6 +221,9 @@ func TestSaveDir(t *testing.T) { Templates: []*chart.File{ {Name: filepath.Join(TemplatesDir, "nested", "dir", "thing.yaml"), Data: []byte("abc: {{ .Values.abc }}")}, }, + ValuesTemplates: []*chart.File{ + {Name: filepath.Join(ValuesTemplatesDir, "other", "nested", "stuff.yaml"), Data: []byte("def: {{ .Values.def }}")}, + }, } if err := SaveDir(c, tmp); err != nil { @@ -240,6 +243,10 @@ func TestSaveDir(t *testing.T) { t.Fatal("Templates data did not match") } + if len(c2.ValuesTemplates) != 1 || c2.ValuesTemplates[0].Name != filepath.Join(ValuesTemplatesDir, "other", "nested", "stuff.yaml") { + t.Fatal("ValuesTemplates data did not match") + } + if len(c2.Files) != 1 || c2.Files[0].Name != "scheherazade/shahryar.txt" { t.Fatal("Files data did not match") } diff --git a/pkg/chartutil/testdata/frobnitz/charts/mariner/values/placeholder.yaml b/pkg/chartutil/testdata/frobnitz/charts/mariner/values/placeholder.yaml new file mode 100644 index 000000000..29c11843a --- /dev/null +++ b/pkg/chartutil/testdata/frobnitz/charts/mariner/values/placeholder.yaml @@ -0,0 +1 @@ +# This is a placeholder. diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index cacd4b136..a3181ef2d 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -28,6 +28,7 @@ import ( "github.com/pkg/errors" "k8s.io/client-go/rest" + "sigs.k8s.io/yaml" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" @@ -64,7 +65,7 @@ type Engine struct { // section contains a value named "bar", that value will be passed on to the // bar chart during render time. func (e Engine) Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, error) { - // update values and dependencies + // parse values templates and update values and dependencies if err := e.updateRenderValues(chrt, values); err != nil { return nil, err } @@ -302,10 +303,10 @@ func cleanupExecError(filename string, err error) error { return err } -// updateRenderValues update render values with chart values. +// updateRenderValues update render values with chart values and values templates. func (e Engine) updateRenderValues(c *chart.Chart, vals chartutil.Values) error { var sb strings.Builder - // update values and dependencies + // parse values templates and update values and dependencies if err := e.recUpdateRenderValues(c, vals, nil, &sb); err != nil { return err } @@ -344,7 +345,7 @@ func (e Engine) recUpdateRenderValues(c *chart.Chart, vals chartutil.Values, tag return err } next["Values"] = nvals - // Get validations errors of chart values + // Get validations errors of chart values, before applying values template if c.Schema != nil { err = chartutil.ValidateAgainstSingleSchema(nvals, c.Schema) if err != nil { @@ -352,6 +353,34 @@ func (e Engine) recUpdateRenderValues(c *chart.Chart, vals chartutil.Values, tag sb.WriteString(err.Error()) } } + // Get all values templates of the chart + templates := map[string]renderable{} + newParentID := c.ChartFullPath() + for _, t := range c.ValuesTemplates { + if !isTemplateValid(c, t.Name) { + continue + } + templates[path.Join(newParentID, t.Name)] = renderable{ + tpl: string(t.Data), + vals: next, + basePath: path.Join(newParentID, "values"), + } + } + // Render all values templates + rendered, err := e.render(templates) + if err != nil { + return err + } + // Parse and apply all values templates + if len(rendered) > 0 { + for _, filename := range sortValuesTemplates(rendered) { + src := map[string]interface{}{} + if err := yaml.Unmarshal([]byte(rendered[filename]), &src); err != nil { + return errors.Wrap(err, fmt.Sprintf("cannot load %s", filename)) + } + chartutil.CoalesceTablesUpdate(nvals, src) + } + } // Get tags of the root if c.IsRoot() { tags = chartutil.GetTags(nvals) @@ -361,7 +390,7 @@ func (e Engine) recUpdateRenderValues(c *chart.Chart, vals chartutil.Values, tag if err != nil { return err } - // Recursive upudate on enabled dependencies + // Recursive update on enabled dependencies for _, child := range c.Dependencies() { err = e.recUpdateRenderValues(child, next, tags, sb) if err != nil { @@ -371,6 +400,18 @@ func (e Engine) recUpdateRenderValues(c *chart.Chart, vals chartutil.Values, tag return nil } +// sortValuesTemplates sorts the rendered yaml values files from lowest to highest priority +func sortValuesTemplates(tpls map[string]string) []string { + keys := make(sort.StringSlice, len(tpls)) + i := 0 + for key := range tpls { + keys[i] = key + i++ + } + sort.Sort(keys) + return keys +} + func sortTemplates(tpls map[string]renderable) []string { keys := make([]string, len(tpls)) i := 0 diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index 745cf256f..361d23018 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -742,7 +742,197 @@ func TestRenderRecursionLimit(t *testing.T) { if got := out["overlook/templates/quote"]; got != expect { t.Errorf("Expected %q, got %q (%v)", expect, got, out) } +} + +func TestUpdateRenderValues_values_templates(t *testing.T) { + values := map[string]interface{}{} + rv := map[string]interface{}{ + "Release": map[string]interface{}{ + "Name": "Test Name", + }, + "Values": values, + } + c := loadChart(t, "testdata/values_templates") + if err := new(Engine).updateRenderValues(c, rv); err != nil { + t.Fatal(err) + } + if v, ok := values["releaseName"]; !ok { + t.Errorf("field 'releaseName' missing") + } else if vs, ok := v.(string); !ok || vs != "Test Name" { + t.Errorf("wrong value on field 'releaseName': %v", v) + } + // Check root remplacements + if v, ok := values["replaced"]; !ok { + t.Errorf("field 'replaced' missing") + } else if vs := v.(string); vs != "values/replaced2.yaml" { + t.Errorf("wrong priority on field 'replaced', value from %s", vs) + } + if v, ok := values["currentReplaced1"]; !ok { + t.Errorf("field 'currentReplaced1' missing") + } else if vs := v.(string); vs != "values.yaml" { + t.Errorf("wrong evaluation order on field 'currentReplaced1', value from %s", vs) + } + if v, ok := values["currentReplaced2"]; !ok { + t.Errorf("field 'currentReplaced2' missing") + } else if vs := v.(string); vs != "values.yaml" { + t.Errorf("wrong evaluation order on field 'currentReplaced2', value from %s", vs) + } + // check root coalesce + if vm, ok := values["coalesce"]; !ok { + t.Errorf("field 'coalesce' missing") + } else { + m := vm.(map[string]interface{}) + if v, ok := m["old"]; !ok { + t.Errorf("field 'coalesce.old' missing") + } else if vs := v.(string); vs != "values.yaml" { + t.Errorf("wrong priority on field 'coalesce.old', value from %s", vs) + } + if v, ok := m["common"]; !ok { + t.Errorf("field 'coalesce.common' missing") + } else if vs := v.(string); vs != "values/coalesce.yaml" { + t.Errorf("wrong priority on field 'coalesce.common', value from %s", vs) + } + if v, ok := m["new"]; !ok { + t.Errorf("field 'coalesce.new' missing") + } else if vs := v.(string); vs != "values/coalesce.yaml" { + t.Errorf("wrong priority on field 'coalesce.new', value from %s", vs) + } + } + // check root global + if vm, ok := values["global"]; !ok { + t.Errorf("field 'global' missing") + } else { + m := vm.(map[string]interface{}) + if v, ok := m["parentValues"]; !ok || !v.(bool) { + t.Errorf("field 'global.parentValues' missing") + } + if v, ok := m["parentTemplate"]; !ok || !v.(bool) { + t.Errorf("field 'global.parentTemplate' missing") + } + if _, ok := m["subValues"]; ok { + t.Errorf("field 'global.subValues' unexpected") + } + if _, ok := m["subTeamplate"]; ok { + t.Errorf("field 'global.subTeamplate' unexpected") + } + } + // check subchart + if vm, ok := values["subchart"]; !ok { + t.Errorf("field 'subchart' missing") + } else { + // check subchart evaluated + m := vm.(map[string]interface{}) + if v, ok := m["evaluated"]; !ok || !v.(bool) { + t.Errorf("chart 'subchart' not evaluated") + } + // check subchart replaced + if v, ok := m["replaced1"]; !ok { + t.Errorf("field 'subchart.replaced1' missing") + } else if vs := v.(string); vs != "values.yaml" { + t.Errorf("wrong priority on field 'subchart.replaced1', value from %s", vs) + } + if v, ok := m["replaced2"]; !ok { + t.Errorf("field 'subchart.replaced2' missing") + } else if vs := v.(string); vs != "subchart/values/replaced.yaml" { + t.Errorf("wrong priority on field 'subchart.replaced2', value from %s", vs) + } + if v, ok := m["replaced3"]; !ok { + t.Errorf("field 'subchart.replaced3' missing") + } else if vs := v.(string); vs != "values/sub_replaced.yaml" { + t.Errorf("wrong priority on field 'subchart.replaced3', value from %s", vs) + } + if v, ok := m["replaced4"]; !ok { + t.Errorf("field 'subchart.replaced4' missing") + } else if vs := v.(string); vs != "subchart/values/replaced.yaml" { + t.Errorf("wrong priority on field 'subchart.replaced4', value from %s", vs) + } + if v, ok := m["currentReplaced2"]; !ok { + t.Errorf("field 'subchart.currentReplaced2' missing") + } else if vs := v.(string); vs != "values.yaml" { + t.Errorf("wrong evaluation order on field 'subchart.currentReplaced2', value from %s", vs) + } + // check subchart coalesce + if vm, ok := m["coalesce"]; !ok { + t.Errorf("field 'subchart.coalesce' missing") + } else { + m := vm.(map[string]interface{}) + if v, ok := m["value1"]; !ok { + t.Errorf("field 'subchart.coalesce.value1' missing") + } else if vs := v.(string); vs != "values.yaml" { + t.Errorf("wrong priority on field 'subchart.coalesce.value1', value from %s", vs) + } + if v, ok := m["value2"]; !ok { + t.Errorf("field 'subchart.coalesce.value2' missing") + } else if vs := v.(string); vs != "values.yaml" { + t.Errorf("wrong priority on field 'subchart.coalesce.value2', value from %s", vs) + } + if v, ok := m["value3"]; !ok { + t.Errorf("field 'subchart.coalesce.value3' missing") + } else if vs := v.(string); vs != "subchart/values/coalesce.yaml" { + t.Errorf("wrong priority on field 'subchart.coalesce.value3', value from %s", vs) + } + if v, ok := m["value4"]; !ok { + t.Errorf("field 'subchart.coalesce.value4' missing") + } else if vs := v.(string); vs != "subchart/values.yaml" { + t.Errorf("wrong priority on field 'subchart.coalesce.value4', value from %s", vs) + } + if v, ok := m["value5"]; !ok { + t.Errorf("field 'subchart.coalesce.value5' missing") + } else if vs := v.(string); vs != "subchart/values/coalesce.yaml" { + t.Errorf("wrong priority on field 'subchart.coalesce.value5', value from %s", vs) + } + if v, ok := m["value6"]; !ok { + t.Errorf("field 'subchart.coalesce.value6' missing") + } else if vs := v.(string); vs != "subchart/values/coalesce.yaml" { + t.Errorf("wrong priority on field 'subchart.coalesce.value6', value from %s", vs) + } + } + // check subchart global + if vm, ok := m["global"]; !ok { + t.Errorf("field 'subchart.global' missing") + } else { + m := vm.(map[string]interface{}) + if v, ok := m["parentValues"]; !ok || !v.(bool) { + t.Errorf("field 'subchart.global.parentValues' missing") + } + if v, ok := m["parentTemplate"]; !ok || !v.(bool) { + t.Errorf("field 'subchart.global.parentTemplate' missing") + } + if v, ok := m["subTeamplate"]; !ok || !v.(bool) { + t.Errorf("field 'subchart.global.subTeamplate' missing") + } + if v, ok := m["parentValues"]; !ok || !v.(bool) { + t.Errorf("field 'subchart.global.parentValues' missing") + } + } + // check subchart globalEvaluated + if vm, ok := m["globalEvaluated"]; !ok { + t.Errorf("field 'subchart.globalEvaluated' missing") + } else { + m := vm.(map[string]interface{}) + if v, ok := m["parentValues"]; !ok { + t.Errorf("field 'subchart.globalEvaluated.parentValues' missing") + } else if vb, ok := v.(bool); !ok || !vb { + t.Errorf("field 'subchart.globalEvaluated.parentValues' has wrong value: %v", vb) + } + if v, ok := m["parentTemplate"]; !ok { + t.Errorf("field 'subchart.globalEvaluated.parentTemplate' missing") + } else if vb, ok := v.(bool); !ok || !vb { + t.Errorf("field 'subchart.globalEvaluated.parentTemplate' has wrong value: %v", vb) + } + if v, ok := m["subValues"]; !ok { + t.Errorf("field 'subchart.globalEvaluated.subValues' missing") + } else if vb, ok := v.(bool); !ok || !vb { + t.Errorf("field 'subchart.globalEvaluated.subValues' has wrong value: %v", vb) + } + if v, ok := m["subTeamplate"]; !ok { + t.Errorf("field 'subchart.globalEvaluated.subTeamplate' missing") + } else if v != nil { + t.Errorf("field 'subchart.globalEvaluated.subTeamplate' has wrong value: %v", v) + } + } + } } func TestUpdateRenderValues_dependencies(t *testing.T) { @@ -827,6 +1017,14 @@ func TestUpdateRenderValues_dependencies(t *testing.T) { t.Errorf("value 'importValues.imported' not imported") } } + if vm, ok := values["importTemplate"]; !ok { + t.Errorf("value 'importTemplate' not imported") + } else { + m := vm.(map[string]interface{}) + if v, ok := m["imported"]; !ok || !v.(bool) { + t.Errorf("value 'importTemplate.imported' not imported") + } + } if vm, ok := values["subImport"]; !ok { t.Errorf("value 'subImport' not imported") } else { @@ -836,6 +1034,16 @@ func TestUpdateRenderValues_dependencies(t *testing.T) { } else if vs, ok := v.(string); !ok || vs != "values.yaml" { t.Errorf("wrong 'subImport.old' imported: %v", v) } + if v, ok := m["common"]; !ok { + t.Errorf("value 'subImport.common' not imported") + } else if vs, ok := v.(string); !ok || vs != "values/import.yaml" { + t.Errorf("wrong 'subImport.common' imported: %v", v) + } + if v, ok := m["new"]; !ok { + t.Errorf("value 'subImport.new' not imported") + } else if vs, ok := v.(string); !ok || vs != "values/import.yaml" { + t.Errorf("wrong 'subImport.old' imported: %v", v) + } } names := extractChartNames(c) diff --git a/pkg/engine/testdata/dependencies/charts/import_values/values/import.yaml b/pkg/engine/testdata/dependencies/charts/import_values/values/import.yaml new file mode 100644 index 000000000..a79dddd45 --- /dev/null +++ b/pkg/engine/testdata/dependencies/charts/import_values/values/import.yaml @@ -0,0 +1,5 @@ +import: + common: "values/import.yaml" + new: "values/import.yaml" +importTemplate: + imported: true diff --git a/pkg/engine/testdata/dependencies/values.yaml b/pkg/engine/testdata/dependencies/values.yaml index 9148fc233..ae2ed6ccb 100644 --- a/pkg/engine/testdata/dependencies/values.yaml +++ b/pkg/engine/testdata/dependencies/values.yaml @@ -1,7 +1,7 @@ condition: - "true": true - "false": false - "null": null + "true": false + "false": true + "null": false tags: - true_tag: true - false_tag: false + true_tag: false + false_tag: true \ No newline at end of file diff --git a/pkg/engine/testdata/dependencies/values/condition.yaml b/pkg/engine/testdata/dependencies/values/condition.yaml new file mode 100644 index 000000000..cdf5d0186 --- /dev/null +++ b/pkg/engine/testdata/dependencies/values/condition.yaml @@ -0,0 +1,4 @@ +condition: + "true": true + "false": false + "null": null diff --git a/pkg/engine/testdata/dependencies/values/tags.yaml b/pkg/engine/testdata/dependencies/values/tags.yaml new file mode 100644 index 000000000..3e06d0d66 --- /dev/null +++ b/pkg/engine/testdata/dependencies/values/tags.yaml @@ -0,0 +1,3 @@ +tags: + true_tag: true + false_tag: false diff --git a/pkg/engine/testdata/values_templates/Chart.yaml b/pkg/engine/testdata/values_templates/Chart.yaml new file mode 100644 index 000000000..ef6bac8b8 --- /dev/null +++ b/pkg/engine/testdata/values_templates/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +description: A Helm chart for Kubernetes +name: parentchart +version: 0.1.0 diff --git a/pkg/engine/testdata/values_templates/charts/subchart/Chart.yaml b/pkg/engine/testdata/values_templates/charts/subchart/Chart.yaml new file mode 100644 index 000000000..e8831783e --- /dev/null +++ b/pkg/engine/testdata/values_templates/charts/subchart/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +description: A Helm chart for Kubernetes +name: subchart +version: 0.1.0 +dependencies: diff --git a/pkg/engine/testdata/values_templates/charts/subchart/values.yaml b/pkg/engine/testdata/values_templates/charts/subchart/values.yaml new file mode 100644 index 000000000..08ad6a7ca --- /dev/null +++ b/pkg/engine/testdata/values_templates/charts/subchart/values.yaml @@ -0,0 +1,13 @@ +# should coalesce with parent global +global: + subValues: true +# should be evaluated +evaluated: true +# original value should be kept +replaced1: "subchart/values.yaml" +replaced3: "subchart/values.yaml" +# should cloalesce with parent values.yaml +coalesce: + value2: "subchart/values.yaml" + value4: "subchart/values.yaml" + value5: "subchart/values.yaml" diff --git a/pkg/engine/testdata/values_templates/charts/subchart/values/coalesce.yaml b/pkg/engine/testdata/values_templates/charts/subchart/values/coalesce.yaml new file mode 100644 index 000000000..e0ed61adf --- /dev/null +++ b/pkg/engine/testdata/values_templates/charts/subchart/values/coalesce.yaml @@ -0,0 +1,5 @@ +# should cloalesce with both values.yaml +coalesce: + value3: "subchart/values/coalesce.yaml" + value5: "subchart/values/coalesce.yaml" + value6: "subchart/values/coalesce.yaml" diff --git a/pkg/engine/testdata/values_templates/charts/subchart/values/global.yaml b/pkg/engine/testdata/values_templates/charts/subchart/values/global.yaml new file mode 100644 index 000000000..c328ad356 --- /dev/null +++ b/pkg/engine/testdata/values_templates/charts/subchart/values/global.yaml @@ -0,0 +1,9 @@ +# should coalesce with parent global +global: + subTeamplate: true +# should capture everything except subTeamplate +globalEvaluated: + parentValues: {{ .Values.global.parentValues }} + parentTemplate: {{ .Values.global.parentTemplate }} + subValues: {{ .Values.global.subValues }} + subTeamplate: {{ .Values.global.subTeamplate }} diff --git a/pkg/engine/testdata/values_templates/charts/subchart/values/replaced.yaml b/pkg/engine/testdata/values_templates/charts/subchart/values/replaced.yaml new file mode 100644 index 000000000..e3df8c1d1 --- /dev/null +++ b/pkg/engine/testdata/values_templates/charts/subchart/values/replaced.yaml @@ -0,0 +1,4 @@ +# replacement should work +replaced2: "subchart/values/replaced.yaml" +replaced4: "subchart/values/replaced.yaml" +currentReplaced2: "{{ .Values.replaced2 }}" diff --git a/pkg/engine/testdata/values_templates/values.yaml b/pkg/engine/testdata/values_templates/values.yaml new file mode 100644 index 000000000..8714ced77 --- /dev/null +++ b/pkg/engine/testdata/values_templates/values.yaml @@ -0,0 +1,20 @@ +# should appear in subcharts too +global: + parentValues: true +# should be replaced by values templates values/replaced[12].yaml +replaced: "values.yaml" +# should coalesce with values/coalesce.yaml +coalesce: + old: "values.yaml" + common: "values.yaml" + +subchart: + # should replaced by subchart/values/replaced.yaml + replaced1: "values.yaml" + replaced2: "values.yaml" + # should coalesce with values/sub_coalesce.yaml, subchart/values.yaml + # and subchart/values/coalesce.yaml + coalesce: + value1: "values.yaml" + value2: "values.yaml" + value3: "values.yaml" diff --git a/pkg/engine/testdata/values_templates/values/coalesce.yaml b/pkg/engine/testdata/values_templates/values/coalesce.yaml new file mode 100644 index 000000000..9a1673df9 --- /dev/null +++ b/pkg/engine/testdata/values_templates/values/coalesce.yaml @@ -0,0 +1,4 @@ +# should cloalesce with values.yaml +coalesce: + common: "values/coalesce.yaml" + new: "values/coalesce.yaml" diff --git a/pkg/engine/testdata/values_templates/values/global.yaml b/pkg/engine/testdata/values_templates/values/global.yaml new file mode 100644 index 000000000..5de1bbe31 --- /dev/null +++ b/pkg/engine/testdata/values_templates/values/global.yaml @@ -0,0 +1,3 @@ +# should appear in subcharts too +global: + parentTemplate: true diff --git a/pkg/engine/testdata/values_templates/values/release.yaml b/pkg/engine/testdata/values_templates/values/release.yaml new file mode 100644 index 000000000..ef86f3999 --- /dev/null +++ b/pkg/engine/testdata/values_templates/values/release.yaml @@ -0,0 +1 @@ +releaseName: {{ .Release.Name }} diff --git a/pkg/engine/testdata/values_templates/values/replaced1.yaml b/pkg/engine/testdata/values_templates/values/replaced1.yaml new file mode 100644 index 000000000..e30830c6c --- /dev/null +++ b/pkg/engine/testdata/values_templates/values/replaced1.yaml @@ -0,0 +1,4 @@ +# shoud be replaced again by replaced2.yaml +replaced: "values/replaced1.yaml" +# should still be "values.yaml" +currentReplaced1: "{{ .Values.replaced }}" diff --git a/pkg/engine/testdata/values_templates/values/replaced2.yaml b/pkg/engine/testdata/values_templates/values/replaced2.yaml new file mode 100644 index 000000000..2e14ce47e --- /dev/null +++ b/pkg/engine/testdata/values_templates/values/replaced2.yaml @@ -0,0 +1,4 @@ +# shoud be the final value +replaced: "values/replaced2.yaml" +# should still be "values.yaml" +currentReplaced2: "{{ .Values.replaced }}" diff --git a/pkg/engine/testdata/values_templates/values/sub_replaced.yaml b/pkg/engine/testdata/values_templates/values/sub_replaced.yaml new file mode 100644 index 000000000..b1b34fda7 --- /dev/null +++ b/pkg/engine/testdata/values_templates/values/sub_replaced.yaml @@ -0,0 +1,5 @@ + +subchart: + # should replaced by subchart/values/replaced.yaml + replaced3: "values/sub_replaced.yaml" + replaced4: "values/sub_replaced.yaml" diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index 29ed67026..9224b7498 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -74,13 +74,13 @@ func TestBadChart(t *testing.T) { if strings.Contains(msg.Err.Error(), "dependencies are not valid in the Chart file with apiVersion") { e5 = true } - // This comes from the dependency check, which loads dependency info from the Chart.yaml - if strings.Contains(msg.Err.Error(), "unable to load chart") { + + if strings.Contains(msg.Err.Error(), "chart.metadata.name is required") { e6 = true } } } - if !e || !e2 || !e3 || !e4 || !e5 || !w || !i || !e6 { + if !e || !e2 || !e3 || !e4 || !e5 || !e6 || !w || !i { t.Errorf("Didn't find all the expected errors, got %#v", m) } } diff --git a/pkg/lint/rules/dependencies.go b/pkg/lint/rules/dependencies.go index abecd1feb..0df62875f 100644 --- a/pkg/lint/rules/dependencies.go +++ b/pkg/lint/rules/dependencies.go @@ -20,8 +20,6 @@ import ( "fmt" "strings" - "github.com/pkg/errors" - "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/lint/support" @@ -32,21 +30,14 @@ import ( // See https://github.com/helm/helm/issues/7910 func Dependencies(linter *support.Linter) { c, err := loader.LoadDir(linter.ChartDir) - if !linter.RunLinterRule(support.ErrorSev, "", validateChartFormat(err)) { - return + if err != nil { + return // None of our business, Templates should deal with that } linter.RunLinterRule(support.ErrorSev, linter.ChartDir, validateDependencyInMetadata(c)) linter.RunLinterRule(support.WarningSev, linter.ChartDir, validateDependencyInChartsDir(c)) } -func validateChartFormat(chartError error) error { - if chartError != nil { - return errors.Errorf("unable to load chart\n\t%s", chartError) - } - return nil -} - func validateDependencyInChartsDir(c *chart.Chart) (err error) { dependencies := map[string]struct{}{} missing := []string{} diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index 9a3a2a1ba..0500b68a7 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -19,7 +19,6 @@ package rules import ( "fmt" "os" - "path" "path/filepath" "regexp" "strings" @@ -48,20 +47,18 @@ var validName = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([- // Templates lints the templates in the Linter. func Templates(linter *support.Linter, values map[string]interface{}, namespace string, strict bool) { - fpath := "templates/" - templatesPath := filepath.Join(linter.ChartDir, fpath) + path := "" - templatesDirExist := linter.RunLinterRule(support.WarningSev, fpath, validateTemplatesDir(templatesPath)) + // No warning for values templates directory yet + // linter.RunLinterRule(support.WarningSev, "values/", validateTemplatesDir(filepath.Join(linter.ChartDir, "values/"))) // Templates directory is optional for now - if !templatesDirExist { - return - } + linter.RunLinterRule(support.WarningSev, "templates/", validateTemplatesDir(filepath.Join(linter.ChartDir, "templates/"))) // Load chart and parse templates chart, err := loader.Load(linter.ChartDir) - chartLoaded := linter.RunLinterRule(support.ErrorSev, fpath, err) + chartLoaded := linter.RunLinterRule(support.ErrorSev, path, err) if !chartLoaded { return @@ -72,25 +69,46 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace Namespace: namespace, } - cvals, err := chartutil.CoalesceValues(chart, values) - if err != nil { - return - } - valuesToRender, err := chartutil.ToRenderValues(chart, cvals, options, nil) + valuesToRender, err := chartutil.ToRenderValues(chart, values, options, nil) if err != nil { - linter.RunLinterRule(support.ErrorSev, fpath, err) + linter.RunLinterRule(support.ErrorSev, path, err) return } var e engine.Engine e.LintMode = true renderedContentMap, err := e.Render(chart, valuesToRender) - renderOk := linter.RunLinterRule(support.ErrorSev, fpath, err) + renderOk := linter.RunLinterRule(support.ErrorSev, path, err) if !renderOk { return } + /* Iterate over all the values templates to check: + - It is a .yaml file + - All the values in the template file is defined + - {{}} include | quote + */ + for _, template := range chart.ValuesTemplates { + fileName, data := template.Name, template.Data + path = fileName + + linter.RunLinterRule(support.ErrorSev, path, validateAllowedExtension(fileName)) + // These are v3 specific checks to make sure and warn people if their + // chart is not compatible with v3 + linter.RunLinterRule(support.WarningSev, path, validateNoCRDHooks(data)) + linter.RunLinterRule(support.ErrorSev, path, validateNoReleaseTime(data)) + + // NOTE: disabled for now, Refs https://github.com/helm/helm/issues/1463 + // Check that all the templates have a matching value + //linter.RunLinterRule(support.WarningSev, path, validateNoMissingValues(templatesPath, valuesToRender, preExecutedTemplate)) + + // NOTE: disabled for now, Refs https://github.com/helm/helm/issues/1037 + // linter.RunLinterRule(support.WarningSev, path, validateQuotes(string(preExecutedTemplate))) + + // e.Render already have already checked if the content is a valid Yaml file + } + /* Iterate over all the templates to check: - It is a .yaml file - All the values in the template file is defined @@ -100,13 +118,13 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace */ for _, template := range chart.Templates { fileName, data := template.Name, template.Data - fpath = fileName + path = fileName - linter.RunLinterRule(support.ErrorSev, fpath, validateAllowedExtension(fileName)) + linter.RunLinterRule(support.ErrorSev, path, validateAllowedExtension(fileName)) // These are v3 specific checks to make sure and warn people if their // chart is not compatible with v3 - linter.RunLinterRule(support.WarningSev, fpath, validateNoCRDHooks(data)) - linter.RunLinterRule(support.ErrorSev, fpath, validateNoReleaseTime(data)) + linter.RunLinterRule(support.WarningSev, path, validateNoCRDHooks(data)) + linter.RunLinterRule(support.ErrorSev, path, validateNoReleaseTime(data)) // We only apply the following lint rules to yaml files if filepath.Ext(fileName) != ".yaml" || filepath.Ext(fileName) == ".yml" { @@ -115,12 +133,12 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace // NOTE: disabled for now, Refs https://github.com/helm/helm/issues/1463 // Check that all the templates have a matching value - //linter.RunLinterRule(support.WarningSev, fpath, validateNoMissingValues(templatesPath, valuesToRender, preExecutedTemplate)) + //linter.RunLinterRule(support.WarningSev, path, validateNoMissingValues(templatesPath, valuesToRender, preExecutedTemplate)) // NOTE: disabled for now, Refs https://github.com/helm/helm/issues/1037 - // linter.RunLinterRule(support.WarningSev, fpath, validateQuotes(string(preExecutedTemplate))) + // linter.RunLinterRule(support.WarningSev, path, validateQuotes(string(preExecutedTemplate))) - renderedContent := renderedContentMap[path.Join(chart.Name(), fileName)] + renderedContent := renderedContentMap[filepath.Join(chart.Name(), fileName)] if strings.TrimSpace(renderedContent) != "" { var yamlStruct K8sYamlStruct // Even though K8sYamlStruct only defines a few fields, an error in any other @@ -129,10 +147,10 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace // If YAML linting fails, we sill progress. So we don't capture the returned state // on this linter run. - linter.RunLinterRule(support.ErrorSev, fpath, validateYamlContent(err)) - linter.RunLinterRule(support.ErrorSev, fpath, validateMetadataName(&yamlStruct)) - linter.RunLinterRule(support.ErrorSev, fpath, validateNoDeprecations(&yamlStruct)) - linter.RunLinterRule(support.ErrorSev, fpath, validateMatchSelector(&yamlStruct, renderedContent)) + linter.RunLinterRule(support.ErrorSev, path, validateYamlContent(err)) + linter.RunLinterRule(support.ErrorSev, path, validateMetadataName(&yamlStruct)) + linter.RunLinterRule(support.ErrorSev, path, validateNoDeprecations(&yamlStruct)) + linter.RunLinterRule(support.ErrorSev, path, validateMatchSelector(&yamlStruct, renderedContent)) } } }