确保在使用text/template包执行YAML时,类型是一个列表。

huangapple go评论83阅读模式
英文:

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

问题

我正在使用text/template包来动态构建我的k8s清单,我几乎成功地创建了所需的输出。

由于目标类型是YAML,我希望确保生成的.ownerReferences.secrets的类型在YAML中被创建为列表类型,即每个条目前面有一个-

我期望实现的输出是:

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

但是,使用下面的代码尝试后:

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)
	}
}

我能够生成以下输出:

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

但我想确保类型准确,以便被正确的YAML解码器接受。

同时,我也希望对我现有的模板定义进行任何改进。

Playground链接- https://go.dev/play/p/EbxcvGcYr9r

英文:

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

答案1

得分: 2

要使示例模板输出所需节点的YAML序列,只需在子节点前面加上-。例如:

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

然而,text/template没有支持检查正确的YAML语法。如果您需要确保生成的文本是有效的YAML,您需要编写相应的测试。

但是,就像在Go中生成JSON时通常使用结构体和encoding/json一样,使用结构体和gopkg.in/yaml.v3可以生成一致有效的YAML。

英文:

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.

huangapple
  • 本文由 发表于 2022年8月19日 22:49:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/73418582.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定