4

I am using Helm to deploy to a Kubernetes cluster. I have researched configmaps and found it is possible to retrieve data from a file and put it into the configmap.

I have the following configmap.yaml:

kind: ConfigMap 
apiVersion: v1 
metadata:
  name: {{ .Values.app.configMap }}
  namespace: {{ .Values.app.namespace }}
data:
    config.json: |-
      {{ .Files.Glob "my-config.json" | indent 2}}

and my deployment.yaml contains the relevant volumeMount (if I put actual json data directly into configmap.yaml then the config deploys). My configmap.yaml and deployment.yaml are both kept in /chart/templates but I keep my-config.json within the base helm chart directory, outside of the templates folder.

When I try deploying with the chart, I get the following error:

Error: template: chart/templates/configmap.yaml:8:54: executing "chart/templates/configmap.yaml" at <2>: wrong type for value; expected string; got engine.files

How can I use the .json file in my configmap without putting the raw json data directly into the yaml file?

0

2 Answers 2

13

The .Files object is described in the Helm Built-in Objects documentation. .Files.Glob returns a list of files matching some pattern, like *.json; you probably want .Files.Get instead to return the file content.

YAML is also very sensitive to whitespace handling and indentation. When you do retrieve the file, you probably want that line to start at the first column, but then call the indent function with some number more than the indent level of the previous line. This also indents the first line, and you can double-check with helm template that the right thing came out.

data:
  {{-/* Note, indent of only two spaces */}}
  config.json: |-
{{ .Files.Get "my-config.json" | indent 4 }}
{{/* .Get, not .Glob; indent 4 spaces, more than 2 above */}}
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you! If I wanted the json file to depend on a variable in a values.yaml, is there a way to do this? Currently I've tried: {{ .Files.Get "{{ .Values.app.config }}.json" | indent 4}} but this returns an empty config as far as I can see.
Once you're inside the curly braces, you're in template language, so you don't need more curly braces. But try {{ .Files.Get (printf "%s.json" .Values.app.config) | indent 4 }} to fill it in from a variable.
You saved me. IMHO the examples in the official documentation are utterly misleading: helm.sh/docs/chart_template_guide/accessing_files they use 3 files with just a single line, which means the whole indenting issue does not turn up and you end up thinking helm will automatically indent the contents of the file.. I believe the official documentation should be amended to use files with at least 2 lines, so that indent handling issues can be discussed
The documentation only mentions using .Files.Lines, but does not really explicitly say to do that to handle indentation. Also it probably is less efficient (?).
I tried {{ .Files.Get (printf "%s.json" .Values.app.config) | indent 4 }}, but it returns empty config
1

There are 2 other ways to include a file and properly indent its contents:

  1. Include it line by line as mentioned in the documentation:

    data:
      key: |
        {{- range .Files.Lines "myfile.txt" }}
        {{ . }}{{ end }}
    

    this template will be repeated for each line, therefore every line will have the correct indentation of 4 spaces.

  2. use the {{- to remove initial whitespace and introduce an explicit newline in the template:

    data:
      key: |
        {{- "\n" }}
        {{- .Files.Get "myfile.txt" | indent 4 }}
    

Both these solutions produce:

data:
  key: |
    contents of
    myfile.txt!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.