Control Flow in helm


Control Flow in helm

In this tutorial, we are going to discuss about Flow control in helm charts. The important building block of the template is this flow control and it will be achieved using 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 any other languages where the condition will be evaluated using the pipeline and 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 then It’s going to 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 evaluated is true, then the blocks within that will get executed and we will be having a else condition where if all the above conditions failed, then the statements within the else conditions will be executed. 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,

  1. A boolean false
  2. A numeric zero
  3. An empty string
  4. A nil (empty or null)
  5. 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.

Here within the values file, already we do have a key called owner, within that i do have a collection of key and value. I do have the keys like name and place.

[email protected]:~/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 decision.

Now Let me go ahead and change the templates, within the template, let me go ahead and edit it.

[email protected]:~/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 the indentation is very important in golang. Otherwise its going to give error messages.

[email protected]:~$ 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 it 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.

[email protected]:~/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.

[email protected]:~$ 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 as well, 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”.

[email protected]:~/mychart$ cat values.yaml 
message: Welcome to waytoeasylearn
website: www.waytoeasylearn.com
owner:
  name: Ashok Kumar
  place: Hyderabad
[email protected]:~/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.

[email protected]:~$ 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 do have an empty line above isNamePresent and within YAML file empty lines is 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 2 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.

[email protected]:~/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.

[email protected]:~$ 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/[email protected]/command.go:850
 github.com/spf13/cobra.(Command).ExecuteC         /go/pkg/mod/github.com/spf13/[email protected]/command.go:958 github.com/spf13/cobra.(Command).Execute
        /go/pkg/mod/github.com/spf13/[email protected]/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. The reason why I am demonstrating various options most of the time the mistakes happen in this specific area of indentation while using the conditional statements.

Now, let me go ahead and correct this.

[email protected]:~/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 above snippet should work. But at the same time, let’s understand how to remove the blank line that we had got, so that can be removed using a minus symbol before if and a minus symbol before end.

That means the new line in that specific location should be removed.

[email protected]:~/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 and that will be removed. Now, let me go ahead and do a dry run.

[email protected]:~$ 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 new line 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 so that can be provided by adding a dash after string Ashok Kumar and end.

[email protected]:~/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 try to add after ownerPlace where that will fail because that’s not a valid yaml file.

[email protected]:~$ 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/[email protected]/command.go:850
 github.com/spf13/cobra.(Command).ExecuteC         /go/pkg/mod/github.com/spf13/[email protected]/command.go:958 github.com/spf13/cobra.(Command).Execute
        /go/pkg/mod/github.com/spf13/[email protected]/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 a right option as well. The right thing to do is remove the new line in the beginning of each condition as well as 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 in case 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. The reason why I am not installing and uninstalling, the dry run is sufficient enough to evaluate the condition and how that particular manifest file would look like.

So we have seen what are the different options to use the if else conditions And the important thing to take care of removing the new line as well as what to do and what not to do while adding the conditional statements.

Control Flow in helm


Scroll to top