Replace variables in yaml template

1. yaml complex syntax

The two most important things in YAML, you must master these two kinds of data and be familiar with how to convert to json

  • Object: a collection of key-value pairs, also known as mapping (mapping) / hash (hashes) / dictionary (dictionary, the entire yaml file itself is an object. Write a resource.yaml file
    about prometheus below
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  creationTimestamp: null
  labels:
    prometheus: k8s
    role: alert-rules
  name: prometheus-template-rules
  namespace: monitoring

Converted to json object is:

{
    
    
  "apiVersion": "monitoring.coreos.com/v1",
  "kind": "PrometheusRule",
  "metadata": {
    
    
    "creationTimestamp": null,
    "labels": {
    
    
      "prometheus": "k8s",
      "role": "alert-rules"
    },
    "name": "prometheus-template-rules",
    "namespace": "monitoring"
  }
}

It is worth noting that there are multiple key and value key-value pairs in an object like metadata, so you must be familiar with what this indentation represents. In fact, it doesn't matter how many spaces are indented. The main thing is that things in the same position must be aligned, just like creationTimestamp and labels, name, and namespace are key-value pairs in matadata, and must be aligned.

  • Array: A set of values ​​arranged in order, also known as a sequence (sequence) / list (list)
spec:
  groups:
    - name: kkdd
      rule:
        - alert: ingressAlert
          for: 1s
          expr: xioad
          labels:
            nodename: '{
    
    {.NodeName}}'
          annotations:
            containerID: label.name
            podName: label.pod
        - alert: egressAlert
          for: 1s
          expr: xxxxadad
          

The result of converting to json, the result is that groups is a list, which contains an object, and rule is also a list, but there are 2 objects in it.

{
    
    
  "spec": {
    
    
    "groups": [
    
      {
    
    
        "name": "kkdd",
        "rule": [
        
          {
    
    
            "alert": "ingressAlert",
            "for": "1s",
            "expr": "xioad",
            "labels": {
    
    
              "nodename": "{
    
    {.NodeName}}"
            },
            "annotations": {
    
    
              "containerID": "label.name",
              "podName": "label.pod"
            }
          },
          
          {
    
    
            "alert": "egressAlert",
            "for": "1s",
            "expr": "xxxxadad"
          }
          
        ]
      }
      
    ]
    
  }
  
}

2. Replace variables in the template

The main purpose is to replace the variable template.yaml with variables to generate the result yaml.
Solution: golang provides the text/template package, which we can use to render templates.
Step 1: Prepare the template, I created a template.yaml in this directory

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  creationTimestamp: null
  labels:
    prometheus: k8s
    role: alert-rules
  name: prometheus-template-rules
  namespace: monitoring
spec:
  groups:
  {
    
    {
    
    - range .Resources}} ###这里主要是for循环一个结构体
  - name: {
    
    {
    
    .NodeName}}-resources-limit-{
    
    {
    
    .ResourceValue}}unit.rules
    rules:
    - alert: ingressAlert {
    
    {
    
    "{
    
    {.value}} "}} {
    
    {
    
    "$"}}
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="{
    
    {
    
    .ResourceValue}}"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{
    
    namespace="default",node="{
    
    {
    
    .NodeName}}"}[5m])) BY (instance, pod) / 128) > 200 * {
    
    {
    
    .ResourceValue}}
      labels: 
        nodename: "{
    
    {.NodeName}}"
      annotations:
        containerID: "{
    
    {
    
    "{
    
    { $labels.name }}"}}" # notifications sended with the messages
        podName: "{
    
    {
    
    "{
    
    { $labels.pod }}"}}"
    - alert: egressAlert 
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="{
    
    {
    
    .ResourceValue}}"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{
    
    namespace="default",node="{
    
    {
    
    .NodeName}}"}[5m])) BY (instance, pod) / 128) > 200 * {
    
    {
    
    .ResourceValue}}
      labels: 
        nodename: "{
    
    {.NodeName}}"
      annotations:
        containerID: "{
    
    {
    
    "{
    
    { $labels.name }}"}}" # notifications sended with the messages
        podName: "{
    
    {
    
    "{
    
    { $labels.pod }} "}}"
  {
    
    {
    
    - end }}

Step 2: Write go code to replace;
the part of Golang code that needs to loop uses the syntax { {- range .Resources}}, { {- end}}. The parts wrapped in it can be generated repeatedly, and are stitched together in one file.
Golang code:

package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
	"text/template"
)
type DeployTemplDatas struct {
    
    
	Resources []DeployTemplData
}
type DeployTemplData struct {
    
    
	NodeName string
	ResourceValue int
}

//主入口函数
func main() {
    
    
	nodeNms := []string{
    
    "nodeName1","nodeName2"}
	resourceVals := []int{
    
    111,2}
	dd := generateObjects(nodeNms,resourceVals)
	ParseFiles(nodeNms,resourceVals)
}
func ParseFiles(nodeNms []string,resourceVals []int ){
    
    
	t := template.New("test")
	t = template.Must(template.ParseFiles("./template.yaml"))
	
	data := generateObjects(nodeNms,resourceVals)
	userFile := "result.yaml"
    fout, err := os.Create(userFile) //create the file in the directory which the present file belongs to 
	if err != nil {
    
    
        fmt.Println(userFile, err)
        return
    }
	// 传入一个DeployTemplData结构体切片
	t.Execute(fout, data)

}
// @title    generateObjects
// @description   to generate the objects with the different nodeName and resourceValue
//生成len(nodeNames)*len(resourceVals)个对象
func generateObjects(nodeNames []string,resourceVals []int) DeployTemplDatas{
    
    
	datas := make([]DeployTemplData,0,len(nodeNames)*len(resourceVals))
	for i :=0;i<len(nodeNames);i++{
    
    
		for j:=0;j<len(resourceVals);j++{
    
    
			data := DeployTemplData{
    
    
				NodeName: nodeNames[i],
				ResourceValue: resourceVals[j],
			}
			datas = append(datas, data)
		}

	}
	temldatas := DeployTemplDatas{
    
    
		Resources: datas,
	}
	return temldatas
}

