How to use if/else loop in Helm - kubernetes

I am trying to use if/else-if/else loop in helm chart. Basically, I want to add ENV configs in configfile based on the if/else condition. Below is the logic:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.applicationName }}-configmap
labels:
projectName: {{ .Values.applicationName }}
environment: {{ .Values.environment }}
type: configmap
data:
{{- if eq .Values.environment "production" }}
{{ .Files.Get "config-prod.yaml" | nindent 2}}
{{- else if eq .Values.environment "development" }}
{{ .Files.Get "config-dev.yaml" | nindent 2}}
{{- else }}
{{ .Files.Get "config-stage.yaml" | nindent 2}}
{{- end }}
But I am not getting the desired output and facing some issue. Can anybody help me out with this?
Edit1: I have added my modified configmap.yaml as per the suggestions, helm install/template command gives Error: YAML parse error on demo2/templates/configmap.yaml: error converting YAML to JSON: yaml: line 14: did not find expected key error.
also my config-prod and config-stage is being rendered (as per the condition if I give environment: production then config-prod.yaml is being added and if I give environment: stage/null then config-stage.yaml is being added.

Your question would benefit from more specifics.
Please consider adding the following to your question:
How are you trying this? What commands exactly did you run?
How are you "not getting the desired output"? What output did you get?
Please also include:
the relevant entries from your values.yaml
the config-dev.yaml and config-stage.yaml files
Have you run helm template to generate the templates that Helm would apply to your cluster? This would be a good way to diagnose the issue.
I wonder whether you're chomping too much whitespace.
And you should just chomp left, i.e. {{- .... }} rather than left+right {{- ... -}}.

Sorry guys, it was my mistake, my dev-config.yaml has envs and it was defined like key=value, instead of key: value.

Related

helm --set to select environment

Struggling with some helm templating...
I'm trying to pass a separate yaml file with springboot parameters to helm, and have them split by environment... then I want to pass the environment to helm using --set env=staging
Feels like I've tried everything but clearly I'm lacking a fundamental understanding...
My _helpers.tpl contains these:
{{- define "env" }}
{{- printf "%s" .Values.env }}
{{- end }}
{{ define "configmap.metadata" }}
name: {{ .Values.name }}-config
{{ end }}
{{ define "configmap.properties" }}
{{ index .Values.environment (include "env" .) "properties" | indent 4 }}
{{ end }}
The template for the config map:
apiVersion: v1
kind: ConfigMap
metadata:
{{ include "configmap.metadata" . }}
data:
app.properties: |-
{{ include "configmap.properties" .}}
And the yaml file containing the properties looks like this:
environment:
staging:
properties:
spring:
datasource:
url: something
username: something
password: something
app1:
key: something
secret: something
baseUri: something
app2:
bootstrap_server: something
bootstrap_port: something
registry_schema: something
production:
properties:
spring:
etc, etc
And then I want to select the environment using set. I'm testing with:
helm template test . -f values.yaml -f properties.yaml --set env=staging
I think I've just tried so many things that I just can't see the wood for the trees! The error I'm seeing is:
Error: template: microservice/templates/configmap.yaml:7:7: executing "microservice/templates/configmap.yaml" at <include "configmap.properties" .>: error calling include: template: microservice/templates/_helpers.tpl:56:76: executing "configmap.properties" at <4>: wrong type for value; expected string; got map[string]interface {}
EDIT:
After tweaking, I'm still getting an error, but I'm seeing something in the configmap.. but I wonder if the error is due to the 8 spaces on the first line..
data:
app.properties: |-
app2:
bootstrap_port: something
bootstrap_server: something
registry_schema: something
app1:
baseUri: something
key: something
secret: something
spring:
datasource:
password: something
url: something
username: something
I think your actual error message is around the way you're using the .Values.environment.production.properties value. It's a YAML map, but the indent function expects it to be a string. You should be able to see some odd indentation and maybe an odd [map spring [map datasource ...]] string if you use the helm template --debug option.
When you go to render the ConfigMap, you need to make sure to do two things. Since the data you have is structured properties, you need to use the lightly-documented toYaml function to convert it back to YAML. This will begin at the first column, so you need to apply the indent function to it, and then you need to make sure the markup that invokes it is also at the first column (indent should be the only thing that supplies indentation).
data:
app.properties: |-
{{ include "configmap.properties" . | indent 4}}
{{/*- starts at column 1, but includes the `indent` function */}}
{{ define "configmap.properties" }}
{{- index .Values.environment (.Values.env) "properties" | toYaml }}
{{/*- starts at first column, includes `toYaml`, does not include `indent` */}}
{{- end }}

Helm's v3 Example Doesn't Show Multi-line Properties. Get YAML to JSON parse error

In Helm's v3 documentation: Accessing Files Inside Templates, the author gives an example of 3 properties (toml) files; where each file has only one key/value pair.
The configmap.yaml looks like this. I'm only adding one config.toml for simplicity.
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-config
data:
{{- $files := .Files }}
{{- range tuple "config.toml" }}
{{ . }}: |-
{{ $files.Get . }}
{{- end }}
This works fine, until I add a second line to the config.toml file.
config.toml
replicaCount=1
foo=bar
Then I get an Error: INSTALLATION FAILED: YAML parse error on deploy/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: could not find expected ':'
Any thoughts will be appreciated.
Thanks
Helm will read in that file, but it is (for good or bad) a text templating engine. It does not understand that you are trying to compose a YAML file and thus it will not help you. That's actually why you will see so many, many templates in the wild with {{ .thing | indent 8 }} or {{ .otherThing | toYaml }} -- because you need to help Helm know in what context it is emitting the text
Thus, in your specific case, you'll want the indent filter with a value of 4 because your current template has two spaces for the key indent level, and two more spaces for the value block scalar
data:
{{- $files := .Files }}
{{- range tuple "config.toml" }}
{{ . }}: |-
{{ $files.Get . | indent 4 }}
{{/* notice this ^^^ template expression is flush left,
because the 'indent' is handling whitespace, not the golang template itself */}}
{{- end }}
Also, while this is the specific answer to your question, don't overlook the .AsConfig section on that page which seems much more likely to be what you really want to happen, and requires less indent math

Create configmap with outside yaml files for kubernetes

I'm quite new for kubernetes. I am trying to create configmap with using yaml file which was user defined.
helm upgrade --install test --namespace test --create-namespace . -f xxx/user-defined.yaml
user can add any yaml file with using 'f' option.
for example;
cars.yaml
cars:
- name: Mercedes
model: E350
So command will be;
helm upgrade --install test --namespace test --create-namespace . -f xxx/cars.yaml
My question is, I want to create configmap which is name 'mercedes-configmap'
I need to read that values from cars.yaml and create automaticaly configmap with name and data of cars.yaml
Update,
I've created below configmap template;
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.cars.name }}-configmap
data:
{{- range .Files }}
{{ .Files.Get . | toYaml | quote }}
{{- end }}
The only issue that I faced, I couldnt get the whole file data.
Welcome to the community!
I have created a helm template for configmap. It works this way: you can pass configmap name - name and file name - fname where data is stored and/or it can read files from a specific folder.
Please find the template (first 3 lines are commented, it's two working implementations of logic to check values existing):
{{/*
{{ if not (or (empty .Values.name) (empty .Values.fname)) }}
*/}}
{{ if and (not (empty .Values.name)) (not (empty .Values.fname)) }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.name }}-configmap
data:
{{- ( .Files.Glob .Values.fname ).AsConfig | nindent 2 }}
---
{{ end }}
{{ $currentScope := .}}
{{ range $path, $_ := .Files.Glob "userfiles/*.yaml" }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ base $path | trimSuffix ".yaml" }}-configmap
data:
{{- with $currentScope}}
{{ base $path }}: |
{{- ( .Files.Get $path ) | nindent 4 }}
{{- end }}
---
{{ end }}
First part of the template checks if configmap name and file name are set and if so, it renders it. Second part goes to userfiles directory and gets all yamls within.
You find github repo where I shared file examples and configmap.
To render the template with cars2.yaml and with/without files within userfiles directory:
helm template . --set name=cars2 --set fname=cars2.yaml
To render the same template with only files in userfiles directory:
helm template .
P.S. helm v3.5.4 was used
Useful links:
Accessing files in helm
Flow control
File path functions

