From b20b81bcf530695ce856b66f12fb7beb95882931 Mon Sep 17 00:00:00 2001 From: Stefan Kurek Date: Thu, 20 Oct 2022 06:21:55 -0400 Subject: [PATCH] [receiver/snmp] SNMP Receiver client refactor (#15347) --- .chloggen/snmpreceiver-client-refactor.yaml | 16 + receiver/snmpreceiver/client.go | 98 ++- receiver/snmpreceiver/client_test.go | 593 +++++++----------- receiver/snmpreceiver/goSNMPWrapper.go | 23 +- .../internal/mocks/goSNMPWrapper.go | 50 +- 5 files changed, 329 insertions(+), 451 deletions(-) create mode 100755 .chloggen/snmpreceiver-client-refactor.yaml diff --git a/.chloggen/snmpreceiver-client-refactor.yaml b/.chloggen/snmpreceiver-client-refactor.yaml new file mode 100755 index 000000000000..5ca4d00e4762 --- /dev/null +++ b/.chloggen/snmpreceiver-client-refactor.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: snmpreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: changes the client of the SNMP metric receiver to only return data in its functions rather than try to process that data + +# One or more tracking issues related to the change +issues: [13409] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: diff --git a/receiver/snmpreceiver/client.go b/receiver/snmpreceiver/client.go index a7787f018ce5..9aa959c455a0 100644 --- a/receiver/snmpreceiver/client.go +++ b/receiver/snmpreceiver/client.go @@ -45,17 +45,14 @@ type snmpData struct { valueType oidDataType } -// processFunc our own function type to better control what data can be passed in -type processFunc func(data snmpData) error - // client is used for retrieving data from a SNMP environment type client interface { // GetScalarData retrieves SNMP scalar data from a list of passed in OIDS, - // then the passed in function is performed on each piece of data - GetScalarData(oids []string, processFn processFunc, scraperErrors *scrapererror.ScrapeErrors) + // then returns the retrieved data + GetScalarData(oids []string, scraperErrors *scrapererror.ScrapeErrors) []snmpData // GetIndexedData retrieves SNMP indexed data from a list of passed in OIDS, - // then the passed in function is performed on each piece of data - GetIndexedData(oids []string, processFn processFunc, scraperErrors *scrapererror.ScrapeErrors) + // then returns the retrieved data + GetIndexedData(oids []string, scraperErrors *scrapererror.ScrapeErrors) []snmpData // Connect makes a connection to the SNMP host Connect() error // Close closes a connection to the SNMP host @@ -201,13 +198,14 @@ func (c *snmpClient) Close() error { return c.client.Close() } -// GetScalarData retrieves scalar metrics from passed in scalar OIDs. The returned data -// is then also passed into the provided function. +// GetScalarData retrieves and returns scalar data from passed in scalar OIDs. // Note: These OIDs must all end in ".0" for the SNMP GET to work correctly -func (c *snmpClient) GetScalarData(oids []string, processFn processFunc, scraperErrors *scrapererror.ScrapeErrors) { +func (c *snmpClient) GetScalarData(oids []string, scraperErrors *scrapererror.ScrapeErrors) []snmpData { + scalarData := []snmpData{} + // Nothing to do if there are no OIDs if len(oids) == 0 { - return + return scalarData } // Group OIDs into chunks based on the max amount allowed in a single SNMP GET @@ -226,7 +224,7 @@ func (c *snmpClient) GetScalarData(oids []string, processFn processFunc, scraper } if err = c.Connect(); err != nil { scraperErrors.AddPartial(len(oidChunk), fmt.Errorf("problem with getting scalar data: problem connecting while trying to reset connection: %w", err)) - return + return scalarData } } continue @@ -246,60 +244,34 @@ func (c *snmpClient) GetScalarData(oids []string, processFn processFunc, scraper scraperErrors.AddPartial(1, fmt.Errorf("problem with getting scalar data: data for OID '%s' not a supported type", data.Name)) continue } - // Process the data - if err := processFn(clientSNMPData); err != nil { - scraperErrors.AddPartial(1, fmt.Errorf("problem with getting scalar data: problem with processing data for OID '%s': %w", data.Name, err)) - continue - } + + // Add the data to be returned + scalarData = append(scalarData, clientSNMPData) } } + + return scalarData } // GetIndexedData retrieves indexed metrics from passed in column OIDs. The returned data // is then also passed into the provided function. -func (c *snmpClient) GetIndexedData(oids []string, processFn processFunc, scraperErrors *scrapererror.ScrapeErrors) { +func (c *snmpClient) GetIndexedData(oids []string, scraperErrors *scrapererror.ScrapeErrors) []snmpData { + indexedData := []snmpData{} + // Nothing to do if there are no OIDs if len(oids) == 0 { - return + return indexedData } // For each column based OID for _, oid := range oids { - // Because BulkWalk and Walk do not return errors if the given OID doesn't exist, we need to keep track of whether - // BulkWalk called the walkFn or not. This will allow us to know if there was a problem with given OID - walkFnCalled := false - // Create a walkFunc which is a required argument for the gosnmp Walk functions - walkFn := func(data gosnmp.SnmpPDU) error { - walkFnCalled = true - // If there is no value, then stop processing - if data.Value == nil { - scraperErrors.AddPartial(1, fmt.Errorf("problem with getting indexed data: data for OID '%s' not found", data.Name)) - return nil - } - // Convert data into the more simplified data type - clientSNMPData := c.convertSnmpPDUToSnmpData(data) - // Keep track of which column OID this data came from as well - clientSNMPData.parentOID = oid - // If the value type is not supported, then ignore - if clientSNMPData.valueType == notSupportedVal { - scraperErrors.AddPartial(1, fmt.Errorf("problem with getting indexed data: data for OID '%s' not a supported type", data.Name)) - return nil - } - - // Process the data - if err := processFn(clientSNMPData); err != nil { - scraperErrors.AddPartial(1, fmt.Errorf("problem with getting indexed data: problem with processing data for OID '%s': %w", data.Name, err)) - } - - return nil - } - // Call the correct gosnmp Walk function based on SNMP version var err error + var snmpPDUs []gosnmp.SnmpPDU if c.client.GetVersion() == gosnmp.Version1 { - err = c.client.Walk(oid, walkFn) + snmpPDUs, err = c.client.WalkAll(oid) } else { - err = c.client.BulkWalk(oid, walkFn) + snmpPDUs, err = c.client.BulkWalkAll(oid) } if err != nil { scraperErrors.AddPartial(1, fmt.Errorf("problem with getting indexed data: problem with SNMP WALK for OID '%v': %w", oid, err)) @@ -310,13 +282,33 @@ func (c *snmpClient) GetIndexedData(oids []string, processFn processFunc, scrape } if err = c.Connect(); err != nil { scraperErrors.AddPartial(len(oids), fmt.Errorf("problem with getting indexed data: problem connecting while trying to reset connection: %w", err)) - return + return indexedData } } - } else if !walkFnCalled { - scraperErrors.AddPartial(1, fmt.Errorf("problem with getting indexed data: problem with SNMP WALK for OID '%v': Could not find any data for given OID", oid)) + } + + for _, snmpPDU := range snmpPDUs { + // If there is no value, then stop processing + if snmpPDU.Value == nil { + scraperErrors.AddPartial(1, fmt.Errorf("problem with getting indexed data: data for OID '%s' not found", snmpPDU.Name)) + continue + } + // Convert data into the more simplified data type + clientSNMPData := c.convertSnmpPDUToSnmpData(snmpPDU) + // Keep track of which column OID this data came from as well + clientSNMPData.parentOID = oid + // If the value type is not supported, then ignore + if clientSNMPData.valueType == notSupportedVal { + scraperErrors.AddPartial(1, fmt.Errorf("problem with getting indexed data: data for OID '%s' not a supported type", snmpPDU.Name)) + continue + } + + // Add the data to be returned + indexedData = append(indexedData, clientSNMPData) } } + + return indexedData } // chunkArray takes an initial array and splits it into a number of smaller diff --git a/receiver/snmpreceiver/client_test.go b/receiver/snmpreceiver/client_test.go index e118f39aa6c9..4468eac561c4 100644 --- a/receiver/snmpreceiver/client_test.go +++ b/receiver/snmpreceiver/client_test.go @@ -215,29 +215,22 @@ func TestGetScalarData(t *testing.T) { { desc: "No OIDs does nothing", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors - client.GetScalarData([]string{}, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData([]string{}, &scraperErrors) require.NoError(t, scraperErrors.Combine()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client failures adds error", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} getError := errors.New("Bad GET") mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("Get", []string{"1"}).Return(nil, getError) @@ -248,19 +241,16 @@ func TestGetScalarData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting scalar data: problem with SNMP GET for OIDs '%v': %w", oidSlice, getError) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client timeout failures tries to reset connection", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} getError := errors.New("request timeout (after 0 retries)") mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("Get", []string{"1"}).Return(nil, getError) @@ -273,19 +263,16 @@ func TestGetScalarData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting scalar data: problem with SNMP GET for OIDs '%v': %w", oidSlice, getError) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client reset connection fails on connect adds error", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} getError := errors.New("request timeout (after 0 retries)") mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("Get", []string{"1"}).Return(nil, getError) @@ -299,24 +286,27 @@ func TestGetScalarData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) expectedErr1 := fmt.Errorf("problem with getting scalar data: problem with SNMP GET for OIDs '%v': %w", oidSlice, getError) expectedErr2 := fmt.Errorf("problem with getting scalar data: problem connecting while trying to reset connection: %w", connectErr) expectedErr := fmt.Errorf(expectedErr1.Error() + "; " + expectedErr2.Error()) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { - desc: "GoSNMP Client partial failures still processes", + desc: "GoSNMP Client partial failures still return successes", testFunc: func(t *testing.T) { - processCnt := 0 - processFn := func(snmpData snmpData) error { - processCnt++ - return nil + expectedSNMPData := []snmpData{ + { + oid: "2", + value: int64(1), + valueType: integerVal, + }, } pdu1 := gosnmp.SnmpPDU{ Value: 1, - Name: "1", + Name: "2", Type: gosnmp.Integer, } getError := errors.New("Bad GET") @@ -333,20 +323,16 @@ func TestGetScalarData(t *testing.T) { var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1", "2"} badOIDSlice := []string{"1"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting scalar data: problem with SNMP GET for OIDs '%v': %w", badOIDSlice, getError) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) - require.Equal(t, 1, processCnt) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { - desc: "GoSNMP Client returned nil value does not process", + desc: "GoSNMP Client returned nil value does not return data", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) pdu := gosnmp.SnmpPDU{ Value: nil, @@ -363,19 +349,16 @@ func TestGetScalarData(t *testing.T) { var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} badOID := "1" - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting scalar data: data for OID '%s' not found", badOID) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { - desc: "GoSNMP Client returned unsupported type value does not process", + desc: "GoSNMP Client returned unsupported type value does not return data", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) pdu := gosnmp.SnmpPDU{ Value: true, @@ -392,126 +375,36 @@ func TestGetScalarData(t *testing.T) { var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} badOID := "1" - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting scalar data: data for OID '%s' not a supported type", badOID) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) - }, - }, - { - desc: "Failures processing returned values adds an error", - testFunc: func(t *testing.T) { - processErr := errors.New("Process Problem") - processFn := func(snmpData snmpData) error { - return processErr - } - mockGoSNMP := new(mocks.MockGoSNMPWrapper) - pdu := gosnmp.SnmpPDU{ - Value: 1, - Name: "1", - Type: gosnmp.Integer, - } - mockGoSNMP.On("Get", []string{"1"}). - Return(&gosnmp.SnmpPacket{Variables: []gosnmp.SnmpPDU{pdu}}, nil) - mockGoSNMP.On("GetMaxOids", mock.Anything).Return(2) - client := &snmpClient{ - logger: zap.NewNop(), - client: mockGoSNMP, - } - var scraperErrors scrapererror.ScrapeErrors - oidSlice := []string{"1"} - badOID := "1" - client.GetScalarData(oidSlice, processFn, &scraperErrors) - expectedErr := fmt.Errorf("problem with getting scalar data: problem with processing data for OID '%s': %w", badOID, processErr) - require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) - }, - }, - { - desc: "Partial failures processing add partial errors", - testFunc: func(t *testing.T) { - processErr := errors.New("Process Problem") - processFn := func(snmpData snmpData) error { - if snmpData.oid == "1" { - return processErr - } - - require.Equal(t, snmpData.oid, "2") - require.Equal(t, snmpData.valueType, integerVal) - require.Equal(t, snmpData.value, int64(2)) - return nil - } - mockGoSNMP := new(mocks.MockGoSNMPWrapper) - pdu1 := gosnmp.SnmpPDU{ - Value: 1, - Name: "1", - Type: gosnmp.Integer, - } - pdu2 := gosnmp.SnmpPDU{ - Value: 2, - Name: "2", - Type: gosnmp.Integer, - } - mockGoSNMP.On("Get", []string{"1", "2"}). - Return(&gosnmp.SnmpPacket{Variables: []gosnmp.SnmpPDU{pdu1, pdu2}}, nil) - mockGoSNMP.On("GetMaxOids", mock.Anything).Return(2) - client := &snmpClient{ - logger: zap.NewNop(), - client: mockGoSNMP, - } - var scraperErrors scrapererror.ScrapeErrors - oidSlice := []string{"1", "2"} - badOID := "1" - client.GetScalarData(oidSlice, processFn, &scraperErrors) - expectedErr := fmt.Errorf("problem with getting scalar data: problem with processing data for OID '%s': %w", badOID, processErr) - require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) - }, - }, - { - desc: "Process function called on each returned value", - testFunc: func(t *testing.T) { - processCnt := 0 - processFn := func(snmpData snmpData) error { - if snmpData.oid == "1" { - require.Equal(t, snmpData.valueType, integerVal) - require.Equal(t, snmpData.value, int64(1)) - processCnt++ - } - if snmpData.oid == "2" { - require.Equal(t, snmpData.valueType, integerVal) - require.Equal(t, snmpData.value, int64(2)) - processCnt++ - } - return nil - } - mockGoSNMP := new(mocks.MockGoSNMPWrapper) - pdu1 := gosnmp.SnmpPDU{ - Value: 1, - Name: "1", - Type: gosnmp.Integer, - } - pdu2 := gosnmp.SnmpPDU{ - Value: 2, - Name: "2", - Type: gosnmp.Integer, - } - mockGoSNMP.On("Get", []string{"1", "2"}). - Return(&gosnmp.SnmpPacket{Variables: []gosnmp.SnmpPDU{pdu1, pdu2}}, nil) - mockGoSNMP.On("GetMaxOids", mock.Anything).Return(2) - client := &snmpClient{ - logger: zap.NewNop(), - client: mockGoSNMP, - } - var scraperErrors scrapererror.ScrapeErrors - oidSlice := []string{"1", "2"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) - require.NoError(t, scraperErrors.Combine()) - require.Equal(t, 2, processCnt) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "Large amount of OIDs handled in chunks", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - return nil + expectedSNMPData := []snmpData{ + { + oid: "1", + value: int64(1), + valueType: integerVal, + }, + { + oid: "2", + value: int64(1), + valueType: integerVal, + }, + { + oid: "3", + value: int64(1), + valueType: integerVal, + }, + { + oid: "4", + value: int64(1), + valueType: integerVal, + }, } mockGoSNMP := new(mocks.MockGoSNMPWrapper) pdu1 := gosnmp.SnmpPDU{ @@ -543,18 +436,20 @@ func TestGetScalarData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1", "2", "3", "4"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) require.NoError(t, scraperErrors.Combine()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client float data type properly converted", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - require.Equal(t, snmpData.oid, "1") - require.Equal(t, snmpData.valueType, floatVal) - require.Equal(t, snmpData.value, 1.0) - return nil + expectedSNMPData := []snmpData{ + { + oid: "1", + value: 1.0, + valueType: floatVal, + }, } mockGoSNMP := new(mocks.MockGoSNMPWrapper) pdu1 := gosnmp.SnmpPDU{ @@ -570,18 +465,15 @@ func TestGetScalarData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) require.NoError(t, scraperErrors.Combine()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client float data type with bad value adds error", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) pdu1 := gosnmp.SnmpPDU{ Value: true, @@ -596,19 +488,16 @@ func TestGetScalarData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting scalar data: data for OID '1' not a supported type") require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client float data type with bad string value adds error", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) pdu1 := gosnmp.SnmpPDU{ Value: "bad", @@ -623,19 +512,16 @@ func TestGetScalarData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting scalar data: data for OID '1' not a supported type") require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client int data type with bad value adds error", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) pdu1 := gosnmp.SnmpPDU{ Value: uint64(math.MaxUint64), @@ -650,19 +536,21 @@ func TestGetScalarData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting scalar data: data for OID '1' not a supported type") require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client string data type properly converted", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - require.Equal(t, snmpData.oid, "1") - require.Equal(t, snmpData.valueType, stringVal) - require.Equal(t, snmpData.value, "test") - return nil + expectedSNMPData := []snmpData{ + { + oid: "1", + value: "test", + valueType: stringVal, + }, } mockGoSNMP := new(mocks.MockGoSNMPWrapper) pdu1 := gosnmp.SnmpPDU{ @@ -678,8 +566,9 @@ func TestGetScalarData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetScalarData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetScalarData(oidSlice, &scraperErrors) require.NoError(t, scraperErrors.Combine()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, } @@ -697,56 +586,46 @@ func TestGetIndexedData(t *testing.T) { { desc: "No OIDs does nothing", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors - client.GetIndexedData([]string{}, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData([]string{}, &scraperErrors) require.NoError(t, scraperErrors.Combine()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client failures adds error", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} walkError := errors.New("Bad WALK") mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Return(walkError) + mockGoSNMP.On("BulkWalkAll", "1").Return(nil, walkError) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetIndexedData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting indexed data: problem with SNMP WALK for OID '1': %w", walkError) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client timeout failures tries to reset connection", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} walkError := errors.New("request timeout (after 0 retries)") mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Return(walkError) + mockGoSNMP.On("BulkWalkAll", "1").Return(nil, walkError) mockGoSNMP.On("Close", mock.Anything).Return(nil) mockGoSNMP.On("Connect", mock.Anything).Return(nil) client := &snmpClient{ @@ -755,23 +634,20 @@ func TestGetIndexedData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetIndexedData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting indexed data: problem with SNMP WALK for OID '1': %w", walkError) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client reset connection fails on connect adds errors", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} walkError := errors.New("request timeout (after 0 retries)") mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Return(walkError) + mockGoSNMP.On("BulkWalkAll", "1").Return(nil, walkError) mockGoSNMP.On("Close", mock.Anything).Return(nil) connectErr := errors.New("can't connect") mockGoSNMP.On("Connect", mock.Anything).Return(connectErr) @@ -781,339 +657,316 @@ func TestGetIndexedData(t *testing.T) { } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - client.GetIndexedData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData(oidSlice, &scraperErrors) expectedErr1 := fmt.Errorf("problem with getting indexed data: problem with SNMP WALK for OID '1': %w", walkError) expectedErr2 := fmt.Errorf("problem with getting indexed data: problem connecting while trying to reset connection: %w", connectErr) expectedErr := fmt.Errorf(expectedErr1.Error() + "; " + expectedErr2.Error()) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { - desc: "GoSNMP Client partial failures still processes", + desc: "GoSNMP Client partial failures still returns successes", testFunc: func(t *testing.T) { - processCnt := 0 - processFn := func(snmpData snmpData) error { - processCnt++ - return nil + expectedSNMPData := []snmpData{ + { + parentOID: "2", + oid: "2.1", + value: int64(1), + valueType: integerVal, + }, } pdu1 := gosnmp.SnmpPDU{ Value: 1, - Name: "1", + Name: "2.1", Type: gosnmp.Integer, } walkError := errors.New("Bad Walk") mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Return(walkError).Once() - mockGoSNMP.On("BulkWalk", "2", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - require.NoError(t, walkFn(pdu1)) - }).Return(nil) + mockGoSNMP.On("BulkWalkAll", "1").Return(nil, walkError).Once() + mockGoSNMP.On("BulkWalkAll", "2").Return([]gosnmp.SnmpPDU{pdu1}, nil).Once() client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1", "2"} - client.GetIndexedData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting indexed data: problem with SNMP WALK for OID '1': %w", walkError) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) - require.Equal(t, 1, processCnt) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { - desc: "GoSNMP Client returned nil value does not process", + desc: "GoSNMP Client returned nil value does not return data", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) + badOID := "1.1" pdu := gosnmp.SnmpPDU{ Value: nil, - Name: "1", + Name: badOID, Type: gosnmp.Integer, } - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - require.NoError(t, walkFn(pdu)) - }).Return(nil) + mockGoSNMP.On("BulkWalkAll", "1").Return([]gosnmp.SnmpPDU{pdu}, nil) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - badOID := "1" - client.GetIndexedData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting indexed data: data for OID '%s' not found", badOID) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { - desc: "GoSNMP Client returned unsupported type value does not process", + desc: "GoSNMP Client returned unsupported type value does not return data", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) + badOID := "1.1" pdu := gosnmp.SnmpPDU{ Value: true, - Name: "1", + Name: badOID, Type: gosnmp.Boolean, } - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - require.NoError(t, walkFn(pdu)) - }).Return(nil) + mockGoSNMP.On("BulkWalkAll", "1").Return([]gosnmp.SnmpPDU{pdu}, nil) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors oidSlice := []string{"1"} - badOID := "1" - client.GetIndexedData(oidSlice, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData(oidSlice, &scraperErrors) expectedErr := fmt.Errorf("problem with getting indexed data: data for OID '%s' not a supported type", badOID) require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) - }, - }, - { - desc: "Process function called on each returned value", - testFunc: func(t *testing.T) { - processCnt := 0 - processFn := func(snmpData snmpData) error { - if snmpData.oid == "1" { - require.Equal(t, snmpData.valueType, integerVal) - require.Equal(t, snmpData.value, int64(1)) - processCnt++ - } - if snmpData.oid == "2" { - require.Equal(t, snmpData.valueType, integerVal) - require.Equal(t, snmpData.value, int64(2)) - processCnt++ - } - return nil + require.Equal(t, expectedSNMPData, returnedSNMPData) + }, + }, + { + desc: "Return multiple good values", + testFunc: func(t *testing.T) { + expectedSNMPData := []snmpData{ + { + parentOID: "1", + oid: "1.1", + value: int64(1), + valueType: integerVal, + }, + { + parentOID: "1", + oid: "1.2", + value: int64(2), + valueType: integerVal, + }, + { + parentOID: "2", + oid: "2.1", + value: int64(3), + valueType: integerVal, + }, + { + parentOID: "2", + oid: "2.2", + value: int64(4), + valueType: integerVal, + }, } mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) pdu1 := gosnmp.SnmpPDU{ Value: 1, - Name: "1", + Name: "1.1", Type: gosnmp.Integer, } pdu2 := gosnmp.SnmpPDU{ Value: 2, - Name: "2", + Name: "1.2", + Type: gosnmp.Integer, + } + pdu3 := gosnmp.SnmpPDU{ + Value: 3, + Name: "2.1", + Type: gosnmp.Integer, + } + pdu4 := gosnmp.SnmpPDU{ + Value: 4, + Name: "2.2", Type: gosnmp.Integer, } - mockGoSNMP.On("Get", []string{"1", "2"}). - Return(&gosnmp.SnmpPacket{Variables: []gosnmp.SnmpPDU{pdu1, pdu2}}, nil) - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - returnErr := walkFn(pdu1) - require.NoError(t, returnErr) - }).Return(nil) - mockGoSNMP.On("BulkWalk", "2", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - returnErr := walkFn(pdu2) - require.NoError(t, returnErr) - }).Return(nil) + mockGoSNMP.On("BulkWalkAll", "1").Return([]gosnmp.SnmpPDU{pdu1, pdu2}, nil) + mockGoSNMP.On("BulkWalkAll", "2").Return([]gosnmp.SnmpPDU{pdu3, pdu4}, nil) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors - client.GetIndexedData([]string{"1", "2"}, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData([]string{"1", "2"}, &scraperErrors) require.NoError(t, scraperErrors.Combine()) - require.Equal(t, 2, processCnt) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client float data type properly converted", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - require.Equal(t, snmpData.oid, "1") - require.Equal(t, snmpData.valueType, floatVal) - require.Equal(t, snmpData.value, 1.0) - return nil + expectedSNMPData := []snmpData{ + { + parentOID: "1", + oid: "1.1", + value: 1.0, + valueType: floatVal, + }, } mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) - pdu1 := gosnmp.SnmpPDU{ + pdu := gosnmp.SnmpPDU{ Value: 1.0, - Name: "1", + Name: "1.1", Type: gosnmp.OpaqueDouble, } - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - returnErr := walkFn(pdu1) - require.NoError(t, returnErr) - }).Return(nil) + mockGoSNMP.On("BulkWalkAll", "1").Return([]gosnmp.SnmpPDU{pdu}, nil) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors - client.GetIndexedData([]string{"1"}, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData([]string{"1"}, &scraperErrors) require.NoError(t, scraperErrors.Combine()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client float data type with bad value adds error", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) - pdu1 := gosnmp.SnmpPDU{ + pdu := gosnmp.SnmpPDU{ Value: true, - Name: "1", + Name: "1.1", Type: gosnmp.OpaqueDouble, } - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - returnErr := walkFn(pdu1) - require.NoError(t, returnErr) - }).Return(nil) + mockGoSNMP.On("BulkWalkAll", "1").Return([]gosnmp.SnmpPDU{pdu}, nil) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors - client.GetIndexedData([]string{"1"}, processFn, &scraperErrors) - expectedErr := fmt.Errorf("problem with getting indexed data: data for OID '1' not a supported type") + returnedSNMPData := client.GetIndexedData([]string{"1"}, &scraperErrors) + expectedErr := fmt.Errorf("problem with getting indexed data: data for OID '1.1' not a supported type") require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client float data type with bad string value adds error", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) - pdu1 := gosnmp.SnmpPDU{ + pdu := gosnmp.SnmpPDU{ Value: "bad", - Name: "1", + Name: "1.1", Type: gosnmp.OpaqueDouble, } - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - returnErr := walkFn(pdu1) - require.NoError(t, returnErr) - }).Return(nil) + mockGoSNMP.On("BulkWalkAll", "1").Return([]gosnmp.SnmpPDU{pdu}, nil) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors - client.GetIndexedData([]string{"1"}, processFn, &scraperErrors) - expectedErr := fmt.Errorf("problem with getting indexed data: data for OID '1' not a supported type") + returnedSNMPData := client.GetIndexedData([]string{"1"}, &scraperErrors) + expectedErr := fmt.Errorf("problem with getting indexed data: data for OID '1.1' not a supported type") require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client int data type with bad value adds error", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - // We don't want this to be tested - require.True(t, false) - return nil - } + expectedSNMPData := []snmpData{} mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) - pdu1 := gosnmp.SnmpPDU{ + pdu := gosnmp.SnmpPDU{ Value: uint64(math.MaxUint64), - Name: "1", + Name: "1.1", Type: gosnmp.Counter64, } - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - returnErr := walkFn(pdu1) - require.NoError(t, returnErr) - }).Return(nil) + mockGoSNMP.On("BulkWalkAll", "1").Return([]gosnmp.SnmpPDU{pdu}, nil) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors - client.GetIndexedData([]string{"1"}, processFn, &scraperErrors) - expectedErr := fmt.Errorf("problem with getting indexed data: data for OID '1' not a supported type") + returnedSNMPData := client.GetIndexedData([]string{"1"}, &scraperErrors) + expectedErr := fmt.Errorf("problem with getting indexed data: data for OID '1.1' not a supported type") require.EqualError(t, scraperErrors.Combine(), expectedErr.Error()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client string data type properly converted", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - require.Equal(t, snmpData.oid, "1") - require.Equal(t, snmpData.valueType, stringVal) - require.Equal(t, snmpData.value, "test") - return nil + expectedSNMPData := []snmpData{ + { + parentOID: "1", + oid: "1.1", + value: "test", + valueType: stringVal, + }, } mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version2c) - pdu1 := gosnmp.SnmpPDU{ + pdu := gosnmp.SnmpPDU{ Value: []byte("test"), - Name: "1", + Name: "1.1", Type: gosnmp.OctetString, } - mockGoSNMP.On("BulkWalk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - returnErr := walkFn(pdu1) - require.NoError(t, returnErr) - }).Return(nil) + mockGoSNMP.On("BulkWalkAll", "1").Return([]gosnmp.SnmpPDU{pdu}, nil) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors - client.GetIndexedData([]string{"1"}, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData([]string{"1"}, &scraperErrors) require.NoError(t, scraperErrors.Combine()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, { desc: "GoSNMP Client v1 uses normal Walk function", testFunc: func(t *testing.T) { - processFn := func(snmpData snmpData) error { - require.Equal(t, snmpData.oid, "1") - require.Equal(t, snmpData.valueType, integerVal) - require.Equal(t, snmpData.value, int64(1)) - return nil + expectedSNMPData := []snmpData{ + { + parentOID: "1", + oid: "1.1", + value: int64(1), + valueType: integerVal, + }, } mockGoSNMP := new(mocks.MockGoSNMPWrapper) mockGoSNMP.On("GetVersion", mock.Anything).Return(gosnmp.Version1) - pdu1 := gosnmp.SnmpPDU{ + pdu := gosnmp.SnmpPDU{ Value: 1, - Name: "1", + Name: "1.1", Type: gosnmp.Counter32, } - mockGoSNMP.On("Walk", "1", mock.AnythingOfType("gosnmp.WalkFunc")).Run(func(args mock.Arguments) { - walkFn := args.Get(1).(gosnmp.WalkFunc) - returnErr := walkFn(pdu1) - require.NoError(t, returnErr) - }).Return(nil) + mockGoSNMP.On("WalkAll", "1").Return([]gosnmp.SnmpPDU{pdu}, nil) mockGoSNMP.On("GetMaxOids", mock.Anything).Return(2) client := &snmpClient{ logger: zap.NewNop(), client: mockGoSNMP, } var scraperErrors scrapererror.ScrapeErrors - client.GetIndexedData([]string{"1"}, processFn, &scraperErrors) + returnedSNMPData := client.GetIndexedData([]string{"1"}, &scraperErrors) require.NoError(t, scraperErrors.Combine()) + require.Equal(t, expectedSNMPData, returnedSNMPData) }, }, } diff --git a/receiver/snmpreceiver/goSNMPWrapper.go b/receiver/snmpreceiver/goSNMPWrapper.go index d36ede6c5d82..6b115b649256 100644 --- a/receiver/snmpreceiver/goSNMPWrapper.go +++ b/receiver/snmpreceiver/goSNMPWrapper.go @@ -37,18 +37,17 @@ type goSNMPWrapper interface { // Get sends an SNMP GET request Get(oids []string) (result *gosnmp.SnmpPacket, err error) - // Walk retrieves a subtree of values using GETNEXT - a request is made for each - // value, unlike BulkWalk which does this operation in batches. As the tree is - // walked walkFn is called for each new value. The function immediately returns - // an error if either there is an underlaying SNMP error (e.g. GetNext fails), - // or if walkFn returns an error. - Walk(rootOid string, walkFn gosnmp.WalkFunc) error - - // BulkWalk retrieves a subtree of values using GETBULK. As the tree is - // walked walkFn is called for each new value. The function immediately returns - // an error if either there is an underlaying SNMP error (e.g. GetBulk fails), - // or if walkFn returns an error. - BulkWalk(rootOid string, walkFn gosnmp.WalkFunc) error + // WalkAll is similar to Walk but returns a filled array of all values rather + // than using a callback function to stream results. Caution: if you have set + // x.AppOpts to 'c', WalkAll may loop indefinitely and cause an Out Of Memory - + // use Walk instead. + WalkAll(rootOid string) (results []gosnmp.SnmpPDU, err error) + + // BulkWalkAll is similar to BulkWalk but returns a filled array of all values + // rather than using a callback function to stream results. Caution: if you + // have set x.AppOpts to 'c', BulkWalkAll may loop indefinitely and cause an + // Out Of Memory - use BulkWalk instead. + BulkWalkAll(rootOid string) (results []gosnmp.SnmpPDU, err error) // GetTransport gets the Transport GetTransport() string diff --git a/receiver/snmpreceiver/internal/mocks/goSNMPWrapper.go b/receiver/snmpreceiver/internal/mocks/goSNMPWrapper.go index 3b73f30c1fd2..24bc7d009eab 100644 --- a/receiver/snmpreceiver/internal/mocks/goSNMPWrapper.go +++ b/receiver/snmpreceiver/internal/mocks/goSNMPWrapper.go @@ -14,18 +14,27 @@ type MockGoSNMPWrapper struct { mock.Mock } -// BulkWalk provides a mock function with given fields: rootOid, walkFn -func (_m *MockGoSNMPWrapper) BulkWalk(rootOid string, walkFn gosnmp.WalkFunc) error { - ret := _m.Called(rootOid, walkFn) +// BulkWalkAll provides a mock function with given fields: rootOid +func (_m *MockGoSNMPWrapper) BulkWalkAll(rootOid string) ([]gosnmp.SnmpPDU, error) { + ret := _m.Called(rootOid) - var r0 error - if rf, ok := ret.Get(0).(func(string, gosnmp.WalkFunc) error); ok { - r0 = rf(rootOid, walkFn) + var r0 []gosnmp.SnmpPDU + if rf, ok := ret.Get(0).(func(string) []gosnmp.SnmpPDU); ok { + r0 = rf(rootOid) } else { - r0 = ret.Error(0) + if ret.Get(0) != nil { + r0 = ret.Get(0).([]gosnmp.SnmpPDU) + } } - return r0 + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(rootOid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } // Close provides a mock function with given fields: @@ -271,18 +280,27 @@ func (_m *MockGoSNMPWrapper) SetVersion(version gosnmp.SnmpVersion) { _m.Called(version) } -// Walk provides a mock function with given fields: rootOid, walkFn -func (_m *MockGoSNMPWrapper) Walk(rootOid string, walkFn gosnmp.WalkFunc) error { - ret := _m.Called(rootOid, walkFn) +// WalkAll provides a mock function with given fields: rootOid +func (_m *MockGoSNMPWrapper) WalkAll(rootOid string) ([]gosnmp.SnmpPDU, error) { + ret := _m.Called(rootOid) - var r0 error - if rf, ok := ret.Get(0).(func(string, gosnmp.WalkFunc) error); ok { - r0 = rf(rootOid, walkFn) + var r0 []gosnmp.SnmpPDU + if rf, ok := ret.Get(0).(func(string) []gosnmp.SnmpPDU); ok { + r0 = rf(rootOid) } else { - r0 = ret.Error(0) + if ret.Get(0) != nil { + r0 = ret.Get(0).([]gosnmp.SnmpPDU) + } } - return r0 + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(rootOid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } type mockNewGoSNMPWrapperT interface {