The third step is to get the result:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  creationTimestamp: null
  labels:
    prometheus: k8s
    role: alert-rules
  name: prometheus-template-rules
  namespace: monitoring
spec:
  groups:
  - name: nodeName1-resources-limit-1unit.rules
    rules:
    - alert: ingressAlert {
    
    {
    
    .value}}  $
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="1"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{
    
    namespace="default",node="nodeName1"}[5m])) BY (instance, pod) / 128) > 200 * 1
      labels: 
        nodename: "nodeName1"
      annotations:
        containerID: "{
    
    { $labels.name }}" # notifications sended with the messages
        podName: "{
    
    { $labels.pod }}"
    - alert: egressAlert 
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="1"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{
    
    namespace="default",node="nodeName1"}[5m])) BY (instance, pod) / 128) > 200 * 1
      labels: 
        nodename: "nodeName1"
      annotations:
        containerID: "{
    
    { $labels.name }}" # notifications sended with the messages
        podName: "{
    
    { $labels.pod }} "
  - name: nodeName1-resources-limit-2unit.rules
    rules:
    - alert: ingressAlert {
    
    {
    
    .value}}  $
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="2"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{
    
    namespace="default",node="nodeName1"}[5m])) BY (instance, pod) / 128) > 200 * 2
      labels: 
        nodename: "nodeName1"
      annotations:
        containerID: "{
    
    { $labels.name }}" # notifications sended with the messages
        podName: "{
    
    { $labels.pod }}"
    - alert: egressAlert 
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="2"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{
    
    namespace="default",node="nodeName1"}[5m])) BY (instance, pod) / 128) > 200 * 2
      labels: 
        nodename: "nodeName1"
      annotations:
        containerID: "{
    
    { $labels.name }}" # notifications sended with the messages
        podName: "{
    
    { $labels.pod }} "
  - name: nodeName2-resources-limit-1unit.rules
    rules:
    - alert: ingressAlert {
    
    {
    
    .value}}  $
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="1"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{
    
    namespace="default",node="nodeName2"}[5m])) BY (instance, pod) / 128) > 200 * 1
      labels: 
        nodename: "nodeName2"
      annotations:
        containerID: "{
    
    { $labels.name }}" # notifications sended with the messages
        podName: "{
    
    { $labels.pod }}"
    - alert: egressAlert 
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="1"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{
    
    namespace="default",node="nodeName2"}[5m])) BY (instance, pod) / 128) > 200 * 1
      labels: 
        nodename: "nodeName2"
      annotations:
        containerID: "{
    
    { $labels.name }}" # notifications sended with the messages
        podName: "{
    
    { $labels.pod }} "
  - name: nodeName2-resources-limit-2unit.rules
    rules:
    - alert: ingressAlert {
    
    {
    
    .value}}  $
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="2"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_receive_bytes_total{
    
    namespace="default",node="nodeName2"}[5m])) BY (instance, pod) / 128) > 200 * 2
      labels: 
        nodename: "nodeName2"
      annotations:
        containerID: "{
    
    { $labels.name }}" # notifications sended with the messages
        podName: "{
    
    { $labels.pod }}"
    - alert: egressAlert 
      for: 1s      # status from pending to firing for 1s 
      # expr for test         
      expr: max(kube_pod_labels{
    
    label_unit="2"}) by (pod, label_unit)  * on(pod) group_right(label_unit) (sum(rate(container_network_transmit_bytes_total{
    
    namespace="default",node="nodeName2"}[5m])) BY (instance, pod) / 128) > 200 * 2
      labels: 
        nodename: "nodeName2"
      annotations:
        containerID: "{
    
    { $labels.name }}" # notifications sended with the messages
        podName: "{
    
    { $labels.pod }} "

Parse:

  1. I prepared a slice of resources containing four objects, and then traversed and replaced, generating four na,
  2. What does the - in { {-}} do? You can remove the space that occupies this line. If you don’t add this -, then range will occupy one line, that is, the result will be an empty line in the range line.
  3. Resources is an array or a slice. The dot "." in the loop represents each object in the current loop array, and the fields in the object can be represented by .XXX.
  4. If we want to replace safely, we don’t want { {.value}} to be replaced, ignore and skip this replacement, and output { {.value}} as it is, the method is: { { " { { {.value}} "}}; For details, you can see the above example, the dollar sign, and the dot are all involved.

3. Summary

  • The key to complete the function is to know that the loop of Golang's template uses { {range.xxx}}{ {end}} syntax; how to write the original output in the template.
  • To expand, the template can also have other functions such as expressions, conditional judgments, etc. For details, click —> Li Wenzhou's blog

Guess you like

Origin blog.csdn.net/liuzr_/article/details/127790435