Helm iterate over complex values

Im trying to iterate over the following values in my helm values.yaml using a helm helper .tpl

Values:

pubSub:
  - topicName: topic-1
    topicEnvVar: TOPIC_1
    subscriptions:
      - subscriptionName: subscription-1
        subscriptionEnvVar: SUBSCRIPTION_1
      - subscriptionName: subscription-2
        subscriptionEnvVar: SUBSCRIPTION_2
  - topicName: topic-2
    topicEnvVar: TOPIC_2
    subscriptions: {}
  - topicName: topic-3
    topicEnvVar: TOPIC_3
    subscriptions: {}

and the helper I’m trying to use is:

{{- range $topic, $envVar := .Values.pubSub }}
- name: {{ $envVar }}
  value: {{ $topic.topicName }}
{{- range $subName, $subEnvVar := $topic.subscriptions }}
- name: {{ $subEnvVar }}
  value: {{ $subName }}
{{- end }}
{{- end }}

Effectively, I would like it to iterate over the list of maps, and take out the pubs topic name and the topic environment variable name, and output them as:

- name: TOPIC_1
  value: topic-1
- name: TOPIC_2
  value: topic-2
- name: TOPIC_3
  value: topic-3

And the same for the subscriptions:

- name: SUBSCRIPTION_1
  value: subscription-1
- name: SUBSCRIPTION_2
  value: subscription-2

For context, the list within the values.yaml is being fed into a helm template for https://marketplace.upbound.io/providers/upbound/provider-gcp/v0.8.0/resources/pubsub.gcp.upbound.io/Subscription/v1beta1 which allows the creation of GCP pubs items via K8s resources.

When running a helm template . --debug, I can see that my k8s resource creates as expected, however when it’s trying to go through the steps of creating the list which I will be using in the env block of the deployment.yaml (helper seen above), it bombs out with:

Error: template: chart/templates/deployment.yaml:38:16: executing "chart/templates/deployment.yaml" at <include "chart.envVarsFull" .>: error calling include: template: chart/templates/_envVarsHelper.tpl:77:18: executing "chart.envVarsFull" at <$topic.topicName>: can't evaluate field topicName in type int

helm.go:84: [debug] template: chart/templates/deployment.yaml:38:16: executing "chart/templates/deployment.yaml" at <include "chart.envVarsFull" .>: error calling include: template: chart/templates/_envVarsHelper.tpl:77:18: executing "chart.envVarsFull" at <$topic.topicName>: can't evaluate field topicName in type int

Would anyone know how I can structure my helper config correctly to allow me to output as I’m expecting? 😀

Cheers!

.Values.pubSub is a list. If you run a range loop over that and assign two variables, the variables are the zero-based index and list item. It does not try to rebind variables based on the contents of the list item.

One thing you could do to see this is to print out the items directly

{{- range $index, $item := .Values.pubSub -}}
# {{ $index }}: {{ $item.topicName }}
{{ end -}}

which will print out

# 0: topic-1
# 1: topic-2
# 2: topic-3

The easiest way to fix this is to just use a single value assignment in the range loop. This will get assigned the loop item.

{{- range $topic := .Values.pubSub -}}
- name: {{ $topic.topicEnvVar }}
  value: {{ $topic.topicName }}
{{ end -}}

You could also take advantage of range rebinding the . special variable and not assign a variable at all.

{{- range .Values.pubSub -}}
- name: {{ .topicEnvVar }}
  value: {{ .topicName }}
{{ range .subscriptions -}}
- name: {{ .subscriptionEnvVar }}
  value: {{ .subscriptionName }}
{{ end -}}
{{- end -}}

range is part of the core Go text/template language, and its behavior is documented in the text/template package documentation.

Leave a Comment