Search code examples
goyamlkubernetes-helmunmarshallinggo-templates

Is there a way to validate/parse a YAML file with go-template variables in it?


I have a "YAML" file. And I want to validate it before I render the go-template variables in it. For example:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

The typical YAML parser doesn't work here, as it will parse { as the start of a map.

err := yaml.Unmarshal(data, &Content)
// Failed to parse the provided YAML: yaml: line 4: did not find expected key

I wonder if there is any package that can help me do this? I've searched online for a while but have no luck. Thanks for any help!


Solution

  • It's not just the YAML parser complaining: that actually is invalid YAML (because the {...} is inline mapping syntax). That looks like it comes from the Kubernetes Helm deployment tool, and some routine-but-interesting uses really actually require rendering the YAML.

    In practice what you probably want is to use the helm template command to render a chart to multi-document YAML, and then run a YAML validator on that. It doesn't seem to be documented, but Helm version 3 will actually do this validation on its own (Helm 2 doesn't) so if your chart produces invalid YAML you'll get an error at that point.

    The way Helm works, it interprets this "YAML" file as a plain text file and applies Go text/template templating to it, and then reads it back as YAML. To some extent you could make this valid YAML by quoting strings yourself:

    name: "{{ .Release.Name }}-configmap"
    

    But there's some fairly common constructs where this will actually break the generated YAML. For example, the helm create template generates

    {{/* _helpers.tpl */}}
    {{- define "<CHARTNAME>.labels" -}}
    helm.sh/chart: {{ include "<CHARTNAME>.chart" . }}
    {{- end -}}
    
    metadata:
      name: {{ include "<CHARTNAME>.fullname" . }}
      labels:
        {{- include "<CHARTNAME>.labels" . | nindent 4 }}
    

    and no amount of quoting will make this valid YAML. It's very possible to put something into the "labels" helper template that's not valid in a YAML mapping context and you want to catch that in your validation stage.