Im trying to create one secret with multiple file in it.
My value.yaml ( the format of the multiline is not yaml or json)
secretFiles:
- name: helm-template-file
subPath: ".file1"
mode: "0644"
value: |
This is a multiline
value, aka heredoc.
Then my secret file template is secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: {{ include "helm-template.fullname" . }}-file
namespace: {{ .Release.Namespace }}
labels:
app: {{ include "helm-template.name" . }}
chart: {{ include "helm-template.chart" . }}
type: Opaque
stringData:
{{- range .Values.secretFiles }}
{{ .subPath}}: |
{{ .value | indent 4}}
{{- end }}
The helm install gives error "error converting YAML to JSON: yaml: line 12: did not find expected comment or line break". How can I fix it? Thank you.
values.yaml
secretFiles:
- name: helm-template-file
subPath: ".file1"
mode: "0644"
value: |
This is a multiline
value, aka heredoc.
- name: helm-template-file2
subPath: ".file2"
mode: "0644"
value: |
This is a multiline222
value, aka heredoc.
xxx_tpl.yaml
...
stringData:
{{- range .Values.secretFiles }}
{{ .subPath}}: |
{{- .value | nindent 4}}
{{- end }}
output
...
stringData:
.file1: |
This is a multiline
value, aka heredoc.
.file2: |
This is a multiline222
value, aka heredoc.
ref:
nindent
The nindent function is the same as the indent function, but
prepends a new line to the beginning of the string.
indent
The indent function indents every line in a given string to the specified indent width
When you indent a line, you need to make sure the markup in the line starts at the very first column.
stringData:
{{- range .Values.secretFiles }}
{{ .subPath}}: |
{{ .value | indent 4}}{{/* no space at start of this line */}}
{{- end }}
In the form you have in the original question, the four spaces at the start of the line are copied to the output, then the indent expression adds four more spaces to the start of every line. This results in the first line being indented by eight spaces, and the second line by 4, and that inconsistency results in the YAML parse error you see.
You'd also be able to see this visually if you run helm template --debug over your chart; you'll see the same error but also the template output that can't be parsed.
(#z.x's answer solves the same problem a different way: putting the - inside the curly braces removes both the leading whitespace and also the preceding newline, and then changing indent to nindent puts the newline back.)
Related
This is a snippet from helpers.tpl of my helm chart:
{{/*
Pod-specific labels - added to pod template only
Adding a revision label to the pod will cause it to restart every time the chart is deployed.
*/}}
{{- define "app.podLabels" -}}
helm-revision: {{ .Release.Revision | quote }}
{{- end }}
Including it in pod labels like this:
labels:
{{- include "app.podLabels" . | nindent 8 }}
The result would be as shown below. The quotes around 1 is required because Kubernetes accepts string labels only.
labels:
helm-revision: "1"
I need to use the same template for an init container, replacing the : with = like this:
args:
- "pod"
- "-l {{ include "app.podLabels" . | replace ": " "=" }}"
But the output would be an incorrect yaml:
args:
- "pod"
- "-l helm-revision="1""
with error:
error converting YAML to JSON: yaml: line 34: did not find expected '-' indicator
What I actually want is something like this, that doesn't contain quotes around 1:
args:
- "pod"
- "-l helm-revision=1"
How can I achieve this?
This can be achieved by replacing " with nothing ( In effect, removes "). Escaping the quotes using \ character would be needed.
Also adding a replace function to remove newlines and add , as a separator between labels. This would be helpful if more than one pod-specific label is present. But make sure this will work in your case when rendering the template.
args:
- "pod"
- "-l {{ include "app.podLabels" . | replace ": " "=" | replace "\n" ", " | replace "\"" "" }}"
I have a variable block configuring triggers in a Keda scaled object like so:
# [...]
autoscaling:
enabled: true
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus-server.prometheus.svc.cluster.local
metricName: prometheus_redis_message_count
query: avg(redis_queue_job_states_total{state=~"waiting|active", namespace="{{ $.Release.Namespace }}", queue="reports"}) without (instance, pod, pod_template_hash, state)
threshold: '1'
activationThreshold: '1'
# [...]
as you can see, autoscaling.triggers[0].metadata.query contains a variable ( .Release.Namespace ) which does not get rendered when using the toYaml function (which is understood).
Is there a way, maybe with some named template magic or so, to put all items in triggers into my rendered template while also rendering vars contained inside (like .Release.Namespace?)
Right now I have it like this (which does work for now so I can proceed), but obviously is not great because it's way to static (won't allow multiple triggers or even other trigger types in the future):
# [...]
- type: prometheus
metadata:
serverAddress: http://prometheus-server.prometheus.svc.cluster.local
metricName: prometheus_redis_message_count
{{- with index .autoscaling.triggers 0 }}
query: {{ tpl .metadata.query $ }}
{{- end }}
threshold: '1'
activationThreshold: '1'
# [...]
edit:
thanks to David's reply I was able to write it like so:
triggers:
{{- range .autoscaling.triggers }}
- type: {{ .type }}
metadata:
query: {{ tpl .metadata.query $ }}
serverAddress: {{ tpl .metadata.serverAddress $ }}
threshold: {{ tpl .metadata.threshold $ | quote }}
activationThreshold: {{ tpl .metadata.activationThreshold $ | quote}}
metricName: {{ tpl .metadata.metricName $ }}
{{- end }}
which makes it a valid array and also templates all the fields. Anyway, thanks for the help!
The quick-and-dirty answer is to just run tpl on the output of toYaml. toYaml takes an arbitrary structure and returns a string, but at that point it's just a string and there's nothing particularly special about it.
triggers:
{{ tpl (toYaml .Values.autoscaling.triggers) . | indent 2 }}
I'm not clear that anything more nuanced is possible without iterating through the entire list and running tpl on each individual structure.
triggers:
{{- range .Values.autoscaling.triggers }}
- type: {{ .type }}
metadata:
query: {{ tpl .metadata.query $ }}
{{- end }}
Neither the core Go templating language nor the Sprig extensions have any sort of generic "map" function that could operate on the values of a nested object while retaining its structure.
I have a Yaml file in a folder as abc.yaml and the content is
metadata:
test1: apple
test2: banana
test3: cat
container:
image: foo
text: xyz
variables:
ojb: one
meta: two
and I have another file values.yaml.j2 which needs part of the above content.
metadata:
test4: dog
test5: elephant
{{ .... Here I need test1, test2, test3 from the above (abc.yaml).... }}
container:
name: test
{{ .... Here I need image and text from the above (abc.yaml) ....}}
variables:
ping: pong
{{ ..... Here I need ojb and meta from the above (abc.yaml) .... }}
When I was exploring Helm go templates, I found, Files.Lines will return line by line. But I need specific lines as I mentioned above.
Any solution with go template wo get the part of other yaml file?
If you know the other file is YAML, Helm contains a lightly-documented fromYaml extension that can parse it.
{{- $abc := .Files.Get "abc.yaml" | fromYaml }}
From there you have a couple of options on how to proceed. One tool you have is the corresponding, also lightly-documented, toYaml extension that converts an arbitrary structure back to YAML.
So one choice is to directly emit the values you think you need:
metadata:
test4: dog
test5: elephant
test1: {{ $abc.metadata.test1 }}
test2: {{ $abc.metadata.test2 }}
test3: {{ $abc.metadata.test3 }}
A second is to emit the new values for each block, plus the existing content:
metadata:
test4: dog
test5: elephant
{{ $abc.metadata | toYaml | indent 2 -}}
A third is to modify the structure in-place, and then ask Helm to write out the whole thing as YAML. Unusual for Helm template functions, set modifies the dictionary it's given in place.
{{- $_ := $abc.metadata | set "test4" "dog" | set "test5" "elephant" -}}
{{- toYaml $abc -}}
I have the following structure in values.yaml file:
upstreams:
- service_name: service_a
mapped_port: 1000
- service_name: service_b
mapped_port: 1001
I want this to be rendered like this in my deployment.yaml template:
"service-upstreams": "service_a:1000, service_b:1001"
Any idea how to do that?
You need to iterate over the objects in the upstreams value and concatenate the values.
Definition of upstream helper template
templates/_helpers.tpl
{{- define "sample.upstreams" -}}
{{- if .Values.upstreams }}
{{- range .Values.upstreams }}{{(print .service_name ":" .mapped_port ) }},{{- end }}
{{- end }}
{{- end }}
Using the template (in this example as a label)
templates/deployment.yaml
metadata:
labels:
{{- if .Values.upstreams }}
service-upstreams: {{- include "sample.upstreams" . | trimSuffix "," | quote }}
{{- end }}
I'm not trimming the comma in the template because trimSuffix does not accept curly brackets as part of an argument
I would refer to the answer David Maze linked and range documentation
I can both use
{{- range .Values.xxx }}
and
{{ range .Values.xxx }}
in my Helm, and the result is the same. Are they totally the same thing?
Also, is the hyphen necessary?
The hyphen removes any whitespace adjacent to the template construct. Often this isn't strictly necessary but it makes the rendered output more readable. Since YAML is whitespace-sensitive sometimes it is required.
Basic example:
environment:
{{ range .Values.xxx }}
- { name: {{ . }}, value: "test" }
{{ end }}
Renders to:
environment:
- { name: a, value: "test" }
- { name: b, value: "test" }
On the range line, after the }} and before the -, there is a newline and two spaces; these are required for it to be valid YAML. Before both of the {{ there is an additional newline and this isn't required, so you can use {{- to suppress it.
environment:
{{- range .Values.xxx }}
- { name: {{ . }}, value: "test" }
{{- end }}
environment:
- { name: a, value: "test" }
- { name: b, value: "test" }
This is also useful with functions like nindent that include their own newlines.
items: {{- .Values.xxx | toYaml | nindent 2 }}
items:
- a
- b
toYaml converts the list [a, b] to the YAML string - a\n- b; nindent 2 adds an initial newline, and two spaces at the start of each line \n - a\n - b; and then the - removes the extra space before the newline that's being emitted.
You can put the - inside the closing }} too, with the same effect, but that tends to eat the next line's indentation, so it tends to be a little less useful.
(Remember that helm template will render a chart to stdout without sending it off to the Kubernetes API server, so you can see what these things expand to.)