Support Linter for Values

pull/899/head
Miguel Martinez 9 years ago
parent bb875b5657
commit 7bb4893cad

@ -220,33 +220,20 @@ func (s *releaseServer) InstallRelease(c ctx.Context, req *services.InstallRelea
return nil, errMissingChart return nil, errMissingChart
} }
ts := timeconv.Now()
name, err := s.uniqName(req.Name) name, err := s.uniqName(req.Name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
overrides := map[string]interface{}{ ts := timeconv.Now()
"Release": map[string]interface{}{ options := map[string]interface{}{"namespace": s.env.Namespace, "releaseName": name, "releaseTime": ts}
"Name": name, valuesToRender, err := chartutil.ToRenderValues(req.Chart, req.Values, options)
"Time": ts,
"Namespace": s.env.Namespace,
"Service": "Tiller",
},
"Chart": req.Chart.Metadata,
}
// Render the templates
// TODO: Fix based on whether chart has `engine: SOMETHING` set.
vals, err := chartutil.CoalesceValues(req.Chart, req.Values, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
overrides["Values"] = vals
renderer := s.engine(req.Chart) renderer := s.engine(req.Chart)
files, err := renderer.Render(req.Chart, overrides) files, err := renderer.Render(req.Chart, valuesToRender)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -288,6 +288,27 @@ func coalesceTables(dst, src map[string]interface{}) map[string]interface{} {
return dst return dst
} }
// ToRenderValues composes the struct from the data coming from the Releases, Charts and Values files
func ToRenderValues(chrt *chart.Chart, chrtVals *chart.Config, options map[string]interface{}) (Values, error) {
overrides := map[string]interface{}{
"Release": map[string]interface{}{
"Name": options["releaseName"],
"Time": options["releaseTime"],
"Namespace": options["namespace"],
"Service": "Tiller",
},
"Chart": chrt.Metadata,
}
vals, err := CoalesceValues(chrt, chrtVals, nil)
if err != nil {
return nil, err
}
overrides["Values"] = vals
return overrides, nil
}
// istable is a special-purpose function to see if the present thing matches the definition of a YAML table. // istable is a special-purpose function to see if the present thing matches the definition of a YAML table.
func istable(v interface{}) bool { func istable(v interface{}) bool {
_, ok := v.(map[string]interface{}) _, ok := v.(map[string]interface{})

@ -19,17 +19,18 @@ package rules
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"os"
"path/filepath"
"regexp"
"strings"
"text/template"
"github.com/Masterminds/sprig" "github.com/Masterminds/sprig"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/engine" "k8s.io/helm/pkg/engine"
"k8s.io/helm/pkg/lint/support" "k8s.io/helm/pkg/lint/support"
"k8s.io/helm/pkg/timeconv" "k8s.io/helm/pkg/timeconv"
"os"
"path/filepath"
"regexp"
"strings"
"text/template"
) )
func Templates(linter *support.Linter) { func Templates(linter *support.Linter) {
@ -51,18 +52,9 @@ func Templates(linter *support.Linter) {
return return
} }
// Based on cmd/tiller/release_server.go options := map[string]interface{}{"namespace": "testNamespace", "releaseName": "testRelease", "releaseTime": timeconv.Now()}
overrides := map[string]interface{}{ valuesToRender, err := chartutil.ToRenderValues(chart, chart.Values, options)
"Release": map[string]interface{}{ renderedContentMap, err := engine.New().Render(chart, valuesToRender)
"Name": "testRelease",
"Service": "Tiller",
"Time": timeconv.Now(),
},
"Chart": chart.Metadata,
}
chartValues, _ := chartutil.CoalesceValues(chart, chart.Values, overrides)
renderedContentMap, err := engine.New().Render(chart, chartValues)
renderOk := linter.RunLinterRule(support.ErrorSev, validateNoError(err)) renderOk := linter.RunLinterRule(support.ErrorSev, validateNoError(err))
@ -88,7 +80,7 @@ func Templates(linter *support.Linter) {
} }
// Check that all the templates have a matching value // Check that all the templates have a matching value
linter.RunLinterRule(support.WarningSev, validateNonMissingValues(fileName, templatesPath, chartValues, preExecutedTemplate)) linter.RunLinterRule(support.WarningSev, validateNonMissingValues(fileName, templatesPath, valuesToRender, preExecutedTemplate))
linter.RunLinterRule(support.WarningSev, validateQuotes(fileName, string(preExecutedTemplate))) linter.RunLinterRule(support.WarningSev, validateQuotes(fileName, string(preExecutedTemplate)))

@ -17,9 +17,12 @@ limitations under the License.
package rules package rules
import ( import (
"k8s.io/helm/pkg/lint/support" "os"
"path/filepath"
"strings" "strings"
"testing" "testing"
"k8s.io/helm/pkg/lint/support"
) )
const templateTestBasedir = "./testdata/albatross" const templateTestBasedir = "./testdata/albatross"
@ -73,7 +76,7 @@ func TestValidateQuotes(t *testing.T) {
} }
func TestTemplate(t *testing.T) { func TestTemplateParsing(t *testing.T) {
linter := support.Linter{ChartDir: templateTestBasedir} linter := support.Linter{ChartDir: templateTestBasedir}
Templates(&linter) Templates(&linter)
res := linter.Messages res := linter.Messages
@ -86,3 +89,22 @@ func TestTemplate(t *testing.T) {
t.Errorf("Unexpected error: %s", res[0]) t.Errorf("Unexpected error: %s", res[0])
} }
} }
var wrongTemplatePath string = filepath.Join(templateTestBasedir, "templates", "fail.yaml")
var ignoredTemplatePath string = filepath.Join(templateTestBasedir, "fail.yaml.ignored")
// Test a template with all the existing features:
// namespaces, partial templates
func TestTemplateIntegrationHappyPath(t *testing.T) {
// Rename file so it gets ignored by the linter
os.Rename(wrongTemplatePath, ignoredTemplatePath)
defer os.Rename(ignoredTemplatePath, wrongTemplatePath)
linter := support.Linter{ChartDir: templateTestBasedir}
Templates(&linter)
res := linter.Messages
if len(res) != 0 {
t.Fatalf("Expected no error, got %d, %v", len(res), res)
}
}

@ -0,0 +1,16 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{define "name"}}{{default "nginx" .Values.nameOverride | trunc 24 }}{{end}}
{{/*
Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this
(by the DNS naming spec).
*/}}
{{define "fullname"}}
{{- $name := default "nginx" .Values.nameOverride -}}
{{printf "%s-%s" .Release.Name $name | trunc 24 -}}
{{end}}

@ -1,2 +0,0 @@
metadata:
name: {{.name | default "foo" | title}}

@ -0,0 +1,18 @@
# This is a service gateway to the replica set created by the deployment.
# Take a look at the deployment.yaml for general notes about this chart.
apiVersion: v1
kind: Service
metadata:
name: "{{ .Values.name }}"
labels:
heritage: {{ .Release.Service | quote }}
release: {{ .Release.Name | quote }}
chart: "{{.Chart.Name}}-{{.Chart.Version}}"
spec:
ports:
- port: {{default 80 .Values.httpPort | quote}}
targetPort: 80
protocol: TCP
name: http
selector:
app: {{template "fullname" .}}
Loading…
Cancel
Save