How to concat string to result of .AsConfig in helm? - go

I have config like this:
{{- with .Files.Glob "files/my-files/*.json" }}
{{ .AsConfig | indent 2 }}
{{- end }}
In the end of each file I want to add "FIHISHED!"
How can I achieve it in helm ?

The .AsConfig method renders and returns all files as a single YAML text. So you can't format the result.
If you want to list all files (with content), separated with an arbitrary text, I suggest to do this "yourself". Files is a map of files, mapping from string name to []byte content.
{{- with .Files.Glob "files/my-files/*.json" }}
{{ range $name, $content := . -}}
{{ printf "-%s:\n%s\nFINISHED!" $name $content | indent 2 }}:
{{- end }}
{{- end }}

Related

Helm template for Vault annotation

I'm trying to nest one template into another, namely I have a k8s deployment.yaml which should be templated by helm. However, it is already using Vault template in annotation field responsible for injecting secrets into the pod.
Without Helm template it looks like this:
vault.hashicorp.com/agent-inject-template-.env: |
{{- with secret (print "envs/data/test") -}}{{- range $k, $v := .Data.data -}}
{{ $k }}={{ $v }}
{{ end }}{{- end -}}
Now, I would like to make a template for Helm and replace path envs/data/test with value coming from Helm values. So I've tried to use it like that:
vault.hashicorp.com/agent-inject-template-.env: |
{{- with secret (print {{ .Values.path }}) -}}{{- range $k, $v := .Data.data -}}
{{ $k }}={{ $v }}
{{ end }}{{- end -}}
This however does not work meaning {{ .Values.path }} is outputed as is, as a string.
How can I template over another template and resolve {{ .Values.path }} as a variable?

Check if a key/value exists in helm chart yaml and add a value to it if exists, otherwise create a new key-pair value

Let's say that I have the following structure in one helm template file
{{- define "deployAnnotations" -}}
"key1" : "value1",
"key2" : "value2"
"ip_range": "20.20.20.20/32"
{{- end -}}
and the above are included in the deployment.yaml file of my helm chart
template:
metadata:
annotations:
{{ include "podAnnotations" . | nindent 8 }}
Now I want to add one more annotation that also define in a template file the following one:
{{- define "ipdeployAnnotations" -}}
ip_range: 10.10.10.10/32
{{- end -}}
My question is how can I search if ip_range exists in the podAnnotations structure. If exists I just want to add the 10.10.10.10/32 to the existing line , otherwise I would like to create a new one.
I imagine something like below but in operator is not working for me , and also I do not know how to add the additional value to ip_range
template:
metadata:
annotations:
{{ include "podAnnotations" . | nindent 8 }}
{{ - if "ip_range" in "podAnnotations" }}
// do something in order to have the following result
"ip_range": "20.20.20.20/32", "10.10.10.10/32"
{{- else }}
{{ include "ipdeployAnnotations" . | nindent 8 }}
{{- end }}
You may convert it to a struct first, and then use it in the way of manipulating dictionary.
templates/_helper.tpl
{{- define "deployAnnotations" -}}
"key1" : "value1"
"key2" : "value2"
"ip_range": "20.20.20.20/32"
{{- end -}}
{{- define "ipdeployAnnotations" -}}
ip_range: "10.10.10.10/32"
{{- end -}}
templates/xxx.yaml
...
{{- $da := (include "deployAnnotations" . | fromYaml) }}
{{- $ida := (include "ipdeployAnnotations" . | fromYaml) }}
{{- if (hasKey $da "ip_range") }}
{{- $_ := set $da "ip_range" (printf "%s, %s" $da.ip_range $ida.ip_range) }}
{{- else }}
{{- $_ := set $da "ip_range" $ida.ip_range }}
{{- end }}
{{- range $k, $v := $da }}
{{ $k }}: {{ $v }}
{{- end }}
...
output
ip_range: 20.20.20.20/32, 10.10.10.10/32
key1: value1
key2: value2

Controlling indents in Go templates

I have the following Go template:
{{ range $job, $steps := .jobs -}}
{{ $job -}}:
{{ range $steps -}}
{{ . }}
{{ end }}
{{- end }}
It's producing output that looks like the following:
job1:
step1
step2
job2: <--- This should not be indented
step1
step2
All jobs after job1 are indented four spaces. It's not apparent to me why the template engine would decide to arbitrarily indent the remaining jobs. How can I control indentation so that the output appears as so:
job1:
step1
step2
job2:
step1
step2
job2's identation does not come from where you think: it comes from the spaces and newline between printing the steps:
{{ range $steps -}}
{{ . }} <-- starting from here, and the indentation of the next line
{{ end }}
So the newline and the indentation after step2 of job1 is outputted, and you start job2 right there: already indented.
If you insert newlines and indentation only where you want them in the output, you get what you want:
{{ range $job, $steps := .jobs}}{{ $job }}:{{ range $steps }}
{{ . }}{{ end }}
{{ end }}
Or format your template the way you want, and disable indentation everywhere, and explicitly output newlines and indentation where you want them:
{{ range $job, $steps := .jobs -}}
{{- $job -}}:{{"\n"}}
{{- range $steps -}}
{{" "}}{{- . -}}{{"\n"}}
{{- end -}}
{{- end }}
Or a third solution:
{{ range $job, $steps := .jobs -}}
{{ $job }}:
{{- range $steps }}
{{ . }}{{ end }}
{{ end }}
These all output (try them on the Go Playground):
job1:
step1
step2
job2:
step1
step2

