Search code examples
kubernetes-helm

helm templates with helpers dont reconigze .Values


i get errors using a template with one parameter, no .Values is recognized inside the template on _helpers.tpl, but only inside define "mychart.virtualserver" section. Another sections with out get paremeters works well with .Values, any solution?

configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-virtual-servers
data:
  default.conf: |
      {{- include "mychart.virtualserver"  (dict "subdomain" "peleadmin") | nindent 6 }}

_helpers.tpl

{{- define "mychart.virtualserver" -}}
{{- $subdomain := .subdomain | default "peleadmin" }}
{{ .Values.domain}};
{{- end -}}

values.yaml

domain: devazure.peruprop.com

i get this error:

Error: template: mychart/templates/nginx-virtual-servers.yaml:7:10: executing "mychart/templates/nginx-virtual-servers.yaml" at <include "mychart.virtualserver" (dict "subdomain" "peleadmin")>: error calling include: template: mychart/templates/_helpers.tpl:85:10: executing "mychart.virtualserver" at <.Values.domain>: nil pointer evaluating interface {}.domain
helm.go:86: 2025-01-29 20:26:05.484493 +0100 CET m=+0.105932542 [debug] template: mychart/templates/nginx-virtual-servers.yaml:7:10: executing "mychart/templates/nginx-virtual-servers.yaml" at <include "mychart.virtualserver" (dict "subdomain" "peleadmin")>: error calling include: template: mychart/templates/_helpers.tpl:85:10: executing "mychart.virtualserver" at <.Values.domain>: nil pointer evaluating interface {}.domain

Solution

  • In the Go text/template language, .Values looks up a field Values on a special variable .. . is very context-dependent (What is, and what use cases have the dot "." in helm charts?).

    Within a define template, . is the single parameter to the template. Where you're calling the template in a (Helm-specific) include call, though, you're not passing in the top-level ., you're only passing in a dictionary with a subdomain key.

    That is: within the included template, .subdomain and .Values are the same syntax, and both refer to the template parameter.

    When you call (either template or include) another template, if you need a top-level Helm value like .Values or .Files, you need to pass the top-level Helm object as or within the template parameter. Most commonly you just pass the top-level value down as-is, include "some-template" . using . as the parameter. If you need some other setting, though, you need to explicitly pass the top-level object as part of the parameter.

    I've historically named this object "top". If you're passing a dictionary in already, you can include it:

    {{- include "mychart.virtualserver"  (dict "subdomain" "peleadmin" "top" .) -}}
    {{/*                                                           add ^^^^^^^ */}}
    
    {{- define "mychart.virtualserver" -}}
    {{- $subdomain := .subdomain | default "peleadmin" }}
    {{ .top.Values.domain}};
    {{/*^^^            */}}
    {{- end -}}
    

    You could also extract the specific value you need out in the caller.

    {{- $params := dict "domain" .Values.domain "subdomain" "peleadmin" -}}
    {{- include "mychart.virtualserver" $params -}}
    

    Then in the template you could refer to .domain and .subdomain as fields of ., but you'd have no way to get back to the top-level .Values.