6

I am using go templates to create yaml definitions for kubernetes. I am trying to nest templates but run into issues where I can't re-use a definition simply because the indention is wrong when included. I.e., in one case the contents need indentation but do not in another. How can I control the indention of included content?

Example below. I am reusing pod.tmpl, in the first case it can be included as is. In the second case I need to indent the entire contents so it becomes member of service

{{ if (eq .Case "pod")
  # NO indenting
  {{ template "pod" }}
{{ end }}

{{ if (eq .Case "service")
  service:
    # need to indent! so contents become members of service:
    {{ template "pod" }}
{{ end }}
Guillaume Racicot
  • 32,627
  • 7
  • 60
  • 103
dirtbikejunkie
  • 431
  • 5
  • 4
  • 1
    Why not use a YAML parser instead of a generic text template engine? It seems to me you're using the wrong tool for the job here. That being said, if you don't want spaces then ... don't type them? – Martin Tournoij May 06 '17 at 16:15
  • There is an issue right now https://github.com/hairyhenderson/gomplate/issues/290#issuecomment-382597288 – Nick Roz Aug 21 '18 at 22:04

4 Answers4

4

@Giovanni Bassi's answer only works in helm. The include function is defined in helm here.

Combining with indent from sprig from @tmirks answer, you get:

func renderTemplate(templatePath string, vars interface{}, out io.Writer) error {
    t := template.New(filepath.Base(templatePath))
    var funcMap template.FuncMap = map[string]interface{}{}
    // copied from: https://github.com/helm/helm/blob/8648ccf5d35d682dcd5f7a9c2082f0aaf071e817/pkg/engine/engine.go#L147-L154
    funcMap["include"] = func(name string, data interface{}) (string, error) {
        buf := bytes.NewBuffer(nil)
        if err := t.ExecuteTemplate(buf, name, data); err != nil {
            return "", err
        }
        return buf.String(), nil
    }

    t, err := t.Funcs(sprig.TxtFuncMap()).Funcs(funcMap).ParseFiles(templatePath)
    if err != nil {
        return err
    }
    err = t.Execute(out, &vars)
    if err != nil {
        return err
    }
    return nil
}

then

{{ include "pod" | indent 4 }}
s12chung
  • 1,487
  • 1
  • 11
  • 28
1

You should be able to pipe the output of your template to the indent function available in the sprig package:

{{ if (eq .Case "service")
  service:
    # need to indent! so contents become members of service:
{{ template "pod" | indent 4 }}
{{ end }}
Flimzy
  • 60,850
  • 13
  • 104
  • 147
tmirks
  • 453
  • 5
  • 11
1

You can indent freely, but you need to use include instead of template, as template is an action and can't be passed to other functions:

{{ include "pod" | indent 4 }}

See the Helm guide for more info.

Giovanni Bassi
  • 662
  • 5
  • 15
0

I found I can work around the issue if I indent the contents of pod.tmpl and then indent the top portion to align as below

{{ if (eq $template "pod.tmpl") }}
    apiVersion: v1
    kind: Pod
{{ end }}
{{ if (eq $template "deployment.tmpl") }}
apiVersion: v1
kind: Deployment
metadata:
  name: {{ .Name }}-deployment
spec:
  replicas: {{ .Scale }}
  template:
{{template "pod" dict "Version" $version "Domain" $domain "Image" $image "ImageDerived" $imageDerived "Service" . }}
dirtbikejunkie
  • 431
  • 5
  • 4