how split if statement over multiple lines in helm chart - kubernetes

Im trying to format my yml to be more readable.
I have an if statement that is really long with a bunch of and/ors and I would like to be able to spread it across multiple lines
So something along the lines of
{{-if or
(eq 'abc' .values.foo)
(eq 'def' . values.bar)
}}
Def:'works'
{{- end}}
But this throws up errors for incomplete if statement.
Is there some special character or syntax I can use to achieve the above?

helm supports direct line breaks without special characters.
Missing a space between {{ and if.
There is an extra space between . and values.
String constants require double quotes.
demo:
values.yaml
foo: xxx
bar: yyy
templates/cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test
labels:
{{- include "test.labels" . | nindent 4 }}
data:
cfg: |-
{{- if or
(eq "abc" .Values.foo)
(eq "def" .Values.bar)
}}
if
{{- else }}
else
{{- end }}
cmd
helm template --debug test .
output
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
cfg: |-
else

Related

Helm default value throws error converting YAML to JSON

I have a basic kubernetes helm template like below
apiVersion: v1
kind: ConfigMap
metadata:
name: test
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/version: {{ .Chart.AppVersion }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
data:
config.tpl: |
{{- default ((tpl .Values.configTpl .) | indent 4) (tpl (.Files.Get "files/config.tpl") . | indent 4) -}}
and the values.yml file
configTpl: |
{{ x=8gwifi.org }}
When i apply the helm chart it throw me an error
❯ helm upgrade mychart . --namespace=test --create-namespace --debug
upgrade.go:142: [debug] preparing upgrade for mychart
Error: UPGRADE FAILED: YAML parse error on 8gwifi.org-test/templates/configmap-logfilegen.yaml: error converting YAML to JSON: yaml: line 11: did not find expected comment or line break
helm.go:84: [debug] error converting YAML to JSON: yaml: line 11: did not find expected comment or line break
I tried different configuration
config.tpl: |
{{- default (tpl .Values.configTpl . | indent 4) (tpl (.Files.Get "files/config.tpl") . | indent 4) -}}
still resulting in same error, Is there a way to specify a config value if none is passed then used the hardcoded one
I'm sure it's an YAML syntx issue couldn't figure it out checked all cases
Based on David suggestion
Template debug is showing this
data:
config.tpl: |-
x := 8gwifi.org
y := "functions"
I can cleary see y is not indent and throwing YAML syntax error, not sure how to fix this
This is the updated definition
data:
config.tpl: |-
{{ (tpl .Values.configTpl . | indent 4) | default (tpl (.Files.Get "files/config.tpl") . | indent 4) -}}
values.yml
configTpl: |
x := "8gwifi.org"
y := "function"
You're hitting problems with whitespace in the first line of the block scalar. You should check two things:
The template block containing indent must not itself be indented, it must start at the first column of its line; and
The template block containing indent must not have a - inside the opening curly braces.
{{- $configTpl := .Values.configTpl | default (.Files.Get "tiles/config.tpl") }}
config.tpl: |
{{ tpl $configTpl . | indent 4 }}
The templating language isn't really aware of YAML syntax as it runs. If you have spaces in front of the indent line, they will get emitted, and then indent adds its own leading space, resulting in the last output you get where the first line is indented extra. The - whitespace control marker will also consume the preceding newline, resulting in the first line of the output being on the same line as the YAML block scalar marker.

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 }}

Creating a configMap from file is critical to file type and lines count in the file

I have a template that creates a configMap from the jmeter-test-data-file-configmap.yaml file in helm chart:
{{- if .Values.env.datafile }}
apiVersion: v1
kind: ConfigMap
metadata:
name: jmeter-testdata
data:
{{ .Values.env.datafile }}: |-
{{ .Files.Get .Values.env.datafile | indent 4}}
{{- end }}
the corresponding yaml.configuration is:
env:
testfile: sample
datafile: example.csv
When I do the helm upgrade, everything is ok, if the example.csv is a single line text file like that:
1,1
but is it would have at least two or even more lines
1,1
2,2
the deployment fails with unrelated error message:
upgrade.go:123: [debug] preparing upgrade for jmeter
Error: UPGRADE FAILED: YAML parse error on jmeter/templates/jmeter-test-data-file-configmap.yaml: error converting YAML to JSON: yaml: line 7: did not find expected key
helm.go:81: [debug] error converting YAML to JSON: yaml: line 7: did not find expected key
YAML parse error on jmeter/templates/jmeter-test-data-file-configmap.yaml
and the debug details are:
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.(*Upgrade).prepareUpgrade
/home/circleci/helm.sh/helm/pkg/action/upgrade.go:215
helm.sh/helm/v3/pkg/action.(*Upgrade).Run
/home/circleci/helm.sh/helm/pkg/action/upgrade.go:124
main.newUpgradeCmd.func2
/home/circleci/helm.sh/helm/cmd/helm/upgrade.go:155
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
UPGRADE FAILED
main.newUpgradeCmd.func2
/home/circleci/helm.sh/helm/cmd/helm/upgrade.go:157
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
So, the error points to this line:
{{ .Values.env.datafile }}: |-
What could be wrong here and how can the file itself hurt the template processing because of its new lines? We tired /r/n, /n, /r with no success, all the same
We also tried to hadcode the line:7 like that:
{{- if .Values.env.datafile }}
apiVersion: v1
kind: ConfigMap
metadata:
name: jmeter-testdata
data:
example.csv: |-
{{ .Files.Get .Values.env.datafile | indent 4}}
{{- end }}
and still the same error. And even to replace the template value with the hardcode:
{{- if .Values.env.datafile }}
apiVersion: v1
kind: ConfigMap
metadata:
name: jmeter-testdata
data:
{{ (printf "example.csv" ) }}: |-
{{ .Files.Get (printf "example.csv" ) | indent 4}}
{{- end }}
But still the same error.
And that doesn't happens with almost the same config, that bring the multiline xml file to the configMap exactly the same way:
apiVersion: v1
kind: ConfigMap
metadata:
name: jmeter-test
data:
test.jmx: |-
{{ .Files.Get (printf "%s.jmx" .Values.env.testfile ) | indent 4}}
I suppose, that for some reason, probaby the intend is't applied to all lines for csv file, when it is applied to the jmx file. But how to figure that out ad how to work it around?
UPD:
1, 1
2, 2
3, 3
"intending" files manually like above made the trick, it was deployed, however this file isn't ok to use for the needs then. How to avoid that?
If you have a line containing indent it probably needs to begin at the start of the line, even if it's in otherwise indented context.
{{- if .Values.env.datafile }}
...
data:
{{ .Values.env.datafile }}: |-
{{ .Files.Get .Values.env.datafile | indent 4}}
{{/*- previous line is not indented */}}
{{- end }}
In your original example, let's focus on these two lines:
{{ .Values.env.datafile }}: |-
{{ .Files.Get .Values.env.datafile | indent 4}}
## (these two spaces are important)
Now, if the input line is your second example
1,1
2,2
Now: the line containing indent 4 is itself indented by 2 spaces. So in that line you have the two spaces at the start of the line, plus the four spaces from indent 4, so 6 spaces; then a newline and four spaces from indent 4, but no start-of-line spaces (you're still in the output from indent), so only 4 spaces.
test.jmx: |-
1,1
2,2
If you run helm template --debug on your original chart, you will still get the YAML parsing error, but it should also print out this output.
In some contexts you may find it slightly more aesthetic to use nindent, which includes a newline before the first line's indentation, in combination with a - just inside the curly braces to consume the preceding whitespace (including both spaces and newlines). This should also work:
data:
{{ .Values.env.datafile }}: |-
{{- .Files.Get .Values.env.datafile | nindent 4}}
{{/*- indented, starts with -, uses nindent */}}
But also for example:
metadata:
labels: {{- include "common.labels" . | nindent 4 }}
annotations: {{- include "common.annotations" . | nindent 4 }}
{{ .Files.Get (printf "%s" .Values.env.datafile ) | nindent 4}}
instead of
{{ .Files.Get (printf "%s" .Values.env.datafile ) | indent 4}}
has fixed the problem.
But for me it is still unclear why the problem has been arisen for the csv file, while wasn't there for the XML files. Is it all due to the spaces?

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

How to use if/else loop in Helm

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.