Helm: generate comma separated list
Asked Answered
E

8

36

Using Helm templates, I'm trying to generate a list of server names based on a number in values.yaml. The dot for this template is set to the number (its a float64).

{{- define "zkservers" -}}
{{- $zkservers := list -}}
{{- range int . | until -}}
{{- $zkservers := print "zk-" . ".zookeeper" | append $zkservers -}}
{{- end -}}
{{- join "," $zkservers -}}
{{- end -}}

For an input of, say, 3 I'm expecting this to produce:

zk-0.zookeeper,zk-1.zookeeper,zk-2.zookeeper

It produces nothing.

I understand that the line within the range block is a no-op since the variable $zkservers is a new variable each time the loop iterates. It is not the same variable as the $zkservers in the outer scope.

I hope the intention is clear of what I want to do. I am at a loss how to do it.

Anyone know how to do this with Helm templates?

Epicritic answered 6/12, 2017 at 7:12 Comment(0)
O
81

For those from 2020+ it now can be achieved as simple as that:

{{ join "," .Values.some.array }}

It produces the correct output: value: "test1,test2,test3"

At least it works with (more or less) recent versions of helm-cli:

Client: &version.Version{SemVer:"v2.16.2", GitCommit:"bbdfe5e7803a12bbdf97e94cd847859890cf4050", GitTreeState:"clean"}
Openwork answered 7/4, 2020 at 19:8 Comment(6)
This is definitely the best answer as of 2020Canikin
This does not cover how you would concatenate for each element zk-i.zookeepr where i would be the original array elementBlackleg
And it continues to be the correct answer in 2021Peary
Strange I don't see this documented on the helm function list. helm.sh/docs/chart_template_guide/function_listMercurochrome
@PaulMiller Indeed. I think it's better to turn to sprig library documentation when it comes to helm3 templating, since most functions are taken from there AFAIK: godoc.org/github.com/Masterminds/sprig Helm maintainers also mention the original docs at the bottom of the document you've provided: Note, the documentation for many of these functions come from Sprig. Sprig is a template function library available to Go applications.Openwork
Continues to work in 2022 as well!Aftergrowth
E
36

Another quick way of doing it:

{{- define "helm-toolkit.utils.joinListWithComma" -}}
{{- $local := dict "first" true -}}
{{- range $k, $v := . -}}{{- if not $local.first -}},{{- end -}}{{- $v -}}{{- $_ := set $local "first" false -}}{{- end -}}
{{- end -}}

If you give this input like:

test:
- foo
- bar

And call with:

{{ include "helm-toolkit.utils.joinListWithComma" .Values.test }}

You'll get the following rendered:

foo,bar

This is from OpenStack-Helm's Helm-toolkit chart, which is a collection of utilities for similar purposes.

Everhart answered 23/9, 2018 at 14:1 Comment(0)
A
18

I faced with the same problem and your solution with dictionary saved my day. It's a good workaround and it can be just a little simpler:

{{- define "zkservers" -}}
{{- $zk := dict "servers" (list) -}}
{{- range int . | until -}}
{{- $noop := printf "zk-%d.zookeeper" . | append $zk.servers | set $zk "servers" -}}
{{- end -}}
{{- join "," $zk.servers -}}
{{- end -}}
Antineutron answered 7/3, 2018 at 8:53 Comment(2)
Found github.com/Masterminds/sprig/tree/master/docs which helps explain how this template language works, but still struggling with | append $zk.servers | set $zk "servers"Khz
It's not clear why $dot has to be a dict which contains the list? Is that because you can't reassign the value of $zk within the range block?Bramlett
T
10

You're currently defining a new varialbe in the scope of the list while you want to alter the existing value.

In order to fix your bug, you only need to change the way you assign the value to $zkservers:

    - {{- $zkservers := print "zk-" . ".zookeeper" | append $zkservers -}}
    + {{- $zkservers = print "zk-" . ".zookeeper" | append $zkservers -}}  

which gives you the following script:

{{- define "zkservers" -}}
{{- $zkservers := list -}}
{{- range int . | until -}}
{{- $zkservers = print "zk-" . ".zookeeper" | append $zkservers -}}
{{- end -}}
{{- join "," $zkservers -}}
{{- end -}}

With this slight modification, {{ include "zkservers" 3 }}gives you the output zk-0.zookeeper,zk-1.zookeeper,zk-2.zookeeper

Teal answered 4/12, 2019 at 10:14 Comment(1)
Nice, simpler than the dict shenanigansSadi
L
8

I was doing the same but on elasticsearch helm chart. Please find my example

values.yml:

...
replicaCount: 3
...

StatefulSets.yaml:

...
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.registry_address }}/{{ .Values.image.name }}:{{ .Chart.AppVersion }}"
          env:
            - name: ELASTICSEARCH_CLUSTER_NAME
              value: "{{ .Values.env.ELASTICSEARCH_CLUSTER_NAME }}"
            - name: ELASTICSEARCH_DISCOVERY_ZEN_PING_UNICAST_HOSTS
              value: "{{ template "nodes" .Values }}"
...

_helpers.tpl:

{{/* vim: set filetype=mustache: */}}

{{- define "nodes" -}}
{{- $nodeCount := .replicaCount | int }}
  {{- range $index0 := until $nodeCount -}}
    {{- $index1 := $index0 | add1 -}}
elasticsearch-{{ $index0 }}.elasticsearch{{ if ne $index1 $nodeCount }},{{ end }}
  {{- end -}}
{{- end -}}

This produces a comma separated list:

...
            - name: ELASTICSEARCH_DISCOVERY_ZEN_PING_UNICAST_HOSTS
              value: "elasticsearch-0.elasticsearch,elasticsearch-1.elasticsearch,elasticsearch-2.elasticsearch"

...
Lawful answered 30/7, 2018 at 11:13 Comment(0)
H
4

Not sure why this was not yet mentioned.

Using join for lists of primitive type items should be most forward. However, if you're iterating over a list of maps and want a character (comma) separated string of a certain property of the list's items, this seems to be the most obvious solution:

 value: {{ range $i, $value := .Values.listOfMaps }}{{ if ne $i 0 }},{{ end }}{{ $value.someProperty }}{{ end }}
Hauberk answered 20/3, 2023 at 8:6 Comment(1)
Thank you! This is exactly the kind of thing I was looking for.Formation
E
3

I got it working using:

{{- define "zkservers" -}}
{{- $dot := dict "nodes" (int .) "servers" (list) -}}
{{- template "genservers" $dot -}}
{{- join "," $dot.servers -}}
{{- end -}}

{{- define "genservers" -}}
{{- range until .nodes -}}
{{- $noop := print "zk-" . ".zookeeper" | append $.servers | set $ "servers" -}}
{{- end -}}
{{- end -}}

Seems a little bit verbose for what should normally be a simple one/two liner :)

Epicritic answered 6/12, 2017 at 8:15 Comment(0)
T
3

How about just rendering and then trimming?

{{- include "template" . | trimSuffix "," -}}
Taffeta answered 2/1, 2020 at 11:15 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.