30

I am doing this now:

value: {{ required "A valid .Values.foo entry required!" .Values.foo }}

But to give this same message for all required values in the templates is cumbersome and clutters the templates in my opinion.

Is there a better way where we could define it outside the template \ or a cleaner way to do it within the template itself?

Chillax
  • 4,418
  • 21
  • 56
  • 91
  • 3
    Completely agree with this. The required function as it is implemented right now does more damage (in the readability of the file) than good. The message should have a default value, because you always want to tell the operator the same: value X is missing. This syntax should be enough, in my opinion: {{ + .Values.foo }} – Quido Jan 20 '21 at 23:25

7 Answers7

23

Define the required values on top of your manifest as variables utilizing the required function.

E.g. deployment.yaml:

{{- $name := .Values.name | required ".Values.name is required." -}}

---
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: {{ $name }}
 ....
t0r0X
  • 4,212
  • 1
  • 38
  • 34
pijemcolu
  • 2,257
  • 22
  • 36
  • 1
    THX! Until now the best answer. During `helm lint` it prints INFO message for missing values and does not fail, but for `helm template` and `helm upgrade` it reliably breaks with error as values are missing. – t0r0X Aug 19 '22 at 15:23
  • 1
    Can this be done without `$name := .Values.name`? Ideally, I don't want to create any variables, but using `{{- required ".Values.name is required." .Values.name -}}` on its own causes `.Values.name` to be rendered. – David Wesby Nov 08 '22 at 09:05
  • Any way to do this "globally" for all templates? Like in helpers but without needing a template? – Gaël J Apr 05 '23 at 09:02
12

You could do something by taking advantage of range and the fact that null will fail the required check. So in your values.yaml you could have this section for required env vars:

reqEnv:
 - name: "VAR1"
   value: null
 - name: "VAR2"
   value: null

And in the env section of the Deployment you then have:

{{- range .Values.reqEnv }}
          {{ .name }}: {{ required "A value must be entered for all reqEnv entries" .value }}
{{- end }}

Then the user gets an error unless they set all required values of the reqEnv section in their values file or as paramters. Unfortunately what you lose by doing this is the detail of which var is missing. This could be why the official helm charts seem to prefer using required in the way that you already are.

Ryan Dawson
  • 11,832
  • 5
  • 38
  • 61
  • I tried passing in the particular .name but found it wasn't evaluated. One would expect there to be a way to refine this with tpl to get the particular entry name in the message. Not finding it easy to do so though. Perhaps the helm required function could be enhanced to pass its string parameter through tpl automatically. – Ryan Dawson Dec 24 '18 at 15:04
  • Possibly the spring fail function could allow for something better - https://github.com/helm/helm/issues/5174 – Ryan Dawson Jan 25 '19 at 19:22
4

I stumbled across the same issue and found a solution I wanted to add: What worked great for me is to create a required.yaml inside the template folder and put all required values inside like so:

{{- $_ := required "value_1 is a required value" .Values.value_1}}
{{- $_ := required "value_2 is a required value" .Values.value_2}}

Works great and has the advantage of having all required values at one place and also having custom error messages for each.

Hope this helps.

3

You can use helm lint with --strict flag to check undefined values

$ helm lint --strict . 
==> Linting .
[INFO] Chart.yaml: icon is recommended
[ERROR] templates/: render error in "mychart/templates/service.yaml": template: mychart/templates/service.yaml:10:19: executing "mychart/templates/service.yaml" at <.Values.foo>: map has no entry for key "foo"

Error: 1 chart(s) linted, 1 chart(s) failed
edbighead
  • 5,607
  • 5
  • 29
  • 35
  • Doesn't this mean an extra command to be run before the helm install ? I would want it to throw the error when I try to run the helm install. – Chillax Dec 20 '18 at 11:17
  • Unfortunately, helm install does not support strict checking. You can extract your required check in _helpers.tpl file instead, this will keep template files tidy and will be checked during helm install – edbighead Dec 20 '18 at 11:36
  • I have two cases where `helm lint --strict ...` doesn't find the missing values, and command `helm template ...` fails only in one of these two cases. It simply is unreliable... In the end I used the solution from @pijemcolu which uses the `required` function available in templates. – t0r0X Aug 19 '22 at 11:49
2

To expose name of missing item to required text you can do something like this:

{{- range $field, $my_key := $data }}
 {{- if hasKey $dic1 $my_key }}
  {{ $field }}: {{ index $dic1 $my_key | b64enc}}
 {{- else if hasKey $dic2 $my_key }}
  {{ $field }}: {{ index $dic2 $my_key | b64enc}}
 {{- else }}
  {{ $field }}: {{ required (printf "key %s is missing" $my_key) nil }}
 {{- end }}
{{- end }}
2

I've come up with an alternative hack trying to solve this problem. It's questionable whether this is actually any better that the built in solution, but I thought it might be worth noting down here as an option.

Add a function to your _helpers.tpl (or wherever):

{{/*
Require and include a value
*/}}
{{- define "require" -}}
    {{- $scope := index . 0 -}}
    {{- $name := index . 1 -}}
    {{required (print "Missing required value: " $name) (index $scope "Values" $name)}}
{{- end}}

Then in your template call it with:

value: {{ include "require" (list . "foo") }}

If a value is missing, it errors with message:

Missing required value: foo

Otherwise, it inserts the value.


Edit: To make this work for nested values, you need a slightly more complex helper:

{{/*
Index a nested component
*/}}
{{- define "indexNested" -}}
    {{- $message := index . 0 -}}
    {{- $object := index . 1 -}}
    {{- $path := (mustRegexSplit "\\." (index . 2) -1) -}}
    {{- range $path -}}
        {{- if not $object -}}
            {{ fail $message }}
        {{- end -}}
        {{- $object = index $object . -}}
    {{- end -}}
    {{ required $message $object }}
{{- end}}

{{/*
Require and include a value
*/}}
{{- define "require" -}}
    {{- $scope := index . 0 -}}
    {{- $name := index . 1 -}}
    {{ include "indexNested" (list (print "Missing required value: " $name) $scope.Values $name) }}
{{- end}}

Now you can access the foo.bar value with:

{{ include "require" (list . "foo.bar") }}
user31601
  • 2,482
  • 1
  • 12
  • 22
0

Helm 3 allows you to define schema files that will be used for validation of Values on helm install, among other commands. You just need to define a values.schema.json file with a JsonSchema spec. Read about it at https://helm.sh/docs/topics/charts/#schema-files