Using an include statement as the default value - kubernetes-helm

I am creating a helm chart in which I want to specify a default for a value using a template function. Specifically I want to either use the override value image.name, or default to the template function chart.name:
{{ .Values.image.name | default include chart.name . }}
But when linting the chart I have the following error:
[ERROR] templates/: render error in "chart/templates/deployment.yaml": template: chart/templates/deployment.yaml:22:81: executing "chart/templates/deployment.yaml" at <include>: wrong number of args for include: want 2 got 0
Is it possible to use an included template function as the default value? Or can I only use literals?

You can. Just enclose your include statement in parentheses:
{{ .Values.image.name | default (include "chart.name" .)}}
Please see using the default function

Related

Helm tpl function to render a file does not work

I am trying to render a file using the tpl function. I am retrieving the content of the file using Files.Get, which works fine until I use tpl function on it.
My input file is:
apiVersion: autoscaling/v2beta2
My helm template is:
{{- $files := .Files }}
{{- tpl ($files.Get "files/autoscaling.yaml" ) . -}}
I had to use $files because it would throw the error:
at <.Files.Get>: can't evaluate field Files in type interface {}
The output that I see when I run the helm template is
Error: template: subchart-demoapp/templates/sub-deployments.yaml:5:47: executing "subchart-demoapp/templates/sub-deployments.yaml" at <.>: wrong type for value; expected chartutil.Values; got string
helm.go:84: [debug] template: subchart-demoapp/templates/sub-deployments.yaml:5:47: executing "subchart-demoapp/templates/sub-deployments.yaml" at <.>: wrong type for value; expected chartutil.Values; got string
My helm version is:
version.BuildInfo{Version:"v3.2.1", GitCommit:"fe51cd1e31e6a202cba7dead9552a6d418ded79a", GitTreeState:"clean", GoVersion:"go1.13.10"}
Thanks for any help.
Figured it out. tpl function when used in a range block needs the top-level context as the second argument. Ref: Helm Issue
Replaced the . with $ and it works as expected.

can't access helm .Values from a named template with non global context passed in

I'm trying to use a Helm named template that I plan to include with several different contexts, and the template has many values that are the same for all contexts.
Whenever I pass a context to template or include to invoke the named template, the references to .Values do not work, which is understandable because I'm explicitly setting a lower context.
In the Helm documentation for with, it claims there is a "global" variable $ that will allow reference to the global .Values, e.g., {{ $.Values... }}. This does not work (the example below shows the error).
I've also tried defining variables (using :=) and "enclosing" the include inside that variable definition (via indentation - I don't know if it matters) to make that variable available within the named template, but this doesn't work either.
I've also tried putting these in "globals" as described here which is more of a subchart thing and this doesn't work either.
So, I'm out of Helm tricks to make this work and will sadly have to re-define these many same variable many times - which makes the entire named template solution a bit less elegant - or just go back to having largely duplicate partially-parameterized templates.
What am I missing?
$ helm version
Client: &version.Version{SemVer:"v2.9+unreleased", GitCommit:"", GitTreeState:"clean"}
Values.yaml:
---
commonSetting1: "common1"
commonSetting2: "common2"
context1:
setting1: "c1s1"
setting2: "c1s2"
context2:
setting1: "c2s1"
setting2: "c2s2"
deployment.yaml:
---
{{- define "myNamedTemplate" }}
- name: {{ .setting1 }}
image: {{ $.Values.commonSetting1 }}
{{- include "myNamedTemplate" .Values.context1 }}
{{- include "myNamedTemplate" .Values.context2 }}
$ helm template test-0.1.0.tgz
Error: render error in "test/templates/deployment.yaml": template: test/templates/deployment.yaml:7:4: executing "test/templates/deployment.yaml" at <include "myNamedTemp...>: error calling include: template: test/templates/deployment.yaml:4:19: executing "myNamedTemplate" at <$.Values.commonSetti...>: can't evaluate field commonSetting1 in type interface {}
When I do this, I tend to explicitly pass in the top-level context object as a parameter. This gets a little tricky because the Go text/template templates only take a single parameter, so you need to use the (Helm/Sprig) list function to package multiple parameters together, and then the (standard text/template) index function to unpack them.
The template definition would look like:
{{- define "myNamedTemplate" }}
{{- $top := index . 0 }}
{{- $context := index . 1 }}
- name: {{ $context.setting1 }}
image: {{ $top.Values.commonSetting1 }}
{{ end }}
When you invoke it, you would then need to explicitly pass the current context as a parameter:
{{ include "myNamedTemplate" (list . .Values.context1) }}