Helm include only existing named template

I'm using Helm for to deploy multiple K8s deployments. In some deployments I need to include extra environment variables, but for the majority of deployment the standard env. variables are enough. I would like to have named template for those deployments that must have extra env. variables.
Can I include a named template only if the named template exist?
Something like this:
{{ range $idx, $svc := .Values.services }}
kind: Deployment
metadata:
name: {{ $svc.name }}
spec:
containers:
- name: {{ $svc.name }}
env:
- name: JAVA_OPTS
- value: {{ $svc.javaOpts }}
# if template_exists (print $svc.name "-env")
{{ include (print $svc.name "-env") . | indent 12 }}
# end
{{- end -}}
It's in pseudo-code. How to do the # if part?
Thank you.
The easiest way would be to add additional key like templateExists: true to your services and check it with a simple if statement in your deployment:
{{- if $svc.templateExists }}
{{ include (print $svc.name "-env") . | indent 8 }}
{{- end -}}
services:
svc1:
templateExists: true
name: svc1
javaOpts: "-Xms128m -Xmx512m"
svc2:
name: svc2
javaOpts: "-Xms256m -Xmx512m"
Here is a solution that I came up now. I check if there are any files in the chart that matches the pattern [service]-env.yaml and if there are then I include the content of that file in the deployment.
{{- range $path, $_ := $f.Glob "**-env.yaml" }}
{{- if contains $svc.app.name $path }}
{{ $f.Get $path | indent 8 }}
{{- end }}
{{- end }}
That way, for services that require extra env. variables we can include a file in files/service-env.yaml and those variables will be added to the deployment. For services that do not require such variables, it's left empty.

