Search code examples
kubernetes-helmistio

Prevent 'range' block from executing over an empty map when Values is not defined


I am facing an odd behaviour of helm when using the range iterator. My template looks like something like this

{{- range .Values.authorizationPolicies -}}
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: {{ .name }}-authorization-policy

... 
{{- end -}}

When I don't set anything from my values.yaml I see the error below

Error: INSTALLATION FAILED: template: microservice/templates/authorization-policies.yaml:5:11: executing "microservice/templates/authorization-policies.yaml" at <.name>: can't evaluate field name in type interface {}
helm.go:84: [debug] template: microservice/templates/authorization-policies.yaml:5:11: executing "microservice/templates/authorization-policies.yaml" at <.name>: can't evaluate field name in type interface {}
INSTALLATION FAILED
main.newInstallCmd.func2
        helm.sh/helm/v3/cmd/helm/install.go:154
github.com/spf13/cobra.(*Command).execute
        github.com/spf13/[email protected]/command.go:940
github.com/spf13/cobra.(*Command).ExecuteC
        github.com/spf13/[email protected]/command.go:1068
github.com/spf13/cobra.(*Command).Execute
        github.com/spf13/[email protected]/command.go:992
main.main
        helm.sh/helm/v3/cmd/helm/helm.go:83
runtime.main
        runtime/proc.go:267
runtime.goexit
        runtime/asm_arm64.s:1197

However, if I define authorizationPolicies: [], then the range doesn't iterate.

Seems to me that Helm does not distinguish between a non-existent value and an empty list or map. If the value is not specified in the values file, Helm treats it as an empty map.

Is there any workaround for this?


Solution

  • The easiest answer is to include the definition of authorizationPolicies: [] as an empty list in your chart's values.yaml file. Someone installing the chart can still provide a different value using a helm install -f alternate values file.

    The second-easiest answer is to provide a default empty list when setting up the range loop

    {{ range .Values.authorizationPolicies | default list }}
    ...
    {{ end }}
    

    If the value isn't defined anywhere, then .Values.authorizationPolicies has a special value of nil. This is different from an empty list or an empty map; it's considered "false" for purposes of conditionals or the default function. In the underlying Go implementation, the best Go type the template engine has to work with is the "anything" type interface{} and that's why you see it in the error message.