helm: $ does not point to the root in named templates

Consider the following template

# templates/bla.yaml
{{- define "baseLabels" -}}
app.kubernetes.io/instance: {{ $.Release.Name }}
app.kubernetes.io/part-of: {{ .name }}
{{- end -}}

{{- with .Values }}
apiVersion: v1
kind: Service
metadata:
  name: {{ .name }}
  labels:
    {{- include "baseLabels" . | nindent 4 }}
{{- end }}

that is templated with helm template release . --set name=foo.

I would expect $.Release.Name to be interpolated to release, and .name to be interpolated to foo. However, this yields the error:

Error: template: templates/bla.yaml:11:8: executing "templates/bla.yaml" at <include "baseLabels" .>: 
error calling include: template: templates/bla.yaml:2:32: executing "baseLabels" at <$.Release.Name>: nil pointer evaluating interface {}.Name

Specifically, even though, in the macro, I am using $.Release.Name to point to the root, this root is not the root that I was expecting it to be (the root of the project), but is instead the root of the named template (we can check this by removing the offending line and using $.name)

There are two questions here:

  1. Isn’t this against the statement we make in the docs

    However, there is one variable that is always global - $ - this variable will always point to the root context. [...]

  2. How do we define a named template that receives some scope (e.g. .name above) but also uses the root scope ($.Release.Name)?

Note that if we use {{- include "baseLabels" $ | nindent 4 }}, we lose the .name assigned by the with statement.

Output of helm version: version.BuildInfo{Version:"v3.1.1", GitCommit:"afe70585407b420d0097d07b21c47dc511525ac8", GitTreeState:"clean", GoVersion:"go1.13.8"}

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 4
  • Comments: 17 (6 by maintainers)

Commits related to this issue

Most upvoted comments

@bacongobbler IMO this is not a good answer. In the simple case presented this might work, but in the case of a range where you want both complex data from the root values and the current element this won’t work. You can obviously pass a merged dict, but this is really not intuitive and it should at the very least be mentioned as an exception in the documentation.

@bacongobbler can you reopen this issue? As mentioned by @jorgecarleitao, if we define a named template that receives some scope, then $ no longer points to the root context. The documentation says just the opposite. So, this is either a bug or a wrong statement in the documentation. Thanks for your support.

In your define, change .name to .Values.name. By passing $ you are passing along the root context, which means you’ll have to traverse the tree once more to see that value.

An alternative option would be to reconstruct a new variable that has both the release name as well as the name passed by values. sprig provides a function called dict which can be used to assemble a new dictionary. That dictionary can be passed along to that function call, like so:

{{- include "baseLabels" (dict "releaseName" $.Release.Name "name" .name) | nindent 4 }}

And then in your baselabels function:

{{- define "baseLabels" -}}
app.kubernetes.io/instance: {{ .releaseName }}
app.kubernetes.io/part-of: {{ .name }}
{{- end -}}

Hope this helps.

Closing as answered. Please let us know if you have any further questions.

Ah sorry, typo on my end. Try passing just $?