Home > Back-end >  Go yaml how to add new entry to yaml file
Go yaml how to add new entry to yaml file

Time:10-23

I need to add entry to a yaml file from struct value config.Sif["snk_prod"] (I need to fill it on runtime) and try the following , I tried the following but I got an error when filling the struct, any idea?

package main

import "gopkg.in/yaml.v3"

const document = `
spec:
  mec:
    customConfig:
      sif:
        prom_exporter:
          type: prometheus_exporter
        snk_dev:   
          type: sk_hc_logs
          inputs:
            - tesslt
          ep: ${NT}
          dken: ${SN}
`

type YamlObject map[string]any

type CustomConfig struct {
    Sif map[string]interface{} `yaml:"sif,omitempty"`
}

type ecfg struct {
    Type   string   `yaml:"type,omitempty"`
    Inputs []string `yaml:"inputs,omitempty"`
    Ep     string   `yaml:"ep,omitempty"`
    Dken   string   `yaml:"dken,omitempty"`
}

func main() {
    t := CustomConfig{}
    config := &t
   // -------I need to add it as struct values as I got the values on runtime dynamically  
    config.Sif["snk_prod"] = ecfg{
        Type:   "sk_hc_ls",
        Inputs: []string{"tesslt"},
        Ep:     "${NT}",
    }
    yamlBytes, err := yaml.Marshal(t)

    doc := make(YamlObject)
    if err := yaml.Unmarshal([]byte(document), &doc); err != nil {
        panic(err)
    }
    addon := make(YamlObject)
    if err := yaml.Unmarshal(yamlBytes, &addon); err != nil {
        panic(err)
    }
    node := findChild(doc, "spec", "mec", "customConfig", "sif")
    if node == nil {
        panic("Must not happen")
    }

    for key, val := range addon {
        (*node)[key] = val
    }
    outDoc, err := yaml.Marshal(doc)
    if err != nil {
        panic(err)
    }
    println(string(outDoc))
}

func findChild(obj YamlObject, path ...string) *YamlObject {
    if len(path) == 0 {
        return &obj
    }
    key := path[0]
    child, ok := obj[key]
    if !ok {
        return nil
    }
    obj, ok = child.(YamlObject)
    if !ok {
        return nil
    }
    return findChild(obj, path[1:]...)
}

https://go.dev/play/p/6CHsOJPXqpw

After searching I found this answer https://stackoverflow.com/a/74089724/6340176 which is quite similar to mine, the change is the that I need to add it as struct value

at the end I need to add new entry under sif

At the end The output should be like following

spec:
  mec:
    customConfig:
      sif:
        prom_exporter:
          type: prometheus_exporter
        snk_dev:   
          type: sk_hc_logs
          inputs:
            - tesslt
          ep: ${NT}
          dken: ${SN}
        snk_prod:   
          type: sk_hc_ls
          inputs:
            - tesslt
          ep: ${NT}

CodePudding user response:

Replace the creation of the yamlBytes as follows:

    t := make(map[string]interface{})
    t["snk_prod"] = ecfg{
        Type:   "sk_hc_ls",
        Inputs: []string{"tesslt"},
        Ep:     "${NT}",
    }
    yamlBytes, err := yaml.Marshal(t)

Then you will get the expected result.

BTW: The panic is triggered because you are trying to insert a value into an uninitialized map (config.Sif is nil). You could simply create an empty map using, for example, the following line of code before assigning values:

config.Sif = make(map[string]interface{})

but there would be an additional unwanted sif node in the code, e.g. something like this:

    ...
    sif:
        prom_exporter:
            type: prometheus_exporter
        sif:
            snk_prod:
    ...

Therefore, the yaml snippet to be added dynamically should be generated as shown at the beginning.

  • Related