Helm Charts - How do I use `default` on undefined object property values?

Using Helm, I was under the impression default would be the fallback if a variable is not defined. However, it doesn't appear Helm can get to values in sub-object hashes:
type: {{ default "NodePort" .Values.fpm.service.type }}
If .Values.fpm.service or service.type is not defined, it should use 9000.
However, attempting to template this throws a nil pointer error:
<.Values.fpm.service.type>: nil pointer evaluating interface {}.type
Is there a way to simply perform this level of variable testing? Or am I subjected to an if/else test?
The intent of this is to optionally define .fpm.service (and [..].type) within your values.yaml file.
(I'm building a Helm Library chart to handle optional definitions by main charts)
According to the official Helm doc (Using Default Function), the syntax is different and you should use it this way:
type: {{ .Values.fpm.service.type | default "NodePort" | quote }}
Doesn't look like there's really a good way to stop Helm from trying to dive into non-existing objects. I moved into a single line if condition, and it worked:
type: {{ if .Values.fpm.service -}} {{ .default "NodePort" .Values.fpm.service.type | quote }} {{- else -}} "NodePort" {{- end }}
This way, I check if fpm.service exists first, before trying .type check. It works, whether .service and .service.type is or is not defined.

How to include default value with tpl function call

I have top level chart and one of the subcharts. In subchart I want to use variables that defined in level chart, and if it is not found - use default value.
I have code like this in one of deployment definitions in my subchart
name: {{tpl .Values.global.my.GlobalValue .}}
where Values.global.my.GlobalValue - is parameter from top level chart.
Problem is when I try to install only subchart - I am failing, I need some defaults.
I tried to puth like below and it is not working
name: {{default defaultName tpl .Values.global.my.GlobalValue .}}
name: {{tpl .Values.global.my.GlobalValue . | defaultName}}
Could you please advise the correct way to do that.
As per Using the default function:
One function frequently used in templates is the default function:
default DEFAULT_VALUE GIVEN_VALUE. This function allows you to specify
a default value inside of the template, in case the value is omitted.
You should use:
name: {{ .Values.global.my.GlobalValue | default "defaultName" | quote }}

How to fail a helm release based on inputs in values.yaml

I'm installing up a helm chart using helm install command. I have values.yaml which takes a few inputs from the user. One of the keys in values.yaml is action, which can only take three predefined values (let's say action1, action2 and action3) as an input. Any other value other than this is invalid.
When a user provides the value to action field in values.yaml and trigger the helm install command, the first thing I need to check is that if the action key has a valid value or not. If the action value is invalid, I want the release to be failed with a proper error message.
e.g.: In case the user has given action: action4, this is not valid and release should fail as .Values.action can only be action1, action2, or action3.
How I can achieve this use case and which file should be best to handle this validation considering the helm structure?
I was able to achieve the use case with below changes.
Added the following code in _helpers.tpl
{{- define "actionValidate" -}}
{{ $action := .Values.actions }}
{{- if or (eq $action "action1") (eq $action "action2") (eq $action "action3") -}}
true
{{- end -}}
{{- end -}}
Invoked this function from a .tpl file like this:-
{{ include "actionValidate" . | required "Action value is incorrect. The valid values are 'action1', 'action2', 'action3' " }}
With HelmV3 there is now an easier way. Just specify a schema that includes your values.
For example:
title: Values
type: object
properties:
action:
description: Some action
type: string
pattern: "^(action1|action2|action3)$"
Not enough rep to comment. However, in response to #Saurabh, you now must YAML comment out the function invocation. Otherwise, Go Template will encounter an invalid return type runtime error from that random true value existing in the middle of the invocation file.
Example
# validation.yaml
---
#{{ include "actionValidate" . | required "Action value is incorrect. The valid values are 'action1', 'action2', 'action3' " }}