appending to YAML file using go lang
I writing a golang program which append rule to the file as mentioned below Required format:
customRules:
custom-rules.yaml: |-
- rule: Pod Created in Kube Namespace
append: true
condition: and (k8s_audit_never_true)
source: k8s_audit
- rule: Create files below dev
append: true
condition: and (never_true)
source: syscall
I wrote a go program which failing to be in the above format I can't get what Iam missing.
package main
import (
"fmt"
"io/ioutil"
"log"
"gopkg.in/yaml.v2"
)
type AutoGenerated struct {
CustomRules CustomRules `yaml:"customRules"`
}
type CustomRulesYaml struct {
Rule string `yaml:"rule"`
Append bool `yaml:"append"`
Condition string `yaml:"condition"`
Source string `yaml:"source"`
}
type CustomRules struct {
CustomRulesYaml []CustomRulesYaml `yaml:"custom-rules.yaml"`
}
func main() {
// yfile, err := ioutil.ReadFile("/home/revaa/falco/custom_rules.yaml")
// if err != nil {
// log.Fatal(err)
// }
c1 := CustomRulesYaml{"K8s serviceaccount created", false, "(never_true)", "k8s-audit"}
c2 := CustomRulesYaml{"k8s service created", false, "never_true", "k8s-audit"}
c := []CustomRulesYaml{c1, c2}
c3 := CustomRules{c}
data := AutoGenerated{c3}
check, err := yaml.Marshal(&data)
if err != nil {
log.Fatal(err)
}
err2 := ioutil.WriteFile("/home/revaa/falco/custom_rules.yaml", check, 0)
if err2 != nil {
log.Fatal(err2)
}
fmt.Println("data written")
}
Here is my go code, on running the program the YAML is not getting appended in the above format. The values are appended as below instead.
customRules:
custom-rules.yaml:
- rule: K8s serviceaccount created
append: false
condition: (never_true)
source: k8s-audit
- rule: k8s service created
append: false
condition: never_true
source: k8s-audit
Why Iam not getting the YAML file in the required format?
Solution 1:
Your required input format represents the following YAML structure:
- There is a dictionary with one key-value pair.
- The key is
customRules
. - The value is a dictionary.
- The key is
The dictionary stored in the value above has one entry:
- The key is
custom-rules.yaml
. - The value is a string.
The string stored in the value above is:
"- rule: Pod Created in Kube Namespace\n append: true\n condition: and (k8s_audit_never_true)\n source: k8s_audit\n- rule: Create files below dev\n append: true\n condition: and (never_true)\n source: syscall"
That is, this is not a list type. It's a single string.
Now, the fact is that this single string is valid—albeit slightly dodgy—YAML, and if read, it will produce a list (a slice, in Go) of 2 elements, each of which is a dictionary (generally corresponding to a map or struct type in Go).
Your code is close to right, then, if you really do need this. Instead of wrapping the []CustomRulesYaml
in a type, you need to marshal twice. Here's a variant of your code on the Go Playground whose output is:
custom-rules.yaml: |
- rule: K8s serviceaccount created
append: false
condition: (never_true)
source: k8s-audit
- rule: k8s service created
append: false
condition: never_true
source: k8s-audit
Now, note that this output has a pipe symbol |
without a suffix hyphen -
. That's because the marshaled string, string(asBytes)
, ends with a newline. It probably should end with a newline, which is why yaml.Marshal
produced one. But your sample input doesn't end with a newline, which is why your sample input has |-
instead of just |
: the -
means "don't include that newline".
To get that from your existing code, you will have to strip off the newline, e.g., add:
asBytes = asBytes[0:len(asBytes)-1] // delete trailing newline
before building the string in c3
and marshaling it.