Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use gosmi for SNMP traps #9307

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ require (
github.com/Shopify/sarama v1.27.2
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
github.com/aerospike/aerospike-client-go v1.27.0
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1004
github.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9
github.com/antchfx/xmlquery v1.3.5
Expand Down Expand Up @@ -112,6 +112,7 @@ require (
github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 // indirect
github.com/signalfx/golib/v3 v3.3.0
github.com/sirupsen/logrus v1.6.0
github.com/sleepinggenius2/gosmi v0.4.2
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
github.com/stretchr/testify v1.7.0
github.com/tbrandon/mbserver v0.0.0-20170611213546-993e1772cc62
Expand Down
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ github.com/aerospike/aerospike-client-go v1.27.0/go.mod h1:zj8LBEnWBDOVEIJt8LvaR
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/go-thrift v0.0.0-20170109061633-7914173639b2/go.mod h1:CxCgO+NdpMdi9SsTlGbc0W+/UNxO3I0AabOEJZ3w61w=
github.com/alecthomas/kong v0.2.1/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
github.com/alecthomas/participle v0.4.1 h1:P2PJWzwrSpuCWXKnzqvw0b0phSfH1kJo4p2HvLynVsI=
github.com/alecthomas/participle v0.4.1/go.mod h1:T8u4bQOSMwrkTWOSyt8/jSFPEnRtd0FKFMjVfYBlqPs=
github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/alecthomas/repr v0.0.0-20210301060118-828286944d6a/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
Expand All @@ -134,6 +140,9 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2c
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1004 h1:YtaYjXmemIMyySUbs0VGFPqsLpsNHf4TW/L6yqpJQ9s=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1004/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4=
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9 h1:FXrPTd8Rdlc94dKccl7KPmdmIbVh/OjelJ8/vgMRzcQ=
github.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9/go.mod h1:eliMa/PW+RDr2QLWRmLH1R1ZA4RInpmvOzDDXtaIZkc=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
Expand Down Expand Up @@ -1005,6 +1014,10 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sleepinggenius2/gosmi v0.4.2 h1:XNK6vNuiODDiDa4MXVdWBHLnyeqorM4ov92WgkBjO7w=
github.com/sleepinggenius2/gosmi v0.4.2/go.mod h1:l8OniPmd3bJzw0MXP2/qh7AhP/e+bTY2CNivIhsnDT0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
Expand Down
95 changes: 30 additions & 65 deletions plugins/inputs/snmp_trap/snmp_trap.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
package snmp_trap

import (
"bufio"
"bytes"
"fmt"
"net"
"os/exec"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/sleepinggenius2/gosmi"
"github.com/sleepinggenius2/gosmi/types"

"github.com/gosnmp/gosnmp"
)

var defaultTimeout = config.Duration(time.Second * 5)

type execer func(config.Duration, string, ...string) ([]byte, error)

type mibEntry struct {
mibName string
oidText string
Expand Down Expand Up @@ -52,11 +50,6 @@ type SnmpTrap struct {
makeHandlerWrapper func(gosnmp.TrapHandlerFunc) gosnmp.TrapHandlerFunc

Log telegraf.Logger `toml:"-"`

cacheLock sync.Mutex
cache map[string]mibEntry

execCmd execer
}

var sampleConfig = `
Expand Down Expand Up @@ -101,6 +94,29 @@ func (s *SnmpTrap) Gather(_ telegraf.Accumulator) error {
}

func init() {
gosmi.Init()
gosmi.AppendPath("/usr/share/snmp/mibs")
root := "/usr/share/snmp/mibs"
var folders []string
folders = append(folders, root)
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if info.Mode()&os.ModeSymlink != 0 {
s, _ := os.Readlink(path)
folders = append(folders, s)
}
return nil
})
for _, folder := range folders {
filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
gosmi.AppendPath(path)
} else if info.Mode()&os.ModeSymlink == 0 {
gosmi.LoadModule(info.Name())
}
return nil
})
}

inputs.Add("snmp_trap", func() telegraf.Input {
return &SnmpTrap{
timeFunc: time.Now,
Expand All @@ -111,23 +127,6 @@ func init() {
})
}

func realExecCmd(timeout config.Duration, arg0 string, args ...string) ([]byte, error) {
cmd := exec.Command(arg0, args...)
var out bytes.Buffer
cmd.Stdout = &out
err := internal.RunTimeout(cmd, time.Duration(timeout))
if err != nil {
return nil, err
}
return out.Bytes(), nil
}

func (s *SnmpTrap) Init() error {
s.cache = map[string]mibEntry{}
s.execCmd = realExecCmd
return nil
}

func (s *SnmpTrap) Start(acc telegraf.Accumulator) error {
s.acc = acc
s.listener = gosnmp.NewTrapListener()
Expand Down Expand Up @@ -367,47 +366,13 @@ func makeTrapHandler(s *SnmpTrap) gosnmp.TrapHandlerFunc {
}

func (s *SnmpTrap) lookup(oid string) (e mibEntry, err error) {
s.cacheLock.Lock()
defer s.cacheLock.Unlock()
var ok bool
if e, ok = s.cache[oid]; !ok {
// cache miss. exec snmptranslate
e, err = s.snmptranslate(oid)
if err == nil {
s.cache[oid] = e
}
return e, err
}
return e, nil
}

func (s *SnmpTrap) clear() {
s.cacheLock.Lock()
defer s.cacheLock.Unlock()
s.cache = map[string]mibEntry{}
}

func (s *SnmpTrap) load(oid string, e mibEntry) {
s.cacheLock.Lock()
defer s.cacheLock.Unlock()
s.cache[oid] = e
}

func (s *SnmpTrap) snmptranslate(oid string) (e mibEntry, err error) {
var out []byte
out, err = s.execCmd(s.Timeout, "snmptranslate", "-Td", "-Ob", "-m", "all", oid)

var node gosmi.SmiNode
node, err = gosmi.GetNodeByOID(types.OidMustFromString(oid))
if err != nil {
return e, err
}

scanner := bufio.NewScanner(bytes.NewBuffer(out))
ok := scanner.Scan()
if err = scanner.Err(); !ok && err != nil {
return e, err
}

e.oidText = scanner.Text()
e.oidText = node.RenderQualified()

i := strings.Index(e.oidText, "::")
if i == -1 {
Expand Down
68 changes: 6 additions & 62 deletions plugins/inputs/snmp_trap/snmp_trap_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package snmp_trap

import (
"fmt"
"net"
"strconv"
"strings"
Expand All @@ -17,29 +16,6 @@ import (
"github.com/stretchr/testify/require"
)

func TestLoad(t *testing.T) {
s := &SnmpTrap{}
require.Nil(t, s.Init())

defer s.clear()
s.load(
".1.3.6.1.6.3.1.1.5.1",
mibEntry{
"SNMPv2-MIB",
"coldStart",
},
)

e, err := s.lookup(".1.3.6.1.6.3.1.1.5.1")
require.NoError(t, err)
require.Equal(t, "SNMPv2-MIB", e.mibName)
require.Equal(t, "coldStart", e.oidText)
}

func fakeExecCmd(_ config.Duration, x string, y ...string) ([]byte, error) {
return nil, fmt.Errorf("mock " + x + " " + strings.Join(y, " "))
}

func newMsgFlagsV3(secLevel string) gosnmp.SnmpV3MsgFlags {
var msgFlags gosnmp.SnmpV3MsgFlags
switch strings.ToLower(secLevel) {
Expand Down Expand Up @@ -242,30 +218,6 @@ func TestReceiveTrap(t *testing.T) {
),
},
},
//Check that we're not running snmptranslate to look up oids
//when we shouldn't be. This sends and receives a valid trap
//but metric production should fail because the oids aren't in
//the cache and oid lookup is intentionally mocked to fail.
{
name: "missing oid",
version: gosnmp.Version2c,
trap: gosnmp.SnmpTrap{
Variables: []gosnmp.SnmpPDU{
{
Name: ".1.3.6.1.2.1.1.3.0",
Type: gosnmp.TimeTicks,
Value: now,
},
{
Name: ".1.3.6.1.6.3.1.1.4.1.0", // SNMPv2-MIB::snmpTrapOID.0
Type: gosnmp.ObjectIdentifier,
Value: ".1.3.6.1.6.3.1.1.5.1", // coldStart
},
},
},
entries: []entry{}, //nothing in cache
metrics: []telegraf.Metric{},
},
//v1 enterprise specific trap
{
name: "v1 trap enterprise",
Expand Down Expand Up @@ -305,16 +257,16 @@ func TestReceiveTrap(t *testing.T) {
"snmp_trap", // name
map[string]string{ // tags
"oid": ".1.2.3.0.55",
"name": "enterpriseOID",
"mib": "enterpriseMIB",
"name": "iso",
"mib": "<well-known>",
"version": "1",
"source": "127.0.0.1",
"agent_address": "10.20.30.40",
"community": "public",
},
map[string]interface{}{ // fields
"sysUpTimeInstance": uint(now),
"valueOID": "payload",
"iso": "payload",
},
fakeTime,
),
Expand Down Expand Up @@ -359,16 +311,16 @@ func TestReceiveTrap(t *testing.T) {
"snmp_trap", // name
map[string]string{ // tags
"oid": ".1.3.6.1.6.3.1.1.5.1",
"name": "coldStartOID",
"mib": "coldStartMIB",
"name": "coldStart",
"mib": "SNMPv2-MIB",
"version": "1",
"source": "127.0.0.1",
"agent_address": "10.20.30.40",
"community": "public",
},
map[string]interface{}{ // fields
"sysUpTimeInstance": uint(now),
"valueOID": "payload",
"iso": "payload",
},
fakeTime,
),
Expand Down Expand Up @@ -1293,19 +1245,11 @@ func TestReceiveTrap(t *testing.T) {
PrivProtocol: tt.privProto,
PrivPassword: tt.privPass,
}
require.Nil(t, s.Init())
// Don't look up oid with snmptranslate.
s.execCmd = fakeExecCmd
var acc testutil.Accumulator
require.Nil(t, s.Start(&acc))
defer s.Stop()

// Preload the cache with the oids we'll use in this test
// so snmptranslate and mibs don't need to be installed.
for _, entry := range tt.entries {
s.load(entry.oid, entry.e)
}

var goSNMP gosnmp.GoSNMP
if tt.version == gosnmp.Version3 {
msgFlags := newMsgFlagsV3(tt.secLevel)
Expand Down