Read an array in helm template from value file - kubernetes-helm

I am trying to set and read array value like described below , parsing of yaml template file to json is failing , please suggest resolution.
template file :
spec:
arguments: {{ toYaml .Values.sparkapplication.spec.arguments | indent 6 }}
values file :
sparkapplication :
spec:
arguments:
- val: "/spark_app_prop/config.properties"
- val: "/spark_app_prop/log4j.properties"
expected parsed result in template file should be :
spec:
arguments: [ "/tmp/spark-streaming-poc-app-1.0.0.1/infa_conf/config.properties", "/tmp/spark-streaming-poc-app-1.0.0.1/infa_conf/log4j.properties" ]

values.yaml
sparkapplication :
spec:
arguments:
- val: "/spark_app_prop/config.properties"
- val: "/spark_app_prop/log4j.properties"
template/cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
{{- $list := list }}
{{- range .Values.sparkapplication.spec.arguments }}
{{- $list = append $list .val }}
{{- end }}
arguments: {{ toJson $list }}
output
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
arguments: ["/spark_app_prop/config.properties","/spark_app_prop/log4j.properties"]

Related

How do I pass a map as a Helm tpl string?

I'm trying to populate the annotations on a service which is templated like this:
apiVersion: v1
kind: Service
metadata:
name: example
namespace: {{ .Release.Namespace }}
annotations:
{{- if .Values.service.annotations }}
{{ tpl .Values.service.annotations . | nindent 4 | trim }}
{{- end }}
(rest omitted for brevity.)
I tried to populate the service.annotations like this in my values.yaml:
service:
annotations:
foo: my-foo
bar: 6
baz: false
... but Helm errored out with [ERROR] templates/: template: my-chart/templates/service.yaml:20:18: executing "my-chart/templates/service.yaml" at <.Values.service.annotations>: wrong type for value; expected string; got map[string]interface {}
I tried reading the docs for the tpl function but they just showed examples for how to interpolate a string from a different variable, or how to pass values from an external file.
How do I set the annotations on this service? I don't have any control over the template.
update
You need to understand the essence of the problem, my previous answer is the style required for the final rendering, based on this, you just need to understand the usage of tpl and try to render the template as written before.
helm tpl
values.yaml
service:
annotations: "{{ toYaml .Values.service.fields | trim }}"
fields:
foo: my-foo
bar: 6
baz: false
template
apiVersion: v1
kind: Service
metadata:
name: example
namespace: {{ .Release.Namespace }}
annotations:
{{- if .Values.service.annotations }}
{{ tpl .Values.service.annotations . | nindent 4 | trim }}
{{- end }}
...
cmd
helm template --debug test .
output
apiVersion: v1
kind: Service
metadata:
name: test
namespace: default
annotations:
bar: 6
baz: false
foo: my-foo
...
As David Maze said.
In service.yaml, annotations must be a YAML string.
You may try
tempaltes/service.yaml
apiVersion: v1
kind: Service
metadata:
name: example
namespace: {{ .Release.Namespace }}
{{- if .Values.service.annotations }}
annotations:
{{ toYaml .Values.service.annotations | nindent 4 | trim }}
{{- end }}

lookup configmap value in helm template

Say I have a configmap like this, and I want to get the value(12301) of version 123v1 in map_a, what is the correct way?
apiVersion: v1
kind: ConfigMap
metadata:
name: myconfig
namespace: default
data:
test.yml: |
map_a:
"123v1":
"Version": 12301
"Type": "abc"
......
Here is my attempts:
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config
data:
{{- $configmap := (lookup "v1" "ConfigMap" "default" "myconfig") }}
{{- if $configmap }}
{{- $models := get $configmap.data "test.yml" }}
version: {{ $models.map_a.123v1.Version }}
{{- end }}
$ helm template .
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /root/test-lookup
Error: parse error at (test-lookup/templates/config.yaml:9): ".123v"
helm.go:88: [debug] parse error at (test-lookup/templates/config.yaml:9): ".123v"
The pipe symbol at the end of a line in YAML signifies that any indented text that follows should be interpreted as a multi-line scalar value. See the YAML spec. This is also mentioned in the helm doc |-
{{ $models }} is a value behind a pipe symbol of myconfig>data>test.yml.
So, the value of the expression {{ $models }} is a string instead of a map. In other words, {{ $models. map_a }} is an illegal operation.
The real value of {{ $models }} is a multi-line string, the string content is:
map_a:
"123v1":
"Version": 12301
"Type": "abc"
This can work here, of course the result is not what you want:
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config
data:
{{- $configmap := (lookup "v1" "ConfigMap" "default" "myconfig") }}
{{- if $configmap }}
{{- $models := get $configmap.data "test.yml" }}
version: {{ $models | quote }}
{{- end }}
output:
apiVersion: v1
data:
version: |
map_a:
"123v1":
"Version": 12301
"Type": "abc"
kind: ConfigMap
metadata:
annotations:
...
So in order to achieve your purpose, you have to operate {{ $models }} in accordance with the method of operating strings.
config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config
data:
{{- $configmap := (lookup "v1" "ConfigMap" "default" "myconfig") }}
{{- if $configmap }}
{{- $models := get $configmap.data "test.yml" }}
{{- range ( split "\n" $models) }}
{{- if ( contains "Version" .) }}
version: {{ (split ":" .)._1 | trim | quote }}
{{- end }}
{{- end }}
{{- end }}
output:
apiVersion: v1
data:
version: "12301"
kind: ConfigMap
metadata:
annotations:
...

