34

I need to loop through a list of instances and create 1 stateful set for every instance. However, inside range I then limit myself to the scope of that loop. I need to access some global values in my statefulset.

I've solved it by just putting all global objects I need in an env variable but... this very seems hacky.

What is the correct way to loop through ranges while still being able to reference global objects?

Example of my loop

{{- $values := .Values -}}
{{- $release := .Release -}}

{{- range .Values.nodes }}

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ $release.Name }} <-- Global Scope
  labels:
    .
    .
    .    
        env:
          - name: IP_ADDRESS
            value: {{ .ip_address }} <-- From range scope
    .
    .
    .
{{- end }}

Example of values

# Global
image:
  repository: ..ecr.....

# Instances
nodes:

  - node1:
    name: node-1
    iP: 1.1.1.1
  - node2:
    name: node-2
    iP: 1.1.1.1
Community
  • 1
  • 1
LoganHenderson
  • 1,222
  • 4
  • 12
  • 24
  • Possible duplicate of [Golang template (helm) iterating over a list of maps](https://stackoverflow.com/questions/45198856/golang-template-helm-iterating-over-a-list-of-maps) – BMW Mar 18 '19 at 01:28
  • do you need to conditionally add a file separator (`---`) to split the various StatefulSet instances? – lmsurprenant Sep 30 '20 at 20:13

4 Answers4

66

When entering a loop block you lose your global context when using .. You can access the global context by using $. instead.

As written in the Helm docs -

there is one variable that is always global - $ - this variable will always point to the root context. This can be very useful when you are looping in a range and need to know the chart's release name.

In your example, using this would look something like:

{{- range .Values.nodes }}
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ $.Release.Name }}
  labels:
    .
    .
    .    
        env:
          - name: IP_ADDRESS
            value: {{ .ip_address }}
    .
    .
    .
{{- end }}
austin_ce
  • 1,063
  • 15
  • 28
Yaniv Oliver
  • 3,372
  • 1
  • 19
  • 20
23

The question is about the global scope, but it is possible to keep access to any outer scope by storing it, like this:

{{- $outer := . -}}

Then, if you use named variables for the range, like this:

{{- range $idx, $node := .Values.nodes }}

You don't need ., so you can restore the outer scope, like this:

{{- with $outer -}}

In your example, using this would look something like:

{{- $outer := . -}}
{{- range $idx, $node := .Values.nodes }}
{{- with $outer -}}
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ .Release.Name }}
  labels:
    .
    .
    .    
        env:
          - name: IP_ADDRESS
            value: {{ $node.ip_address }}
    .
    .
    .
{{- end }}
Lars Christian Jensen
  • 1,407
  • 1
  • 13
  • 14
15

If you need to access the global scope only, simply add {{- with $ -}} will do.

{{- range $idx, $node := .Values.nodes }}
{{- with $ -}}
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ .Release.Name }}
  labels:
    .
    .
    .    
        env:
          - name: IP_ADDRESS
            value: {{ $node.ip_address }}
    .
    .
    .
{{- end }}
{{- end }}
Thomas8
  • 1,117
  • 1
  • 11
  • 22
Terany
  • 171
  • 1
  • 5
  • Ensure you also close the `{{- with $ -}}` with an `{{- end }}` for helm Version:"v3.6.3" – briancollins081 Feb 25 '22 at 08:10
  • 1
    Instead of using the `with` block you can also add a `$` before any value reference within a `range`. For example, `{{ $.Release.Name}}` in the code above. Same thing works for values. For example, `{{ $.Values.someGlobalProp }}` – wsams Aug 22 '22 at 17:39
1

The best way is not to call many external objects inside the loop.

you can declare release name at the top in a variable to overcome this issue:

{{- $release_name := .Release.Name -}}
Abhi
  • 51
  • 3
  • Can you show me how I could accomplish the above without using external object in loop. Is there a different way you would structure the values.yaml data? – LoganHenderson Mar 19 '19 at 02:03
  • check this one https://gist.github.com/abhiTamrakar/ad77b1a8eb8e9950d05c01e1b1500469 – Abhi Mar 20 '19 at 06:22