Helm Template If/Else: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(19 intermediate revisions by the same user not shown)
Line 6: Line 6:


=Overview=
=Overview=
<code>if</code>/<code>else</code> can be used to create conditional blocks.


 
The <code>if</code> control structures evaluate pipelines, not just values. A value is a special case of a pipeline:
<tt>if</tt>/<tt>else</tt> can be used to create conditional blocks.
 
The if control structures evaluate pipelines, not just values (values are a special case of a pipeline):
 
<syntaxhighlight lang='yaml'>
<syntaxhighlight lang='yaml'>
{{ if PIPELINE }}
{{ if PIPELINE }}
Line 24: Line 21:
A pipeline evaluates to <code>false</code> if the result of the pipeline, or the value, is:
A pipeline evaluates to <code>false</code> if the result of the pipeline, or the value, is:
* a boolean false
* a boolean false
* a numeric zero
* <span id='Numeric_Zero'></span>a numeric zero. ⚠️. Also see [[Helm Notable Values|Notable Values]].
* an empty string
* an empty string
* a <code>nil</code> (empty or null)
* a <code>nil</code> (empty or null)
Line 42: Line 39:
==nil pointer evaluating interface==
==nil pointer evaluating interface==


While <code>nil</code> (missing) values are evaluated to false, this only applies to the '''leaf''' of the YAML path. All intermediate path elements leading to the leaf must exist, and must NOT be empty, otherwise the template rendering engine will error out with:
While <code>nil</code> (empty or missing) values are evaluated to false, this only applies to the '''leaf''' of the YAML path. All intermediate path elements leading to the leaf must exist, and must NOT be empty, otherwise the template rendering engine will error out with a message similar to:
<syntaxhighlight lang='text'>
<syntaxhighlight lang='text'>
Error: template: simplest/templates/configmap.yaml:6:16: executing "simplest/templates/configmap.yaml" at <.Values.appearance.color>: nil pointer evaluating interface {}.color
Error: template: simplest/templates/configmap.yaml:6:16: executing "simplest/templates/configmap.yaml" at <.Values.appearance.color>: nil pointer evaluating interface {}.color
Line 52: Line 49:
</syntaxhighlight>
</syntaxhighlight>


where values.yaml is
where the input <code>values.yaml</code> is:
<syntaxhighlight lang='yaml'>
<syntaxhighlight lang='yaml'>
appearance:
appearance:
</syntaxhighlight>
If the root key <code> appearance</code> is missing altogether, the failure is identical.
The error was caused by the fact that there is no collection (map) under <code>appearance</code>, or there is no <code>appearance</code> at all, so the attempt to locate the <code>color</code> in a non-existed map errored out. To fix it, one approach is to check the non-nilness of all intermediate YAML path elements:
<syntaxhighlight lang='yaml'>
{{- if .Values.appearance }}{{ if .Values.appearance.color }}
...
{{- end }}{{ end }}
</syntaxhighlight>
Using an <code>and</code> function is not an option, because unlike an AND operator in most languages, shortcutting is not used when evaluating function's arguments, so:
<syntaxhighlight lang='yaml'>
{{ if and .Values.appearance .Values.appearance.color }} ...
</syntaxhighlight>
will trigger:
<syntaxhighlight lang='text'>
Error: template: simplest/templates/configmap.yaml:6:39: executing "simplest/templates/configmap.yaml" at <.Values.appearance.color>: nil pointer evaluating interface {}.color
</syntaxhighlight>
Another approach is to make the collection not empty, by adding at least one element (even if the element is empty):
<syntaxhighlight lang='yaml'>
appearance:
  somethingelse:
</syntaxhighlight>
</syntaxhighlight>


Line 72: Line 93:
The following conditional evaluates to true and the embedded content is rendered if the configuration element does NOT exist:
The following conditional evaluates to true and the embedded content is rendered if the configuration element does NOT exist:
<syntaxhighlight lang='yaml'>
<syntaxhighlight lang='yaml'>
{{- if not .Values.myApp.something }}
{{ if not .Values.myApp.something }}
...  
...  
{{- end }}
{{ end }}
</syntaxhighlight>
 
==Negation==
<syntaxhighlight lang='yaml'>
{{ if not ... }}
...
{{ end }}
</syntaxhighlight>
</syntaxhighlight>



Latest revision as of 02:17, 9 February 2022

External

Internal

Overview

if/else can be used to create conditional blocks.

The if control structures evaluate pipelines, not just values. A value is a special case of a pipeline:

{{ if PIPELINE }}
  # Do something
{{ else if OTHER_PIPELINE }}
  # Do something else
{{ else }}
  # Default case
{{ end }}

A pipeline evaluates to false if the result of the pipeline, or the value, is:

  • a boolean false
  • a numeric zero. ⚠️. Also see Notable Values.
  • an empty string
  • a nil (empty or null)
  • an empty collection (map, slice, tuple, dict, array).

In any other case, the condition is evaluated to true.

Example:

{{ if .Values.debug }}
  # Do something
{{ else }}
  # Do something else
{{ end }}

nil pointer evaluating interface

While nil (empty or missing) values are evaluated to false, this only applies to the leaf of the YAML path. All intermediate path elements leading to the leaf must exist, and must NOT be empty, otherwise the template rendering engine will error out with a message similar to:

Error: template: simplest/templates/configmap.yaml:6:16: executing "simplest/templates/configmap.yaml" at <.Values.appearance.color>: nil pointer evaluating interface {}.color

The above failure was generated by the expression:

{{- if .Values.appearance.color }} ...

where the input values.yaml is:

appearance:

If the root key appearance is missing altogether, the failure is identical.

The error was caused by the fact that there is no collection (map) under appearance, or there is no appearance at all, so the attempt to locate the color in a non-existed map errored out. To fix it, one approach is to check the non-nilness of all intermediate YAML path elements:

{{- if .Values.appearance }}{{ if .Values.appearance.color }} 
...
{{- end }}{{ end }}

Using an and function is not an option, because unlike an AND operator in most languages, shortcutting is not used when evaluating function's arguments, so:

{{ if and .Values.appearance .Values.appearance.color }} ...

will trigger:

Error: template: simplest/templates/configmap.yaml:6:39: executing "simplest/templates/configmap.yaml" at <.Values.appearance.color>: nil pointer evaluating interface {}.color

Another approach is to make the collection not empty, by adding at least one element (even if the element is empty):

appearance:
  somethingelse:

Expressions

if expressions are built with functions: eq, ne, lt, gt, and, or, so the function name is provided first, followed by the arguments. Functions can be grouped with ( ).

Testing the Existence of Two Configuration Elements in the Same Expression

{{- if or .Values.myApp.config.local .Values.myApp.config.nfs }}
   ...
{{- end }}

Testing the Non-Existence of a Configuration Element

The following conditional evaluates to true and the embedded content is rendered if the configuration element does NOT exist:

{{ if not .Values.myApp.something }}
... 
{{ end }}

Negation

{{ if not ... }}
... 
{{ end }}

Testing Equality and Inequality of Values

{{- if eq .Values.myApp.color "blue" }}
... 
{{- end }}
{{- if ne .Values.myApp.color "blue" }}
... 
{{- end }}
{{- if eq .Values.myApp.something .Values.myApp.somethingElse }}
... 
{{- end }}
{{- if and (eq .Values.myApp.color "blue") (eq .Values.myApp.shape "square") }}
... 
{{- end }}

Interesting Links