Flatten Dictionary with Helm

4/17/2020

Is there a way to flatten a dictionary with helm? I want to provide environment variables to the application from the chart by flattening a YAML config located in values.yaml. The config can look like. (Not Actual)

config:
 server:
  port: 3333
 other:
  setting:
    name: test

And would like to provide environment variables as

- name: CONFIG_SERVER_PORT
  value: 3333
- name: CONFIG_OTHER_SETTING_NAME
  value: test

I have considered using Kubernetes config maps but this would mean deploying slightly different instances of the app with random release names so that the config is not overwritten. This library https://github.com/jeremywohl/flatten provides a way to flatten a map[string]interface{} with delimeters. Is there a way to provide a custom pipe for helm that uses the library or another way to flatten the config?

-- user3533087
go
go-templates
kubernetes
kubernetes-helm

3 Answers

4/18/2020

I'm not aware of anything like that built in. Sprig provides most of the useful functions for helm templates but the dict functions just cover the primitives.

You could define a named template that does the business and recurses down the config dict/map. Then include the template where needed:

{{- define "recurseFlattenMap" -}}
{{- $map := first . -}}
{{- $label := last . -}}
{{- range $key, $val := $map -}}
  {{- $sublabel := list $label $key | join "_" | upper -}}
  {{- if kindOf $val | eq "map" -}}
    {{- list $val $sublabel | include "recurseFlattenMap" -}}
  {{- else -}}
- name: {{ $sublabel | quote }}
  value: {{ $val | quote }}
{{ end -}}
{{- end -}}
{{- end -}}

Passing the config data in is a little complex due to the addition of a label parameter and templates are only passed a single scope.

env: {{ list .Values.config "CONFIG" | include "recurseFlattenMap" | nindent 2 }}   

With the example values:

config:
  server:
    port: 3333
  first: astr
  other:
    setting:
      name: test

Results in

$ helm template . 
---
# Source: so61280873/templates/config.yaml
env: 
  - name: "CONFIG_FIRST" 
    value: "astr"
  - name: "CONFIG_OTHER_SETTING_NAME" 
    value: "test"
  - name: "CONFIG_SERVER_PORT" 
    value: "3333"
-- Matt
Source: StackOverflow

4/17/2020

Probably not. You might be able to implement this in pure Gotpl with some of the Sprig functions and a lot of local variables but ... don't. You cannot add custom functions to Helm without recompiling it. Just use the native format directly.

-- coderanger
Source: StackOverflow

4/17/2020

The question you are asking is possible. dont have sources near by. but try something like this.

// chart

apiVersion: apps/v1beta1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: {{ template "name" . }}          
          command: [{{ range $i, $e := .Values.container.command }}{{ if $i }}, {{$e|quote}}{{else}}{{$e|quote}}{{end}}{{end}}]          
          env:
          {{- range .Values.container.env }}
            - name: {{ .name }}
              value: "{{ .value }}"
          {{- end }}


// values

container:  
  command: ["cmd", "sub_cmd", "sub_sub_cmd"]    
  env:
      - name: CONFIG_SERVER_PORT
      value: 3333
      - name: CONFIG_OTHER_SETTING_NAME
      value: test
-- bobra
Source: StackOverflow