92 lines
2.1 KiB
Go
92 lines
2.1 KiB
Go
|
package snmp_trap
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"bytes"
|
||
|
"errors"
|
||
|
"os/exec"
|
||
|
"strings"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"github.com/influxdata/telegraf/config"
|
||
|
"github.com/influxdata/telegraf/internal"
|
||
|
"github.com/influxdata/telegraf/internal/snmp"
|
||
|
)
|
||
|
|
||
|
type execer func(config.Duration, string, ...string) ([]byte, error)
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
type netsnmpTranslator struct {
|
||
|
// Each translator has its own cache and each plugin instance has
|
||
|
// its own translator. This is different than the snmp plugin
|
||
|
// which has one global cache.
|
||
|
//
|
||
|
// We may want to change snmp_trap to
|
||
|
// have a global cache although it's not as important for
|
||
|
// snmp_trap to be global because there is usually only one
|
||
|
// instance, while it's common to configure many snmp instances.
|
||
|
cacheLock sync.Mutex
|
||
|
cache map[string]snmp.MibEntry
|
||
|
execCmd execer
|
||
|
timeout config.Duration
|
||
|
}
|
||
|
|
||
|
func (s *netsnmpTranslator) lookup(oid string) (e snmp.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 *netsnmpTranslator) snmptranslate(oid string) (e snmp.MibEntry, err error) {
|
||
|
var out []byte
|
||
|
out, err = s.execCmd(s.timeout, "snmptranslate", "-Td", "-Ob", "-m", "all", 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()
|
||
|
|
||
|
i := strings.Index(e.OidText, "::")
|
||
|
if i == -1 {
|
||
|
return e, errors.New("not found")
|
||
|
}
|
||
|
e.MibName = e.OidText[:i]
|
||
|
e.OidText = e.OidText[i+2:]
|
||
|
return e, nil
|
||
|
}
|
||
|
|
||
|
func newNetsnmpTranslator(timeout config.Duration) *netsnmpTranslator {
|
||
|
return &netsnmpTranslator{
|
||
|
execCmd: realExecCmd,
|
||
|
cache: make(map[string]snmp.MibEntry),
|
||
|
timeout: timeout,
|
||
|
}
|
||
|
}
|