fix SNMPv1 walks failing due to unsupported GETBULK
use GETNEXT-based WalkAll for v1 devices instead of BulkWalkAll
This commit is contained in:
parent
01cd109d10
commit
92f7c2ed85
2 changed files with 96 additions and 4 deletions
10
snmp.go
10
snmp.go
|
|
@ -13,6 +13,7 @@ import (
|
||||||
// snmpQuerier abstracts SNMP operations for testability.
|
// snmpQuerier abstracts SNMP operations for testability.
|
||||||
type snmpQuerier interface {
|
type snmpQuerier interface {
|
||||||
Get(oids []string) (*gosnmp.SnmpPacket, error)
|
Get(oids []string) (*gosnmp.SnmpPacket, error)
|
||||||
|
WalkAll(rootOid string) ([]gosnmp.SnmpPDU, error)
|
||||||
BulkWalkAll(rootOid string) ([]gosnmp.SnmpPDU, error)
|
BulkWalkAll(rootOid string) ([]gosnmp.SnmpPDU, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,8 +60,15 @@ func executeSnmpJob(job *pb.AgentJob, resultCh chan<- *pb.SnmpResult) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case pb.QueryType_WALK:
|
case pb.QueryType_WALK:
|
||||||
|
// SNMPv1 doesn't support GETBULK, use GETNEXT-based WalkAll instead
|
||||||
|
useV1Walk := dev.Version == "1" || dev.Version == "v1"
|
||||||
for _, baseOID := range q.Oids {
|
for _, baseOID := range q.Oids {
|
||||||
results, err := conn.BulkWalkAll(baseOID)
|
var results []gosnmp.SnmpPDU
|
||||||
|
if useV1Walk {
|
||||||
|
results, err = conn.WalkAll(baseOID)
|
||||||
|
} else {
|
||||||
|
results, err = conn.BulkWalkAll(baseOID)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Warn("snmp walk failed", "device", dev.Ip, "oid", baseOID, "error", err)
|
slog.Warn("snmp walk failed", "device", dev.Ip, "oid", baseOID, "error", err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
90
snmp_test.go
90
snmp_test.go
|
|
@ -271,16 +271,28 @@ func TestSnmpDialDefault(t *testing.T) {
|
||||||
|
|
||||||
// mockSnmpQuerier implements snmpQuerier for testing.
|
// mockSnmpQuerier implements snmpQuerier for testing.
|
||||||
type mockSnmpQuerier struct {
|
type mockSnmpQuerier struct {
|
||||||
getFunc func(oids []string) (*gosnmp.SnmpPacket, error)
|
getFunc func(oids []string) (*gosnmp.SnmpPacket, error)
|
||||||
walkFunc func(rootOid string) ([]gosnmp.SnmpPDU, error)
|
walkFunc func(rootOid string) ([]gosnmp.SnmpPDU, error)
|
||||||
closeCalled bool
|
bulkWalkFunc func(rootOid string) ([]gosnmp.SnmpPDU, error)
|
||||||
|
closeCalled bool
|
||||||
|
walkAllCalled bool
|
||||||
|
bulkWalkCalled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockSnmpQuerier) Get(oids []string) (*gosnmp.SnmpPacket, error) {
|
func (m *mockSnmpQuerier) Get(oids []string) (*gosnmp.SnmpPacket, error) {
|
||||||
return m.getFunc(oids)
|
return m.getFunc(oids)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockSnmpQuerier) WalkAll(rootOid string) ([]gosnmp.SnmpPDU, error) {
|
||||||
|
m.walkAllCalled = true
|
||||||
|
return m.walkFunc(rootOid)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mockSnmpQuerier) BulkWalkAll(rootOid string) ([]gosnmp.SnmpPDU, error) {
|
func (m *mockSnmpQuerier) BulkWalkAll(rootOid string) ([]gosnmp.SnmpPDU, error) {
|
||||||
|
m.bulkWalkCalled = true
|
||||||
|
if m.bulkWalkFunc != nil {
|
||||||
|
return m.bulkWalkFunc(rootOid)
|
||||||
|
}
|
||||||
return m.walkFunc(rootOid)
|
return m.walkFunc(rootOid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -500,6 +512,78 @@ func TestExecuteSnmpJob(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("WALK v1 uses WalkAll", func(t *testing.T) {
|
||||||
|
orig := snmpDial
|
||||||
|
defer func() { snmpDial = orig }()
|
||||||
|
|
||||||
|
mock := &mockSnmpQuerier{
|
||||||
|
walkFunc: func(rootOid string) ([]gosnmp.SnmpPDU, error) {
|
||||||
|
return []gosnmp.SnmpPDU{
|
||||||
|
{Name: ".1.3.6.1.2.1.2.2.1.1.1", Type: gosnmp.Integer, Value: 1},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
snmpDial = func(dev *pb.SnmpDevice) (snmpQuerier, func(), error) {
|
||||||
|
return mock, func() {}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan *pb.SnmpResult, 1)
|
||||||
|
executeSnmpJob(&pb.AgentJob{
|
||||||
|
JobId: "1",
|
||||||
|
SnmpDevice: &pb.SnmpDevice{Ip: "10.0.0.1", Version: "1"},
|
||||||
|
Queries: []*pb.SnmpQuery{
|
||||||
|
{QueryType: pb.QueryType_WALK, Oids: []string{".1.3.6.1.2.1.2.2.1.1"}},
|
||||||
|
},
|
||||||
|
}, ch)
|
||||||
|
|
||||||
|
result := <-ch
|
||||||
|
if len(result.OidValues) != 1 {
|
||||||
|
t.Errorf("got %d oid values, want 1", len(result.OidValues))
|
||||||
|
}
|
||||||
|
if !mock.walkAllCalled {
|
||||||
|
t.Error("expected WalkAll to be called for v1")
|
||||||
|
}
|
||||||
|
if mock.bulkWalkCalled {
|
||||||
|
t.Error("BulkWalkAll should not be called for v1")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("WALK v2c uses BulkWalkAll", func(t *testing.T) {
|
||||||
|
orig := snmpDial
|
||||||
|
defer func() { snmpDial = orig }()
|
||||||
|
|
||||||
|
mock := &mockSnmpQuerier{
|
||||||
|
walkFunc: func(rootOid string) ([]gosnmp.SnmpPDU, error) {
|
||||||
|
return []gosnmp.SnmpPDU{
|
||||||
|
{Name: ".1.3.6.1.2.1.2.2.1.1.1", Type: gosnmp.Integer, Value: 1},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
snmpDial = func(dev *pb.SnmpDevice) (snmpQuerier, func(), error) {
|
||||||
|
return mock, func() {}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan *pb.SnmpResult, 1)
|
||||||
|
executeSnmpJob(&pb.AgentJob{
|
||||||
|
JobId: "1",
|
||||||
|
SnmpDevice: &pb.SnmpDevice{Ip: "10.0.0.1", Version: "2c"},
|
||||||
|
Queries: []*pb.SnmpQuery{
|
||||||
|
{QueryType: pb.QueryType_WALK, Oids: []string{".1.3.6.1.2.1.2.2.1.1"}},
|
||||||
|
},
|
||||||
|
}, ch)
|
||||||
|
|
||||||
|
result := <-ch
|
||||||
|
if len(result.OidValues) != 1 {
|
||||||
|
t.Errorf("got %d oid values, want 1", len(result.OidValues))
|
||||||
|
}
|
||||||
|
if !mock.bulkWalkCalled {
|
||||||
|
t.Error("expected BulkWalkAll to be called for v2c")
|
||||||
|
}
|
||||||
|
if mock.walkAllCalled {
|
||||||
|
t.Error("WalkAll should not be called for v2c")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("channel full drops", func(t *testing.T) {
|
t.Run("channel full drops", func(t *testing.T) {
|
||||||
orig := snmpDial
|
orig := snmpDial
|
||||||
defer func() { snmpDial = orig }()
|
defer func() { snmpDial = orig }()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue