Helm 'if' condition in one line - kubernetes-helm

I was trying to put the if condition in a single line of the helm template:
- name: ENV_VARIABLE
value: {{- if .Values.condition }}"Value1"{{- else }}"Value2"{{- end }}
However, I'm getting error:
Error: YAML parse error on chart/templates/deployment.yaml: error
converting YAML to JSON: yaml: line NN: could not find expected ':'
So I've ended up with multi-line condition:
- name: ENV_VARIABLE
{{- if .Values.condition }}
value: "Value1"
{{- else }}
value: "Value2"
{{- end }}
which is working fine, but is very uncompact.
Is there a way to use one-liner if condition in helm?

What you do works, but you use the leading hyphen, which removes all preceding whitespace.
The below will render as value:foo due to the hyphen.
value: {{- "foo" }}
If you remove the hyphen, it should work.
That said, there is also the ternary function which could fit here.
ternary
The ternary function takes two values, and a test value. If the test value is true, the first value will be returned. If the test value is empty, the second value will be returned. This is similar to the c ternary operator.
true test value
ternary "foo" "bar" true
or
true | ternary "foo" "bar"
- name: ENV_VARIABLE
value: {{ .Values.condition | ternary "value1" "value2" | quote }}

Related

Helm equals to one of multiple values

I want to have a condition that will be considered as "true" if .Values.envName is "dev" + the release namespace name is one of a closed list. otherwise, it should be "false".
Tried the following, but seems like it gets unexpected "false" when I ran it with .Values.envName = dev & .Values.envName = ns-1:
env:
- name: MY_ENV
{{- if and (eq .Values.envName "dev") (regexMatch "^(?!^ns-1$)(?!^ns-2$).*$" .Release.Namespace)}}
value: 'true'
{{- else }}
value: 'false'
{{- end }}
A general note - if there is a better way to use eq with multiple possible values please let me know.
You can use has to test if some item is in a list; and then you can use list to construct a list of known items.
So for your example, if the test is that envName is exactly dev, and the namespace is either ns-1 or ns-2, then you can say
env:
{{- $isDev := eq .Values.envName "dev" }}
{{- $isNs := list "ns-1" "ns-2" | has .Release.Namespace }}
- name: MY_ENV
value: {{ and $isDev $isNs | toString | quote }}
You could do this case with a regular expression too. The start-of-string test ^ and the end-of-string test $ generally need to be outside parentheses; I wouldn't worry about "non-greedy matches" if you're just trying to determine whether a string matches without extracting things. Here I might write either of
{{- $isNs := regexMatch "^ns-[12]$" .Release.Namespace }}
{{- $isNs := regexMatch "^ns-1|ns-2$" .Release.Namespace }}
If you've got an enumerated list of values that don't neatly fall into a regex, using has and list is probably clearer.

Using a defined helper as an iteration for a range

While recently writing a helm chart, I ran into an issue that I couldn't find a solution to.
Basically, I am trying to range off of a defined value (labels), but appear to be running into an issue because the defined value is a string and not a map. I tried to convert it with toYaml to no avail:
{{- range $key, $value := ( include "myChart.selectorLabels" . | toYaml ) }}
- key: {{ $key }}
operator: In
values:
- {{ $value }}
{{- end }}
Example error with toYaml:
COMBINED OUTPUT:
Error: Failed to render chart: exit status 1: Error: template: myApp/templates/deployment.yaml:103:77: executing "myApp/templates/deployment.yaml" at <toYaml>: range can't iterate over |-
app.kubernetes.io/name: myApp
app.kubernetes.io/instance: env-myApp
conf-sha: 0b92fad469486fedb6ad012c1b5f22c
Example error without toYaml (note lack of linebreak before first value):
COMBINED OUTPUT:
Error: Failed to render chart: exit status 1: Error: template: myApp/templates/deployment.yaml:103:73: executing "myApp/templates/deployment.yaml" at <.>: range can't iterate over app.kubernetes.io/name: myApp
app.kubernetes.io/instance: env-myApp
conf-sha: 0b92fad469486fedb6ad012c1b5f22c
Expected render:
- key: app.kubernetes.io/name
operator: In
values:
- myApp
- key: app.kubernetes.io/instance
operator: In
values:
- env-myApp
- key: conf-sha
operator: In
values:
- 0b92fad469486fedb6ad012c1b5f22c
I think there must be a more elegant solution to this in helm's templating that I am missing.
Helm has two extension functions to convert between strings and complex YAML structures. You're calling toYaml which takes an arbitrary object and serializes it to a YAML string. What you actually have is the string result from include which happens to be parseable YAML, and you need the opposite function, fromYaml.
{{- range $key, $value := ( include "myChart.selectorLabels" . | fromYaml ) }}
{{/*- not toYaml ^^^^ */}}
Neither function is especially well-documented. They are specific to Helm. There are corresponding toJson and fromJson that work similarly.