How to return a map object from template in Helm function?

I have a function that I want to call in another function. I want it to return a map, but instead it returns the toString representation of the map. It is an actual map inside the function, but not outside it.
{{- define "app.getSubKey" -}}
{{- $name := .source }}
{{- range $key, $value := .keys }}
{{- if kindIs "int" $value }}
{{- $name = index $name (int $value) }}
{{- else }}
{{- $name = index $name $value }}
{{- end }}
{{- end }}
{{- if kindIs "string" $name }}
{{- trim $name }}
{{- else }}
{{ $name }}
{{- end }}
{{- end }}
When I call this function on the below YAML with {{- include "app.getSubKey" (dict "source" .Values.vars "keys" (list 0)) }}, inside the function $name is a map (I used kindOf to check this) but outside it's of kind string. How can I get it returned as a map?
vars:
- name: something
value: blah
To be precise: your app.getSubKey is not a function, it is a named template and as such, it does not return anything. On the other hand, include is a function. It takes as arguments a template name and its context, and returns rendered template as a string. You cannot change the type of the include function return value.
Said that, I see two options:
if your goal is to get a properly formatted YAML from the include "app.getSubKey" call (still as a string) use toYaml function inside the named template, i.e.:
{{- define "app.getSubKey" -}}
...
{{- else }}
{{- $name | toYaml | nindent 0 }}
{{- end }}
{{- end }}
nindent 0 is necessary to get a properly left align YAML
if you want to get an actual dictionary (for further processing), you need to convert the string returned from the include call back to an object (the toYaml in the named template is still required):
{{- $d := dict "source" .Values.vars "keys" (list 0) | include "app.getSubKey" | fromYaml -}}
The function fromYaml is undocumented, so using it might be a bit risky. The only trace of it I found in the official docs is in the examples on the library charts page.
BTW, the app.getSubKey logic doesn't seem correct: it will fail for the keys list with more then one element.
If app.getSubKey returns an array, you must use fromYamlArray to "decode" the data.

Convert YAML string to dict in Helm template

I am creating a chart for a project that has a binary that when executed generates a configuration file in YAML format that looks like this:
---
PARAM_1: value1
PARAM_2: value2
My chart needs to read this file and and load all of its values into environment variables in a container, so I created a variable config in my values.yaml file and when the chart is installed I am passing the file content using --set-file:
helm install <CHART> --set-file config=/path/to/yaml/config/file
Next I create a ConfigMap withe the value of .Values.config:
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
{{ .Values.config }}
The problem I am having is that I need to do two things with values of config:
prefix all keys with a predefined value (so in the example above I would MY_APP_PARAM_1 as key)
make sure the values are all string, otherwise the ConfigMap will fail
How can I parse the value of .Values.config in my template as a dict so that I can use a range loop do these changes?
In the end I was able to do something like this:
{{ $lines := splitList "\n" .Values.config -}}
{{- range $lines }}
{{- if not (. | trim | empty) -}}
{{- $kv := . | splitn ":" 2 -}}
{{ printf "MY_APP_%s: %s" $kv._0 ($kv._1 | trim | quote) | indent 2 }}
{{ end -}}
{{- end -}}
I had a hard time getting the {{- vs {{ right, and helm install --debug --dry-run . help a lot in this part.
It's kind of messy, so I would be very interested in seeing if anyone has a better solution.
If You need to work with more tricky YAML (map in a map) You can use this:
List Handler (list to comma separated string)
{{- define "helm-toolkit.utils.joinListWithComma" -}}
{{- $local := dict "first" true -}}
{{- range $k, $v := . -}}{{- if not $local.first -}}, {{ end -}}{{ $v -}}{{- $_ := set $local "first" false -}}{{- end -}}
{{- end -}}
Convert Yaml dict to the properties-like look
{{- define "utils.yaml2properties" }}
{{- $yaml := . -}}
{{- range $key, $value := $yaml }}
{{- if kindIs "map" $value -}}
{{ $top:=$key }}
{{- range $key, $value := $value }}
{{- if kindIs "map" $value }}
{{- $newTop := printf "%s.%s" $top $key }}
{{- include "utils.yaml2properties" (dict $newTop $value) }}
{{- else if kindIs "slice" $value }}
{{ $top }}.{{ $key }}={{ include "helm-toolkit.utils.joinListWithComma" $value }}
{{- else }}
{{ $top }}.{{ $key }}={{ $value }}
{{- end }}
{{- end }}
{{- else if kindIs "slice" $value }}
{{ $key }}={{ include "helm-toolkit.utils.joinListWithComma" $value }}
{{- else }}
{{ $key }}={{ $value }}
{{- end }}
{{- end }}
{{- end }}
Use (example from K8s configMap)
{{- define "config.yaml" }}
vault.pki:
enabled: {{.Values.vault.pki.enabled}}
role: idverify
common-name: idverify
role:
map:
list:
- one
- two
{{- end }}
data:
bootstrap.properties: |
{{ (include "utils.yaml2properties" (include "config.yaml" . | fromYaml )) | indent 4 }}

Resources