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