Convert string to YAML map - kubernetes-helm

In values.yaml I have another yaml config encoded to base64. In a template I decode it with
{{ $config := b64dec .Values.config }}
and I need to access it like a map, so what is needed is a kind of analogue of file AsConfig but for string.

You can use Helm's fromYaml function (haven't found any documentation besides this commit)
config.yaml which is encoded with cat config.yaml | base64
xxx: yyy
zzz: qqq
values.yaml
config: eHh4OiB5eXkKenp6OiBxcXEK
secret.yaml
{{ $config := (b64dec .Values.config) | fromYaml }}
apiVersion: v1
kind: Secret
metadata:
name: secret
type: Opaque
data:
test: {{ $config.xxx }}
helm template
/mnt/c/home/chart> helm template .
---
# Source: chart/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: secret
type: Opaque
data:
test: yyy

Related

Helm Variables inside ConfigMap File

So I had a ConfigMap with a json configuration file in it, like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config-map
data:
config.json: |+
{
"some-url": "{{ .Values.myApp.someUrl }}"
}
But I've moved to having my config files outside the ConfigMap's yaml, and just referencing them there, like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config-map
data:
config.json: |-
{{ .Files.Get .Values.myApp.configFile | indent 4 }}
But now I want my json to look like the following
{
"some-url": "{{ .Values.myApp.someUrl }}"
}
The only thing I tried is what I just showed. I 'm not even sure how to look for this answer.
Is it even possible?
At the time of reading the file, its content is a string. It's not evaluated as template, and therefore you cannot use variables like you do.
However, helm has a function for this purpose specifically called tpl:
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config-map
data:
config.json: |-
{{ tpl (.Files.Get .Values.myApp.configFile) $ | indent 4 }}
The tpl function takes a template string and renders it with some context. This is useful when you have template snippets in your values file or like in your case in some files content.

defining url in helm chart values as a variable

I have the following yaml file in values.yaml
ingress:
enabled: false
url: {{ .Release.Name }}.abc.com
but when I lint it with helm it shows the following error
Error: cannot load values.yaml: error converting YAML to JSON: yaml: line 14: did not find expected key
if I put "{{ .Release.Name }}.abc.com" it then the .Release.Name is not working. Im new to helm. thank you
helm doesn't support re-rendering like this, you need to use named template to make it work.
Named Template
e.g.
templates/_helpers.tpl
...
{{- define "ingressConfig" -}}
ingress:
enabled: false
url: {{ .Release.Name }}.abc.com
{{- end -}}
...
Use it in other templates like configmap.yaml
templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
data: |-
{{- include "ingressConfig" . | nindent 4 }}
cmd
helm template --debug test .
output
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
data: |-
ingress:
enabled: false
url: test.abc.com

Helm create secret from env file

Kubectl provides a nice way to convert environment variable files into secrets using:
$ kubectl create secret generic my-env-list --from-env-file=envfile
Is there any way to achieve this in Helm? I tried the below snippet but the result was quite different:
kind: Secret
metadata:
name: my-env-list
data:
{{ .Files.Get "envfile" | b64enc }}
It appears kubectl just does the simple thing and only splits on a single = character so the Helm way would be to replicate that behavior (helm has regexSplit which will suffice for our purposes):
apiVersion: v1
kind: Secret
data:
{{ range .Files.Lines "envfile" }}
{{ if . }}
{{ $parts := regexSplit "=" . 2 }}
{{ index $parts 0 }}: {{ index $parts 1 | b64enc }}
{{ end }}
{{ end }}
that {{ if . }} is because .Files.Lines returned an empty string which of course doesn't comply with the pattern
Be aware that kubectl's version accepts barewords looked up from the environment which helm has no support for doing, so if your envfile is formatted like that, this specific implementation will fail
I would like to use env files but it seems to be helm doesn't support that yet.
Instead of using an env file you could use a yaml file.
I mean to convert from this env file
#envfile
MYENV1=VALUE1
MYENV2=VALUE2
to this yaml file (verify the yaml format, always it should be an empty space after the colon)
#envfile.yaml
MYENV1: VALUE1
MYENV2: VALUE2
After this, you should move the envfile.yaml generated in the root folder of your helm chart (same level of values yaml files)
You have to set up your secret.yaml in this way:
apiVersion: v1
kind: Secret
metadata:
name: my-secret
annotations:
checksum/config: {{ (tpl (.Files.Glob "envfile.yaml").AsSecrets . ) | sha256sum }}
type: Opaque
data:
{{- $v := $.Files.Get "envfile.yaml" | fromYaml }}
{{- range $key, $val := $v }}
{{ $key | indent 2 }}: {{ $val | b64enc }}
{{- end}}
We are iterating in the data property the envfile.yaml generated and encoding the value to base64. The result secret will be the next:
kubectl get secret my-secret -o yaml
apiVersion: v1
data:
MYENV1: VkFMVUUx
MYENV2: VkFMVUUy
kind: Secret
metadata:
annotations:
checksum/config: 8365925e9f9cf07b2a2b7f2ad8525ff79837d67eb0d41bb64c410a382bc3fcbc
creationTimestamp: "2022-07-09T10:25:16Z"
labels:
app.kubernetes.io/managed-by: Helm
name: my-secret
resourceVersion: "645673"
uid: fc2b3722-e5ef-435e-85e0-57c63725bd8b
type: Opaque
Also, I'm using checksum/config annotation to update the secret object every time a value is updated.

