How can you call a helm 'helper' template from a subchart with the correct context?
Asked Answered
H

5

29

Helm charts define helper templates in _helpers.tpl which are used to create normalized names for the services. The standard form of the template for a service (DNS) name is:

{{- define "postgresql.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

If using postgresql as a subchart, how are you supposed to use DNS-based service discovery to refer to it? A common pattern seems to be to copy the subchart helpers into the parent chart.

{{- define "keycloak.postgresql.fullname" -}}
{{- $name := default "postgresql" .Values.postgresql.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

This is total madness for obvious reasons!!!

Surely there's a better way to use the subchart helper? If you could create a context object then it would be possible to invoke it, something like:

value: {{ template "postgresql.fullname" ({Chart: {Name: 'not-used'}, Release: {Name: .Release.Name}, Values: { nameOverride: .Values.postgresql.nameOverride}}) }}

Sadly I have no idea how to actually create such a context dynamically. This would still break if the helper function changed to reference new properties, but in an obvious way.

Alternatively, a different way to make available the service name from a subchart?

Heighho answered 13/12, 2017 at 11:31 Comment(2)
I believe this same issue is described in helm#4314. No solution or work-around is yet mentioned there.Register
It seems the canonical issue is github.com/helm/helm/issues/3920. Still open at time of writing.Heighho
B
32

As of https://github.com/helm/helm/pull/9957 (merged August 31, 2021 and released in Helm 3.7), you can invoke the subchart's named template in the context of that subchart by using .Subcharts.[chartName] as the second argument.

For example, assuming your keycloak subchart names it service like {{ template "keycloak.fullname" . }}-http you could refer to that service's name from a parent chart as follows:

{{ template "keycloak.fullname" .Subcharts.keycloak }}-http
Batwing answered 10/10, 2021 at 13:57 Comment(3)
My subchart has dashes in its name and so I am getting "bad character U+002D '-'" errors when trying to call it using the method above. Can this be circumvented?Vowel
@Vowel you can use the index function, e.g. {{ include "ray-cluster.labels" (index .Subcharts "ray-cluster") }}Colettacolette
This took WAAAY to long to find. It seems to be very poorly documented and referenced elsewhere. I thought it had to be possible though I'm surprised it took until 2021 to implement!Fablan
Y
19

I wrote an issue helm/helm#4535 that summarizes the status-quo and proposes an enhancement to Helm which will solve this case.

For anyone looking for an interim solution, I wrote (see my follow-up comment for details) a meta-template that calls any given template in an "ersatz" subchart's scope. It works by synthesizing a dot-object. It is not perfect (not all fields are synthesized), but it will do:

{{- define "call-nested" }}
{{- $dot := index . 0 }}
{{- $subchart := index . 1 }}
{{- $template := index . 2 }}
{{- include $template (dict "Chart" (dict "Name" $subchart) "Values" (index $dot.Values $subchart) "Release" $dot.Release "Capabilities" $dot.Capabilities) }}
{{- end }}

Usage (to call a redis.fullname template of a redis subchart):

{{ include "call-nested" (list . "redis" "redis.fullname") }}
Yazbak answered 26/8, 2018 at 8:36 Comment(0)
H
1

Well, this is something that isn't very straightforward somehow.

I think what is going on here are the practices Helm follows and what is possible with the templates.

One practice is "charts work out of the box" - so whether its a sub-chart or stand-alone, it should just work. This has some consequences on what you need to configure to properly namespace the resources you deploy and that are referenced.

I had a very similar issue. See How to reference a value defined in a template in a sub-chart in helm for kubernetes?.

My "solution" to this is to redefine the postgres.fullname in my own _helpers.tpl:

{{- define "postgresql.fullname" -}}
{{- $name := printf "%s-%s" .Values.global.appId .Values.global.fkNameId -}}
{{- printf "%s-%s" $name "postgresql" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

Since release names must be unique per tiller installation - and we have one tiller in the cluster - I sort of took some distance from using the release name as part of the references and and own naming convention.

The defines in the templates are global. So you could just use those if you're good with the release name prefix that defaults the PostgreSQL chart:

{{- define "postgresql.fullname" -}}
{{- $name := printf "%s-%s" .Values.global.appId .Values.global.fkNameId -}}
{{- printf "%s-%s" $name "postgresql" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

I could not come up with release names that would not duplicate service names ("webshop-service-webshop-service"), so I tend to not use them since I need them per namespace, not per tiller instance.

Once I define the name from the sub-chart I reference it in my services. I'm ok with it since I know what chart I reference and what it uses for namings. But it’s true: should I upgrade the sub-chart I need to check if the names are still the same. But since that "fullname" is quite common I think I'm good. And some tests would fail anyway.

But not a beautiful "solution".

Not an answer - just good enough for me :)

Hornbeam answered 8/1, 2018 at 16:13 Comment(2)
wemu, your two examples are identical. Was the second one supposed to point out an alternative way?Register
@Register thanks for noticing. Sadly I'm not really sure what I was going for. I think I wanted to reference the postgres.fullname default from github.com/helm/charts/blob/master/stable/postgresql/templates/… using the release name as part of its default fullname - not my own convention again.Hornbeam
M
1

From what I understand, a named template is available globally to all parent and subcharts. This is not true however, for values. Parent values are not accessible to a sub chart but subchart values can be accessed by a parent.

Quoted from The Chart Template Developer's Guide, Declaring and using templates with define and template...

"There is one really important detail to keep in mind when naming templates: template names are global. If you declare two templates with the same name, whichever one is loaded last will be the one used. Because templates in subcharts are compiled together with top-level templates, you should be careful to name your templates with chart-specific names."

References

Mireillemireles answered 12/2, 2018 at 12:0 Comment(1)
All the links are half-broken - they all lead to the generic "The Chart Template Developer's Guide". The anchors (e.g. #declaring-and-using-templates-with-define-and-template) don't work (at least not with JavaScript allow listing). Can you fix it? (But without "Edit:", "Update:", or similar - the answer should appear as if it was written today.)Ourselves
B
1

To access a value from a chart you do the following:

{{ template "keycloak.fullname" . }}

To access a value from a sub chart

{{ template "keycloak.fullname" .Subcharts.keycloak }}

Note that those values can be found in the helper.tpl

Baldheaded answered 25/4, 2022 at 10:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.