From f9ded8fdd898dda30881ed530dd0f05768ea7af2 Mon Sep 17 00:00:00 2001 From: Daniel Nelson Date: Mon, 20 Nov 2017 16:48:30 -0800 Subject: [PATCH] Fix snmp tools output parsing when they contain Windows eols (#3396) --- plugins/inputs/snmp/snmp.go | 96 ++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/plugins/inputs/snmp/snmp.go b/plugins/inputs/snmp/snmp.go index c4f66f519..7d3cb7298 100644 --- a/plugins/inputs/snmp/snmp.go +++ b/plugins/inputs/snmp/snmp.go @@ -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,37 +978,33 @@ 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] - switch tc { - case "MacAddress", "PhysAddress": - conversion = "hwaddr" - case "InetAddressIPv4", "InetAddressIPv6", "InetAddress": - conversion = "ipaddr" - } - } + for scanner.Scan() { + line := scanner.Text() - 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 - } - if i := strings.Index(obj, "("); i != -1 { - obj = obj[i+1:] - oidNum += "." + obj[:strings.Index(obj, ")")] - } else { - oidNum += "." + obj + 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, " }") + + for _, obj := range strings.Split(objs, " ") { + if len(obj) == 0 { + continue + } + if i := strings.Index(obj, "("); i != -1 { + obj = obj[i+1:] + oidNum += "." + obj[:strings.Index(obj, ")")] + } else { + oidNum += "." + obj + } + } + break } }