Files.Get concatenated string value appears empty after helm template in Kubernetes Configmap

I'm using a configmap with a dynamic filename defined as below. However, after I do helm template the value for the filename is empty:
apiVersion: v1
kind: ConfigMap
metadata:
name: krb5-configmap
data:
krb5.conf: |-
{{ .Files.Get (printf "%s//krb5-%s.conf" .Values.kerberosConfigDirectory .Values.environment) | indent 4 }}
kerberosConfigDirectory: kerberos-configs (set in Values.yaml)
Folder structure:
k8s:
templates
configmap.yaml
kerberos-configs
krb5-dev.conf
After helm template the data value looks like this:
data:
krb5.conf: |-
--
I can't figure out why the value for the filename is empty. Note that I'm able to run the helm template command successfully.
You have an extra / and extra indentation in you file. Working example:
apiVersion: v1
kind: ConfigMap
metadata:
name: krb5-configmap
data:
krb5.conf: |-
{{ .Files.Get (printf "%s/krb5-%s.conf" .Values.kerberosConfigDirectory .Values.environment) | indent 4 }}

How can I generate a configmap from a directory of files that need to be templated?

I can generate the ConfigMap from the directory but they are not translating the template directives or values. Below is an example of the Release.Namespace template directive not being output in the ConfigMap.
.
|____Chart.yaml
|____charts
|____.helmignore
|____templates
| |____my-scripts.yaml
|____values.yaml
|____test-files
|____test1.txt
---
# templates/myscripts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scripts
namespace: {{ .Release.Namespace }}
data:
test.txt: |-
{{ .Files.Get "test-files/test1.txt" | indent 4}}
# test-files/test1.txt
test file
{{ .Release.Namespace }}
When I run helm install . --dry-run --debug --namespace this-should-print here's what I'm getting vs what I'm expecting:
Actual:
---
# Source: test/templates/my-scripts.yaml
# templates/myscripts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scripts
namespace: test
data:
test.txt: |-
# test-files/test1.txt
test file
{{ .Release.Namespace }}
Expected:
---
# Source: test/templates/my-scripts.yaml
# templates/myscripts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scripts
namespace: test
data:
test.txt: |-
# test-files/test1.txt
test file
this-should-print
Alternatively, I would be interested in every file in a specified directory being output in the format like:
<filename>: |-
<content>
I've found a way of doing it using the tpl function:
---
# templates/myscripts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scripts
namespace: {{ .Release.Namespace }}
data:
test.txt: |-
{{ tpl ( .Files.Get "test-files/test1.txt" ) . | indent 4 }}
The new output is exactly as expected:
# templates/myscripts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scripts
namespace: this-should-print
data:
test.txt: |-
# test-files/test1.txt
test file
this-should-print
And for bonus points, getting all files from a directory without having to update this list within the config map:
---
# templates/myscripts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scripts
namespace: {{ .Release.Namespace }}
data:
{{ tpl (.Files.Glob "groovy-scripts/*").AsConfig . | indent 4 }}
.Files.Get will take the raw contents of those files and dump it into your resulting YAMLs, if you want those file contents to be subject to Helm template rendering themselves, this approach won't work. You can instead create named templates and then include them within other templates.
Directory Structure: tree
.
├── Chart.yaml
├── templates
│   ├── _test1.tpl
│   └── my-scripts.yaml
└── values.yaml
Template: cat templates/my-scripts.yaml
---
# templates/myscripts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scripts
namespace: {{ .Release.Namespace }}
data:
test.txt: |-
{{- include "mychart.test1" . | indent 4 }}
Helper: cat templates/_test1.tpl
{{- define "mychart.test1" }}
test file
{{ .Release.Namespace }}
{{- end }}
Result: helm template . --namespace this-should-print
---
# Source: helm/templates/my-scripts.yaml
---
# templates/myscripts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scripts
namespace: this-should-print
data:
test.txt: |-
test file
this-should-print