Fix snmp tools output parsing when they contain Windows eols (#3396)

This commit is contained in:
Daniel Nelson 2017-11-20 16:48:30 -08:00 committed by GitHub
parent 662e2df779
commit f9ded8fdd8
1 changed files with 48 additions and 48 deletions

View File

@ -1,6 +1,7 @@
package snmp
import (
"bufio"
"bytes"
"fmt"
"math"
@ -88,7 +89,7 @@ func execCmd(arg0 string, args ...string) ([]byte, error) {
if err, ok := err.(*exec.ExitError); ok {
return nil, NestedError{
Err: err,
NestedErr: fmt.Errorf("%s", bytes.TrimRight(err.Stderr, "\n")),
NestedErr: fmt.Errorf("%s", bytes.TrimRight(err.Stderr, "\r\n")),
}
}
return nil, err
@ -856,24 +857,26 @@ func snmpTableCall(oid string) (mibName string, oidNum string, oidText string, f
tagOids := map[string]struct{}{}
// We have to guess that the "entry" oid is `oid+".1"`. snmptable and snmptranslate don't seem to have a way to provide the info.
if out, err := execCmd("snmptranslate", "-Td", oidFullName+".1"); err == nil {
lines := bytes.Split(out, []byte{'\n'})
for _, line := range lines {
if !bytes.HasPrefix(line, []byte(" INDEX")) {
scanner := bufio.NewScanner(bytes.NewBuffer(out))
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, " INDEX") {
continue
}
i := bytes.Index(line, []byte("{ "))
i := strings.Index(line, "{ ")
if i == -1 { // parse error
continue
}
line = line[i+2:]
i = bytes.Index(line, []byte(" }"))
i = strings.Index(line, " }")
if i == -1 { // parse error
continue
}
line = line[:i]
for _, col := range bytes.Split(line, []byte(", ")) {
tagOids[mibPrefix+string(col)] = struct{}{}
for _, col := range strings.Split(line, ", ") {
tagOids[mibPrefix+col] = struct{}{}
}
}
}
@ -883,15 +886,16 @@ func snmpTableCall(oid string) (mibName string, oidNum string, oidText string, f
if err != nil {
return "", "", "", nil, Errorf(err, "getting table columns")
}
cols := bytes.SplitN(out, []byte{'\n'}, 2)[0]
scanner := bufio.NewScanner(bytes.NewBuffer(out))
scanner.Scan()
cols := scanner.Text()
if len(cols) == 0 {
return "", "", "", nil, fmt.Errorf("could not find any columns in table")
}
for _, col := range bytes.Split(cols, []byte{' '}) {
for _, col := range strings.Split(cols, " ") {
if len(col) == 0 {
continue
}
col := string(col)
_, isTag := tagOids[mibPrefix+col]
fields = append(fields, Field{Name: col, Oid: mibPrefix + col, IsTag: isTag})
}
@ -953,18 +957,18 @@ func snmpTranslateCall(oid string) (mibName string, oidNum string, oidText strin
return "", "", "", "", err
}
bb := bytes.NewBuffer(out)
oidText, err = bb.ReadString('\n')
if err != nil {
return "", "", "", "", Errorf(err, "getting OID text")
scanner := bufio.NewScanner(bytes.NewBuffer(out))
ok := scanner.Scan()
if !ok && scanner.Err() != nil {
return "", "", "", "", Errorf(scanner.Err(), "getting OID text")
}
oidText = oidText[:len(oidText)-1]
oidText = scanner.Text()
i := strings.Index(oidText, "::")
if i == -1 {
// was not found in MIB.
if bytes.Index(bb.Bytes(), []byte(" [TRUNCATED]")) >= 0 {
if bytes.Contains(out, []byte("[TRUNCATED]")) {
return "", oid, oid, "", nil
}
// not truncated, but not fully found. We still need to parse out numeric OID, so keep going
@ -974,28 +978,21 @@ func snmpTranslateCall(oid string) (mibName string, oidNum string, oidText strin
oidText = oidText[i+2:]
}
if i := bytes.Index(bb.Bytes(), []byte(" -- TEXTUAL CONVENTION ")); i != -1 {
bb.Next(i + len(" -- TEXTUAL CONVENTION "))
tc, err := bb.ReadString('\n')
if err != nil {
return "", "", "", "", Errorf(err, "getting textual convention")
}
tc = tc[:len(tc)-1]
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, " -- TEXTUAL CONVENTION ") {
tc := strings.TrimPrefix(line, " -- TEXTUAL CONVENTION ")
switch tc {
case "MacAddress", "PhysAddress":
conversion = "hwaddr"
case "InetAddressIPv4", "InetAddressIPv6", "InetAddress":
conversion = "ipaddr"
}
}
} else if strings.HasPrefix(line, "::= { ") {
objs := strings.TrimPrefix(line, "::= { ")
objs = strings.TrimSuffix(objs, " }")
i = bytes.Index(bb.Bytes(), []byte("::= { "))
bb.Next(i + len("::= { "))
objs, err := bb.ReadString('}')
if err != nil {
return "", "", "", "", Errorf(err, "getting numeric oid")
}
objs = objs[:len(objs)-1]
for _, obj := range strings.Split(objs, " ") {
if len(obj) == 0 {
continue
@ -1007,6 +1004,9 @@ func snmpTranslateCall(oid string) (mibName string, oidNum string, oidText strin
oidNum += "." + obj
}
}
break
}
}
return mibName, oidNum, oidText, conversion, nil
}