Can kubernetes-helm templates use variables?

rideswitch picture rideswitch · Mar 16, 2017 · Viewed 12.1k times · Source

I have a generic template for a k8s resource that I want to expand n times (if you are curious, it is so that I can create n members of a mongo cluster and they are using the statefulset resource so that each member has a stable network name).

Obviously I need different values each time through the loop. I am looping over a series of indices generated by the Sprig "until" function. But the $index for the loop does not get set in the "." namespace. So I am unable to refer the the current iteration inside of my defined template in my _helpers.tpl file.

here is an example template w/full k8s resource yaml (I'm abbreviating most of it):

{{- define "mytest" -}} 
---
apiVersion: apps/v1beta1
kind: StatefulSet
  abbreviated...
  containers:
  - name: mongod-$index
  abbreviated...
{{- end -}}

caller:

{{ range $index, $e := until .Values.mongod_count }}
    {{include "mytest" .}}
{{ end}}

I just get: undefined variable "$index"

I have tried with blocks too, like this in my (caller) template:

{{ $foo := "somevalue" }}
{{ define "my_extra_labels" }} bla {{ .Values.test }}_{{$foo}}{{end}}
{{ template "mytest" . }}

And this in my _helpers.tpl

{{/* Test stuff */}} 
{{- define "mytest" -}}
hello: world_how_are_{{ block "my_extra_labels" . }}{{ end }}
{{- end -}} 

The variable $foo is not defined in the "define" body.

This template scoping feels so restrictive that at this point I can't see how to use it to solve my current scenario.

Is there some way to shove variables into the "." namespace? And if so (crossing my fingers) is there a way to merge namespaces in some way so that I can still access .Values and .Chart variables?

Answer

kscoder picture kscoder · Aug 11, 2017

Templates in helm cannot access variables. However, the context handed to the template is a dictionary. The sprig library is accessible from within the Go templates and can be used to manipulate dictionaries.

Take this simplified template:

{{- define "mytest" -}} 
  - name: mongod-{{ .index }}
{{- end -}}

You can now call this template as an example:

{{ range $index := until 5 }}
  {{- $p := dict "index" $index }}
  {{include "mytest" $p}}
{{- end -}}

This will output:

- name: mongod-0
- name: mongod-1
- name: mongod-2
- name: mongod-3
- name: mongod-4

You can also add items to an existing or the current scoped dictionary:

{{- $_ := set . "index" "none" }}
{{include "mytest" .}}

The $_ is used to suppress undesired output as "set" returns the new dictionary. The above returns:

- name: mongod-none

Any values added to the dictionary will live beyond the call. If you want to avoid polluting an existing dictionary you can force a deep copy with:

{{-  $d := merge (dict) . -}}

Anything added to "$d" will not exist in ".".