trying to remove first and last square brackets from json injecting data into configmap using helm - kubernetes

I have data in a JSON file and am adding each line as key value into a ConfigMap using Helm, but i need to remove first and last curly brackets.
Below is the JSON file content:
{
"type": "PurposeResourcesDefinition",
"version": "1.0",
"purposeId": "p#####",
"description": "Artifactory container registry",
"resources": [{
"type": "artifactory.containerregistry",
"name": "<repository name prefixed with the purpose>"
]
}
I am using the below Helm syntax:
data:
{{ range .Files.Lines "foo/app.json" }}
{{ . }}{{ end }}
How can I remove the surrounding curly brackets using Helm templating?

If you know that { and } will be on lines by themselves, you can just skip them. This isn't especially robust, but it will work for the example you show.
data:
{{- range .Files.Lines "foo/app.json" }}
{{- if and (ne . "{") (ne . "}") }}
{{ . }}
{{- end }}
At a higher level, it looks like you're trying to read in a JSON file and then write these values out as the contents of a ConfigMap. Stripping the leading and trailing braces will work because of the syntactic similarities between YAML and JSON, but it might be better to actively convert from one format to the other. Helm has several undocumented conversion functions including fromJson and toYaml. So you can also write this as:
data: {{- .Files.Get "foo/app.json" | fromJson | toYaml | nindent 2 }}

Related

Helm: render variable in a block inserted with toYaml

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.

How to Return Part of another YAML file in Helm Go Template

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

helm multiline file inside range

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.)

Helm 3, convert array of objects in values.yaml into comma separated string

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

How to use printf in this Helm template function?

I created this Helm template function in my templates/_helpers.yaml file. It simply gets the gets the value of an array element (the index .Values... part), based on the passed-in environment. It works fine.
{{/*
Function to get min CPU units
*/}}
{{- define "microserviceChart.minCpuUnits" -}}
{{ index .Values.valuesPerEnvironment.cpuUnits ((pluck .Values.environment .Values.environments | first | default .Values.environments.sandbox) | int) | quote }}
{{- end }}
For example, in my values.yaml file
environments:
sandbox: 0
staging: 1
production: 2
valuesPerEnvironment:
cpuUnits: [512, 512, 1024]
so my template function returns "512", "512", "1024" based on my passed-in environment. However, can I use printf to it adds m to these values? In other words, I want it to return "1024m" for production. I tried the following but I get a syntax error
{{/*
Function to get min CPU units
*/}}
{{- define "microserviceChart.minCpuUnits" -}}
{{- printf "%dm" index .Values.valuesPerEnvironment.cpuUnits ((pluck .Values.environment .Values.environments | first | default .Values.environments.sandbox) | int) | quote }}
{{- end }}
Instead of trying to get the arguments in the right order for printf, you could include the m in the template body. You'll also need to make the "..." explicit, instead of using the quote function, to get the m inside the quotes.
Expanded out (note that {{- and -}} will delete whitespace before and after, including newlines):
{{- define "microserviceChart.minCpuUnits" -}}
"
{{- index .Values.valuesPerEnvironment.cpuUnits ((pluck .Values.environment .Values.environments | first | default .Values.environments.sandbox) | int) -}}
m"
{{- end }}
The heck with it. I just made my values.yaml like this, and I get the same result.
environments:
sandbox: 0
staging: 1
production: 2
valuesPerEnvironment:
cpuUnits: [512m, 512m, 1024m]
It'd still be cool to know if I can do this in the function, so if someone answers the actual question, I'll accept that as the answer.