master
go 204 lines 4.84 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package snmp
4
5 import (
6 "context"
7 _ "embed"
8 "fmt"
9 "time"
10
11 "github.com/gosnmp/gosnmp"
12 "github.com/netdata/netdata/go/plugins/plugin/framework/vnodes"
13
14 "github.com/netdata/netdata/go/plugins/logger"
15 "github.com/netdata/netdata/go/plugins/pkg/confopt"
16 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
17 "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/snmp/ddsnmp"
18 "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/snmp/ddsnmp/ddsnmpcollector"
19 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/pinger"
20 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/snmputils"
21 )
22
23 //go:embed "config_schema.json"
24 var configSchema string
25
26 func init() {
27 collectorapi.Register("snmp", collectorapi.Creator{
28 JobConfigSchema: configSchema,
29 Defaults: collectorapi.Defaults{
30 UpdateEvery: 10,
31 },
32 Create: func() collectorapi.CollectorV1 { return New() },
33 Config: func() any { return &Config{} },
34 Methods: snmpMethods,
35 MethodHandler: snmpFunctionHandler,
36 })
37 }
38
39 func New() *Collector {
40 c := &Collector{
41 Config: Config{
42 CreateVnode: true,
43 VnodeDeviceDownThreshold: 3,
44 Community: "public",
45 Options: OptionsConfig{
46 Port: 161,
47 Retries: 1,
48 Timeout: 5,
49 Version: gosnmp.Version2c.String(),
50 MaxOIDs: 20,
51 MaxRepetitions: 25,
52 },
53 User: UserConfig{
54 SecurityLevel: "authPriv",
55 AuthProto: "sha512",
56 PrivProto: "aes192c",
57 },
58 Ping: PingConfig{
59 Enabled: true,
60 ProbeConfig: pinger.ProbeConfig{
61 Privileged: true,
62 Packets: 3,
63 Interval: confopt.Duration(time.Millisecond * 100),
64 Network: "ip",
65 },
66 },
67 },
68
69 charts: &collectorapi.Charts{},
70 seenScalarMetrics: make(map[string]bool),
71 seenTableMetrics: make(map[string]bool),
72 seenProfiles: make(map[string]bool),
73
74 ifaceCache: newIfaceCache(),
75 licensing: newLicensingIntegration(),
76
77 newPinger: pinger.New,
78 newSnmpClient: gosnmp.NewHandler,
79 newDdSnmpColl: func(cfg ddsnmpcollector.Config) ddCollector {
80 return ddsnmpcollector.New(cfg)
81 },
82 }
83
84 c.funcRouter = newFuncRouter(c.ifaceCache)
85 c.licensing.registerFunction(c.funcRouter)
86
87 return c
88 }
89
90 type (
91 Collector struct {
92 collectorapi.Base
93 Config `yaml:",inline" json:""`
94
95 vnode *vnodes.VirtualNode
96
97 charts *collectorapi.Charts
98 seenScalarMetrics map[string]bool
99 seenTableMetrics map[string]bool
100 seenProfiles map[string]bool
101
102 ifaceCache *ifaceCache // interface metrics cache for functions
103 licensing *licensingIntegration
104 bgp *bgpIntegration // BGP metric normalization and function state
105 funcRouter *funcRouter // function router for method handlers
106
107 pingClient pinger.Client
108 newPinger func(pinger.Config, *logger.Logger) (pinger.Client, error)
109
110 snmpClient gosnmp.Handler
111 newSnmpClient func() gosnmp.Handler
112
113 ddSnmpColl ddCollector
114 newDdSnmpColl func(ddsnmpcollector.Config) ddCollector
115
116 sysInfo *snmputils.SysInfo
117 snmpProfiles []*ddsnmp.Profile
118
119 adjMaxRepetitions uint32
120
121 disableBulkWalk bool
122 }
123 ddCollector interface {
124 Collect() ([]*ddsnmp.ProfileMetrics, error)
125 CollectDeviceMetadata() (map[string]ddsnmp.MetaTag, error)
126 }
127 )
128
129 func (c *Collector) Configuration() any {
130 return c.Config
131 }
132
133 func (c *Collector) Init(context.Context) error {
134 if err := c.validateConfig(); err != nil {
135 return fmt.Errorf("config validation failed: %v", err)
136 }
137
138 if _, err := c.initSNMPClient(); err != nil {
139 return fmt.Errorf("failed to initialize SNMP client: %v", err)
140 }
141
142 if c.PingOnly || c.Ping.Enabled {
143 pr, err := c.initPinger()
144 if err != nil {
145 return fmt.Errorf("failed to initialize ping client: %v", err)
146 }
147 c.pingClient = pr
148 }
149
150 return nil
151 }
152
153 func (c *Collector) Check(ctx context.Context) error {
154 if c.snmpClient == nil {
155 snmpClient, err := c.initAndConnectSNMPClient()
156 if err != nil {
157 return fmt.Errorf("failed to init and connect SNMP client: %v", err)
158 }
159 c.snmpClient = snmpClient
160 }
161
162 if _, err := snmputils.GetSysInfo(c.snmpClient); err != nil {
163 return err
164 }
165
166 if c.PingOnly && c.pingClient != nil {
167 if _, err := c.pingClient.Probe(ctx, c.Hostname); err != nil && isPingUnrecoverableError(err) {
168 return fmt.Errorf("ping check failed: %v", err)
169 }
170 }
171
172 return nil
173 }
174
175 func (c *Collector) Charts() *collectorapi.Charts {
176 return c.charts
177 }
178
179 func (c *Collector) Collect(ctx context.Context) map[string]int64 {
180 mx, err := c.collect(ctx)
181 if err != nil {
182 c.Error(err)
183 }
184
185 if len(mx) == 0 {
186 return nil
187 }
188
189 return mx
190 }
191
192 func (c *Collector) Cleanup(ctx context.Context) {
193 if c.funcRouter != nil {
194 c.funcRouter.Cleanup(ctx)
195 }
196 ddsnmp.DeviceRegistry.Unregister(c.deviceRegistryKey())
197 if c.snmpClient != nil {
198 _ = c.snmpClient.Close()
199 }
200 }
201
202 func (c *Collector) VirtualNode() *vnodes.VirtualNode {
203 return c.vnode
204 }