Search code examples
kubernetes-helmgo-templates

helm template won't recognize variables


I'm trying to write a helm yaml template doing the following:

My-deployment-template.yaml:

{{- if eq $.Values.value "6" -}}
{{- $var1 := (toString $.Values.something6) -}}
{{- $var2 := (toString $.Values.somethingelse6) -}}
{{- else if eq $.Values.value "7"  -}}
{{- $var1 := (toString $.Values.something7) -}}
{{- $var2 := (toString $.Values.somethingelse7) -}}
{{- end }} 
...
... (in the same file )
{{- ..... |replace "Placeholder1" $var1 | replace "Placeholder2" $var2 }}}`

but the $var1 and $var2 are not recognized outside of the if scope I've created. How can i overcome this issue ?

When I use helm upgrade... I get the following:

undefined variable "$var1" ...
undefined variable "$var2" ...

Solution

  • There's a couple of approaches to this problem as you've laid it out.

    The Go text/template language supports assignment without creating a new variable $var = value (=, not :=). This was new in Go 1.11, but that release has been out for over three years now, and most tools including Helm should incorporate it. So you can create the variable outside the if block and then change it inside.

    {{- $var1 := "" -}}
    
    {{- if eq $.Values.value "6" -}}
    {{- $var1 = (toString $.Values.something6) -}}
    {{- end }}
    
    {{- ... | replace "Placeholder1" $var1 | ... -}}
    

    As you've shown the code, all of the values have similar names. If this is true globally then you can construct the name once and use the standard template index function to look it up. This would let you avoid the if block entirely.

    {{- $var1name := printf "something%s" $.Values.value -}}
    {{- $var1 := index $.Values $var1name | toString -}}
    

    If you can restructure your values, then using a YAML map instead of a list of similarly-named values could be easier.

    # values.yaml
    value: "6"
    something:
      "6": foo
    
    {{- $var1 := index $.Values.something $.Values.value | toString -}}
    

    Finally, rather than having multiple sets of configuration in a single values file and trying to switch between them, if you can restructure things to keep only one set of configuration in a file, that's best still. You can use the helm install -f option to provide additional configuration when you install the chart.

    {{/* templates/foo.yaml */}}
    {{ ... | replace "Placeholder1" .Values.something | ... }}
    
    # values.yaml
    
    # something specifies the value used for `Placeholder1`.
    something: a reasonable default used it nothing else is specied
    
    # values6.yaml, which could be outside the chart directory
    something: the sixth per-environment value
    
    helm install -f values6.yaml ...
    

    (In other questions I've seen setups like this for dev/qa/prod environments, for example. This helm install -f approach both makes it very clear what values are used in production and simplifies the template logic quite a bit.)