Home > Blockchain >  Ensure the type is a list while executing against YAML using text/template package
Ensure the type is a list while executing against YAML using text/template package

Time:08-20

I'm using the text/template package to dynamically construct my k8s manifest and I was almost successful in creating it the required output.

Since the target type is YAML, I want to ensure, the generated type of .ownerReferences and .secrets are created as list types in YAML, i.e. with a leading - on each entry.

The output I'm expecting to achieve is

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: Foobar
  labels:
    app: Foobar
  ownerReferences:
  - uid: 123456789
    kind: FoobarOrchestrator
secrets:
- name: thisisasecret1
- name: thisisasecret2

But with the attempt I have below

package main

import (
    "os"
    "text/template"
)

const serviceAccountTemplate = `---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{.Name}}
{{- if .Labels}}
  labels:
{{- end }}
{{- range $key, $value := .Labels }}
    {{ $key }}: {{ $value }}
{{- end }}
{{- if .OwnerRef}}
  ownerReferences:
{{- end }}
{{- range .OwnerRef }}
    uid: {{ .UID }}
    kind: {{ .Kind }}
{{- end }}
{{- if .Secrets}}
secrets:
{{- end }}
{{- range $value := .Secrets }}
  name: {{ $value }}
{{- end }}
`

func main() {
    type OwnerRef struct {
        UID  string
        Kind string
    }

    data := struct {
        Name     string
        Secrets  []string
        Labels   map[string]string
        OwnerRef []OwnerRef
    }{
        "dude",
        []string{"thisisasecret1", "thisisasecret2"},
        map[string]string{"app": "Foobar"},
        []OwnerRef{OwnerRef{UID: "123456789", Kind: "Foobar"}},
    }

    t := template.New("t")
    t, err := t.Parse(serviceAccountTemplate)
    if err != nil {
        panic(err)
    }

    err = t.Execute(os.Stdout, data)
    if err != nil {
        panic(err)
    }
}

I was able to produce below

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dude
  labels:
    app: Foobar
  ownerReferences:
    uid: 123456789
    kind: Foobar
secrets:
  name: thisisasecret1
  name: thisisasecret2

but I want to be sure, if the types are accurate to be accepted by a proper YAML decoder.

Also would appreciate any enhancements to my existing template definition.

Playground link - https://go.dev/play/p/EbxcvGcYr9r

CodePudding user response:

To make the example template output YAML sequences for the desired nodes you can simply prepend - in front of the child nodes. E.g.

const serviceAccountTemplate = `
...
{{- if .OwnerRef}}
  ownerReferences:
{{- end }}
{{- range .OwnerRef }}
    - uid: {{ .UID }}
      kind: {{ .Kind }}
{{- end }}
{{- if .Secrets}}
secrets:
{{- end }}
{{- range $value := .Secrets }}
  - name: {{ $value }}
{{- end }}
`

https://go.dev/play/p/R86Feu5VZOK


There's however no support in text/template to check for proper YAML syntax. If you need guarantee that the generated text is valid YAML you'll have to write the tests for that.

But, just like when you want to generate JSON in Go you'd normally use structs and encoding/json, so too with YAML you can use structs and gopkg.in/yaml.v3 to generate consistently valid YAML.

  • Related