Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can kubernetes-helm templates use variables?

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?

like image 468
rideswitch Avatar asked Mar 16 '17 01:03

rideswitch


People also ask

How do you declare a variable in Helm template?

In Helm templates, a variable is a named reference to another object. It follows the form $name . Variables are assigned with a special assignment operator: := . We can rewrite the above to use a variable for Release.Name .

What is include in Helm template?

The include function allows you to bring in another template, and then pass the results to other template functions. For example, this template snippet includes a template called mytpl , then lowercases the result, then wraps that in double quotes.

What does {{ }} mean in Helm?

The Helm template syntax is based on the Go programming language's text/template package. The braces {{ and }} are the opening and closing brackets to enter and exit template logic.

Does Helm use Go templates?

Helm has over 60 available functions. Some of them are defined by the Go template language itself. Most of the others are part of the Sprig template library.


2 Answers

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 ".".

like image 59
kscoder Avatar answered Oct 21 '22 09:10

kscoder


I will left this here because some people might be trying to set a static value to a variable in Helm to re-use it in a template and they probably will find this SO question by its title. So, here is a trick:

Update:

There's a better way to do this:

{{- $_ := set . "appName" "app_name_one"-}}

---
apiVersion: v1
kind: Deployment
apiVersion: apps/v1beta2
metadata:
  name: {{ .appName }}

The old advice (don't use it)

Combined with the syntax from the answer above suggested by @kscoder

    ---
    # values.yml

    static_vars:
      app_name_one: app_name_one
      text_to_reuse: text_to_reuse

    ---    
    # templates/deployment.yml

    # now you don't need to copy-n-paste values, just set them here once
    {{- $text_to_reuse := index .Values "static_vars" "text_to_reuse" -}}
    {{- $app_name := index .Values "static_vars" "app_name_one" -}}
    {{- $_ := set . "app_name" $app_name -}}

    apiVersion: v1
    kind: Deployment
    apiVersion: apps/v1beta2
    metadata:
      name: {{ .app_name }}
    spec:
      selector:
        # https://github.com/kubernetes/kubernetes/issues/26202
        matchLabels:
          name: {{ .app_name }}
      template:
        metadata:
          labels:
            name: {{ .app_name }}
            name_alt: {{ $app_name }}
            other_label: {{ $text_to_reuse }}
    # and so on
like image 22
kivagant Avatar answered Oct 21 '22 09:10

kivagant