go.d snmp: add collecting network interface stats (#18014)
Ilya Mashchenko committed
Jun 26, 2024 at 20:00 UTC
45d84b12b06af484f4a4fbe75bdd71f5870b62e2
12 files changed
+1680
-543
src/go/collectors/go.d.plugin/config/go.d/snmp.conf
-38
@@ -8,41 +8,3 @@
8
# community: public
9
# options:
10
# version: 2
11
-# user:
12
-# name: "username"
13
-# level: "authPriv"
14
-# auth_proto: "sha256"
15
-# auth_key: "auth_protocol_passphrase"
16
-# priv_proto: "aes256"
17
-# priv_key: "priv_protocol_passphrase"
18
-# charts:
19
-# - id: "bandwidth_port1"
20
-# title: "Switch Bandwidth for port 1"
21
-# units: "kilobits/s"
22
-# type: "area"
23
-# family: "ports"
24
-# dimensions:
25
-# - name: "in"
26
-# oid: "1.3.6.1.2.1.2.2.1.10.1"
27
-# algorithm: "incremental"
28
-# multiplier: 8
29
-# divisor: 1000
30
-# - name: "out"
31
-# oid: "1.3.6.1.2.1.2.2.1.16.1"
32
-# multiplier: -8
33
-# divisor: 1000
34
-# - id: "bandwidth_port2"
35
-# title: "Switch Bandwidth for port 2"
36
-# units: "kilobits/s"
37
-# type: "area"
38
-# family: "ports"
39
-# dimensions:
40
-# - name: "in"
41
-# oid: "1.3.6.1.2.1.2.2.1.10.2"
42
-# algorithm: "incremental"
43
-# multiplier: 8
44
-# divisor: 1000
45
-# - name: "out"
46
-# oid: "1.3.6.1.2.1.2.2.1.16.2"
47
-# multiplier: -8
48
-# divisor: 1000
src/go/collectors/go.d.plugin/modules/snmp/charts.go
+201
-8
@@ -9,11 +9,204 @@ import (
9
"github.com/netdata/netdata/go/go.d.plugin/agent/module"
10
)
11
12
-func newCharts(configs []ChartConfig) (*module.Charts, error) {
12
+const (
13
+ prioNetIfaceTraffic = module.Priority + iota
14
+ prioNetIfaceUnicast
15
+ prioNetIfaceMulticast
16
+ prioNetIfaceBroadcast
17
+ prioNetIfaceErrors
18
+ prioNetIfaceDiscards
19
+ prioNetIfaceAdminStatus
20
+ prioNetIfaceOperStatus
21
+ prioSysUptime
22
+)
23
+
24
+var netIfaceChartsTmpl = module.Charts{
25
+ netIfaceTrafficChartTmpl.Copy(),
26
+ netIfacePacketsChartTmpl.Copy(),
27
+ netIfaceMulticastChartTmpl.Copy(),
28
+ netIfaceBroadcastChartTmpl.Copy(),
29
+ netIfaceErrorsChartTmpl.Copy(),
30
+ netIfaceDiscardsChartTmpl.Copy(),
31
+ netIfaceAdminStatusChartTmpl.Copy(),
32
+ netIfaceOperStatusChartTmpl.Copy(),
33
+}
34
+
35
+var (
36
+ netIfaceTrafficChartTmpl = module.Chart{
37
+ ID: "snmp_device_net_iface_%s_traffic",
38
+ Title: "SNMP device network interface traffic",
39
+ Units: "kilobits/s",
40
+ Fam: "traffic",
41
+ Ctx: "snmp.device_net_interface_traffic",
42
+ Priority: prioNetIfaceTraffic,
43
+ Type: module.Area,
44
+ Dims: module.Dims{
45
+ {ID: "net_iface_%s_traffic_in", Name: "received", Algo: module.Incremental},
46
+ {ID: "net_iface_%s_traffic_out", Name: "sent", Mul: -1, Algo: module.Incremental},
47
+ },
48
+ }
49
+
50
+ netIfacePacketsChartTmpl = module.Chart{
51
+ ID: "snmp_device_net_iface_%s_unicast",
52
+ Title: "SNMP device network interface unicast packets",
53
+ Units: "packets/s",
54
+ Fam: "packets",
55
+ Ctx: "snmp.device_net_interface_unicast",
56
+ Priority: prioNetIfaceUnicast,
57
+ Dims: module.Dims{
58
+ {ID: "net_iface_%s_ucast_in", Name: "received", Algo: module.Incremental},
59
+ {ID: "net_iface_%s_ucast_out", Name: "sent", Mul: -1, Algo: module.Incremental},
60
+ },
61
+ }
62
+ netIfaceMulticastChartTmpl = module.Chart{
63
+ ID: "snmp_device_net_iface_%s_multicast",
64
+ Title: "SNMP device network interface multicast packets",
65
+ Units: "packets/s",
66
+ Fam: "packets",
67
+ Ctx: "snmp.device_net_interface_multicast",
68
+ Priority: prioNetIfaceMulticast,
69
+ Dims: module.Dims{
70
+ {ID: "net_iface_%s_mcast_in", Name: "received", Algo: module.Incremental},
71
+ {ID: "net_iface_%s_mcast_out", Name: "sent", Mul: -1, Algo: module.Incremental},
72
+ },
73
+ }
74
+ netIfaceBroadcastChartTmpl = module.Chart{
75
+ ID: "snmp_device_net_iface_%s_broadcast",
76
+ Title: "SNMP device network interface broadcast packets",
77
+ Units: "packets/s",
78
+ Fam: "packets",
79
+ Ctx: "snmp.device_net_interface_broadcast",
80
+ Priority: prioNetIfaceBroadcast,
81
+ Dims: module.Dims{
82
+ {ID: "net_iface_%s_bcast_in", Name: "received", Algo: module.Incremental},
83
+ {ID: "net_iface_%s_bcast_out", Name: "sent", Mul: -1, Algo: module.Incremental},
84
+ },
85
+ }
86
+
87
+ netIfaceErrorsChartTmpl = module.Chart{
88
+ ID: "snmp_device_net_iface_%s_errors",
89
+ Title: "SNMP device network interface errors",
90
+ Units: "errors/s",
91
+ Fam: "errors",
92
+ Ctx: "snmp.device_net_interface_errors",
93
+ Priority: prioNetIfaceErrors,
94
+ Dims: module.Dims{
95
+ {ID: "net_iface_%s_errors_in", Name: "inbound", Algo: module.Incremental},
96
+ {ID: "net_iface_%s_errors_out", Name: "outbound", Mul: -1, Algo: module.Incremental},
97
+ },
98
+ }
99
+
100
+ netIfaceDiscardsChartTmpl = module.Chart{
101
+ ID: "snmp_device_net_iface_%s_discards",
102
+ Title: "SNMP device network interface discards",
103
+ Units: "discards/s",
104
+ Fam: "discards",
105
+ Ctx: "snmp.device_net_interface_discards",
106
+ Priority: prioNetIfaceDiscards,
107
+ Dims: module.Dims{
108
+ {ID: "net_iface_%s_discards_in", Name: "inbound", Algo: module.Incremental},
109
+ {ID: "net_iface_%s_discards_out", Name: "outbound", Mul: -1, Algo: module.Incremental},
110
+ },
111
+ }
112
+
113
+ netIfaceAdminStatusChartTmpl = module.Chart{
114
+ ID: "snmp_device_net_iface_%s_admin_status",
115
+ Title: "SNMP device network interface administrative status",
116
+ Units: "status",
117
+ Fam: "status",
118
+ Ctx: "snmp.device_net_interface_admin_status",
119
+ Priority: prioNetIfaceAdminStatus,
120
+ Dims: module.Dims{
121
+ {ID: "net_iface_%s_admin_status_up", Name: "up"},
122
+ {ID: "net_iface_%s_admin_status_down", Name: "down"},
123
+ {ID: "net_iface_%s_admin_status_testing", Name: "testing"},
124
+ },
125
+ }
126
+ netIfaceOperStatusChartTmpl = module.Chart{
127
+ ID: "snmp_device_net_iface_%s_oper_status",
128
+ Title: "SNMP device network interface operational status",
129
+ Units: "status",
130
+ Fam: "status",
131
+ Ctx: "snmp.device_net_interface_oper_status",
132
+ Priority: prioNetIfaceOperStatus,
133
+ Dims: module.Dims{
134
+ {ID: "net_iface_%s_oper_status_up", Name: "up"},
135
+ {ID: "net_iface_%s_oper_status_down", Name: "down"},
136
+ {ID: "net_iface_%s_oper_status_testing", Name: "testing"},
137
+ {ID: "net_iface_%s_oper_status_unknown", Name: "unknown"},
138
+ {ID: "net_iface_%s_oper_status_dormant", Name: "dormant"},
139
+ {ID: "net_iface_%s_oper_status_notPresent", Name: "not_present"},
140
+ {ID: "net_iface_%s_oper_status_lowerLayerDown", Name: "lower_layer_down"},
141
+ },
142
+ }
143
+)
144
+
145
+var (
146
+ uptimeChart = module.Chart{
147
+ ID: "snmp_device_uptime",
148
+ Title: "SNMP device uptime",
149
+ Units: "seconds",
150
+ Fam: "uptime",
151
+ Ctx: "snmp.device_uptime",
152
+ Priority: prioSysUptime,
153
+ Dims: module.Dims{
154
+ {ID: "uptime", Name: "uptime"},
155
+ },
156
+ }
157
+)
158
+
159
+func (s *SNMP) addNetIfaceCharts(iface *netInterface) {
160
+ charts := netIfaceChartsTmpl.Copy()
161
+
162
+ for _, chart := range *charts {
163
+ chart.ID = fmt.Sprintf(chart.ID, cleanIfaceName(iface.ifName))
164
+ chart.Labels = []module.Label{
165
+ {Key: "sysName", Value: s.sysName},
166
+ {Key: "ifDescr", Value: iface.ifDescr},
167
+ {Key: "ifName", Value: iface.ifName},
168
+ {Key: "ifType", Value: ifTypeMapping[iface.ifType]},
169
+ }
170
+ for _, dim := range chart.Dims {
171
+ dim.ID = fmt.Sprintf(dim.ID, iface.ifName)
172
+ }
173
+ }
174
+
175
+ if err := s.Charts().Add(*charts...); err != nil {
176
+ s.Warning(err)
177
+ }
178
+}
179
+
180
+func (s *SNMP) removeNetIfaceCharts(iface *netInterface) {
181
+ px := fmt.Sprintf("snmp_device_net_iface_%s_", cleanIfaceName(iface.ifName))
182
+ for _, chart := range *s.Charts() {
183
+ if strings.HasPrefix(chart.ID, px) {
184
+ chart.MarkRemove()
185
+ chart.MarkNotCreated()
186
+ }
187
+ }
188
+}
189
+
190
+func (s *SNMP) addSysUptimeChart() {
191
+ chart := uptimeChart.Copy()
192
+ chart.Labels = []module.Label{
193
+ {Key: "sysName", Value: s.sysName},
194
+ }
195
+ if err := s.Charts().Add(chart); err != nil {
196
+ s.Warning(err)
197
+ }
198
+}
199
+
200
+func cleanIfaceName(name string) string {
201
+ r := strings.NewReplacer(".", "_", " ", "_")
202
+ return r.Replace(name)
203
+}
204
+
205
+func newUserInputCharts(configs []ChartConfig) (*module.Charts, error) {
206
charts := &module.Charts{}
207
for _, cfg := range configs {
208
if len(cfg.IndexRange) == 2 {
16
- cs, err := newChartsFromIndexRange(cfg)
209
+ cs, err := newUserInputChartsFromIndexRange(cfg)
210
if err != nil {
211
return nil, err
212
}
@@ -21,7 +214,7 @@ func newCharts(configs []ChartConfig) (*module.Charts, error) {
214
return nil, err
215
}
216
} else {
24
- chart, err := newChart(cfg)
217
+ chart, err := newUserInputChart(cfg)
218
if err != nil {
219
return nil, err
220
}
@@ -33,11 +226,11 @@ func newCharts(configs []ChartConfig) (*module.Charts, error) {
226
return charts, nil
227
}
228
36
-func newChartsFromIndexRange(cfg ChartConfig) (*module.Charts, error) {
229
+func newUserInputChartsFromIndexRange(cfg ChartConfig) (*module.Charts, error) {
230
var addPrio int
231
charts := &module.Charts{}
232
for i := cfg.IndexRange[0]; i <= cfg.IndexRange[1]; i++ {
40
- chart, err := newChartWithOIDIndex(i, cfg)
233
+ chart, err := newUserInputChartWithOIDIndex(i, cfg)
234
if err != nil {
235
return nil, err
236
}
@@ -50,8 +243,8 @@ func newChartsFromIndexRange(cfg ChartConfig) (*module.Charts, error) {
243
return charts, nil
244
}
245
53
-func newChartWithOIDIndex(oidIndex int, cfg ChartConfig) (*module.Chart, error) {
54
- chart, err := newChart(cfg)
246
+func newUserInputChartWithOIDIndex(oidIndex int, cfg ChartConfig) (*module.Chart, error) {
247
+ chart, err := newUserInputChart(cfg)
248
if err != nil {
249
return nil, err
250
}
@@ -65,7 +258,7 @@ func newChartWithOIDIndex(oidIndex int, cfg ChartConfig) (*module.Chart, error)
258
return chart, nil
259
}
260
68
-func newChart(cfg ChartConfig) (*module.Chart, error) {
261
+func newUserInputChart(cfg ChartConfig) (*module.Chart, error) {
262
chart := &module.Chart{
263
ID: cfg.ID,
264
Title: cfg.Title,
src/go/collectors/go.d.plugin/modules/snmp/collect.go
+292
-5
@@ -3,20 +3,307 @@
3
package snmp
4
5
import (
6
+ "errors"
7
+ "fmt"
8
+ "log/slog"
9
+ "sort"
10
+ "strings"
11
+
12
+ "github.com/netdata/netdata/go/go.d.plugin/logger"
13
+
14
"github.com/gosnmp/gosnmp"
15
)
16
17
+const (
18
+ oidSysUptime = "1.3.6.1.2.1.1.3.0"
19
+ oidSysName = "1.3.6.1.2.1.1.5.0"
20
+ rootOidIfMibIfTable = "1.3.6.1.2.1.2.2"
21
+ rootOidIfMibIfXTable = "1.3.6.1.2.1.31.1.1"
22
+)
23
+
24
func (s *SNMP) collect() (map[string]int64, error) {
10
- collected := make(map[string]int64)
25
+ if s.sysName == "" {
26
+ sysName, err := s.getSysName()
27
+ if err != nil {
28
+ return nil, err
29
+ }
30
+ s.sysName = sysName
31
+ s.addSysUptimeChart()
32
+ }
33
+
34
+ mx := make(map[string]int64)
35
12
- if err := s.collectOIDs(collected); err != nil {
36
+ if err := s.collectSysUptime(mx); err != nil {
37
return nil, err
38
}
39
16
- return collected, nil
40
+ if s.collectIfMib {
41
+ if err := s.collectNetworkInterfaces(mx); err != nil {
42
+ return nil, err
43
+ }
44
+ }
45
+
46
+ if len(s.oids) > 0 {
47
+ if err := s.collectOIDs(mx); err != nil {
48
+ return nil, err
49
+ }
50
+ }
51
+
52
+ return mx, nil
53
+}
54
+
55
+func (s *SNMP) getSysName() (string, error) {
56
+ resp, err := s.snmpClient.Get([]string{oidSysName})
57
+ if err != nil {
58
+ return "", err
59
+ }
60
+ if len(resp.Variables) == 0 {
61
+ return "", errors.New("no system name")
62
+ }
63
+ return pduToString(resp.Variables[0])
64
+}
65
+
66
+func (s *SNMP) collectSysUptime(mx map[string]int64) error {
67
+ resp, err := s.snmpClient.Get([]string{oidSysUptime})
68
+ if err != nil {
69
+ return err
70
+ }
71
+ if len(resp.Variables) == 0 {
72
+ return errors.New("no system uptime")
73
+ }
74
+ v, err := pduToInt(resp.Variables[0])
75
+ if err != nil {
76
+ return err
77
+ }
78
+
79
+ mx["uptime"] = v / 100 // the time is in hundredths of a second
80
+
81
+ return nil
82
}
83
19
-func (s *SNMP) collectOIDs(collected map[string]int64) error {
84
+func (s *SNMP) collectNetworkInterfaces(mx map[string]int64) error {
85
+ ifMibTable, err := s.walkAll(rootOidIfMibIfTable)
86
+ if err != nil {
87
+ return err
88
+ }
89
+
90
+ ifMibXTable, err := s.walkAll(rootOidIfMibIfXTable)
91
+ if err != nil {
92
+ return err
93
+ }
94
+
95
+ if len(ifMibTable) == 0 && len(ifMibXTable) == 0 {
96
+ if len(s.oids) == 0 {
97
+ return errors.New("no IF-MIB data returned, try decreasing 'max_repetitions'")
98
+ }
99
+
100
+ s.Warningf("no IF-MIB data returned, try decreasing 'max_repetitions' (current: %d)", s.snmpClient.MaxRepetitions())
101
+ s.collectIfMib = false
102
+ return nil
103
+ }
104
+
105
+ for _, i := range s.netInterfaces {
106
+ i.updated = false
107
+ }
108
+
109
+ pdus := make([]gosnmp.SnmpPDU, 0, len(ifMibXTable)+len(ifMibXTable))
110
+ pdus = append(pdus, ifMibTable...)
111
+ pdus = append(pdus, ifMibXTable...)
112
+
113
+ for _, pdu := range pdus {
114
+ i := strings.LastIndexByte(pdu.Name, '.')
115
+ if i == -1 {
116
+ continue
117
+ }
118
+
119
+ idx := pdu.Name[i+1:]
120
+ oid := strings.TrimPrefix(pdu.Name[:i], ".")
121
+
122
+ iface, ok := s.netInterfaces[idx]
123
+ if !ok {
124
+ iface = &netInterface{idx: idx}
125
+ }
126
+
127
+ switch oid {
128
+ case oidIfIndex:
129
+ iface.ifIndex, err = pduToInt(pdu)
130
+ case oidIfDescr:
131
+ iface.ifDescr, err = pduToString(pdu)
132
+ case oidIfType:
133
+ iface.ifType, err = pduToInt(pdu)
134
+ case oidIfMtu:
135
+ iface.ifMtu, err = pduToInt(pdu)
136
+ case oidIfSpeed:
137
+ iface.ifSpeed, err = pduToInt(pdu)
138
+ case oidIfAdminStatus:
139
+ iface.ifAdminStatus, err = pduToInt(pdu)
140
+ case oidIfOperStatus:
141
+ iface.ifOperStatus, err = pduToInt(pdu)
142
+ case oidIfInOctets:
143
+ iface.ifInOctets, err = pduToInt(pdu)
144
+ case oidIfInUcastPkts:
145
+ iface.ifInUcastPkts, err = pduToInt(pdu)
146
+ case oidIfInNUcastPkts:
147
+ iface.ifInNUcastPkts, err = pduToInt(pdu)
148
+ case oidIfInDiscards:
149
+ iface.ifInDiscards, err = pduToInt(pdu)
150
+ case oidIfInErrors:
151
+ iface.ifInErrors, err = pduToInt(pdu)
152
+ case oidIfInUnknownProtos:
153
+ iface.ifInUnknownProtos, err = pduToInt(pdu)
154
+ case oidIfOutOctets:
155
+ iface.ifOutOctets, err = pduToInt(pdu)
156
+ case oidIfOutUcastPkts:
157
+ iface.ifOutUcastPkts, err = pduToInt(pdu)
158
+ case oidIfOutNUcastPkts:
159
+ iface.ifOutNUcastPkts, err = pduToInt(pdu)
160
+ case oidIfOutDiscards:
161
+ iface.ifOutDiscards, err = pduToInt(pdu)
162
+ case oidIfOutErrors:
163
+ iface.ifOutErrors, err = pduToInt(pdu)
164
+ case oidIfName:
165
+ iface.ifName, err = pduToString(pdu)
166
+ case oidIfInMulticastPkts:
167
+ iface.ifInMulticastPkts, err = pduToInt(pdu)
168
+ case oidIfInBroadcastPkts:
169
+ iface.ifInBroadcastPkts, err = pduToInt(pdu)
170
+ case oidIfOutMulticastPkts:
171
+ iface.ifOutMulticastPkts, err = pduToInt(pdu)
172
+ case oidIfOutBroadcastPkts:
173
+ iface.ifOutBroadcastPkts, err = pduToInt(pdu)
174
+ case oidIfHCInOctets:
175
+ iface.ifHCInOctets, err = pduToInt(pdu)
176
+ case oidIfHCInUcastPkts:
177
+ iface.ifHCInUcastPkts, err = pduToInt(pdu)
178
+ case oidIfHCInMulticastPkts:
179
+ iface.ifHCInMulticastPkts, err = pduToInt(pdu)
180
+ case oidIfHCInBroadcastPkts:
181
+ iface.ifHCInBroadcastPkts, err = pduToInt(pdu)
182
+ case oidIfHCOutOctets:
183
+ iface.ifHCOutOctets, err = pduToInt(pdu)
184
+ case oidIfHCOutUcastPkts:
185
+ iface.ifHCOutUcastPkts, err = pduToInt(pdu)
186
+ case oidIfHCOutMulticastPkts:
187
+ iface.ifHCOutMulticastPkts, err = pduToInt(pdu)
188
+ case oidIfHCOutBroadcastPkts:
189
+ iface.ifHCOutMulticastPkts, err = pduToInt(pdu)
190
+ case oidIfHighSpeed:
191
+ iface.ifHighSpeed, err = pduToInt(pdu)
192
+ case oidIfAlias:
193
+ iface.ifAlias, err = pduToString(pdu)
194
+ default:
195
+ continue
196
+ }
197
+
198
+ if err != nil {
199
+ return fmt.Errorf("OID '%s': %v", pdu.Name, err)
200
+ }
201
+
202
+ s.netInterfaces[idx] = iface
203
+ iface.updated = true
204
+ }
205
+
206
+ for _, iface := range s.netInterfaces {
207
+ if iface.ifName == "" {
208
+ continue
209
+ }
210
+
211
+ if !iface.updated {
212
+ delete(s.netInterfaces, iface.idx)
213
+ if iface.hasCharts {
214
+ s.removeNetIfaceCharts(iface)
215
+ }
216
+ continue
217
+ }
218
+ if !iface.hasCharts {
219
+ iface.hasCharts = true
220
+ s.addNetIfaceCharts(iface)
221
+ }
222
+
223
+ px := fmt.Sprintf("net_iface_%s_", iface.ifName)
224
+ mx[px+"traffic_in"] = iface.ifHCInOctets * 8 / 1000 // kilobits
225
+ mx[px+"traffic_out"] = iface.ifHCOutOctets * 8 / 1000 // kilobits
226
+ mx[px+"ucast_in"] = iface.ifHCInUcastPkts
227
+ mx[px+"ucast_out"] = iface.ifHCOutUcastPkts
228
+ mx[px+"mcast_in"] = iface.ifHCInMulticastPkts
229
+ mx[px+"mcast_out"] = iface.ifHCOutMulticastPkts
230
+ mx[px+"bcast_in"] = iface.ifHCInBroadcastPkts
231
+ mx[px+"bcast_out"] = iface.ifHCOutBroadcastPkts
232
+ mx[px+"errors_in"] = iface.ifInErrors
233
+ mx[px+"errors_out"] = iface.ifOutErrors
234
+ mx[px+"discards_in"] = iface.ifInDiscards
235
+ mx[px+"discards_out"] = iface.ifOutDiscards
236
+
237
+ for _, v := range ifAdminStatusMapping {
238
+ mx[px+"admin_status_"+v] = 0
239
+ }
240
+ mx[px+"admin_status_"+ifAdminStatusMapping[iface.ifAdminStatus]] = 1
241
+
242
+ for _, v := range ifOperStatusMapping {
243
+ mx[px+"oper_status_"+v] = 0
244
+ }
245
+ mx[px+"oper_status_"+ifOperStatusMapping[iface.ifOperStatus]] = 1
246
+ }
247
+
248
+ if logger.Level.Enabled(slog.LevelDebug) {
249
+ ifaces := make([]*netInterface, 0, len(s.netInterfaces))
250
+ for _, nif := range s.netInterfaces {
251
+ ifaces = append(ifaces, nif)
252
+ }
253
+ sort.Slice(ifaces, func(i, j int) bool { return ifaces[i].ifIndex < ifaces[j].ifIndex })
254
+ for _, iface := range ifaces {
255
+ s.Debugf("found %s", iface)
256
+ }
257
+ }
258
+
259
+ return nil
260
+}
261
+
262
+func (s *SNMP) walkAll(rootOid string) ([]gosnmp.SnmpPDU, error) {
263
+ if s.snmpClient.Version() == gosnmp.Version1 {
264
+ return s.snmpClient.WalkAll(rootOid)
265
+ }
266
+ return s.snmpClient.BulkWalkAll(rootOid)
267
+}
268
+
269
+func pduToString(pdu gosnmp.SnmpPDU) (string, error) {
270
+ switch pdu.Type {
271
+ case gosnmp.OctetString:
272
+ // TODO: this isn't reliable (e.g. physAddress we need hex.EncodeToString())
273
+ bs, ok := pdu.Value.([]byte)
274
+ if !ok {
275
+ return "", fmt.Errorf("OctetString is not a []byte but %T", pdu.Value)
276
+ }
277
+ return strings.ToValidUTF8(string(bs), "�"), nil
278
+ case gosnmp.Counter32, gosnmp.Counter64, gosnmp.Integer, gosnmp.Gauge32:
279
+ return gosnmp.ToBigInt(pdu.Value).String(), nil
280
+ default:
281
+ return "", fmt.Errorf("unussported type: '%v'", pdu.Type)
282
+ }
283
+}
284
+
285
+func pduToInt(pdu gosnmp.SnmpPDU) (int64, error) {
286
+ switch pdu.Type {
287
+ case gosnmp.Counter32, gosnmp.Counter64, gosnmp.Integer, gosnmp.Gauge32, gosnmp.TimeTicks:
288
+ return gosnmp.ToBigInt(pdu.Value).Int64(), nil
289
+ default:
290
+ return 0, fmt.Errorf("unussported type: '%v'", pdu.Type)
291
+ }
292
+}
293
+
294
+//func physAddressToString(pdu gosnmp.SnmpPDU) (string, error) {
295
+// address, ok := pdu.Value.([]uint8)
296
+// if !ok {
297
+// return "", errors.New("physAddress is not a []uint8")
298
+// }
299
+// parts := make([]string, 0, 6)
300
+// for _, v := range address {
301
+// parts = append(parts, fmt.Sprintf("%02X", v))
302
+// }
303
+// return strings.Join(parts, ":"), nil
304
+//}
305
+
306
+func (s *SNMP) collectOIDs(mx map[string]int64) error {
307
for i, end := 0, 0; i < len(s.oids); i += s.Options.MaxOIDs {
308
if end = i + s.Options.MaxOIDs; end > len(s.oids) {
309
end = len(s.oids)
@@ -44,7 +331,7 @@ func (s *SNMP) collectOIDs(collected map[string]int64) error {
331
gosnmp.OpaqueFloat,
332
gosnmp.OpaqueDouble,
333
gosnmp.Integer:
47
- collected[oid] = gosnmp.ToBigInt(v.Value).Int64()
334
+ mx[oid] = gosnmp.ToBigInt(v.Value).Int64()
335
default:
336
s.Debugf("skipping OID '%s' (unsupported type '%s')", oid, v.Type)
337
}
src/go/collectors/go.d.plugin/modules/snmp/config.go
new
+47
@@ -0,0 +1,47 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package snmp
4
+
5
+type (
6
+ Config struct {
7
+ UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
8
+ Hostname string `yaml:"hostname" json:"hostname"`
9
+ Community string `yaml:"community,omitempty" json:"community"`
10
+ User User `yaml:"user,omitempty" json:"user"`
11
+ Options Options `yaml:"options,omitempty" json:"options"`
12
+ ChartsInput []ChartConfig `yaml:"charts,omitempty" json:"charts"`
13
+ }
14
+ User struct {
15
+ Name string `yaml:"name,omitempty" json:"name"`
16
+ SecurityLevel string `yaml:"level,omitempty" json:"level"`
17
+ AuthProto string `yaml:"auth_proto,omitempty" json:"auth_proto"`
18
+ AuthKey string `yaml:"auth_key,omitempty" json:"auth_key"`
19
+ PrivProto string `yaml:"priv_proto,omitempty" json:"priv_proto"`
20
+ PrivKey string `yaml:"priv_key,omitempty" json:"priv_key"`
21
+ }
22
+ Options struct {
23
+ Port int `yaml:"port,omitempty" json:"port"`
24
+ Retries int `yaml:"retries,omitempty" json:"retries"`
25
+ Timeout int `yaml:"timeout,omitempty" json:"timeout"`
26
+ Version string `yaml:"version,omitempty" json:"version"`
27
+ MaxOIDs int `yaml:"max_request_size,omitempty" json:"max_request_size"`
28
+ MaxRepetitions int `yaml:"max_repetitions,omitempty" json:"max_repetitions"`
29
+ }
30
+ ChartConfig struct {
31
+ ID string `yaml:"id" json:"id"`
32
+ Title string `yaml:"title" json:"title"`
33
+ Units string `yaml:"units" json:"units"`
34
+ Family string `yaml:"family" json:"family"`
35
+ Type string `yaml:"type" json:"type"`
36
+ Priority int `yaml:"priority" json:"priority"`
37
+ IndexRange []int `yaml:"multiply_range,omitempty" json:"multiply_range"`
38
+ Dimensions []DimensionConfig `yaml:"dimensions" json:"dimensions"`
39
+ }
40
+ DimensionConfig struct {
41
+ OID string `yaml:"oid" json:"oid"`
42
+ Name string `yaml:"name" json:"name"`
43
+ Algorithm string `yaml:"algorithm" json:"algorithm"`
44
+ Multiplier int `yaml:"multiplier" json:"multiplier"`
45
+ Divisor int `yaml:"divisor" json:"divisor"`
46
+ }
47
+)
src/go/collectors/go.d.plugin/modules/snmp/config_schema.json
+25
-12
@@ -8,7 +8,7 @@
8
"description": "Data collection interval, measured in seconds.",
9
"type": "integer",
10
"minimum": 1,
11
- "default": 1
11
+ "default": 10
12
},
13
"hostname": {
14
"title": "Hostname",
@@ -46,23 +46,30 @@
46
"exclusiveMinimum": 0,
47
"default": 161
48
},
49
+ "timeout": {
50
+ "title": "Timeout",
51
+ "description": "The timeout duration in seconds for SNMP requests.",
52
+ "type": "integer",
53
+ "minimum": 1,
54
+ "default": 5
55
+ },
56
"retries": {
57
"title": "Retries",
58
"description": "The number of retries to attempt for SNMP requests.",
59
"type": "integer",
60
"minimum": 0,
54
- "default": 161
61
+ "default": 1
62
},
56
- "timeout": {
57
- "title": "Timeout",
58
- "description": "The timeout duration in seconds for SNMP requests.",
63
+ "max_repetitions": {
64
+ "title": "Max repetitions",
65
+ "description": "Controls how many SNMP variables to retrieve in a single GETBULK request.",
66
"type": "integer",
67
"minimum": 1,
61
- "default": 1
68
+ "default": 25
69
},
70
"max_request_size": {
64
- "title": "Max OIDs in request",
65
- "description": "The maximum number of OIDs allowed in a single SNMP request.",
71
+ "title": "Max OIDs",
72
+ "description": "The maximum number of OIDs allowed in a single GET request.",
73
"type": "integer",
74
"minimum": 1,
75
"default": 60
@@ -144,7 +151,6 @@
151
"null"
152
],
153
"uniqueItems": true,
147
- "minItems": 1,
154
"items": {
155
"title": "Chart",
156
"type": [
@@ -284,8 +290,7 @@
290
"required": [
291
"hostname",
292
"community",
287
- "options",
288
- "charts"
293
+ "options"
294
],
295
"additionalProperties": false,
296
"patternProperties": {
@@ -302,6 +307,9 @@
307
"ui:options": {
308
"inline": true
309
}
310
+ },
311
+ "max_repetitions": {
312
+ "ui:help": "A higher value retrieves more data in fewer round trips, potentially improving efficiency. This reduces network overhead compared to sending multiple individual requests. **Important**: Setting a value too high might cause the target device to return no data."
313
}
314
},
315
"user": {
@@ -357,7 +365,12 @@
365
"fields": [
366
"update_every",
367
"hostname",
360
- "community",
368
+ "community"
369
+ ]
370
+ },
371
+ {
372
+ "title": "Conn Options",
373
+ "fields": [
374
"options"
375
]
376
},
src/go/collectors/go.d.plugin/modules/snmp/init.go
+59
-97
@@ -5,71 +5,31 @@ package snmp
5
import (
6
"errors"
7
"fmt"
8
+ "strings"
9
"time"
10
11
"github.com/gosnmp/gosnmp"
12
)
13
13
-var newSNMPClient = gosnmp.NewHandler
14
-
14
func (s *SNMP) validateConfig() error {
16
- if len(s.ChartsInput) == 0 {
17
- return errors.New("'charts' are required but not set")
18
- }
19
-
20
- if s.Options.Version == gosnmp.Version3.String() {
21
- if s.User.Name == "" {
22
- return errors.New("'user.name' is required when using SNMPv3 but not set")
23
- }
24
- if _, err := parseSNMPv3SecurityLevel(s.User.SecurityLevel); err != nil {
25
- return err
26
- }
27
- if _, err := parseSNMPv3AuthProtocol(s.User.AuthProto); err != nil {
28
- return err
29
- }
30
- if _, err := parseSNMPv3PrivProtocol(s.User.PrivProto); err != nil {
31
- return err
32
- }
15
+ if s.Hostname == "" {
16
+ return errors.New("SNMP hostname is required")
17
}
34
-
18
return nil
19
}
20
21
func (s *SNMP) initSNMPClient() (gosnmp.Handler, error) {
39
- client := newSNMPClient()
22
+ client := s.newSnmpClient()
23
41
- if client.SetTarget(s.Hostname); client.Target() == "" {
42
- s.Warningf("'hostname' not set, using the default value: '%s'", defaultHostname)
43
- client.SetTarget(defaultHostname)
44
- }
45
- if client.SetPort(uint16(s.Options.Port)); client.Port() <= 0 || client.Port() > 65535 {
46
- s.Warningf("'options.port' is invalid, changing to the default value: '%d' => '%d'", s.Options.Port, defaultPort)
47
- client.SetPort(defaultPort)
48
- }
49
- if client.SetRetries(s.Options.Retries); client.Retries() < 1 || client.Retries() > 10 {
50
- s.Warningf("'options.retries' is invalid, changing to the default value: '%d' => '%d'", s.Options.Retries, defaultRetries)
51
- client.SetRetries(defaultRetries)
52
- }
53
- if client.SetTimeout(time.Duration(s.Options.Timeout) * time.Second); client.Timeout().Seconds() < 1 {
54
- s.Warningf("'options.timeout' is invalid, changing to the default value: '%d' => '%d'", s.Options.Timeout, defaultTimeout)
55
- client.SetTimeout(defaultTimeout * time.Second)
56
- }
57
- if client.SetMaxOids(s.Options.MaxOIDs); client.MaxOids() < 1 {
58
- s.Warningf("'options.max_request_size' is invalid, changing to the default value: '%d' => '%d'", s.Options.MaxOIDs, defaultMaxOIDs)
59
- client.SetMaxOids(defaultMaxOIDs)
60
- }
24
+ client.SetTarget(s.Hostname)
25
+ client.SetPort(uint16(s.Options.Port))
26
+ client.SetRetries(s.Options.Retries)
27
+ client.SetTimeout(time.Duration(s.Options.Timeout) * time.Second)
28
+ client.SetMaxOids(s.Options.MaxOIDs)
29
+ client.SetMaxRepetitions(uint32(s.Options.MaxRepetitions))
30
62
- ver, err := parseSNMPVersion(s.Options.Version)
63
- if err != nil {
64
- s.Warningf("'options.version' is invalid, changing to the default value: '%s' => '%s'",
65
- s.Options.Version, defaultVersion)
66
- ver = defaultVersion
67
- }
31
+ ver := parseSNMPVersion(s.Options.Version)
32
comm := s.Community
69
- if comm == "" && (ver <= gosnmp.Version2c) {
70
- s.Warningf("'community' not set, using the default value: '%s'", defaultCommunity)
71
- comm = defaultCommunity
72
- }
33
34
switch ver {
35
case gosnmp.Version1:
@@ -79,20 +39,25 @@ func (s *SNMP) initSNMPClient() (gosnmp.Handler, error) {
39
client.SetCommunity(comm)
40
client.SetVersion(gosnmp.Version2c)
41
case gosnmp.Version3:
42
+ if s.User.Name == "" {
43
+ return nil, errors.New("username is required for SNMPv3")
44
+ }
45
client.SetVersion(gosnmp.Version3)
46
client.SetSecurityModel(gosnmp.UserSecurityModel)
84
- client.SetMsgFlags(safeParseSNMPv3SecurityLevel(s.User.SecurityLevel))
47
+ client.SetMsgFlags(parseSNMPv3SecurityLevel(s.User.SecurityLevel))
48
client.SetSecurityParameters(&gosnmp.UsmSecurityParameters{
49
UserName: s.User.Name,
87
- AuthenticationProtocol: safeParseSNMPv3AuthProtocol(s.User.AuthProto),
50
+ AuthenticationProtocol: parseSNMPv3AuthProtocol(s.User.AuthProto),
51
AuthenticationPassphrase: s.User.AuthKey,
89
- PrivacyProtocol: safeParseSNMPv3PrivProtocol(s.User.PrivProto),
52
+ PrivacyProtocol: parseSNMPv3PrivProtocol(s.User.PrivProto),
53
PrivacyPassphrase: s.User.PrivKey,
54
})
55
default:
56
return nil, fmt.Errorf("invalid SNMP version: %s", s.Options.Version)
57
}
58
59
+ s.Info(snmpClientConnInfo(client))
60
+
61
return client, nil
62
}
63
@@ -105,85 +70,82 @@ func (s *SNMP) initOIDs() (oids []string) {
70
return oids
71
}
72
108
-func parseSNMPVersion(version string) (gosnmp.SnmpVersion, error) {
73
+func parseSNMPVersion(version string) gosnmp.SnmpVersion {
74
switch version {
75
case "0", "1":
111
- return gosnmp.Version1, nil
76
+ return gosnmp.Version1
77
case "2", "2c", "":
113
- return gosnmp.Version2c, nil
78
+ return gosnmp.Version2c
79
case "3":
115
- return gosnmp.Version3, nil
80
+ return gosnmp.Version3
81
default:
117
- return gosnmp.Version2c, fmt.Errorf("invalid snmp version value (%s)", version)
82
+ return gosnmp.Version2c
83
}
84
}
85
121
-func safeParseSNMPv3SecurityLevel(level string) gosnmp.SnmpV3MsgFlags {
122
- v, _ := parseSNMPv3SecurityLevel(level)
123
- return v
124
-}
125
-
126
-func parseSNMPv3SecurityLevel(level string) (gosnmp.SnmpV3MsgFlags, error) {
86
+func parseSNMPv3SecurityLevel(level string) gosnmp.SnmpV3MsgFlags {
87
switch level {
88
case "1", "none", "noAuthNoPriv", "":
129
- return gosnmp.NoAuthNoPriv, nil
89
+ return gosnmp.NoAuthNoPriv
90
case "2", "authNoPriv":
131
- return gosnmp.AuthNoPriv, nil
91
+ return gosnmp.AuthNoPriv
92
case "3", "authPriv":
133
- return gosnmp.AuthPriv, nil
93
+ return gosnmp.AuthPriv
94
default:
135
- return gosnmp.NoAuthNoPriv, fmt.Errorf("invalid snmpv3 user security level value (%s)", level)
95
+ return gosnmp.NoAuthNoPriv
96
}
97
}
98
139
-func safeParseSNMPv3AuthProtocol(protocol string) gosnmp.SnmpV3AuthProtocol {
140
- v, _ := parseSNMPv3AuthProtocol(protocol)
141
- return v
142
-}
143
-
144
-func parseSNMPv3AuthProtocol(protocol string) (gosnmp.SnmpV3AuthProtocol, error) {
99
+func parseSNMPv3AuthProtocol(protocol string) gosnmp.SnmpV3AuthProtocol {
100
switch protocol {
101
case "1", "none", "noAuth", "":
147
- return gosnmp.NoAuth, nil
102
+ return gosnmp.NoAuth
103
case "2", "md5":
149
- return gosnmp.MD5, nil
104
+ return gosnmp.MD5
105
case "3", "sha":
151
- return gosnmp.SHA, nil
106
+ return gosnmp.SHA
107
case "4", "sha224":
153
- return gosnmp.SHA224, nil
108
+ return gosnmp.SHA224
109
case "5", "sha256":
155
- return gosnmp.SHA256, nil
110
+ return gosnmp.SHA256
111
case "6", "sha384":
157
- return gosnmp.SHA384, nil
112
+ return gosnmp.SHA384
113
case "7", "sha512":
159
- return gosnmp.SHA512, nil
114
+ return gosnmp.SHA512
115
default:
161
- return gosnmp.NoAuth, fmt.Errorf("invalid snmpv3 user auth protocol value (%s)", protocol)
116
+ return gosnmp.NoAuth
117
}
118
}
119
165
-func safeParseSNMPv3PrivProtocol(protocol string) gosnmp.SnmpV3PrivProtocol {
166
- v, _ := parseSNMPv3PrivProtocol(protocol)
167
- return v
168
-}
169
-
170
-func parseSNMPv3PrivProtocol(protocol string) (gosnmp.SnmpV3PrivProtocol, error) {
120
+func parseSNMPv3PrivProtocol(protocol string) gosnmp.SnmpV3PrivProtocol {
121
switch protocol {
122
case "1", "none", "noPriv", "":
173
- return gosnmp.NoPriv, nil
123
+ return gosnmp.NoPriv
124
case "2", "des":
175
- return gosnmp.DES, nil
125
+ return gosnmp.DES
126
case "3", "aes":
177
- return gosnmp.AES, nil
127
+ return gosnmp.AES
128
case "4", "aes192":
179
- return gosnmp.AES192, nil
129
+ return gosnmp.AES192
130
case "5", "aes256":
181
- return gosnmp.AES256, nil
131
+ return gosnmp.AES256
132
case "6", "aes192c":
183
- return gosnmp.AES192C, nil
133
+ return gosnmp.AES192C
134
case "7", "aes256c":
185
- return gosnmp.AES256C, nil
135
+ return gosnmp.AES256C
136
default:
187
- return gosnmp.NoPriv, fmt.Errorf("invalid snmpv3 user priv protocol value (%s)", protocol)
137
+ return gosnmp.NoPriv
138
+ }
139
+}
140
+
141
+func snmpClientConnInfo(c gosnmp.Handler) string {
142
+ var info strings.Builder
143
+ info.WriteString(fmt.Sprintf("hostname='%s',port='%d',snmp_version='%s'", c.Target(), c.Port(), c.Version()))
144
+ switch c.Version() {
145
+ case gosnmp.Version1, gosnmp.Version2c:
146
+ info.WriteString(fmt.Sprintf(",community='%s'", c.Community()))
147
+ case gosnmp.Version3:
148
+ info.WriteString(fmt.Sprintf(",security_level='%d,%s'", c.MsgFlags(), c.SecurityParameters().Description()))
149
}
150
+ return info.String()
151
}
src/go/collectors/go.d.plugin/modules/snmp/metadata.yaml
+151
-59
@@ -21,22 +21,22 @@ modules:
21
overview:
22
data_collection:
23
metrics_description: |
24
- This collector monitors any SNMP devices and uses the [gosnmp](https://github.com/gosnmp/gosnmp) package.
25
-
26
- It supports:
24
+ This SNMP collector discovers and gathers statistics for network interfaces on SNMP-enabled devices:
25
+
26
+ - Traffic
27
+ - Packets (unicast, multicast, broadcast)
28
+ - Errors
29
+ - Discards
30
+ - Administrative and operational status
31
28
- - all SNMP versions: SNMPv1, SNMPv2c and SNMPv3.
29
- - any number of SNMP devices.
30
- - each SNMP device can be used to collect data for any number of charts.
31
- - each chart may have any number of dimensions.
32
- - each SNMP device may have a different update frequency.
33
- - each SNMP device will accept one or more batches to report values (you can set `max_request_size` per SNMP server, to control the size of batches).
32
+ Additionally, it collects overall device uptime.
33
35
- Keep in mind that many SNMP switches and routers are very slow. They may not be able to report values per second.
36
- `go.d.plugin` reports the time it took for the SNMP device to respond when executed in the debug mode.
34
+ It is compatible with all SNMP versions (v1, v2c, and v3) and uses the [gosnmp](https://github.com/gosnmp/gosnmp) package.
35
38
- Also, if many SNMP clients are used on the same SNMP device at the same time, values may be skipped.
39
- This is a problem of the SNMP device, not this collector. In this case, consider reducing the frequency of data collection (increasing `update_every`).
36
+ **For advanced users**:
37
+
38
+ - You can manually specify custom OIDs (Object Identifiers) to retrieve specific data points beyond the default metrics.
39
+ - However, defining custom charts with dimensions for these OIDs requires manual configuration.
40
method_description: ""
41
supported_platforms:
42
include: []
@@ -50,23 +50,15 @@ modules:
50
limits:
51
description: ""
52
performance_impact:
53
- description: ""
54
- setup:
55
- prerequisites:
56
- list:
57
- - title: Find OIDs
58
- description: |
59
- Use `snmpwalk`, like this:
53
+ description: |
54
+ **Performance Considerations**:
55
61
- ```sh
62
- snmpwalk -t 20 -O fn -v 2c -c public 192.0.2.1
63
- ```
56
+ - **Device limitations**: Many SNMP switches and routers have limited processing power. They might not be able to report data as frequently as desired. You can monitor response times using go.d.plugin in debug mode to identify potential bottlenecks.
57
65
- - `-t 20` is the timeout in seconds.
66
- - `-O fn` will display full OIDs in numeric format.
67
- - `-v 2c` is the SNMP version.
68
- - `-c public` is the SNMP community.
69
- - `192.0.2.1` is the SNMP device.
58
+ - **Concurrent access**: If multiple collectors or tools access the same SNMP device simultaneously, data points might be skipped. This is a limitation of the device itself, not this collector. To mitigate this, consider increasing the collection interval (update_every) to reduce the frequency of requests.
59
+ setup:
60
+ prerequisites:
61
+ list: []
62
configuration:
63
file:
64
name: go.d/snmp.conf
@@ -79,7 +71,7 @@ modules:
71
list:
72
- name: update_every
73
description: Data collection frequency.
82
- default_value: 1
74
+ default_value: 10
75
required: false
76
- name: autodetection_retry
77
description: Recheck interval in seconds. Zero means no recheck will be scheduled.
@@ -87,7 +79,7 @@ modules:
79
required: false
80
- name: hostname
81
description: Target ipv4 address.
90
- default_value: 127.0.0.1
82
+ default_value: ""
83
required: true
84
- name: community
85
description: SNMPv1/2 community string.
@@ -107,10 +99,14 @@ modules:
99
required: false
100
- name: options.timeout
101
description: SNMP request/response timeout.
110
- default_value: 10
102
+ default_value: 5
103
+ required: false
104
+ - name: options.max_repetitions
105
+ description: Controls how many SNMP variables to retrieve in a single GETBULK request.
106
+ default_value: 25
107
required: false
108
- name: options.max_request_size
113
- description: Maximum number of OIDs allowed in one one SNMP request.
109
+ description: Maximum number of OIDs allowed in a single GET request.
110
default_value: 60
111
required: false
112
- name: user.name
@@ -242,10 +238,42 @@ modules:
238
- the SNMP version is `2`.
239
- the SNMP community is `public`.
240
- we will update the values every 10 seconds.
245
- - we define 2 charts `bandwidth_port1` and `bandwidth_port2`, each having 2 dimensions: `in` and `out`.
241
+ config: |
242
+ jobs:
243
+ - name: switch
244
+ update_every: 10
245
+ hostname: 192.0.2.1
246
+ community: public
247
+ options:
248
+ version: 2
249
+ - name: SNMPv3
250
+ description: |
251
+ To use SNMPv3:
252
+
253
+ - use `user` instead of `community`.
254
+ - set `options.version` to 3.
255
+ config: |
256
+ jobs:
257
+ - name: switch
258
+ update_every: 10
259
+ hostname: 192.0.2.1
260
+ options:
261
+ version: 3
262
+ user:
263
+ name: username
264
+ level: authPriv
265
+ auth_proto: sha256
266
+ auth_key: auth_protocol_passphrase
267
+ priv_proto: aes256
268
+ priv_key: priv_protocol_passphrase
269
+ - name: Custom OIDs
270
+ description: |
271
+ In this example:
272
247
- > **SNMPv1**: just set `options.version` to 1.
248
- > **Note**: the algorithm chosen is `incremental`, because the collected values show the total number of bytes transferred, which we need to transform into kbps. To chart gauges (e.g. temperature), use `absolute` instead.
273
+ - the SNMP device is `192.0.2.1`.
274
+ - the SNMP version is `2`.
275
+ - the SNMP community is `public`.
276
+ - we will update the values every 10 seconds.
277
config: |
278
jobs:
279
- name: switch
@@ -285,29 +313,7 @@ modules:
313
oid: "1.3.6.1.2.1.2.2.1.16.2"
314
multiplier: -8
315
divisor: 1000
288
- - name: SNMPv3
289
- description: |
290
- To use SNMPv3:
291
-
292
- - use `user` instead of `community`.
293
- - set `options.version` to 3.
294
-
295
- The rest of the configuration is the same as in the SNMPv1/2 example.
296
- config: |
297
- jobs:
298
- - name: switch
299
- update_every: 10
300
- hostname: 192.0.2.1
301
- options:
302
- version: 3
303
- user:
304
- name: username
305
- level: authPriv
306
- auth_proto: sha256
307
- auth_key: auth_protocol_passphrase
308
- priv_proto: aes256
309
- priv_key: priv_protocol_passphrase
310
- - name: Multiply range
316
+ - name: Custom OIDs with multiply range
317
description: |
318
If you need to define many charts using incremental OIDs, you can use the `charts.multiply_range` option.
319
@@ -395,4 +401,90 @@ modules:
401
enabled: false
402
description: The metrics that will be collected are defined in the configuration file.
403
availability: []
398
- scopes: []
404
+ scopes:
405
+ - name: snmp device
406
+ description: These metrics refer to the SNMP device.
407
+ labels:
408
+ - name: sysName
409
+ description: "SNMP device's system name (OID: [1.3.6.1.2.1.1.5](https://oidref.com/1.3.6.1.2.1.1.5))."
410
+ metrics:
411
+ - name: snmp.device_uptime
412
+ description: SNMP device uptime
413
+ unit: seconds
414
+ chart_type: line
415
+ dimensions:
416
+ - name: uptime
417
+ - name: network interface
418
+ description: Network interfaces of the SNMP device being monitored. These metrics refer to each interface.
419
+ labels:
420
+ - name: sysName
421
+ description: "SNMP device's system name (OID: [1.3.6.1.2.1.1.5](https://oidref.com/1.3.6.1.2.1.1.5))."
422
+ - name: ifDescr
423
+ description: "Network interface description (OID: [1.3.6.1.2.1.2.2.1.2](https://cric.grenoble.cnrs.fr/Administrateurs/Outils/MIBS/?oid=1.3.6.1.2.1.2.2.1.2))."
424
+ - name: ifName
425
+ description: "Network interface name (OID: [1.3.6.1.2.1.2.2.1.2](https://cric.grenoble.cnrs.fr/Administrateurs/Outils/MIBS/?oid=1.3.6.1.2.1.31.1.1.1.1))."
426
+ - name: ifType
427
+ description: "Network interface type (OID: [1.3.6.1.2.1.2.2.1.2](https://cric.grenoble.cnrs.fr/Administrateurs/Outils/MIBS/?oid=1.3.6.1.2.1.2.2.1.3))."
428
+ metrics:
429
+ - name: snmp.device_net_interface_traffic
430
+ description: SNMP device network interface traffic
431
+ unit: kilobits/s
432
+ chart_type: area
433
+ dimensions:
434
+ - name: received
435
+ - name: sent
436
+ - name: snmp.device_net_interface_unicast
437
+ description: SNMP device network interface unicast packets
438
+ unit: packets/s
439
+ chart_type: line
440
+ dimensions:
441
+ - name: received
442
+ - name: sent
443
+ - name: snmp.device_net_interface_multicast
444
+ description: SNMP device network interface multicast packets
445
+ unit: packets/s
446
+ chart_type: line
447
+ dimensions:
448
+ - name: received
449
+ - name: sent
450
+ - name: snmp.device_net_interface_broadcast
451
+ description: SNMP device network interface broadcast packets
452
+ unit: packets/s
453
+ chart_type: line
454
+ dimensions:
455
+ - name: received
456
+ - name: sent
457
+ - name: snmp.device_net_interface_errors
458
+ description: SNMP device network interface errors
459
+ unit: errors/s
460
+ chart_type: line
461
+ dimensions:
462
+ - name: inbound
463
+ - name: outbound
464
+ - name: snmp.device_net_interface_discards
465
+ description: SNMP device network interface discards
466
+ unit: discards/s
467
+ chart_type: line
468
+ dimensions:
469
+ - name: inbound
470
+ - name: outbound
471
+ - name: snmp.device_net_interface_admin_status
472
+ description: SNMP device network interface administrative status
473
+ unit: status
474
+ chart_type: line
475
+ dimensions:
476
+ - name: up
477
+ - name: down
478
+ - name: testing
479
+ - name: snmp.device_net_interface_oper_status
480
+ description: SNMP device network interface operational status
481
+ unit: status
482
+ chart_type: line
483
+ dimensions:
484
+ - name: up
485
+ - name: down
486
+ - name: testing
487
+ - name: unknown
488
+ - name: dormant
489
+ - name: not_present
490
+ - name: lower_layer_down
src/go/collectors/go.d.plugin/modules/snmp/netif.go
new
+412
@@ -0,0 +1,412 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package snmp
4
+
5
+import (
6
+ "fmt"
7
+ "strings"
8
+)
9
+
10
+const (
11
+ oidIfIndex = "1.3.6.1.2.1.2.2.1.1"
12
+ oidIfDescr = "1.3.6.1.2.1.2.2.1.2"
13
+ oidIfType = "1.3.6.1.2.1.2.2.1.3"
14
+ oidIfMtu = "1.3.6.1.2.1.2.2.1.4"
15
+ oidIfSpeed = "1.3.6.1.2.1.2.2.1.5"
16
+ oidIfPhysAddress = "1.3.6.1.2.1.2.2.1.6"
17
+ oidIfAdminStatus = "1.3.6.1.2.1.2.2.1.7"
18
+ oidIfOperStatus = "1.3.6.1.2.1.2.2.1.8"
19
+ oidIfLastChange = "1.3.6.1.2.1.2.2.1.9"
20
+ oidIfInOctets = "1.3.6.1.2.1.2.2.1.10"
21
+ oidIfInUcastPkts = "1.3.6.1.2.1.2.2.1.11"
22
+ oidIfInNUcastPkts = "1.3.6.1.2.1.2.2.1.12"
23
+ oidIfInDiscards = "1.3.6.1.2.1.2.2.1.13"
24
+ oidIfInErrors = "1.3.6.1.2.1.2.2.1.14"
25
+ oidIfInUnknownProtos = "1.3.6.1.2.1.2.2.1.15"
26
+ oidIfOutOctets = "1.3.6.1.2.1.2.2.1.16"
27
+ oidIfOutUcastPkts = "1.3.6.1.2.1.2.2.1.17"
28
+ oidIfOutNUcastPkts = "1.3.6.1.2.1.2.2.1.18"
29
+ oidIfOutDiscards = "1.3.6.1.2.1.2.2.1.19"
30
+ oidIfOutErrors = "1.3.6.1.2.1.2.2.1.20"
31
+
32
+ oidIfName = "1.3.6.1.2.1.31.1.1.1.1"
33
+ oidIfInMulticastPkts = "1.3.6.1.2.1.31.1.1.1.2"
34
+ oidIfInBroadcastPkts = "1.3.6.1.2.1.31.1.1.1.3"
35
+ oidIfOutMulticastPkts = "1.3.6.1.2.1.31.1.1.1.4"
36
+ oidIfOutBroadcastPkts = "1.3.6.1.2.1.31.1.1.1.5"
37
+ oidIfHCInOctets = "1.3.6.1.2.1.31.1.1.1.6"
38
+ oidIfHCInUcastPkts = "1.3.6.1.2.1.31.1.1.1.7"
39
+ oidIfHCInMulticastPkts = "1.3.6.1.2.1.31.1.1.1.8"
40
+ oidIfHCInBroadcastPkts = "1.3.6.1.2.1.31.1.1.1.9"
41
+ oidIfHCOutOctets = "1.3.6.1.2.1.31.1.1.1.10"
42
+ oidIfHCOutUcastPkts = "1.3.6.1.2.1.31.1.1.1.11"
43
+ oidIfHCOutMulticastPkts = "1.3.6.1.2.1.31.1.1.1.12"
44
+ oidIfHCOutBroadcastPkts = "1.3.6.1.2.1.31.1.1.1.13"
45
+ oidIfHighSpeed = "1.3.6.1.2.1.31.1.1.1.15"
46
+ oidIfAlias = "1.3.6.1.2.1.31.1.1.1.18"
47
+)
48
+
49
+type netInterface struct {
50
+ updated bool
51
+ hasCharts bool
52
+ idx string
53
+
54
+ ifIndex int64
55
+ ifDescr string
56
+ ifType int64
57
+ ifMtu int64
58
+ ifSpeed int64
59
+ //ifPhysAddress string
60
+ ifAdminStatus int64
61
+ ifOperStatus int64
62
+ //ifLastChange string
63
+ ifInOctets int64
64
+ ifInUcastPkts int64
65
+ ifInNUcastPkts int64
66
+ ifInDiscards int64
67
+ ifInErrors int64
68
+ ifInUnknownProtos int64
69
+ ifOutOctets int64
70
+ ifOutUcastPkts int64
71
+ ifOutNUcastPkts int64
72
+ ifOutDiscards int64
73
+ ifOutErrors int64
74
+ ifName string
75
+ ifInMulticastPkts int64
76
+ ifInBroadcastPkts int64
77
+ ifOutMulticastPkts int64
78
+ ifOutBroadcastPkts int64
79
+ ifHCInOctets int64
80
+ ifHCInUcastPkts int64
81
+ ifHCInMulticastPkts int64
82
+ ifHCInBroadcastPkts int64
83
+ ifHCOutOctets int64
84
+ ifHCOutUcastPkts int64
85
+ ifHCOutMulticastPkts int64
86
+ ifHCOutBroadcastPkts int64
87
+ ifHighSpeed int64
88
+ ifAlias string
89
+}
90
+
91
+func (n *netInterface) String() string {
92
+ return fmt.Sprintf("iface index='%d',type='%s',name='%s',descr='%s',alias='%s'",
93
+ n.ifIndex, ifTypeMapping[n.ifType], n.ifName, n.ifDescr, strings.ReplaceAll(n.ifAlias, "\n", "\\n"))
94
+}
95
+
96
+var ifAdminStatusMapping = map[int64]string{
97
+ 1: "up",
98
+ 2: "down",
99
+ 3: "testing",
100
+}
101
+
102
+var ifOperStatusMapping = map[int64]string{
103
+ 1: "up",
104
+ 2: "down",
105
+ 3: "testing",
106
+ 4: "unknown",
107
+ 5: "dormant",
108
+ 6: "notPresent",
109
+ 7: "lowerLayerDown",
110
+}
111
+
112
+var ifTypeMapping = map[int64]string{
113
+ 1: "other",
114
+ 2: "regular1822",
115
+ 3: "hdh1822",
116
+ 4: "ddnX25",
117
+ 5: "rfc877x25",
118
+ 6: "ethernetCsmacd",
119
+ 7: "iso88023Csmacd",
120
+ 8: "iso88024TokenBus",
121
+ 9: "iso88025TokenRing",
122
+ 10: "iso88026Man",
123
+ 11: "starLan",
124
+ 12: "proteon10Mbit",
125
+ 13: "proteon80Mbit",
126
+ 14: "hyperchannel",
127
+ 15: "fddi",
128
+ 16: "lapb",
129
+ 17: "sdlc",
130
+ 18: "ds1",
131
+ 19: "e1",
132
+ 20: "basicISDN",
133
+ 21: "primaryISDN",
134
+ 22: "propPointToPointSerial",
135
+ 23: "ppp",
136
+ 24: "softwareLoopback",
137
+ 25: "eon",
138
+ 26: "ethernet3Mbit",
139
+ 27: "nsip",
140
+ 28: "slip",
141
+ 29: "ultra",
142
+ 30: "ds3",
143
+ 31: "sip",
144
+ 32: "frameRelay",
145
+ 33: "rs232",
146
+ 34: "para",
147
+ 35: "arcnet",
148
+ 36: "arcnetPlus",
149
+ 37: "atm",
150
+ 38: "miox25",
151
+ 39: "sonet",
152
+ 40: "x25ple",
153
+ 41: "iso88022llc",
154
+ 42: "localTalk",
155
+ 43: "smdsDxi",
156
+ 44: "frameRelayService",
157
+ 45: "v35",
158
+ 46: "hssi",
159
+ 47: "hippi",
160
+ 48: "modem",
161
+ 49: "aal5",
162
+ 50: "sonetPath",
163
+ 51: "sonetVT",
164
+ 52: "smdsIcip",
165
+ 53: "propVirtual",
166
+ 54: "propMultiplexor",
167
+ 55: "ieee80212",
168
+ 56: "fibreChannel",
169
+ 57: "hippiInterface",
170
+ 58: "frameRelayInterconnect",
171
+ 59: "aflane8023",
172
+ 60: "aflane8025",
173
+ 61: "cctEmul",
174
+ 62: "fastEther",
175
+ 63: "isdn",
176
+ 64: "v11",
177
+ 65: "v36",
178
+ 66: "g703at64k",
179
+ 67: "g703at2mb",
180
+ 68: "qllc",
181
+ 69: "fastEtherFX",
182
+ 70: "channel",
183
+ 71: "ieee80211",
184
+ 72: "ibm370parChan",
185
+ 73: "escon",
186
+ 74: "dlsw",
187
+ 75: "isdns",
188
+ 76: "isdnu",
189
+ 77: "lapd",
190
+ 78: "ipSwitch",
191
+ 79: "rsrb",
192
+ 80: "atmLogical",
193
+ 81: "ds0",
194
+ 82: "ds0Bundle",
195
+ 83: "bsc",
196
+ 84: "async",
197
+ 85: "cnr",
198
+ 86: "iso88025Dtr",
199
+ 87: "eplrs",
200
+ 88: "arap",
201
+ 89: "propCnls",
202
+ 90: "hostPad",
203
+ 91: "termPad",
204
+ 92: "frameRelayMPI",
205
+ 93: "x213",
206
+ 94: "adsl",
207
+ 95: "radsl",
208
+ 96: "sdsl",
209
+ 97: "vdsl",
210
+ 98: "iso88025CRFPInt",
211
+ 99: "myrinet",
212
+ 100: "voiceEM",
213
+ 101: "voiceFXO",
214
+ 102: "voiceFXS",
215
+ 103: "voiceEncap",
216
+ 104: "voiceOverIp",
217
+ 105: "atmDxi",
218
+ 106: "atmFuni",
219
+ 107: "atmIma",
220
+ 108: "pppMultilinkBundle",
221
+ 109: "ipOverCdlc",
222
+ 110: "ipOverClaw",
223
+ 111: "stackToStack",
224
+ 112: "virtualIpAddress",
225
+ 113: "mpc",
226
+ 114: "ipOverAtm",
227
+ 115: "iso88025Fiber",
228
+ 116: "tdlc",
229
+ 117: "gigabitEthernet",
230
+ 118: "hdlc",
231
+ 119: "lapf",
232
+ 120: "v37",
233
+ 121: "x25mlp",
234
+ 122: "x25huntGroup",
235
+ 123: "transpHdlc",
236
+ 124: "interleave",
237
+ 125: "fast",
238
+ 126: "ip",
239
+ 127: "docsCableMaclayer",
240
+ 128: "docsCableDownstream",
241
+ 129: "docsCableUpstream",
242
+ 130: "a12MppSwitch",
243
+ 131: "tunnel",
244
+ 132: "coffee",
245
+ 133: "ces",
246
+ 134: "atmSubInterface",
247
+ 135: "l2vlan",
248
+ 136: "l3ipvlan",
249
+ 137: "l3ipxvlan",
250
+ 138: "digitalPowerline",
251
+ 139: "mediaMailOverIp",
252
+ 140: "dtm",
253
+ 141: "dcn",
254
+ 142: "ipForward",
255
+ 143: "msdsl",
256
+ 144: "ieee1394",
257
+ 145: "if-gsn",
258
+ 146: "dvbRccMacLayer",
259
+ 147: "dvbRccDownstream",
260
+ 148: "dvbRccUpstream",
261
+ 149: "atmVirtual",
262
+ 150: "mplsTunnel",
263
+ 151: "srp",
264
+ 152: "voiceOverAtm",
265
+ 153: "voiceOverFrameRelay",
266
+ 154: "idsl",
267
+ 155: "compositeLink",
268
+ 156: "ss7SigLink",
269
+ 157: "propWirelessP2P",
270
+ 158: "frForward",
271
+ 159: "rfc1483",
272
+ 160: "usb",
273
+ 161: "ieee8023adLag",
274
+ 162: "bgppolicyaccounting",
275
+ 163: "frf16MfrBundle",
276
+ 164: "h323Gatekeeper",
277
+ 165: "h323Proxy",
278
+ 166: "mpls",
279
+ 167: "mfSigLink",
280
+ 168: "hdsl2",
281
+ 169: "shdsl",
282
+ 170: "ds1FDL",
283
+ 171: "pos",
284
+ 172: "dvbAsiIn",
285
+ 173: "dvbAsiOut",
286
+ 174: "plc",
287
+ 175: "nfas",
288
+ 176: "tr008",
289
+ 177: "gr303RDT",
290
+ 178: "gr303IDT",
291
+ 179: "isup",
292
+ 180: "propDocsWirelessMaclayer",
293
+ 181: "propDocsWirelessDownstream",
294
+ 182: "propDocsWirelessUpstream",
295
+ 183: "hiperlan2",
296
+ 184: "propBWAp2Mp",
297
+ 185: "sonetOverheadChannel",
298
+ 186: "digitalWrapperOverheadChannel",
299
+ 187: "aal2",
300
+ 188: "radioMAC",
301
+ 189: "atmRadio",
302
+ 190: "imt",
303
+ 191: "mvl",
304
+ 192: "reachDSL",
305
+ 193: "frDlciEndPt",
306
+ 194: "atmVciEndPt",
307
+ 195: "opticalChannel",
308
+ 196: "opticalTransport",
309
+ 197: "propAtm",
310
+ 198: "voiceOverCable",
311
+ 199: "infiniband",
312
+ 200: "teLink",
313
+ 201: "q2931",
314
+ 202: "virtualTg",
315
+ 203: "sipTg",
316
+ 204: "sipSig",
317
+ 205: "docsCableUpstreamChannel",
318
+ 206: "econet",
319
+ 207: "pon155",
320
+ 208: "pon622",
321
+ 209: "bridge",
322
+ 210: "linegroup",
323
+ 211: "voiceEMFGD",
324
+ 212: "voiceFGDEANA",
325
+ 213: "voiceDID",
326
+ 214: "mpegTransport",
327
+ 215: "sixToFour",
328
+ 216: "gtp",
329
+ 217: "pdnEtherLoop1",
330
+ 218: "pdnEtherLoop2",
331
+ 219: "opticalChannelGroup",
332
+ 220: "homepna",
333
+ 221: "gfp",
334
+ 222: "ciscoISLvlan",
335
+ 223: "actelisMetaLOOP",
336
+ 224: "fcipLink",
337
+ 225: "rpr",
338
+ 226: "qam",
339
+ 227: "lmp",
340
+ 228: "cblVectaStar",
341
+ 229: "docsCableMCmtsDownstream",
342
+ 230: "adsl2",
343
+ 231: "macSecControlledIF",
344
+ 232: "macSecUncontrolledIF",
345
+ 233: "aviciOpticalEther",
346
+ 234: "atmbond",
347
+ 235: "voiceFGDOS",
348
+ 236: "mocaVersion1",
349
+ 237: "ieee80216WMAN",
350
+ 238: "adsl2plus",
351
+ 239: "dvbRcsMacLayer",
352
+ 240: "dvbTdm",
353
+ 241: "dvbRcsTdma",
354
+ 242: "x86Laps",
355
+ 243: "wwanPP",
356
+ 244: "wwanPP2",
357
+ 245: "voiceEBS",
358
+ 246: "ifPwType",
359
+ 247: "ilan",
360
+ 248: "pip",
361
+ 249: "aluELP",
362
+ 250: "gpon",
363
+ 251: "vdsl2",
364
+ 252: "capwapDot11Profile",
365
+ 253: "capwapDot11Bss",
366
+ 254: "capwapWtpVirtualRadio",
367
+ 255: "bits",
368
+ 256: "docsCableUpstreamRfPort",
369
+ 257: "cableDownstreamRfPort",
370
+ 258: "vmwareVirtualNic",
371
+ 259: "ieee802154",
372
+ 260: "otnOdu",
373
+ 261: "otnOtu",
374
+ 262: "ifVfiType",
375
+ 263: "g9981",
376
+ 264: "g9982",
377
+ 265: "g9983",
378
+ 266: "aluEpon",
379
+ 267: "aluEponOnu",
380
+ 268: "aluEponPhysicalUni",
381
+ 269: "aluEponLogicalLink",
382
+ 270: "aluGponOnu",
383
+ 271: "aluGponPhysicalUni",
384
+ 272: "vmwareNicTeam",
385
+ 277: "docsOfdmDownstream",
386
+ 278: "docsOfdmaUpstream",
387
+ 279: "gfast",
388
+ 280: "sdci",
389
+ 281: "xboxWireless",
390
+ 282: "fastdsl",
391
+ 283: "docsCableScte55d1FwdOob",
392
+ 284: "docsCableScte55d1RetOob",
393
+ 285: "docsCableScte55d2DsOob",
394
+ 286: "docsCableScte55d2UsOob",
395
+ 287: "docsCableNdf",
396
+ 288: "docsCableNdr",
397
+ 289: "ptm",
398
+ 290: "ghn",
399
+ 291: "otnOtsi",
400
+ 292: "otnOtuc",
401
+ 293: "otnOduc",
402
+ 294: "otnOtsig",
403
+ 295: "microwaveCarrierTermination",
404
+ 296: "microwaveRadioLinkTerminal",
405
+ 297: "ieee8021axDrni",
406
+ 298: "ax25",
407
+ 299: "ieee19061nanocom",
408
+ 300: "cpri",
409
+ 301: "omni",
410
+ 302: "roe",
411
+ 303: "p2pOverLan",
412
+}
src/go/collectors/go.d.plugin/modules/snmp/snmp.go
+27
-88
@@ -5,9 +5,6 @@ package snmp
5
import (
6
_ "embed"
7
"errors"
8
- "fmt"
9
- "strings"
10
-
8
"github.com/netdata/netdata/go/go.d.plugin/agent/module"
9
10
"github.com/gosnmp/gosnmp"
@@ -20,90 +17,38 @@ func init() {
17
module.Register("snmp", module.Creator{
18
JobConfigSchema: configSchema,
19
Defaults: module.Defaults{
23
- UpdateEvery: defaultUpdateEvery,
20
+ UpdateEvery: 10,
21
},
22
Create: func() module.Module { return New() },
23
Config: func() any { return &Config{} },
24
})
25
}
26
30
-const (
31
- defaultUpdateEvery = 10
32
- defaultHostname = "127.0.0.1"
33
- defaultCommunity = "public"
34
- defaultVersion = gosnmp.Version2c
35
- defaultPort = 161
36
- defaultRetries = 1
37
- defaultTimeout = defaultUpdateEvery
38
- defaultMaxOIDs = 60
39
-)
40
-
27
func New() *SNMP {
28
return &SNMP{
29
Config: Config{
44
- Hostname: defaultHostname,
45
- Community: defaultCommunity,
30
+ Community: "public",
31
Options: Options{
47
- Port: defaultPort,
48
- Retries: defaultRetries,
49
- Timeout: defaultUpdateEvery,
50
- Version: defaultVersion.String(),
51
- MaxOIDs: defaultMaxOIDs,
32
+ Port: 161,
33
+ Retries: 1,
34
+ Timeout: 5,
35
+ Version: gosnmp.Version2c.String(),
36
+ MaxOIDs: 60,
37
+ MaxRepetitions: 25,
38
},
39
User: User{
54
- Name: "",
40
SecurityLevel: "authPriv",
41
AuthProto: "sha512",
57
- AuthKey: "",
42
PrivProto: "aes192c",
59
- PrivKey: "",
43
},
44
},
62
- }
63
-}
45
65
-type (
66
- Config struct {
67
- UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
68
- Hostname string `yaml:"hostname" json:"hostname"`
69
- Community string `yaml:"community,omitempty" json:"community"`
70
- User User `yaml:"user,omitempty" json:"user"`
71
- Options Options `yaml:"options,omitempty" json:"options"`
72
- ChartsInput []ChartConfig `yaml:"charts,omitempty" json:"charts"`
73
- }
74
- User struct {
75
- Name string `yaml:"name,omitempty" json:"name"`
76
- SecurityLevel string `yaml:"level,omitempty" json:"level"`
77
- AuthProto string `yaml:"auth_proto,omitempty" json:"auth_proto"`
78
- AuthKey string `yaml:"auth_key,omitempty" json:"auth_key"`
79
- PrivProto string `yaml:"priv_proto,omitempty" json:"priv_proto"`
80
- PrivKey string `yaml:"priv_key,omitempty" json:"priv_key"`
81
- }
82
- Options struct {
83
- Port int `yaml:"port,omitempty" json:"port"`
84
- Retries int `yaml:"retries,omitempty" json:"retries"`
85
- Timeout int `yaml:"timeout,omitempty" json:"timeout"`
86
- Version string `yaml:"version,omitempty" json:"version"`
87
- MaxOIDs int `yaml:"max_request_size,omitempty" json:"max_request_size"`
88
- }
89
- ChartConfig struct {
90
- ID string `yaml:"id" json:"id"`
91
- Title string `yaml:"title" json:"title"`
92
- Units string `yaml:"units" json:"units"`
93
- Family string `yaml:"family" json:"family"`
94
- Type string `yaml:"type" json:"type"`
95
- Priority int `yaml:"priority" json:"priority"`
96
- IndexRange []int `yaml:"multiply_range,omitempty" json:"multiply_range"`
97
- Dimensions []DimensionConfig `yaml:"dimensions" json:"dimensions"`
98
- }
99
- DimensionConfig struct {
100
- OID string `yaml:"oid" json:"oid"`
101
- Name string `yaml:"name" json:"name"`
102
- Algorithm string `yaml:"algorithm" json:"algorithm"`
103
- Multiplier int `yaml:"multiplier" json:"multiplier"`
104
- Divisor int `yaml:"divisor" json:"divisor"`
46
+ newSnmpClient: gosnmp.NewHandler,
47
+
48
+ collectIfMib: true,
49
+ netInterfaces: make(map[string]*netInterface),
50
}
106
-)
51
+}
52
53
type SNMP struct {
54
module.Base
@@ -111,7 +56,12 @@ type SNMP struct {
56
57
charts *module.Charts
58
114
- snmpClient gosnmp.Handler
59
+ newSnmpClient func() gosnmp.Handler
60
+ snmpClient gosnmp.Handler
61
+
62
+ collectIfMib bool
63
+ netInterfaces map[string]*netInterface
64
+ sysName string
65
66
oids []string
67
}
@@ -123,28 +73,26 @@ func (s *SNMP) Configuration() any {
73
func (s *SNMP) Init() error {
74
err := s.validateConfig()
75
if err != nil {
126
- s.Errorf("config validation: %v", err)
76
+ s.Errorf("config validation failed: %v", err)
77
return err
78
}
79
80
snmpClient, err := s.initSNMPClient()
81
if err != nil {
132
- s.Errorf("SNMP client initialization: %v", err)
82
+ s.Errorf("failed to initialize SNMP client: %v", err)
83
return err
84
}
85
136
- s.Info(snmpClientConnInfo(snmpClient))
137
-
86
err = snmpClient.Connect()
87
if err != nil {
140
- s.Errorf("SNMP client connect: %v", err)
88
+ s.Errorf("SNMP client connection failed: %v", err)
89
return err
90
}
91
s.snmpClient = snmpClient
92
145
- charts, err := newCharts(s.ChartsInput)
93
+ charts, err := newUserInputCharts(s.ChartsInput)
94
if err != nil {
147
- s.Errorf("Population of charts failed: %v", err)
95
+ s.Errorf("failed to create user charts: %v", err)
96
return err
97
}
98
s.charts = charts
@@ -160,9 +108,11 @@ func (s *SNMP) Check() error {
108
s.Error(err)
109
return err
110
}
111
+
112
if len(mx) == 0 {
113
return errors.New("no metrics collected")
114
}
115
+
116
return nil
117
}
118
@@ -179,6 +129,7 @@ func (s *SNMP) Collect() map[string]int64 {
129
if len(mx) == 0 {
130
return nil
131
}
132
+
133
return mx
134
}
135
@@ -187,15 +138,3 @@ func (s *SNMP) Cleanup() {
138
_ = s.snmpClient.Close()
139
}
140
}
190
-
191
-func snmpClientConnInfo(c gosnmp.Handler) string {
192
- var info strings.Builder
193
- info.WriteString(fmt.Sprintf("hostname=%s,port=%d,snmp_version=%s", c.Target(), c.Port(), c.Version()))
194
- switch c.Version() {
195
- case gosnmp.Version1, gosnmp.Version2c:
196
- info.WriteString(fmt.Sprintf(",community=%s", c.Community()))
197
- case gosnmp.Version3:
198
- info.WriteString(fmt.Sprintf(",security_level=%d,%s", c.MsgFlags(), c.SecurityParameters().Description()))
199
- }
200
- return info.String()
201
-}
src/go/collectors/go.d.plugin/modules/snmp/snmp_test.go
+463
-235
@@ -3,16 +3,18 @@
3
package snmp
4
5
import (
6
+ "encoding/hex"
7
"errors"
8
"fmt"
9
"os"
10
"strings"
11
"testing"
12
13
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
14
+
15
"github.com/golang/mock/gomock"
16
"github.com/gosnmp/gosnmp"
17
snmpmock "github.com/gosnmp/gosnmp/mocks"
15
- "github.com/netdata/netdata/go/go.d.plugin/agent/module"
18
"github.com/stretchr/testify/assert"
19
"github.com/stretchr/testify/require"
20
)
@@ -46,15 +48,6 @@ func TestSNMP_Init(t *testing.T) {
48
return New()
49
},
50
},
49
- "fail when 'charts' not set": {
50
- wantFail: true,
51
- prepareSNMP: func() *SNMP {
52
- snmp := New()
53
- snmp.Config = prepareV2Config()
54
- snmp.ChartsInput = nil
55
- return snmp
56
- },
57
- },
51
"fail when using SNMPv3 but 'user.name' not set": {
52
wantFail: true,
53
prepareSNMP: func() *SNMP {
@@ -64,33 +57,6 @@ func TestSNMP_Init(t *testing.T) {
57
return snmp
58
},
59
},
67
- "fail when using SNMPv3 but 'user.level' is invalid": {
68
- wantFail: true,
69
- prepareSNMP: func() *SNMP {
70
- snmp := New()
71
- snmp.Config = prepareV3Config()
72
- snmp.User.SecurityLevel = "invalid"
73
- return snmp
74
- },
75
- },
76
- "fail when using SNMPv3 but 'user.auth_proto' is invalid": {
77
- wantFail: true,
78
- prepareSNMP: func() *SNMP {
79
- snmp := New()
80
- snmp.Config = prepareV3Config()
81
- snmp.User.AuthProto = "invalid"
82
- return snmp
83
- },
84
- },
85
- "fail when using SNMPv3 but 'user.priv_proto' is invalid": {
86
- wantFail: true,
87
- prepareSNMP: func() *SNMP {
88
- snmp := New()
89
- snmp.Config = prepareV3Config()
90
- snmp.User.PrivProto = "invalid"
91
- return snmp
92
- },
93
- },
60
"success when using SNMPv1 with valid config": {
61
wantFail: false,
62
prepareSNMP: func() *SNMP {
@@ -130,56 +96,135 @@ func TestSNMP_Init(t *testing.T) {
96
}
97
}
98
133
-func TestSNMP_Check(t *testing.T) {
99
+func TestSNMP_Cleanup(t *testing.T) {
100
tests := map[string]struct {
135
- prepareSNMP func(m *snmpmock.MockHandler) *SNMP
136
- wantFail bool
101
+ prepareSNMP func(t *testing.T, m *snmpmock.MockHandler) *SNMP
102
}{
138
- "success when 'max_request_size' > returned OIDs": {
139
- wantFail: false,
140
- prepareSNMP: func(m *snmpmock.MockHandler) *SNMP {
103
+ "cleanup call if snmpClient initialized": {
104
+ prepareSNMP: func(t *testing.T, m *snmpmock.MockHandler) *SNMP {
105
snmp := New()
106
snmp.Config = prepareV2Config()
107
+ snmp.newSnmpClient = func() gosnmp.Handler { return m }
108
+ setMockClientInitExpect(m)
109
144
- m.EXPECT().Get(gomock.Any()).Return(&gosnmp.SnmpPacket{
145
- Variables: []gosnmp.SnmpPDU{
146
- {Value: 10, Type: gosnmp.Gauge32},
147
- {Value: 20, Type: gosnmp.Gauge32},
148
- },
149
- }, nil).Times(1)
110
+ require.NoError(t, snmp.Init())
111
+
112
+ m.EXPECT().Close().Times(1)
113
114
return snmp
115
},
116
},
154
- "success when 'max_request_size' < returned OIDs": {
117
+ "cleanup call does not panic if snmpClient not initialized": {
118
+ prepareSNMP: func(t *testing.T, m *snmpmock.MockHandler) *SNMP {
119
+ snmp := New()
120
+ snmp.Config = prepareV2Config()
121
+ snmp.newSnmpClient = func() gosnmp.Handler { return m }
122
+ setMockClientInitExpect(m)
123
+
124
+ require.NoError(t, snmp.Init())
125
+
126
+ snmp.snmpClient = nil
127
+
128
+ return snmp
129
+ },
130
+ },
131
+ }
132
+
133
+ for name, test := range tests {
134
+ t.Run(name, func(t *testing.T) {
135
+ mockSNMP, cleanup := mockInit(t)
136
+ defer cleanup()
137
+
138
+ snmp := test.prepareSNMP(t, mockSNMP)
139
+
140
+ assert.NotPanics(t, snmp.Cleanup)
141
+ })
142
+ }
143
+}
144
+
145
+func TestSNMP_Charts(t *testing.T) {
146
+ tests := map[string]struct {
147
+ prepareSNMP func(t *testing.T, m *snmpmock.MockHandler) *SNMP
148
+ wantNumCharts int
149
+ doCollect bool
150
+ }{
151
+ "if-mib, no custom": {
152
+ doCollect: true,
153
+ wantNumCharts: len(netIfaceChartsTmpl)*4 + 1,
154
+ prepareSNMP: func(t *testing.T, m *snmpmock.MockHandler) *SNMP {
155
+ snmp := New()
156
+ snmp.Config = prepareV2Config()
157
+ setMockClientSysExpect(m)
158
+ setMockClientIfMibExpect(m)
159
+
160
+ return snmp
161
+ },
162
+ },
163
+ "custom, no if-mib": {
164
+ wantNumCharts: 10,
165
+ prepareSNMP: func(t *testing.T, m *snmpmock.MockHandler) *SNMP {
166
+ snmp := New()
167
+ snmp.Config = prepareConfigWithUserCharts(prepareV2Config(), 0, 9)
168
+ snmp.collectIfMib = false
169
+
170
+ return snmp
171
+ },
172
+ },
173
+ }
174
+
175
+ for name, test := range tests {
176
+ t.Run(name, func(t *testing.T) {
177
+ mockSNMP, cleanup := mockInit(t)
178
+ defer cleanup()
179
+
180
+ setMockClientInitExpect(mockSNMP)
181
+
182
+ snmp := test.prepareSNMP(t, mockSNMP)
183
+ snmp.newSnmpClient = func() gosnmp.Handler { return mockSNMP }
184
+
185
+ require.NoError(t, snmp.Init())
186
+
187
+ if test.doCollect {
188
+ _ = snmp.Collect()
189
+ }
190
+
191
+ assert.Equal(t, test.wantNumCharts, len(*snmp.Charts()))
192
+ })
193
+ }
194
+}
195
+
196
+func TestSNMP_Check(t *testing.T) {
197
+ tests := map[string]struct {
198
+ wantFail bool
199
+ prepareSNMP func(m *snmpmock.MockHandler) *SNMP
200
+ }{
201
+ "success when collecting IF-MIB": {
202
wantFail: false,
203
prepareSNMP: func(m *snmpmock.MockHandler) *SNMP {
204
snmp := New()
205
snmp.Config = prepareV2Config()
159
- snmp.Config.Options.MaxOIDs = 1
160
-
161
- m.EXPECT().Get(gomock.Any()).Return(&gosnmp.SnmpPacket{
162
- Variables: []gosnmp.SnmpPDU{
163
- {Value: 10, Type: gosnmp.Gauge32},
164
- {Value: 20, Type: gosnmp.Gauge32},
165
- },
166
- }, nil).Times(2)
206
+ setMockClientIfMibExpect(m)
207
208
return snmp
209
},
210
},
171
- "success when using 'multiply_range'": {
211
+ "success only custom OIDs supported type": {
212
wantFail: false,
213
prepareSNMP: func(m *snmpmock.MockHandler) *SNMP {
214
snmp := New()
175
- snmp.Config = prepareConfigWithIndexRange(prepareV2Config, 0, 1)
215
+ snmp.Config = prepareConfigWithUserCharts(prepareV2Config(), 0, 3)
216
+ snmp.collectIfMib = false
217
218
m.EXPECT().Get(gomock.Any()).Return(&gosnmp.SnmpPacket{
219
Variables: []gosnmp.SnmpPDU{
179
- {Value: 10, Type: gosnmp.Gauge32},
180
- {Value: 20, Type: gosnmp.Gauge32},
220
+ {Value: 10, Type: gosnmp.Counter32},
221
+ {Value: 20, Type: gosnmp.Counter64},
222
{Value: 30, Type: gosnmp.Gauge32},
223
+ {Value: 1, Type: gosnmp.Boolean},
224
{Value: 40, Type: gosnmp.Gauge32},
225
+ {Value: 50, Type: gosnmp.TimeTicks},
226
+ {Value: 60, Type: gosnmp.Uinteger32},
227
+ {Value: 70, Type: gosnmp.Integer},
228
},
229
}, nil).Times(1)
230
@@ -190,26 +235,11 @@ func TestSNMP_Check(t *testing.T) {
235
wantFail: true,
236
prepareSNMP: func(m *snmpmock.MockHandler) *SNMP {
237
snmp := New()
193
- snmp.Config = prepareV2Config()
238
+ snmp.Config = prepareConfigWithUserCharts(prepareV2Config(), 0, 3)
239
+ snmp.collectIfMib = false
240
241
m.EXPECT().Get(gomock.Any()).Return(nil, errors.New("mock Get() error")).Times(1)
242
197
- return snmp
198
- },
199
- },
200
- "fail when all OIDs type is unsupported": {
201
- wantFail: true,
202
- prepareSNMP: func(m *snmpmock.MockHandler) *SNMP {
203
- snmp := New()
204
- snmp.Config = prepareV2Config()
205
-
206
- m.EXPECT().Get(gomock.Any()).Return(&gosnmp.SnmpPacket{
207
- Variables: []gosnmp.SnmpPDU{
208
- {Value: nil, Type: gosnmp.NoSuchInstance},
209
- {Value: nil, Type: gosnmp.NoSuchInstance},
210
- },
211
- }, nil).Times(1)
212
-
243
return snmp
244
},
245
},
@@ -220,10 +250,12 @@ func TestSNMP_Check(t *testing.T) {
250
mockSNMP, cleanup := mockInit(t)
251
defer cleanup()
252
223
- newSNMPClient = func() gosnmp.Handler { return mockSNMP }
224
- defaultMockExpects(mockSNMP)
253
+ setMockClientInitExpect(mockSNMP)
254
+ setMockClientSysExpect(mockSNMP)
255
256
snmp := test.prepareSNMP(mockSNMP)
257
+ snmp.newSnmpClient = func() gosnmp.Handler { return mockSNMP }
258
+
259
require.NoError(t, snmp.Init())
260
261
if test.wantFail {
@@ -240,10 +272,112 @@ func TestSNMP_Collect(t *testing.T) {
272
prepareSNMP func(m *snmpmock.MockHandler) *SNMP
273
wantCollected map[string]int64
274
}{
243
- "success when collecting supported type": {
275
+ "success only IF-MIB": {
276
prepareSNMP: func(m *snmpmock.MockHandler) *SNMP {
277
snmp := New()
246
- snmp.Config = prepareConfigWithIndexRange(prepareV2Config, 0, 3)
278
+ snmp.Config = prepareV2Config()
279
+
280
+ setMockClientIfMibExpect(m)
281
+
282
+ return snmp
283
+ },
284
+ wantCollected: map[string]int64{
285
+ "net_iface_ether1_admin_status_down": 0,
286
+ "net_iface_ether1_admin_status_testing": 0,
287
+ "net_iface_ether1_admin_status_up": 1,
288
+ "net_iface_ether1_bcast_in": 0,
289
+ "net_iface_ether1_bcast_out": 0,
290
+ "net_iface_ether1_discards_in": 0,
291
+ "net_iface_ether1_discards_out": 0,
292
+ "net_iface_ether1_errors_in": 0,
293
+ "net_iface_ether1_errors_out": 0,
294
+ "net_iface_ether1_mcast_in": 0,
295
+ "net_iface_ether1_mcast_out": 0,
296
+ "net_iface_ether1_oper_status_dormant": 0,
297
+ "net_iface_ether1_oper_status_down": 1,
298
+ "net_iface_ether1_oper_status_lowerLayerDown": 0,
299
+ "net_iface_ether1_oper_status_notPresent": 0,
300
+ "net_iface_ether1_oper_status_testing": 0,
301
+ "net_iface_ether1_oper_status_unknown": 0,
302
+ "net_iface_ether1_oper_status_up": 0,
303
+ "net_iface_ether1_traffic_in": 0,
304
+ "net_iface_ether1_traffic_out": 0,
305
+ "net_iface_ether1_ucast_in": 0,
306
+ "net_iface_ether1_ucast_out": 0,
307
+ "net_iface_ether2_admin_status_down": 0,
308
+ "net_iface_ether2_admin_status_testing": 0,
309
+ "net_iface_ether2_admin_status_up": 1,
310
+ "net_iface_ether2_bcast_in": 0,
311
+ "net_iface_ether2_bcast_out": 0,
312
+ "net_iface_ether2_discards_in": 0,
313
+ "net_iface_ether2_discards_out": 0,
314
+ "net_iface_ether2_errors_in": 0,
315
+ "net_iface_ether2_errors_out": 0,
316
+ "net_iface_ether2_mcast_in": 1891,
317
+ "net_iface_ether2_mcast_out": 7386,
318
+ "net_iface_ether2_oper_status_dormant": 0,
319
+ "net_iface_ether2_oper_status_down": 0,
320
+ "net_iface_ether2_oper_status_lowerLayerDown": 0,
321
+ "net_iface_ether2_oper_status_notPresent": 0,
322
+ "net_iface_ether2_oper_status_testing": 0,
323
+ "net_iface_ether2_oper_status_unknown": 0,
324
+ "net_iface_ether2_oper_status_up": 1,
325
+ "net_iface_ether2_traffic_in": 615057509,
326
+ "net_iface_ether2_traffic_out": 159677206,
327
+ "net_iface_ether2_ucast_in": 71080332,
328
+ "net_iface_ether2_ucast_out": 39509661,
329
+ "net_iface_sfp-sfpplus1_admin_status_down": 0,
330
+ "net_iface_sfp-sfpplus1_admin_status_testing": 0,
331
+ "net_iface_sfp-sfpplus1_admin_status_up": 1,
332
+ "net_iface_sfp-sfpplus1_bcast_in": 0,
333
+ "net_iface_sfp-sfpplus1_bcast_out": 0,
334
+ "net_iface_sfp-sfpplus1_discards_in": 0,
335
+ "net_iface_sfp-sfpplus1_discards_out": 0,
336
+ "net_iface_sfp-sfpplus1_errors_in": 0,
337
+ "net_iface_sfp-sfpplus1_errors_out": 0,
338
+ "net_iface_sfp-sfpplus1_mcast_in": 0,
339
+ "net_iface_sfp-sfpplus1_mcast_out": 0,
340
+ "net_iface_sfp-sfpplus1_oper_status_dormant": 0,
341
+ "net_iface_sfp-sfpplus1_oper_status_down": 0,
342
+ "net_iface_sfp-sfpplus1_oper_status_lowerLayerDown": 0,
343
+ "net_iface_sfp-sfpplus1_oper_status_notPresent": 1,
344
+ "net_iface_sfp-sfpplus1_oper_status_testing": 0,
345
+ "net_iface_sfp-sfpplus1_oper_status_unknown": 0,
346
+ "net_iface_sfp-sfpplus1_oper_status_up": 0,
347
+ "net_iface_sfp-sfpplus1_traffic_in": 0,
348
+ "net_iface_sfp-sfpplus1_traffic_out": 0,
349
+ "net_iface_sfp-sfpplus1_ucast_in": 0,
350
+ "net_iface_sfp-sfpplus1_ucast_out": 0,
351
+ "net_iface_sfp-sfpplus2_admin_status_down": 0,
352
+ "net_iface_sfp-sfpplus2_admin_status_testing": 0,
353
+ "net_iface_sfp-sfpplus2_admin_status_up": 1,
354
+ "net_iface_sfp-sfpplus2_bcast_in": 0,
355
+ "net_iface_sfp-sfpplus2_bcast_out": 0,
356
+ "net_iface_sfp-sfpplus2_discards_in": 0,
357
+ "net_iface_sfp-sfpplus2_discards_out": 0,
358
+ "net_iface_sfp-sfpplus2_errors_in": 0,
359
+ "net_iface_sfp-sfpplus2_errors_out": 0,
360
+ "net_iface_sfp-sfpplus2_mcast_in": 0,
361
+ "net_iface_sfp-sfpplus2_mcast_out": 0,
362
+ "net_iface_sfp-sfpplus2_oper_status_dormant": 0,
363
+ "net_iface_sfp-sfpplus2_oper_status_down": 0,
364
+ "net_iface_sfp-sfpplus2_oper_status_lowerLayerDown": 0,
365
+ "net_iface_sfp-sfpplus2_oper_status_notPresent": 1,
366
+ "net_iface_sfp-sfpplus2_oper_status_testing": 0,
367
+ "net_iface_sfp-sfpplus2_oper_status_unknown": 0,
368
+ "net_iface_sfp-sfpplus2_oper_status_up": 0,
369
+ "net_iface_sfp-sfpplus2_traffic_in": 0,
370
+ "net_iface_sfp-sfpplus2_traffic_out": 0,
371
+ "net_iface_sfp-sfpplus2_ucast_in": 0,
372
+ "net_iface_sfp-sfpplus2_ucast_out": 0,
373
+ "uptime": 60,
374
+ },
375
+ },
376
+ "success only custom OIDs supported type": {
377
+ prepareSNMP: func(m *snmpmock.MockHandler) *SNMP {
378
+ snmp := New()
379
+ snmp.Config = prepareConfigWithUserCharts(prepareV2Config(), 0, 3)
380
+ snmp.collectIfMib = false
381
382
m.EXPECT().Get(gomock.Any()).Return(&gosnmp.SnmpPacket{
383
Variables: []gosnmp.SnmpPDU{
@@ -269,12 +403,14 @@ func TestSNMP_Collect(t *testing.T) {
403
"1.3.6.1.2.1.2.2.1.16.2": 50,
404
"1.3.6.1.2.1.2.2.1.10.3": 60,
405
"1.3.6.1.2.1.2.2.1.16.3": 70,
406
+ "uptime": 60,
407
},
408
},
274
- "success when collecting supported and unsupported type": {
409
+ "success only custom OIDs supported and unsupported type": {
410
prepareSNMP: func(m *snmpmock.MockHandler) *SNMP {
411
snmp := New()
277
- snmp.Config = prepareConfigWithIndexRange(prepareV2Config, 0, 2)
412
+ snmp.Config = prepareConfigWithUserCharts(prepareV2Config(), 0, 2)
413
+ snmp.collectIfMib = false
414
415
m.EXPECT().Get(gomock.Any()).Return(&gosnmp.SnmpPacket{
416
Variables: []gosnmp.SnmpPDU{
@@ -293,12 +429,14 @@ func TestSNMP_Collect(t *testing.T) {
429
"1.3.6.1.2.1.2.2.1.10.0": 10,
430
"1.3.6.1.2.1.2.2.1.16.0": 20,
431
"1.3.6.1.2.1.2.2.1.10.1": 30,
432
+ "uptime": 60,
433
},
434
},
298
- "fails when collecting unsupported type": {
435
+ "success only custom OIDs unsupported type": {
436
prepareSNMP: func(m *snmpmock.MockHandler) *SNMP {
437
snmp := New()
301
- snmp.Config = prepareConfigWithIndexRange(prepareV2Config, 0, 2)
438
+ snmp.Config = prepareConfigWithUserCharts(prepareV2Config(), 0, 2)
439
+ snmp.collectIfMib = false
440
441
m.EXPECT().Get(gomock.Any()).Return(&gosnmp.SnmpPacket{
442
Variables: []gosnmp.SnmpPDU{
@@ -313,7 +451,9 @@ func TestSNMP_Collect(t *testing.T) {
451
452
return snmp
453
},
316
- wantCollected: nil,
454
+ wantCollected: map[string]int64{
455
+ "uptime": 60,
456
+ },
457
},
458
}
459
@@ -322,120 +462,112 @@ func TestSNMP_Collect(t *testing.T) {
462
mockSNMP, cleanup := mockInit(t)
463
defer cleanup()
464
325
- newSNMPClient = func() gosnmp.Handler { return mockSNMP }
326
- defaultMockExpects(mockSNMP)
465
+ setMockClientInitExpect(mockSNMP)
466
+ setMockClientSysExpect(mockSNMP)
467
468
snmp := test.prepareSNMP(mockSNMP)
469
+ snmp.newSnmpClient = func() gosnmp.Handler { return mockSNMP }
470
+
471
require.NoError(t, snmp.Init())
472
331
- collected := snmp.Collect()
473
+ mx := snmp.Collect()
474
333
- assert.Equal(t, test.wantCollected, collected)
475
+ assert.Equal(t, test.wantCollected, mx)
476
})
477
}
478
}
479
338
-func TestSNMP_Cleanup(t *testing.T) {
339
- tests := map[string]struct {
340
- prepareSNMP func(t *testing.T, m *snmpmock.MockHandler) *SNMP
341
- }{
342
- "cleanup call if snmpClient initialized": {
343
- prepareSNMP: func(t *testing.T, m *snmpmock.MockHandler) *SNMP {
344
- snmp := New()
345
- snmp.Config = prepareV2Config()
346
- require.NoError(t, snmp.Init())
347
-
348
- m.EXPECT().Close().Times(1)
349
-
350
- return snmp
351
- },
352
- },
353
- "cleanup call does not panic if snmpClient not initialized": {
354
- prepareSNMP: func(t *testing.T, m *snmpmock.MockHandler) *SNMP {
355
- snmp := New()
356
- snmp.Config = prepareV2Config()
357
- require.NoError(t, snmp.Init())
358
- snmp.snmpClient = nil
359
-
360
- return snmp
361
- },
362
- },
363
- }
364
-
365
- for name, test := range tests {
366
- t.Run(name, func(t *testing.T) {
367
- mockSNMP, cleanup := mockInit(t)
368
- defer cleanup()
480
+func mockInit(t *testing.T) (*snmpmock.MockHandler, func()) {
481
+ mockCtl := gomock.NewController(t)
482
+ cleanup := func() { mockCtl.Finish() }
483
+ mockSNMP := snmpmock.NewMockHandler(mockCtl)
484
370
- newSNMPClient = func() gosnmp.Handler { return mockSNMP }
371
- defaultMockExpects(mockSNMP)
485
+ return mockSNMP, cleanup
486
+}
487
373
- snmp := test.prepareSNMP(t, mockSNMP)
374
- assert.NotPanics(t, snmp.Cleanup)
375
- })
488
+func prepareV3Config() Config {
489
+ cfg := prepareV2Config()
490
+ cfg.Options.Version = gosnmp.Version3.String()
491
+ cfg.User = User{
492
+ Name: "name",
493
+ SecurityLevel: "authPriv",
494
+ AuthProto: strings.ToLower(gosnmp.MD5.String()),
495
+ AuthKey: "auth_key",
496
+ PrivProto: strings.ToLower(gosnmp.AES.String()),
497
+ PrivKey: "priv_key",
498
}
499
+ return cfg
500
}
501
379
-func TestSNMP_Charts(t *testing.T) {
380
- tests := map[string]struct {
381
- prepareSNMP func(t *testing.T, m *snmpmock.MockHandler) *SNMP
382
- wantNumCharts int
383
- }{
384
- "without 'multiply_range': got expected number of charts": {
385
- wantNumCharts: 1,
386
- prepareSNMP: func(t *testing.T, m *snmpmock.MockHandler) *SNMP {
387
- snmp := New()
388
- snmp.Config = prepareV2Config()
389
- require.NoError(t, snmp.Init())
502
+func prepareV2Config() Config {
503
+ cfg := prepareV1Config()
504
+ cfg.Options.Version = gosnmp.Version2c.String()
505
+ return cfg
506
+}
507
391
- return snmp
392
- },
508
+func prepareV1Config() Config {
509
+ return Config{
510
+ UpdateEvery: 1,
511
+ Hostname: "192.0.2.1",
512
+ Community: "public",
513
+ Options: Options{
514
+ Port: 161,
515
+ Retries: 1,
516
+ Timeout: 5,
517
+ Version: gosnmp.Version1.String(),
518
+ MaxOIDs: 60,
519
+ MaxRepetitions: 25,
520
},
394
- "with 'multiply_range': got expected number of charts": {
395
- wantNumCharts: 10,
396
- prepareSNMP: func(t *testing.T, m *snmpmock.MockHandler) *SNMP {
397
- snmp := New()
398
- snmp.Config = prepareConfigWithIndexRange(prepareV2Config, 0, 9)
399
- require.NoError(t, snmp.Init())
521
+ }
522
+}
523
401
- return snmp
524
+func prepareConfigWithUserCharts(cfg Config, start, end int) Config {
525
+ if start > end || start < 0 || end < 1 {
526
+ panic(fmt.Sprintf("invalid index range ('%d'-'%d')", start, end))
527
+ }
528
+ cfg.ChartsInput = []ChartConfig{
529
+ {
530
+ ID: "test_chart1",
531
+ Title: "This is Test Chart1",
532
+ Units: "kilobits/s",
533
+ Family: "family",
534
+ Type: module.Area.String(),
535
+ Priority: module.Priority,
536
+ Dimensions: []DimensionConfig{
537
+ {
538
+ OID: "1.3.6.1.2.1.2.2.1.10",
539
+ Name: "in",
540
+ Algorithm: module.Incremental.String(),
541
+ Multiplier: 8,
542
+ Divisor: 1000,
543
+ },
544
+ {
545
+ OID: "1.3.6.1.2.1.2.2.1.16",
546
+ Name: "out",
547
+ Algorithm: module.Incremental.String(),
548
+ Multiplier: 8,
549
+ Divisor: 1000,
550
+ },
551
},
552
},
553
}
554
406
- for name, test := range tests {
407
- t.Run(name, func(t *testing.T) {
408
- mockSNMP, cleanup := mockInit(t)
409
- defer cleanup()
410
-
411
- newSNMPClient = func() gosnmp.Handler { return mockSNMP }
412
- defaultMockExpects(mockSNMP)
413
-
414
- snmp := test.prepareSNMP(t, mockSNMP)
415
- assert.Equal(t, test.wantNumCharts, len(*snmp.Charts()))
416
- })
555
+ for i := range cfg.ChartsInput {
556
+ cfg.ChartsInput[i].IndexRange = []int{start, end}
557
}
418
-}
558
420
-func mockInit(t *testing.T) (*snmpmock.MockHandler, func()) {
421
- mockCtl := gomock.NewController(t)
422
- cleanup := func() { mockCtl.Finish() }
423
- mockSNMP := snmpmock.NewMockHandler(mockCtl)
424
-
425
- return mockSNMP, cleanup
559
+ return cfg
560
}
561
428
-func defaultMockExpects(m *snmpmock.MockHandler) {
562
+func setMockClientInitExpect(m *snmpmock.MockHandler) {
563
m.EXPECT().Target().AnyTimes()
564
m.EXPECT().Port().AnyTimes()
431
- m.EXPECT().Retries().AnyTimes()
432
- m.EXPECT().Timeout().AnyTimes()
433
- m.EXPECT().MaxOids().AnyTimes()
565
m.EXPECT().Version().AnyTimes()
566
m.EXPECT().Community().AnyTimes()
567
m.EXPECT().SetTarget(gomock.Any()).AnyTimes()
568
m.EXPECT().SetPort(gomock.Any()).AnyTimes()
569
m.EXPECT().SetRetries(gomock.Any()).AnyTimes()
570
+ m.EXPECT().SetMaxRepetitions(gomock.Any()).AnyTimes()
571
m.EXPECT().SetMaxOids(gomock.Any()).AnyTimes()
572
m.EXPECT().SetLogger(gomock.Any()).AnyTimes()
573
m.EXPECT().SetTimeout(gomock.Any()).AnyTimes()
@@ -447,74 +579,170 @@ func defaultMockExpects(m *snmpmock.MockHandler) {
579
m.EXPECT().Connect().Return(nil).AnyTimes()
580
}
581
450
-func prepareConfigWithIndexRange(p func() Config, start, end int) Config {
451
- if start > end || start < 0 || end < 1 {
452
- panic(fmt.Sprintf("invalid index range ('%d'-'%d')", start, end))
453
- }
454
- cfg := p()
455
- for i := range cfg.ChartsInput {
456
- cfg.ChartsInput[i].IndexRange = []int{start, end}
457
- }
458
- return cfg
459
-}
582
+func setMockClientSysExpect(m *snmpmock.MockHandler) {
583
+ m.EXPECT().Get([]string{oidSysName}).Return(&gosnmp.SnmpPacket{
584
+ Variables: []gosnmp.SnmpPDU{
585
+ {Value: []uint8("mock-host"), Type: gosnmp.OctetString},
586
+ },
587
+ }, nil).MinTimes(1)
588
461
-func prepareV3Config() Config {
462
- cfg := prepareV2Config()
463
- cfg.Options.Version = gosnmp.Version3.String()
464
- cfg.User = User{
465
- Name: "name",
466
- SecurityLevel: "authPriv",
467
- AuthProto: strings.ToLower(gosnmp.MD5.String()),
468
- AuthKey: "auth_key",
469
- PrivProto: strings.ToLower(gosnmp.AES.String()),
470
- PrivKey: "priv_key",
471
- }
472
- return cfg
589
+ m.EXPECT().Get([]string{oidSysUptime}).Return(&gosnmp.SnmpPacket{
590
+ Variables: []gosnmp.SnmpPDU{
591
+ {Value: uint32(6048), Type: gosnmp.TimeTicks},
592
+ },
593
+ }, nil).MinTimes(1)
594
}
595
475
-func prepareV2Config() Config {
476
- cfg := prepareV1Config()
477
- cfg.Options.Version = gosnmp.Version2c.String()
478
- return cfg
596
+func setMockClientIfMibExpect(m *snmpmock.MockHandler) {
597
+ m.EXPECT().WalkAll(rootOidIfMibIfTable).Return([]gosnmp.SnmpPDU{
598
+ {Name: oidIfIndex + ".1", Value: 1, Type: gosnmp.Integer},
599
+ {Name: oidIfIndex + ".2", Value: 2, Type: gosnmp.Integer},
600
+ {Name: oidIfIndex + ".17", Value: 17, Type: gosnmp.Integer},
601
+ {Name: oidIfIndex + ".18", Value: 18, Type: gosnmp.Integer},
602
+ {Name: oidIfDescr + ".1", Value: []uint8("ether1"), Type: gosnmp.OctetString},
603
+ {Name: oidIfDescr + ".2", Value: []uint8("ether2"), Type: gosnmp.OctetString},
604
+ {Name: oidIfDescr + ".17", Value: []uint8("sfp-sfpplus2"), Type: gosnmp.OctetString},
605
+ {Name: oidIfDescr + ".18", Value: []uint8("sfp-sfpplus1"), Type: gosnmp.OctetString},
606
+ {Name: oidIfType + ".1", Value: 6, Type: gosnmp.Integer},
607
+ {Name: oidIfType + ".2", Value: 6, Type: gosnmp.Integer},
608
+ {Name: oidIfType + ".17", Value: 6, Type: gosnmp.Integer},
609
+ {Name: oidIfType + ".18", Value: 6, Type: gosnmp.Integer},
610
+ {Name: oidIfMtu + ".1", Value: 1500, Type: gosnmp.Integer},
611
+ {Name: oidIfMtu + ".2", Value: 1500, Type: gosnmp.Integer},
612
+ {Name: oidIfMtu + ".17", Value: 1500, Type: gosnmp.Integer},
613
+ {Name: oidIfMtu + ".18", Value: 1500, Type: gosnmp.Integer},
614
+ {Name: oidIfSpeed + ".1", Value: 0, Type: gosnmp.Gauge32},
615
+ {Name: oidIfSpeed + ".2", Value: 1000000000, Type: gosnmp.Gauge32},
616
+ {Name: oidIfSpeed + ".17", Value: 0, Type: gosnmp.Gauge32},
617
+ {Name: oidIfSpeed + ".18", Value: 0, Type: gosnmp.Gauge32},
618
+ {Name: oidIfPhysAddress + ".1", Value: decodePhysAddr("18:fd:74:7e:c5:80"), Type: gosnmp.OctetString},
619
+ {Name: oidIfPhysAddress + ".2", Value: decodePhysAddr("18:fd:74:7e:c5:81"), Type: gosnmp.OctetString},
620
+ {Name: oidIfPhysAddress + ".17", Value: decodePhysAddr("18:fd:74:7e:c5:90"), Type: gosnmp.OctetString},
621
+ {Name: oidIfPhysAddress + ".18", Value: decodePhysAddr("18:fd:74:7e:c5:91"), Type: gosnmp.OctetString},
622
+ {Name: oidIfAdminStatus + ".1", Value: 1, Type: gosnmp.Integer},
623
+ {Name: oidIfAdminStatus + ".2", Value: 1, Type: gosnmp.Integer},
624
+ {Name: oidIfAdminStatus + ".17", Value: 1, Type: gosnmp.Integer},
625
+ {Name: oidIfAdminStatus + ".18", Value: 1, Type: gosnmp.Integer},
626
+ {Name: oidIfOperStatus + ".1", Value: 2, Type: gosnmp.Integer},
627
+ {Name: oidIfOperStatus + ".2", Value: 1, Type: gosnmp.Integer},
628
+ {Name: oidIfOperStatus + ".17", Value: 6, Type: gosnmp.Integer},
629
+ {Name: oidIfOperStatus + ".18", Value: 6, Type: gosnmp.Integer},
630
+ {Name: oidIfLastChange + ".1", Value: 0, Type: gosnmp.TimeTicks},
631
+ {Name: oidIfLastChange + ".2", Value: 3243, Type: gosnmp.TimeTicks},
632
+ {Name: oidIfLastChange + ".17", Value: 0, Type: gosnmp.TimeTicks},
633
+ {Name: oidIfLastChange + ".18", Value: 0, Type: gosnmp.TimeTicks},
634
+ {Name: oidIfInOctets + ".1", Value: 0, Type: gosnmp.Counter32},
635
+ {Name: oidIfInOctets + ".2", Value: 3827243723, Type: gosnmp.Counter32},
636
+ {Name: oidIfInOctets + ".17", Value: 0, Type: gosnmp.Counter32},
637
+ {Name: oidIfInOctets + ".18", Value: 0, Type: gosnmp.Counter32},
638
+ {Name: oidIfInUcastPkts + ".1", Value: 0, Type: gosnmp.Counter32},
639
+ {Name: oidIfInUcastPkts + ".2", Value: 71035992, Type: gosnmp.Counter32},
640
+ {Name: oidIfInUcastPkts + ".17", Value: 0, Type: gosnmp.Counter32},
641
+ {Name: oidIfInUcastPkts + ".18", Value: 0, Type: gosnmp.Counter32},
642
+ {Name: oidIfInNUcastPkts + ".1", Value: 0, Type: gosnmp.Counter32},
643
+ {Name: oidIfInNUcastPkts + ".2", Value: 0, Type: gosnmp.Counter32},
644
+ {Name: oidIfInNUcastPkts + ".17", Value: 0, Type: gosnmp.Counter32},
645
+ {Name: oidIfInNUcastPkts + ".18", Value: 0, Type: gosnmp.Counter32},
646
+ {Name: oidIfInDiscards + ".1", Value: 0, Type: gosnmp.Counter32},
647
+ {Name: oidIfInDiscards + ".2", Value: 0, Type: gosnmp.Counter32},
648
+ {Name: oidIfInDiscards + ".17", Value: 0, Type: gosnmp.Counter32},
649
+ {Name: oidIfInDiscards + ".18", Value: 0, Type: gosnmp.Counter32},
650
+ {Name: oidIfInErrors + ".1", Value: 0, Type: gosnmp.Counter32},
651
+ {Name: oidIfInErrors + ".2", Value: 0, Type: gosnmp.Counter32},
652
+ {Name: oidIfInErrors + ".17", Value: 0, Type: gosnmp.Counter32},
653
+ {Name: oidIfInErrors + ".18", Value: 0, Type: gosnmp.Counter32},
654
+ {Name: oidIfInUnknownProtos + ".1", Value: 0, Type: gosnmp.Counter32},
655
+ {Name: oidIfInUnknownProtos + ".2", Value: 0, Type: gosnmp.Counter32},
656
+ {Name: oidIfInUnknownProtos + ".17", Value: 0, Type: gosnmp.Counter32},
657
+ {Name: oidIfInUnknownProtos + ".18", Value: 0, Type: gosnmp.Counter32},
658
+ {Name: oidIfOutOctets + ".1", Value: 0, Type: gosnmp.Counter32},
659
+ {Name: oidIfOutOctets + ".2", Value: 2769838772, Type: gosnmp.Counter32},
660
+ {Name: oidIfOutOctets + ".17", Value: 0, Type: gosnmp.Counter32},
661
+ {Name: oidIfOutOctets + ".18", Value: 0, Type: gosnmp.Counter32},
662
+ {Name: oidIfOutUcastPkts + ".1", Value: 0, Type: gosnmp.Counter32},
663
+ {Name: oidIfOutUcastPkts + ".2", Value: 39482929, Type: gosnmp.Counter32},
664
+ {Name: oidIfOutUcastPkts + ".17", Value: 0, Type: gosnmp.Counter32},
665
+ {Name: oidIfOutUcastPkts + ".18", Value: 0, Type: gosnmp.Counter32},
666
+ {Name: oidIfOutNUcastPkts + ".1", Value: 0, Type: gosnmp.Counter32},
667
+ {Name: oidIfOutNUcastPkts + ".2", Value: 0, Type: gosnmp.Counter32},
668
+ {Name: oidIfOutNUcastPkts + ".17", Value: 0, Type: gosnmp.Counter32},
669
+ {Name: oidIfOutNUcastPkts + ".18", Value: 0, Type: gosnmp.Counter32},
670
+ {Name: oidIfOutDiscards + ".1", Value: 0, Type: gosnmp.Counter32},
671
+ {Name: oidIfOutDiscards + ".2", Value: 0, Type: gosnmp.Counter32},
672
+ {Name: oidIfOutDiscards + ".17", Value: 0, Type: gosnmp.Counter32},
673
+ {Name: oidIfOutDiscards + ".18", Value: 0, Type: gosnmp.Counter32},
674
+ {Name: oidIfOutErrors + ".1", Value: 0, Type: gosnmp.Counter32},
675
+ {Name: oidIfOutErrors + ".2", Value: 0, Type: gosnmp.Counter32},
676
+ {Name: oidIfOutErrors + ".17", Value: 0, Type: gosnmp.Counter32},
677
+ {Name: oidIfOutErrors + ".18", Value: 0, Type: gosnmp.Counter32},
678
+ }, nil).MinTimes(1)
679
+
680
+ m.EXPECT().WalkAll(rootOidIfMibIfXTable).Return([]gosnmp.SnmpPDU{
681
+ {Name: oidIfName + ".1", Value: []uint8("ether1"), Type: gosnmp.OctetString},
682
+ {Name: oidIfName + ".2", Value: []uint8("ether2"), Type: gosnmp.OctetString},
683
+ {Name: oidIfName + ".17", Value: []uint8("sfp-sfpplus2"), Type: gosnmp.OctetString},
684
+ {Name: oidIfName + ".18", Value: []uint8("sfp-sfpplus1"), Type: gosnmp.OctetString},
685
+ {Name: oidIfInMulticastPkts + ".1", Value: 0, Type: gosnmp.Counter32},
686
+ {Name: oidIfInMulticastPkts + ".2", Value: 0, Type: gosnmp.Counter32},
687
+ {Name: oidIfInMulticastPkts + ".17", Value: 0, Type: gosnmp.Counter32},
688
+ {Name: oidIfInMulticastPkts + ".18", Value: 0, Type: gosnmp.Counter32},
689
+ {Name: oidIfInBroadcastPkts + ".1", Value: 0, Type: gosnmp.Counter32},
690
+ {Name: oidIfInBroadcastPkts + ".2", Value: 0, Type: gosnmp.Counter32},
691
+ {Name: oidIfInBroadcastPkts + ".17", Value: 0, Type: gosnmp.Counter32},
692
+ {Name: oidIfInBroadcastPkts + ".18", Value: 0, Type: gosnmp.Counter32},
693
+ {Name: oidIfOutMulticastPkts + ".1", Value: 0, Type: gosnmp.Counter32},
694
+ {Name: oidIfOutMulticastPkts + ".2", Value: 0, Type: gosnmp.Counter32},
695
+ {Name: oidIfOutMulticastPkts + ".17", Value: 0, Type: gosnmp.Counter32},
696
+ {Name: oidIfOutMulticastPkts + ".18", Value: 0, Type: gosnmp.Counter32},
697
+ {Name: oidIfOutBroadcastPkts + ".1", Value: 0, Type: gosnmp.Counter32},
698
+ {Name: oidIfOutBroadcastPkts + ".2", Value: 0, Type: gosnmp.Counter32},
699
+ {Name: oidIfOutBroadcastPkts + ".17", Value: 0, Type: gosnmp.Counter32},
700
+ {Name: oidIfOutBroadcastPkts + ".18", Value: 0, Type: gosnmp.Counter32},
701
+ {Name: oidIfHCInOctets + ".1", Value: 0, Type: gosnmp.Counter64},
702
+ {Name: oidIfHCInOctets + ".2", Value: 76882188712, Type: gosnmp.Counter64},
703
+ {Name: oidIfHCInOctets + ".17", Value: 0, Type: gosnmp.Counter64},
704
+ {Name: oidIfHCInOctets + ".18", Value: 0, Type: gosnmp.Counter64},
705
+ {Name: oidIfHCInUcastPkts + ".1", Value: 0, Type: gosnmp.Counter64},
706
+ {Name: oidIfHCInUcastPkts + ".2", Value: 71080332, Type: gosnmp.Counter64},
707
+ {Name: oidIfHCInUcastPkts + ".17", Value: 0, Type: gosnmp.Counter64},
708
+ {Name: oidIfHCInUcastPkts + ".18", Value: 0, Type: gosnmp.Counter64},
709
+ {Name: oidIfHCInMulticastPkts + ".1", Value: 0, Type: gosnmp.Counter64},
710
+ {Name: oidIfHCInMulticastPkts + ".2", Value: 1891, Type: gosnmp.Counter64},
711
+ {Name: oidIfHCInMulticastPkts + ".17", Value: 0, Type: gosnmp.Counter64},
712
+ {Name: oidIfHCInMulticastPkts + ".18", Value: 0, Type: gosnmp.Counter64},
713
+ {Name: oidIfHCInBroadcastPkts + ".1", Value: 0, Type: gosnmp.Counter64},
714
+ {Name: oidIfHCInBroadcastPkts + ".2", Value: 0, Type: gosnmp.Counter64},
715
+ {Name: oidIfHCInBroadcastPkts + ".17", Value: 0, Type: gosnmp.Counter64},
716
+ {Name: oidIfHCInBroadcastPkts + ".18", Value: 0, Type: gosnmp.Counter64},
717
+ {Name: oidIfHCOutOctets + ".1", Value: 0, Type: gosnmp.Counter64},
718
+ {Name: oidIfHCOutOctets + ".2", Value: 19959650810, Type: gosnmp.Counter64},
719
+ {Name: oidIfHCOutOctets + ".17", Value: 0, Type: gosnmp.Counter64},
720
+ {Name: oidIfHCOutOctets + ".18", Value: 0, Type: gosnmp.Counter64},
721
+ {Name: oidIfHCOutUcastPkts + ".1", Value: 0, Type: gosnmp.Counter64},
722
+ {Name: oidIfHCOutUcastPkts + ".2", Value: 39509661, Type: gosnmp.Counter64},
723
+ {Name: oidIfHCOutUcastPkts + ".17", Value: 0, Type: gosnmp.Counter64},
724
+ {Name: oidIfHCOutUcastPkts + ".18", Value: 0, Type: gosnmp.Counter64},
725
+ {Name: oidIfHCOutMulticastPkts + ".1", Value: 0, Type: gosnmp.Counter64},
726
+ {Name: oidIfHCOutMulticastPkts + ".2", Value: 28844, Type: gosnmp.Counter64},
727
+ {Name: oidIfHCOutMulticastPkts + ".17", Value: 0, Type: gosnmp.Counter64},
728
+ {Name: oidIfHCOutMulticastPkts + ".18", Value: 0, Type: gosnmp.Counter64},
729
+ {Name: oidIfHCOutBroadcastPkts + ".1", Value: 0, Type: gosnmp.Counter64},
730
+ {Name: oidIfHCOutBroadcastPkts + ".2", Value: 7386, Type: gosnmp.Counter64},
731
+ {Name: oidIfHCOutBroadcastPkts + ".17", Value: 0, Type: gosnmp.Counter64},
732
+ {Name: oidIfHCOutBroadcastPkts + ".18", Value: 0, Type: gosnmp.Counter64},
733
+ {Name: oidIfHighSpeed + ".1", Value: 0, Type: gosnmp.Gauge32},
734
+ {Name: oidIfHighSpeed + ".2", Value: 1000, Type: gosnmp.Gauge32},
735
+ {Name: oidIfHighSpeed + ".17", Value: 0, Type: gosnmp.Gauge32},
736
+ {Name: oidIfHighSpeed + ".18", Value: 0, Type: gosnmp.Gauge32},
737
+ {Name: oidIfAlias + ".1", Value: []uint8(""), Type: gosnmp.OctetString},
738
+ {Name: oidIfAlias + ".2", Value: []uint8("UPLINK2 (2.1)"), Type: gosnmp.OctetString},
739
+ {Name: oidIfAlias + ".17", Value: []uint8(""), Type: gosnmp.OctetString},
740
+ {Name: oidIfAlias + ".18", Value: []uint8(""), Type: gosnmp.OctetString},
741
+ }, nil).MinTimes(1)
742
}
743
481
-func prepareV1Config() Config {
482
- return Config{
483
- UpdateEvery: defaultUpdateEvery,
484
- Hostname: defaultHostname,
485
- Community: defaultCommunity,
486
- Options: Options{
487
- Port: defaultPort,
488
- Retries: defaultRetries,
489
- Timeout: defaultTimeout,
490
- Version: gosnmp.Version1.String(),
491
- MaxOIDs: defaultMaxOIDs,
492
- },
493
- ChartsInput: []ChartConfig{
494
- {
495
- ID: "test_chart1",
496
- Title: "This is Test Chart1",
497
- Units: "kilobits/s",
498
- Family: "family",
499
- Type: module.Area.String(),
500
- Priority: module.Priority,
501
- Dimensions: []DimensionConfig{
502
- {
503
- OID: "1.3.6.1.2.1.2.2.1.10",
504
- Name: "in",
505
- Algorithm: module.Incremental.String(),
506
- Multiplier: 8,
507
- Divisor: 1000,
508
- },
509
- {
510
- OID: "1.3.6.1.2.1.2.2.1.16",
511
- Name: "out",
512
- Algorithm: module.Incremental.String(),
513
- Multiplier: 8,
514
- Divisor: 1000,
515
- },
516
- },
517
- },
518
- },
519
- }
744
+func decodePhysAddr(s string) []uint8 {
745
+ s = strings.ReplaceAll(s, ":", "")
746
+ v, _ := hex.DecodeString(s)
747
+ return v
748
}
src/go/collectors/go.d.plugin/modules/snmp/testdata/config.json
+2
-1
@@ -15,7 +15,8 @@
15
"retries": 123,
16
"timeout": 123,
17
"version": "ok",
18
- "max_request_size": 123
18
+ "max_request_size": 123,
19
+ "max_repetitions": 123
20
},
21
"charts": [
22
{
src/go/collectors/go.d.plugin/modules/snmp/testdata/config.yaml
+1
@@ -14,6 +14,7 @@ options:
14
timeout: 123
15
version: "ok"
16
max_request_size: 123
17
+ max_repetitions: 123
18
charts:
19
- id: "ok"
20
title: "ok"