template之前也使用过,但都是一些最简单的字符串替换,但是从来没有使用过数组的循环遍历.
官方文档在这:https://golang.org/pkg/text/template/ 。 看的云里雾里的
之前做prometheus监控告警的时候为了适配各种类型的告警,把告警表达式模板抽出来了。
avg by(instance,prometheus_replica) (rate(node_cpu_seconds_total{mode = 'system', instance =~ '^{{.host}}.*'}[5m])) * 100
代码简单,expression是PromQL表达式模板,使用{{ 和}}作为定界符,queryMap的key是具体要替换的字符串,比如host,queryMap的value是具体的值,比如10.10.13.2。
func GetQueryPromQlExpr(name, expression string, queryMap map[string]interface{}) string {
tpl := template.Must(template.New(name+"-expr").Delims("{{", "}}").Parse(expression))
var buf bytes.Buffer
err := tpl.Execute(&buf, queryMap)
if err != nil {
klog.Errorf("parse query:%s expression err:%s", name, err.Error())
return ""
}
return buf.String()
}
现在有个需求是给了我一个文件模板,模板里面的内容是动态的,尤其是模板里面还会涉及到数组的使用。
理想效果是这样的:
[masters]
master1.okd.local 10.10.11.1
master2.okd.local 10.10.11.2
master3.okd.local 10.10.11.3
[nodes]
node1.okd.local 10.10.12.1
node2.okd.local 10.10.12.2
node3.okd.local 10.10.12.3
但是前端给到我的是一个master ip的数组,[masters]模块里面的内容具体有多少行,取决于前端传入的master ip数组的大小。
当前给我的数组长度为3,那么就会有3行,同理如果数组长度为10,那么就会生成10行记录。
master后面的数字相当于是数组的索引(从1开始的),在每一行末尾还有一个ip地址。
定义结构体
type Manifest struct {
ClusterDomain string
MasterIps []string
NodeIps []string
}
结构体里面的字段首字母要大写,否则一会儿运行模板的时候无法解析到。
定义字符串模板
ClusterDomain是公共的,要在range里面使用,需要使用$.Var
参考:https://studygolang.com/articles/3071
var manifestTpl = `
[masters]
{{range $index, $value := .MasterIps}}
master{{$index}}.{{$.ClusterDomain}} {{$value}}
{{end}}
[nodes]
{{range $index, $value := .NodeIps}}
master{{$index}}.{{$.ClusterDomain}} {{$value}}
{{end}}
`
循环模板,以及在循环内使用外部变量
func TestTmpl(t *testing.T) {
manifest := Manifest{
ClusterDomain: "okd.local",
MasterIps: []string{"10.10.13.2", "10.10.13.3"},
NodeIps: []string{"10.10.14.2", "10.10.14.3"},
}
manifestTpl, err := template.New("manifest").Parse(manifestTpl)
assert.Equal(t, nil, err)
var buf bytes.Buffer
assert.Equal(t, nil, manifestTpl.Execute(&buf, manifest))
fmt.Println(buf.String())
}
目前这个代码执行出来的结果是下标从0开始。
下标从1开始
如果要让下标从0开始,可以自定义一个inc函数。
funcMap := template.FuncMap{
// The name "inc" is what the function will be called in the template text.
"inc": func(i int) int {
return i + 1
},
}
现在只要模板里面的index都调用inc参数即可实现在原有index基础上加1的效果。
新的模板
var manifestTpl = `
[masters]
{{range $index, $value := .MasterIps}}
master{{inc $index}}.{{$.ClusterDomain}} {{$value}}
{{end}}
[nodes]
{{range $index, $value := .NodeIps}}
master{{inc $index}}.{{$.ClusterDomain}} {{$value}}
{{end}}
`
新的代码
func TestTmpl(t *testing.T) {
manifest := Manifest{
ClusterDomain: "okd.local",
MasterIps: []string{"10.10.13.2", "10.10.13.3"},
NodeIps: []string{"10.10.14.2", "10.10.14.3"},
}
funcMap := template.FuncMap{
// The name "inc" is what the function will be called in the template text.
"inc": func(i int) int {
return i + 1
},
}
manifestTpl, err := template.New("manifest").Funcs(funcMap).Parse(manifestTpl)
assert.Equal(t, nil, err)
var buf bytes.Buffer
assert.Equal(t, nil, manifestTpl.Execute(&buf, manifest))
fmt.Println(buf.String())
}