Helm3: Create .properties files recursively in Configmap

Below are files that I have:
users-values.yaml file :
users:
- foo
- baz
other-values.yaml file:
foo_engine=postgres
foo_url=some_url
foo_username=foofoo
baz_engine=postgres
baz_url=some_url
baz_username=bazbaz
config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-catalog
data:
{{- range $user := .Values.users }}
{{ . }}: |
engine.name={{ printf ".Values.%s_engine" ($user) }}
url={{ printf ".Values.%s_url" ($user) }}
username={{ printf".Values.%s_username" ($user) }}
{{- end }}
deployment-coordinator.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: "{{ .Release.Name }}-coordinator"
labels:
app.kubernetes.io/name: "{{ .Release.Name }}-coordinator"
spec:
replicas: 1
...
template:
metadata:
labels:
app.kubernetes.io/name: "{{ .Release.Name }}-coordinator"
spec:
volumes:
- name: config
configMap:
name: test-catalog
...
volumeMounts:
- name: config
mountPath: "/etc/config"
Then, I do a helm install test mychart.
When I exec into the pod, and cd to /etc/config, I expect to see foo.properties and baz.properties files in there, and each file looks like:
foo.properties: |
engine.name=postgres
url=some_url
username=foofoo
baz.properties: |
engine.name=postgres
url=some_url
username=bazbaz
The answer from Pawel below solved the error I got previously
unexpected bad character U+0022 '"' in command
But, the files are still not created in the /etc/config directory.
So, I was wondering if it's even possible to create the .properties files using helm range as I mentioned in my config.yaml file above.
The reason I wanted to do it the below way is because I have more than 10 users to create .properties files on, not just foo and baz. Just thought it'll be easier if I can do a for loop on it if possible.
data:
{{- range $user := .Values.users }}
{{ . }}: |
engine.name={{ printf ".Values.%s_engine" ($user) }}
url={{ printf ".Values.%s_url" ($user) }}
username={{ printf".Values.%s_username" ($user) }}
{{- end }}

Helm: "Template" keyword

Can someone explain to me what the role of the keyword "template" is in this code :
apiVersion: v1
kind: Secret
metadata:
name: {{ template "identity-openidconnect" . }}
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "microService.name" . }}
release: "{{ .Release.Name }}"
xxxx
xxxxxxxxxxxx
The keyword "template" means, that Helm will find the previously created template and complete the yaml file according to the template in the template. It has to be created in advance. This type of construction allows you to refer to the same scheme many times.
For example, we can define a template to encapsulate a Kubernetes block of labels:
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
Now we can embed this template inside of our existing ConfigMap, and then include it with the template action:
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
{{- template "mychart.labels" }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
When the template engine reads this file, it will store away the reference to mychart.labels until template "mychart.labels" is called. Then it will render that template inline. So the result will look like this:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: running-panda-configmap
labels:
generator: helm
date: 2016-11-02
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
Note: a define does not produce output unless it is called with a template, as in this example.
For more info about templates you can read this page.

Helm not merging array of secrets

I am trying to do merge of multiple values files which has array of secrets.But the merging is not working instead the last values file overrides.
This is my secret template
---
{{- range .Values.secrets }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ required "a valid name is required" .name }}
namespace: ""
type: Opaque
data:
{{- range $key, $val := .data }}
# fix printing the key name in the required string
{{ $key }}: {{ required "a valid key is required" $val }}
{{- end }}
{{- end }}
value1.yaml:
secrets:
- name: "sample"
data:
test: "YXBpa2V5MQo="
value2.yaml:
- name: "sample2"
data:
test: "YXBpa2V5MQo="
helm template secrets-template -f value1.yaml -f value2.yaml
The output is
---
apiVersion: v1
kind: Secret
metadata:
name: sample2
namespace: ""
type: Opaque
data:
# fix printing the key name in the required string
test: YXBpa2V5MQo=
But the expected output is
---
apiVersion: v1
kind: Secret
metadata:
name: sample
namespace: ""
type: Opaque
data:
# fix printing the key name in the required string
test: YXBpa2V5MQo=
---
apiVersion: v1
kind: Secret
metadata:
name: sample2
namespace: ""
type: Opaque
data:
# fix printing the key name in the required string
test: YXBpa2V5MQo=
Any help on this ?
As far as I can tell, helm always overwrites arrays. A work around, is to use dictionaries. For example, use the name of the secret as the key.
template:
---
{{- range $secretName, $secretValue := .Values.secrets }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ required "a valid name is required" $secretName }}
namespace: ""
type: Opaque
data:
{{- range $key, $val := $secretValue }}
# fix printing the key name in the required string
{{ $key }}: {{ required "a valid key is required" $val }}
{{- end }}
{{- end }}
value1.yaml
secrets:
sample:
test: "YXBpa2V5MQo="
value2.yaml
secrets:
sample2:
test: "YXBpa2V5MQo="
Thankyou..it works..I did a small modification.
{{- range $secretName,$secretValue := .Values.secrets }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ required "a valid name is required" $secretName }}
type: {{ $secretValue.type | default "Opaque" }}
data:
{{- range $key, $val := $secretValue.data }}
# fix printing the key name in the required string
{{ $key }}: {{ required "a valid key is required" $val }}
{{- end }}
{{- end }}
values file:
secrets:
sample2:
data:
test2: "YXBpa2V5MQo="
But I am getting below warning eventhough it works fine..Is this a problem?How to fix this warning?
coalesce.go:160: warning: skipped value for secrets: Not a table.