How to pass `false` value to Helm `default`?
Asked Answered
A

4

7

A pattern I've often seen in Helm charts (e.g.) is to set a boolean value to default to true unless some overriding value is provided:

feature_enabled_in_k8s_resource: {{ default true .Values.foo_feature_enabled }}

That is - "if foo_feature_enabled is set to any value in the inputs to Helm (via --set, values.yaml, etc.), set feature_enabled_in_k8s_resource to that value - else (if it is unset), set feature_enabled_in_k8s_resource to true"

However, I'm not able to override that value as I would expect - both setting a false value in values.yaml, and/or passing --set foo_feature_enabled=false as an argument, still result in the template holding a value of true.

I suspect that this is because false is a "falsy" value, and so default parses it as "needing replacement".

Passing a string value ("false" in values.yaml, or --set-string foo_feature_enabled=false) does appear (from helm template [...] output) to set feature_enabled_in_k8s_resource to "false" - but it's not clear whether that will be correctly interpreted by the actual application which results from the Kubernetes (that is - it might interpret a non-empty string as "truthy", setting us right back to the original default behaviour). Even if this works, it feels hacky in a way that suggests that I'm missing the "proper" solution.

(Presumably, the actual fix would be Helm charts to never default to true - but that doesn't help me when working with charts that I don't control!)

Antenna answered 30/10, 2022 at 22:3 Comment(0)
K
8

Your understanding of "truthiness" in combination with default is correct here: default considers 0, false, nil, and empty strings all as "unset" and replaces them with the default value. So if you expect .Values.something to have a Boolean value, .Values.something | default true will always be true.

The least-code solution to this is to specify a value in your chart's values.yaml file:

# values.yaml

# foo_feature_enabled enables the foo feature.
foo_feature_enabled: true
# templates/configmap.yaml
feature_enabled_in_k8s_resource: {{ .Values.foo_feature_enabled }}

Now a helm install --set foo_feature_enabled=false option will override the chart's values.yaml file. But if you don't have that option, there's a default value in values.yaml to use.

If that's not an option, then you need to explicitly check whether the value is set using hasKey in an if block. All of the other shorthands have the same "truthiness" check.

# templates/configmap.yaml
feature_enabled_in_k8s_resource:
{{- if hasKey .Values "foo_feature_enabled" }} {{ .Values.foo_feature_enabled }}
{{- else }} true
{{- end }}
Korykorzybski answered 31/10, 2022 at 10:36 Comment(1)
Relatedly: since 0 is falsey, replicas: {{ .Values.replicas | default 1 }} doesn't allow an operator to disable a Deployment by specifying zero replicas at deploy time.Korykorzybski
F
14

A clean (albeit a little unclear) solution using ne (not-equal)

feature_enabled_in_k8s_resource: {{ ne .Values.foo_feature_enabled false }}
.Values.foo_feature_enabled true false null or empty not specified
feature_enabled_in_k8s_resource true false true true
Frater answered 25/4, 2023 at 11:57 Comment(0)
K
8

Your understanding of "truthiness" in combination with default is correct here: default considers 0, false, nil, and empty strings all as "unset" and replaces them with the default value. So if you expect .Values.something to have a Boolean value, .Values.something | default true will always be true.

The least-code solution to this is to specify a value in your chart's values.yaml file:

# values.yaml

# foo_feature_enabled enables the foo feature.
foo_feature_enabled: true
# templates/configmap.yaml
feature_enabled_in_k8s_resource: {{ .Values.foo_feature_enabled }}

Now a helm install --set foo_feature_enabled=false option will override the chart's values.yaml file. But if you don't have that option, there's a default value in values.yaml to use.

If that's not an option, then you need to explicitly check whether the value is set using hasKey in an if block. All of the other shorthands have the same "truthiness" check.

# templates/configmap.yaml
feature_enabled_in_k8s_resource:
{{- if hasKey .Values "foo_feature_enabled" }} {{ .Values.foo_feature_enabled }}
{{- else }} true
{{- end }}
Korykorzybski answered 31/10, 2022 at 10:36 Comment(1)
Relatedly: since 0 is falsey, replicas: {{ .Values.replicas | default 1 }} doesn't allow an operator to disable a Deployment by specifying zero replicas at deploy time.Korykorzybski
A
2

You can also use ternary function:

feature_enabled_in_k8s_resource: {{ hasKey .Values "foo_feature_enabled" | ternary .Values.foo_feature_enabled true }}

It is longer than using ne but it is clear at first sight.

Alsatia answered 3/11, 2023 at 7:48 Comment(0)
A
-1

Helm evaluates from left to right, hence, in the way it is used it will always be set to true. The Value that is being passed will not matter at all. Change the above to:

feature_enabled_in_k8s_resource: {{ .Values.foo_feature_enabled | default true }}

This will evaluate the supplied Value first, and if not supplied, will use default true value.

Please refer using pipelines in helm.

Amphitrite answered 30/10, 2022 at 22:35 Comment(2)
"Change the above to:" - I'd love to, but I don't control that chart :) is there a way to pass values into this incorrect setup such that it will act as intended?Antenna
Passing false to a default function (helm.sh/docs/chart_template_guide/function_list/#default) evaluates as empty, which in turn forces the value that the template has specified. K8s-at-home charts is a public archive now, it will not be updated. Hopefully the dendrite template will show up soon in some other active repository. For now, if I were you, I will clone it locally, modify the lines as suggested and use helm from local folder as mentioned in here (helm.sh/docs/helm/helm_install). Let me know if you need any help.Amphitrite

© 2022 - 2024 — McMap. All rights reserved.