Helm Flow Control
In this tutorial, we are going to discuss helm flow control. The important building block of the template is this flow control, and it will be achieved using an if-else statement.
Syntax
{{ if PIPELINE }}
# Do something
{{ else if OTHER PIPELINE }}
# DO something else
{{ else }}
# Default case
{{ end }}
This is very similar to the If else statements we have in other languages where the condition will be evaluated using the pipeline. It will be used along with the if or else if conditions.
If the condition gets to true, it will be getting into that particular block, and the statements within the block will get executed; if the condition fails, it will move on to the next condition that is else-if. Again, there is going to be another pipeline or condition evaluation that will be evaluated.
If that evaluation is true, then the blocks within that will get executed. We will have an else condition where if all the above conditions failed, the statements within the else conditions would execute. That’s like a default case.
And else if, else conditions are optional and only if statement is sufficient enough, most of the places we will be using that to verify the conditions and execute a few set of statements.
False Condition
Let’s have a quick check on what all situations the condition would be evaluated as false. If the pipeline is evaluated, as the following values, it will be considered as false,
- A boolean false
- A numeric zero
- An empty string
- A nil (empty or null)
- An empty collection (map, slice, tuple, dict, array)
Example
Now let us see a small example. Here I do have the template. Let me get into the sample template that we had created previously.
Within the values file, we already have a key called owner; within that, I have a collection of keys and values. I do have the keys like name and place.
ashok@waytoeasylearn:~/mychart$ cat values.yaml
message: Welcome to waytoeasylearn
website: www.waytoeasylearn.com
owner:
name: Ashok Kumar
place: Hyderabad
So I’m going to evaluate this specific key name, whether it is equal to a specific value or not. If it is evaluated as true, I will be taking some decisions.
Now Let me go ahead and change the templates; within the template, let me go ahead and edit it.
ashok@waytoeasylearn:~/mychart$ cat templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Sample Config Map"
message: {{ .Values.message }}
website: {{ upper .Values.website }}
ownerName: {{ quote .Values.owner.name }}
ownerPlace: {{ quote .Values.owner.place }}
{{ if eq .Values.owner.name "Ashok Kumar"}}isNamePresent: true {{ end }}
So here I’m going to add a condition if, and I can have the logical conditions like equal, not equal, all possible conditions available.
I’m going to evaluate for Values.owner.name, and that should be equal to “Ashok Kumar.” If this condition succeeded, then I’m going to add another key-value pair. Then I need to end the condition. I don’t want any if-else condition.
Now let me go ahead and do a dry run using the following command. Please note the indentation is very important in golang. Otherwise, it is going to give error messages.
ashok@waytoeasylearn:~$ helm install --debug --dry-run controlflow ./mychart/
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /home/ashok/mychart
NAME: controlflow
LAST DEPLOYED: Thu May 20 16:54:41 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
message: Welcome to waytoeasylearn
owner:
name: Ashok Kumar
place: Hyderabad
qualification: mca
website: www.waytoeasylearn.com
HOOKS:
MANIFEST:
Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: controlflow-configmap
data:
myvalue: "Sample Config Map"
message: Welcome to waytoeasylearn
website: WWW.WAYTOEASYLEARN.COM
ownerName: "Ashok Kumar"
ownerPlace: "Hyderabad"
isNamePresent: true
So the value is evaluated to be true. So what happened? It printed it as true.
What if you change the value?
Now, let me go ahead and change the value.
ashok@waytoeasylearn:~/mychart$ cat values.yaml
message: Welcome to waytoeasylearn
website: www.waytoeasylearn.com
owner:
name: Vinod Kumar
place: Hyderabad
Now let me go ahead and do a dry run using the following command.
ashok@waytoeasylearn:~$ helm install --debug --dry-run controlflow ./mychart/
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /home/ashok/mychart
NAME: controlflow
LAST DEPLOYED: Thu May 20 16:54:41 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
message: Welcome to waytoeasylearn
owner:
name: Vinod Kumar
place: Hyderabad
qualification: mca
website: www.waytoeasylearn.com
HOOKS:
MANIFEST:
Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: controlflow-configmap
data:
myvalue: "Sample Config Map"
message: Welcome to waytoeasylearn
website: WWW.WAYTOEASYLEARN.COM
ownerName: "Vinod Kumar"
ownerPlace: "Hyderabad"
It should not print the value isNamePresent: true, because the condition did not get evaluated.
Now the same way I can have if-else conditions, the very important thing to be noted in this specific condition is how to align this particular statement. Let’s try out a few scenarios.
And before that, I need to change the values so that the condition will get evaluated to be true. So I am changing it back to “Ashok Kumar”.
ashok@waytoeasylearn:~/mychart$ cat values.yaml
message: Welcome to waytoeasylearn
website: www.waytoeasylearn.com
owner:
name: Ashok Kumar
place: Hyderabad
ashok@waytoeasylearn:~/mychart$ cat templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Sample Config Map"
message: {{ .Values.message }}
website: {{ upper .Values.website }}
ownerName: {{ quote .Values.owner.name }}
ownerPlace: {{ quote .Values.owner.place }}
{{ if eq .Values.owner.name "Ashok Kumar"}}
isNamePresent: true
{{ end }}
Now, let me go ahead and execute the dry run.
ashok@waytoeasylearn:~$ helm install --debug --dry-run controlflow ./mychart/
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /home/ashok/mychart
NAME: controlflow
LAST DEPLOYED: Thu May 20 16:54:41 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
message: Welcome to waytoeasylearn
owner:
name: Ashok Kumar
place: Hyderabad
qualification: mca
website: www.waytoeasylearn.com
HOOKS:
MANIFEST:
Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: controlflow-configmap
data:
myvalue: "Sample Config Map"
message: Welcome to waytoeasylearn
website: WWW.WAYTOEASYLEARN.COM
ownerName: "Ashok Kumar"
ownerPlace: "Hyderabad"
isNamePresent: true
If you observe the result very carefully, we have an empty line above isNamePresent, and within the YAML file, empty lines are not going to create a problem.
But that is not advised to have, only the important thing that we need to take over here is the indentation. The indentation is done properly with two spaces (before isNamePresent). So it should work, but it is not recommended.
Now the key-value pair will be indented with two more additional spaces. And that is not a valid YAML file because it should be under another key.
ashok@waytoeasylearn:~/mychart$ cat templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Sample Config Map"
message: {{ .Values.message }}
website: {{ upper .Values.website }}
ownerName: {{ quote .Values.owner.name }}
ownerPlace: {{ quote .Values.owner.place }}
{{ if eq .Values.owner.name "Ashok Kumar"}}
isNamePresent: true
{{ end }}
Now, let me go ahead and do a dry run on this particular case as well and see how the error will be.
ashok@waytoeasylearn:~$ helm install --debug --dry-run controlflow ./mychart/
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /home/ashok/mychart
Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 11: did not find expected key
helm.go:81: [debug] error converting YAML to JSON: yaml: line 11: did not find expected key
YAML parse error on mychart/templates/configmap.yaml
helm.sh/helm/v3/pkg/releaseutil.(manifestFile).sort /home/circleci/helm.sh/helm/pkg/releaseutil/manifest_sorter.go:146 helm.sh/helm/v3/pkg/releaseutil.SortManifests /home/circleci/helm.sh/helm/pkg/releaseutil/manifest_sorter.go:106 helm.sh/helm/v3/pkg/action.(Configuration).renderResources
/home/circleci/helm.sh/helm/pkg/action/action.go:165
helm.sh/helm/v3/pkg/action.(Install).Run /home/circleci/helm.sh/helm/pkg/action/install.go:240 main.runInstall /home/circleci/helm.sh/helm/cmd/helm/install.go:242 main.newInstallCmd.func2 /home/circleci/helm.sh/helm/cmd/helm/install.go:120 github.com/spf13/cobra.(Command).execute
/go/pkg/mod/github.com/spf13/cobra@v1.1.1/command.go:850
github.com/spf13/cobra.(Command).ExecuteC /go/pkg/mod/github.com/spf13/cobra@v1.1.1/command.go:958 github.com/spf13/cobra.(Command).Execute
/go/pkg/mod/github.com/spf13/cobra@v1.1.1/command.go:895
main.main
/home/circleci/helm.sh/helm/cmd/helm/helm.go:80
runtime.main
/usr/local/go/src/runtime/proc.go:204
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1374
So here, I got an error because values are not allowed in this context. I am demonstrating various options most of the time because the mistakes happen in this specific indentation area while using conditional statements.
Now, let me go ahead and correct this.
ashok@waytoeasylearn:~/mychart$ cat templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Sample Config Map"
message: {{ .Values.message }}
website: {{ upper .Values.website }}
ownerName: {{ quote .Values.owner.name }}
ownerPlace: {{ quote .Values.owner.place }}
{{ if eq .Values.owner.name "Ashok Kumar"}}
isNamePresent: true
{{ end }}
Remove spaces
So the above snippet should work. But at the same time, let’s understand how to remove the blank line that we had got so that it can be removed using a minus symbol before if and a minus symbol before the end.
That means the new line in that specific location should be removed.
ashok@waytoeasylearn:~/mychart$ cat templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Sample Config Map"
message: {{ .Values.message }}
website: {{ upper .Values.website }}
ownerName: {{ quote .Values.owner.name }}
ownerPlace: {{ quote .Values.owner.place }}
{{- if eq .Values.owner.name "Ashok Kumar"}}
isNamePresent: true
{{- end }}
So there will be a new line at the starting of this particular condition evaluation, which will remove. Now, let me go ahead and do a dry run.
ashok@waytoeasylearn:~$ helm install --debug --dry-run controlflow ./mychart/
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /home/ashok/mychart
NAME: controlflow
LAST DEPLOYED: Thu May 20 16:54:41 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
message: Welcome to waytoeasylearn
owner:
name: Ashok Kumar
place: Hyderabad
qualification: mca
website: www.waytoeasylearn.com
HOOKS:
MANIFEST:
Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: controlflow-configmap
data:
myvalue: "Sample Config Map"
message: Welcome to waytoeasylearn
website: WWW.WAYTOEASYLEARN.COM
ownerName: "Ashok Kumar"
ownerPlace: "Hyderabad"
isNamePresent: true
Now, there is no newline character. And everything is working fine. Now let’s see, What if I deleted the new line in the end as well. That should also be not done. Anyway, let’s go ahead and try it out.
So here the end, I’m going to remove the existing new line to be provided by adding a dash after string Ashok Kumar and end.
ashok@waytoeasylearn:~/mychart$ cat templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Sample Config Map"
message: {{ .Values.message }}
website: {{ upper .Values.website }}
ownerName: {{ quote .Values.owner.name }}
ownerPlace: {{ quote .Values.owner.place }}
{{- if eq .Values.owner.name "Ashok Kumar" -}}
isNamePresent: true
{{- end -}}
So what will happen? It’ll remove the starting new line as well as the end new line. The isNamePresent is trying to add after ownerPlace where that will fail because that’s not a valid YAML file.
ashok@waytoeasylearn:~$ helm install --debug --dry-run controlflow ./mychart/
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /home/ashok/mychart
Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 11: did not find expected key
helm.go:81: [debug] error converting YAML to JSON: yaml: line 11: did not find expected key
YAML parse error on mychart/templates/configmap.yaml
helm.sh/helm/v3/pkg/releaseutil.(manifestFile).sort /home/circleci/helm.sh/helm/pkg/releaseutil/manifest_sorter.go:146 helm.sh/helm/v3/pkg/releaseutil.SortManifests /home/circleci/helm.sh/helm/pkg/releaseutil/manifest_sorter.go:106 helm.sh/helm/v3/pkg/action.(Configuration).renderResources
/home/circleci/helm.sh/helm/pkg/action/action.go:165
helm.sh/helm/v3/pkg/action.(Install).Run /home/circleci/helm.sh/helm/pkg/action/install.go:240 main.runInstall /home/circleci/helm.sh/helm/cmd/helm/install.go:242 main.newInstallCmd.func2 /home/circleci/helm.sh/helm/cmd/helm/install.go:120 github.com/spf13/cobra.(Command).execute
/go/pkg/mod/github.com/spf13/cobra@v1.1.1/command.go:850
github.com/spf13/cobra.(Command).ExecuteC /go/pkg/mod/github.com/spf13/cobra@v1.1.1/command.go:958 github.com/spf13/cobra.(Command).Execute
/go/pkg/mod/github.com/spf13/cobra@v1.1.1/command.go:895
main.main
/home/circleci/helm.sh/helm/cmd/helm/helm.go:80
runtime.main
/usr/local/go/src/runtime/proc.go:204
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1374
Yes, the parsing failed because that’s not a valid YAML file. So what happened was. After evaluation, this isNamePresent: true will get added next to ownerPlace and the value.
So it’s going to have another colon (:) and that will fail. So this is not the right option as well. The right thing to do is remove the new line at the beginning of each condition and in the end.
And have the indentation and the location from where the condition is getting executed the same place. The text within that will also get aligned if we have this particular condition evaluation, in the beginning, then properly the indentation should be provided.
Conclustion
So this is the right way to do it. The reason I am not installing and uninstalling is that the dry run is sufficient to evaluate the condition and how that particular manifest file would look.
So we have seen the different options to use the if-else conditions, And the important thing to take care of is removing the new line and what to do and what not to do while adding the conditional statements are.