Commit 59806b40 authored by Matt Butcher's avatar Matt Butcher Committed by GitHub

Merge pull request #873 from technosophos/feat/859-namespace-values

feat(*): add Values namespace to templates
parents 1dc95be1 225d3a8a
...@@ -238,13 +238,15 @@ func (s *releaseServer) InstallRelease(c ctx.Context, req *services.InstallRelea ...@@ -238,13 +238,15 @@ func (s *releaseServer) InstallRelease(c ctx.Context, req *services.InstallRelea
// Render the templates // Render the templates
// TODO: Fix based on whether chart has `engine: SOMETHING` set. // TODO: Fix based on whether chart has `engine: SOMETHING` set.
vals, err := chartutil.CoalesceValues(req.Chart, req.Values, overrides) 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, vals) files, err := renderer.Render(req.Chart, overrides)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
apiVersion: v1 apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: "{{.Release.Name}}-{{.Chart.Name}}" name: "{{.Release.Name}}-{{.Values.Name}}"
labels: labels:
# The "heritage" label is used to track which tool deployed a given chart. # The "heritage" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool # It is useful for admins who want to see what releases a particular tool
...@@ -19,7 +19,7 @@ spec: ...@@ -19,7 +19,7 @@ spec:
# called restartPolicy. If it is not found, it will use the default value. # called restartPolicy. If it is not found, it will use the default value.
# {{default "Never" .restartPolicy}} is a slightly optimized version of the # {{default "Never" .restartPolicy}} is a slightly optimized version of the
# more conventional syntax: {{.restartPolicy | default "Never"}} # more conventional syntax: {{.restartPolicy | default "Never"}}
restartPolicy: {{default "Never" .restartPolicy}} restartPolicy: {{default "Never" .Values.restartPolicy}}
containers: containers:
- name: waiter - name: waiter
image: "alpine:3.3" image: "alpine:3.3"
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
{{/* {{/*
Expand the name of the chart. Expand the name of the chart.
*/}} */}}
{{define "name"}}{{default "nginx" .nameOverride | trunc 24 }}{{end}} {{define "name"}}{{default "nginx" .Values.nameOverride | trunc 24 }}{{end}}
{{/* {{/*
Create a default fully qualified app name. Create a default fully qualified app name.
...@@ -10,4 +10,4 @@ Create a default fully qualified app name. ...@@ -10,4 +10,4 @@ Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this We truncate at 24 chars because some Kubernetes name fields are limited to this
(by the DNS naming spec). (by the DNS naming spec).
*/}} */}}
{{define "fullname"}}{{.Release.Name}}-{{default "nginx" .nameOverride | trunc 24 }}{{end}} {{define "fullname"}}{{.Release.Name}}-{{default "nginx" .Values.nameOverride | trunc 24 }}{{end}}
...@@ -11,5 +11,5 @@ metadata: ...@@ -11,5 +11,5 @@ metadata:
data: data:
# When the config map is mounted as a volume, these will be created as # When the config map is mounted as a volume, these will be created as
# files. # files.
index.html: {{ default "Hello" .index | quote }} index.html: {{default "Hello" .Values.index | quote}}
test.txt: test test.txt: test
...@@ -15,7 +15,7 @@ metadata: ...@@ -15,7 +15,7 @@ metadata:
# This makes it easy to audit chart usage. # This makes it easy to audit chart usage.
chart: "{{.Chart.Name}}-{{.Chart.Version}}" chart: "{{.Chart.Name}}-{{.Chart.Version}}"
spec: spec:
replicas: {{ default 1 .replicaCount | quote }} replicas: {{default 1 .Values.replicaCount | quote}}
template: template:
metadata: metadata:
labels: labels:
...@@ -28,8 +28,8 @@ spec: ...@@ -28,8 +28,8 @@ spec:
# is a nice option for the user. Especially in the strange cases like # is a nice option for the user. Especially in the strange cases like
# nginx where the base distro is determined by the tag. Using :latest # nginx where the base distro is determined by the tag. Using :latest
# is frowned upon, using :stable isn't that great either. # is frowned upon, using :stable isn't that great either.
image: "{{default "nginx" .image}}:{{default "stable-alpine" .imageTag}}" image: "{{default "nginx" .Values.image}}:{{default "stable-alpine" .Values.imageTag}}"
imagePullPolicy: {{default "IfNotPresent" .pullPolicy}} imagePullPolicy: {{default "IfNotPresent" .Values.pullPolicy}}
ports: ports:
- containerPort: 80 - containerPort: 80
# This (and the volumes section below) mount the config map as a volume. # This (and the volumes section below) mount the config map as a volume.
......
...@@ -10,7 +10,7 @@ metadata: ...@@ -10,7 +10,7 @@ metadata:
chart: "{{.Chart.Name}}-{{.Chart.Version}}" chart: "{{.Chart.Name}}-{{.Chart.Version}}"
spec: spec:
ports: ports:
- port: {{ default 80 .httpPort | quote }} - port: {{default 80 .Values.httpPort | quote}}
targetPort: 80 targetPort: 80
protocol: TCP protocol: TCP
name: http name: http
......
...@@ -94,11 +94,18 @@ func tableLookup(v Values, simple string) (Values, error) { ...@@ -94,11 +94,18 @@ func tableLookup(v Values, simple string) (Values, error) {
if !ok { if !ok {
return v, ErrNoTable return v, ErrNoTable
} }
vv, ok := v2.(map[string]interface{}) if vv, ok := v2.(map[string]interface{}); ok {
if !ok { return vv, nil
return vv, ErrNoTable }
// This catches a case where a value is of type Values, but doesn't (for some
// reason) match the map[string]interface{}. This has been observed in the
// wild, and might be a result of a nil map of type Values.
if vv, ok := v2.(Values); ok {
return vv, nil
} }
return vv, nil
return map[string]interface{}{}, ErrNoTable
} }
// ReadValues will parse YAML byte data into a Values. // ReadValues will parse YAML byte data into a Values.
......
...@@ -71,6 +71,7 @@ func New() *Engine { ...@@ -71,6 +71,7 @@ func New() *Engine {
func (e *Engine) Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, error) { func (e *Engine) Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, error) {
// Render the charts // Render the charts
tmap := allTemplates(chrt, values) tmap := allTemplates(chrt, values)
fmt.Printf("%v", tmap)
return e.render(tmap) return e.render(tmap)
} }
...@@ -104,7 +105,6 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) { ...@@ -104,7 +105,6 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
rendered := make(map[string]string, len(files)) rendered := make(map[string]string, len(files))
var buf bytes.Buffer var buf bytes.Buffer
for _, file := range files { for _, file := range files {
// log.Printf("Exec %s with %v (%s)", file, tpls[file].vals, tpls[file].tpl)
if err := t.ExecuteTemplate(&buf, file, tpls[file].vals); err != nil { if err := t.ExecuteTemplate(&buf, file, tpls[file].vals); err != nil {
return map[string]string{}, fmt.Errorf("render error in %q: %s", file, err) return map[string]string{}, fmt.Errorf("render error in %q: %s", file, err)
} }
...@@ -137,13 +137,25 @@ func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals char ...@@ -137,13 +137,25 @@ func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals char
} else if c.Metadata != nil && c.Metadata.Name != "" { } else if c.Metadata != nil && c.Metadata.Name != "" {
// An error indicates that the table doesn't exist. So we leave it as // An error indicates that the table doesn't exist. So we leave it as
// an empty map. // an empty map.
tmp, err := parentVals.Table(c.Metadata.Name)
var tmp chartutil.Values
vs, err := parentVals.Table("Values")
if err == nil {
tmp, err = vs.Table(c.Metadata.Name)
} else {
tmp, err = parentVals.Table(c.Metadata.Name)
}
//tmp, err := parentVals["Values"].(chartutil.Values).Table(c.Metadata.Name)
if err == nil { if err == nil {
cvals = tmp cvals = map[string]interface{}{
"Values": tmp,
"Release": parentVals["Release"],
"Chart": c,
}
} }
} }
//log.Printf("racAllTpls values: %v", cvals)
for _, child := range c.Dependencies { for _, child := range c.Dependencies {
recAllTpls(child, templates, cvals, false) recAllTpls(child, templates, cvals, false)
} }
......
...@@ -215,11 +215,13 @@ func TestRenderNestedValues(t *testing.T) { ...@@ -215,11 +215,13 @@ func TestRenderNestedValues(t *testing.T) {
innerpath := "charts/inner/templates/inner.tpl" innerpath := "charts/inner/templates/inner.tpl"
outerpath := "templates/outer.tpl" outerpath := "templates/outer.tpl"
deepestpath := "charts/inner/charts/deepest/templates/deepest.tpl" deepestpath := "charts/inner/charts/deepest/templates/deepest.tpl"
checkrelease := "charts/inner/charts/deepest/templates/release.tpl"
deepest := &chart.Chart{ deepest := &chart.Chart{
Metadata: &chart.Metadata{Name: "deepest"}, Metadata: &chart.Metadata{Name: "deepest"},
Templates: []*chart.Template{ Templates: []*chart.Template{
{Name: deepestpath, Data: []byte(`And this same {{.what}} that smiles {{.global.when}}`)}, {Name: deepestpath, Data: []byte(`And this same {{.Values.what}} that smiles {{.Values.global.when}}`)},
{Name: checkrelease, Data: []byte(`Tomorrow will be {{default "happy" .Release.Name }}`)},
}, },
Values: &chart.Config{Raw: `what: "milkshake"`}, Values: &chart.Config{Raw: `what: "milkshake"`},
} }
...@@ -227,7 +229,7 @@ func TestRenderNestedValues(t *testing.T) { ...@@ -227,7 +229,7 @@ func TestRenderNestedValues(t *testing.T) {
inner := &chart.Chart{ inner := &chart.Chart{
Metadata: &chart.Metadata{Name: "herrick"}, Metadata: &chart.Metadata{Name: "herrick"},
Templates: []*chart.Template{ Templates: []*chart.Template{
{Name: innerpath, Data: []byte(`Old {{.who}} is still a-flyin'`)}, {Name: innerpath, Data: []byte(`Old {{.Values.who}} is still a-flyin'`)},
}, },
Values: &chart.Config{Raw: `who: "Robert"`}, Values: &chart.Config{Raw: `who: "Robert"`},
Dependencies: []*chart.Chart{deepest}, Dependencies: []*chart.Chart{deepest},
...@@ -236,7 +238,7 @@ func TestRenderNestedValues(t *testing.T) { ...@@ -236,7 +238,7 @@ func TestRenderNestedValues(t *testing.T) {
outer := &chart.Chart{ outer := &chart.Chart{
Metadata: &chart.Metadata{Name: "top"}, Metadata: &chart.Metadata{Name: "top"},
Templates: []*chart.Template{ Templates: []*chart.Template{
{Name: outerpath, Data: []byte(`Gather ye {{.what}} while ye may`)}, {Name: outerpath, Data: []byte(`Gather ye {{.Values.what}} while ye may`)},
}, },
Values: &chart.Config{ Values: &chart.Config{
Raw: ` Raw: `
...@@ -258,11 +260,19 @@ global: ...@@ -258,11 +260,19 @@ global:
when: to-day`, when: to-day`,
} }
inject, err := chartutil.CoalesceValues(outer, &injValues, map[string]interface{}{}) tmp, err := chartutil.CoalesceValues(outer, &injValues, map[string]interface{}{})
if err != nil { if err != nil {
t.Fatalf("Failed to coalesce values: %s", err) t.Fatalf("Failed to coalesce values: %s", err)
} }
inject := chartutil.Values{
"Values": tmp,
"Chart": outer.Metadata,
"Release": chartutil.Values{
"Name": "dyin",
},
}
t.Logf("Calculated values: %v", inject) t.Logf("Calculated values: %v", inject)
out, err := e.Render(outer, inject) out, err := e.Render(outer, inject)
...@@ -281,4 +291,8 @@ global: ...@@ -281,4 +291,8 @@ global:
if out[deepestpath] != "And this same flower that smiles to-day" { if out[deepestpath] != "And this same flower that smiles to-day" {
t.Errorf("Unexpected deepest: %q", out[deepestpath]) t.Errorf("Unexpected deepest: %q", out[deepestpath])
} }
if out[checkrelease] != "Tomorrow will be dyin" {
t.Errorf("Unexpected release: %q", out[checkrelease])
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment