qxing
qxing

Reputation: 391

How to access variable out of current range control in helm template

I have a helm template like this,

1  {{- range $device_type := include "example.supportedDevices" . }}
3  {{- $total_worker_sets := get $.Values.all_worker_sets $device_type }}
4  {{- range $item := $total_worker_sets }}
5  {{- if eq $device_type "cpu" }}
6  {{- $type := "cpu" }}
7  {{- else }}
8  {{- $type := $item.name }}
9  {{- end }}
10  {{- range $i, $e := until ($item.worker_sets|int) }}
11  ---
12  apiVersion: apps/v1
13  kind: StatefulSet
14  metadata:
15    name: {{ template "example.fullname" $ }}-worker-{{ $type }}-{{ $i }}
16  spec:
...
{{- end }}
{{- end }}
{{- end }}

and helm lint returns: [ERROR] templates/: parse error at (example/templates/worker.yaml:15): undefined variable "$type"

Upvotes: 3

Views: 2730

Answers (3)

David Maze
David Maze

Reputation: 159495

As @KamolHasan notes in their answer, if you try to define a variable inside an {{ if }}...{{ end }} block, the scope of the variable is that block. Helm (and more specifically the Sprig extension template library) provides a ternary extension function to work around this.

ternary takes three arguments; in order, the true-value, the false-value, and the condition. This specific ordering lets you use template pipeline syntax to provide the condition. It's similar in spirit to the ? : inline-conditional operators in C-like languages

{{ $value := ternary "if-true" "if-false" $condition }}
const char *value = condition ? "if-true" : "if-false";

That would let you promote $type out of the conditional block

{{- range $item := $total_worker_sets }}
{{- $type := eq $device_type "cpu" | ternary "cpu" $item.name }}
{{- range $i, $e := until ($item.worker_sets|int) }}
name: {{ template "example.fullname" $ }}-worker-{{ $type }}-{{ $i }}
{{- end }}
{{- end }}

Upvotes: 1

Kamol Hasan
Kamol Hasan

Reputation: 13516

When you assigned the $type with := inside an if-block, the scope is limited only to that if-block. Define the variable outside the if-block so that you can use it later.

1  {{- range $device_type := include "example.supportedDevices" . }}
3  {{- $total_worker_sets := get $.Values.all_worker_sets $device_type }}
x  {{- $type := "" }}   ### <----define here
4  {{- range $item := $total_worker_sets }}
5  {{- if eq $device_type "cpu" }}
6  {{- $type = "cpu" }}  ### <--- replace :=  with = to avoid re-declaration
7  {{- else }}
8  {{- $type = $item.name }} ### <--- replace :=  with =
9  {{- end }}
10  {{- range $i, $e := until ($item.worker_sets|int) }}
11  ---
12  apiVersion: apps/v1
13  kind: StatefulSet
14  metadata:
15    name: {{ template "example.fullname" $ }}-worker-{{ $type }}-{{ $i }}
16  spec:
...
{{- end }}
{{- end }}
{{- end }}

Upvotes: 4

Sahadat Hossain
Sahadat Hossain

Reputation: 4379

You can use $ to get to the root scope. So instead of .type you can use $.type. Here you used $type, that is why it's showing undefined (undefined variable "$type", rather it would be $.type.

Upvotes: 3

Related Questions