1

I'm unmarshalling a yaml file snmp.yml. and I was wondering if I could get suggestions on creating better structs. This is what I have for now, but I'm guessing the structs I'm creating for Metric is fine but the SNMPyaml needs better restructuring to be fully able to consume the unmarshalled data correctly.

Any suggestions/feedback here is highly appreciated. Thank you in advance!

package system

import (
    "fmt"
    "io/ioutil"
    "log"
    "path/filepath"

    y "gopkg.in/yaml.v2"
)

//SNMPyaml struct
type SNMPyaml struct {
    Metrics Metric `yaml:"metrics"`
}

//Metric exportable
type Metric struct {
    Name string `yaml:"name,omitempty"`
    Oid  string `yaml:"oid"`
    Type string `yaml:"type"`
    Help string `yaml:"help,omitempty"`
}

// Yamlparser 
func Yamlparser() {
    // Read the snmp.yml file
    absPath, _ := filepath.Abs("./app/snmp.yml")
    yamlFile, yamlerror := ioutil.ReadFile(absPath)
    if yamlerror != nil {
        log.Fatalf("ioutil err: %v", yamlerror)
    }

    //Unmarshall

    var c SNMPyaml
    err := y.Unmarshal(yamlFile, &c)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Print(c)

}
  metrics:
  - name: sysStatClientCurConns
    oid: 1.3.6.1.4.1.3375.2.1.1.2.1.8
    type: gauge
    indexes:
      - labelname: sysStatClientCurConns
        type: gauge
  - name: sysClientsslStatCurConns
    oid: 1.3.6.1.4.1.3375.2.1.1.2.9.2
    type: gauge
    indexes:
      - labelname: sysClientsslStatCurConns
        type: gauge
  - name: sysClientSslStatTotNativeConns
    oid: 1.3.6.1.4.1.3375.2.1.1.2.9.6
    type: gauge
    indexes:
      - labelname: sysClientSslStatTotNativeConns
        type: gauge

The error I'm getting for this is:

    2019/07/31 23:25:58 yaml: line 25: mapping values are not allowed in this context
    exit status 1
  • Just a note: You seem to reinvent the wheel a bit, here. As basically, you seem to use a DSL which does pretty much the same as a MIB. I would suggest to rather use something like https://godoc.org/github.com/sleepinggenius2/gosmi and use a more simple YAML file. – Markus W Mahlberg Aug 01 '19 at 07:42

1 Answers1

1

In your input metrics is a sequence (list), so you cannot marshal that into a single Metric. Use a slice: []Metric:

type SNMPyaml struct {
    Metrics []Metric `yaml:"metrics"`
}

Also there is an indexes field, another sequence which you don't have a corresponding field in your Metric struct, and you have an unnecessary Help (at least in the input you provided there is no such field):

type Metric struct {
    Name    string  `yaml:"name,omitempty"`
    Oid     string  `yaml:"oid"`
    Type    string  `yaml:"type"`
    Indexes []Index `yaml:"indexes"`
}

Where indexes can be modeled with this struct:

type Index struct {
    LabelName string `yaml:"labelname"`
    Type      string `yaml:"type"`
}

With these changes it runs, try it on the Go Playground, and produces the following output:

{[{sysStatClientCurConns 1.3.6.1.4.1.3375.2.1.1.2.1.8 gauge [{sysStatClientCurConns gauge}]} {sysClientsslStatCurConns 1.3.6.1.4.1.3375.2.1.1.2.9.2 gauge [{sysClientsslStatCurConns gauge}]} {sysClientSslStatTotNativeConns 1.3.6.1.4.1.3375.2.1.1.2.9.6 gauge [{sysClientSslStatTotNativeConns gauge}]}]}

Also note that there is an online YAML-to-Go converter, where you input your YAML source, and it produces Go data structures modeling your input: https://mengzhuo.github.io/yaml-to-go/

The generated code uses unnamed structs (which is a pain if you have to create values of), but it's a good starting point, and you can easily refactor them to named types. It produces the following model from your YAML input:

type AutoGenerated struct {
    Metrics []struct {
        Name    string `yaml:"name"`
        Oid     string `yaml:"oid"`
        Type    string `yaml:"type"`
        Indexes []struct {
            Labelname string `yaml:"labelname"`
            Type      string `yaml:"type"`
        } `yaml:"indexes"`
    } `yaml:"metrics"`
}
icza
  • 389,944
  • 63
  • 907
  • 827