Unknown object type "nil" in Secret.data.redis-password

I have a tool which is now available to be deployed on Kubernetes. A known person made a document on getithub where he asked to run two power shell files. source
When I run first file 0-install-tools.ps1, it installs tools like virtualbox, minikube, helm and kubernetes-cli.
When I run second file 1-Deploy-Minikube.ps1, it is getting failed on last step where it is executing:
helm install -n qliksense qlik/qliksense -f values.yaml
The person who has created the getithub doc on the same has run it successful but am not sure why it is failing at my windows10 machine.
Following error I am getting:
error validating data: unknown object type "nil" in Secret.data.redis-password
Can you please help me to know why it is failing at my side or there is some problem with the version these powershell files are installing ?
Hardware: 3 core and 8 GB RAM.
I am hoping a positive response from your team.
Thanks,
Rohit
I rerun powershell files several times.
Expected result is mentioned in the article I discussed in content
set the empty properties as:'''''' instead of nil, null or ""
I had same problem. In my case solution is create new function in _helpers.tpl
{{/*
Nullable secret value
*/}}
{{- define "secretValue" -}}
{{- $value := . }}
{{- if $value }}
{{- printf "%s" $value | b64enc }}
{{- else }}
{{- printf "%q" "" }}
{{- end }}
{{- end }}
then in secret.yaml past follow
apiVersion: v1
kind: Secret
metadata:
name: common-secret
type: Opaque
data:
REDIS_PASSWORD: {{ include "secretValue" .Values.redisPassword }}
result is
apiVersion: v1
kind: Secret
metadata:
name: common-secret
type: Opaque
data:
REDIS_PASSWORD: ""
You need to downgrade to Helm 12.3.1 as recently described in the project Troubleshooting.
This error appears during Qlik package installation, when using Helm 2.14. Issue can be reoslve by downgrading to Helm 12.3.1.
choco install kubernetes-helm --version 2.13.1 --yes --force
Make sure to quote the secret value before encrypting it
{{- range $key, $val := .Values.secretEnv }}
{{ $key }}: {{ $val | quote | b64enc }}
{{- end }}