helm escape ` in template yaml file

Does anyone know how to espace ` in helm template?
I try to add \ in front doesn't seem to work
original:
{{- if not .Values.istio_cni.chained }}
k8s.v1.cni.cncf.io/networks: '{{ appendMultusNetwork (index .ObjectMeta.Annotations `k8s.v1.cni.cncf.io/networks`) `istio-cni` }}',
{{- end }}
Tried:
{{- if not .Values.istio_cni.chained }}
k8s.v1.cni.cncf.io/networks: '{{`{{ appendMultusNetwork (index .ObjectMeta.Annotations \`k8s.v1.cni.cncf.io/networks\`) `istio-cni` }}`}}',
{{- end }}
Error:
Error: parse error at (test/templates/istio-sidecar-injector-istio-system-ConfigMap.yaml:29): unexpected "k8s" in operand
In the Go text/template language backticks delimit "raw string constants"; in standard Go, there is no escaping at all inside raw string literals and they cannot contain backticks.
In your example, it looks like you're trying to emit a Go template block into the output. You can make this work if you use double quotes around the variable names inside the template, and then backticks around the whole thing:
# double quotes around string literal
# v v
k8s.v1.cni.cncf.io/networks: '{{`{{ appendMultusNetwork ... "istio-cni" }}`}}'
# ^ ^
# backticks around whole expression

What is the difference between {{- range .Values.xxx }} and {{ range .Values.xxx }} in Helm

I can both use
{{- range .Values.xxx }}
and
{{ range .Values.xxx }}
in my Helm, and the result is the same. Are they totally the same thing?
Also, is the hyphen necessary?
The hyphen removes any whitespace adjacent to the template construct. Often this isn't strictly necessary but it makes the rendered output more readable. Since YAML is whitespace-sensitive sometimes it is required.
Basic example:
environment:
{{ range .Values.xxx }}
- { name: {{ . }}, value: "test" }
{{ end }}
Renders to:
environment:
- { name: a, value: "test" }
- { name: b, value: "test" }
On the range line, after the }} and before the -, there is a newline and two spaces; these are required for it to be valid YAML. Before both of the {{ there is an additional newline and this isn't required, so you can use {{- to suppress it.
environment:
{{- range .Values.xxx }}
- { name: {{ . }}, value: "test" }
{{- end }}
environment:
- { name: a, value: "test" }
- { name: b, value: "test" }
This is also useful with functions like nindent that include their own newlines.
items: {{- .Values.xxx | toYaml | nindent 2 }}
items:
- a
- b
toYaml converts the list [a, b] to the YAML string - a\n- b; nindent 2 adds an initial newline, and two spaces at the start of each line \n - a\n - b; and then the - removes the extra space before the newline that's being emitted.
You can put the - inside the closing }} too, with the same effect, but that tends to eat the next line's indentation, so it tends to be a little less useful.
(Remember that helm template will render a chart to stdout without sending it off to the Kubernetes API server, so you can see what these things expand to.)

Can we use OR operator in Helm yaml files

Can I do something like this in Helm yamls :
{{- if eq .Values.isCar true }} OR {{- if eq .Values.isBus true }}
# do something
{{- end }}
I understand that we can do a single if check. But how would I check for multiple conditions? Are there some operators equivalent to OR and AND?
As indicated in the Helm documentation on operators:
For templates, the operators (eq, ne, lt, gt, and, or and so on) are all implemented as functions. In pipelines, operations can be grouped with parentheses ((, and )).
It means you could use
{{- if or (eq .Values.isCar true) (eq .Values.isBus true) }}
Furthermore, as noted in the if/else structure:
A pipeline is evaluated as false if the value is:
a boolean false
a numeric zero
an empty string
a nil (empty or null)
an empty collection (map, slice, tuple, dict, array)
Under all other conditions, the condition is true.
If your properties (isCar and isBus) are booleans, you can then skip the equal check:
{{- if or .Values.isCar .Values.isBus }}
Note that or can also be used instead of default like this:
{{ or .Values.someSetting "default_value" }}
This would render to .Values.someSetting if it is set or to
"default_value" otherwise.