Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/integrations/v2/snmp_exporter/snmp.go
5414 views
1
package snmp_exporter
2
3
import (
4
"context"
5
"fmt"
6
"net/http"
7
"path"
8
"time"
9
10
"github.com/gorilla/mux"
11
"github.com/grafana/agent/pkg/integrations/v2"
12
"github.com/grafana/agent/pkg/integrations/v2/autoscrape"
13
"github.com/grafana/agent/pkg/integrations/v2/metricsutils"
14
"github.com/prometheus/common/model"
15
"github.com/prometheus/prometheus/config"
16
"github.com/prometheus/prometheus/discovery"
17
"github.com/prometheus/prometheus/discovery/targetgroup"
18
19
"github.com/go-kit/log"
20
"github.com/go-kit/log/level"
21
"github.com/prometheus/client_golang/prometheus"
22
"github.com/prometheus/client_golang/prometheus/promhttp"
23
"github.com/prometheus/snmp_exporter/collector"
24
snmp_config "github.com/prometheus/snmp_exporter/config"
25
)
26
27
type snmpHandler struct {
28
cfg *Config
29
modules *snmp_config.Config
30
log log.Logger
31
}
32
33
func (sh *snmpHandler) Targets(ep integrations.Endpoint) []*targetgroup.Group {
34
integrationNameValue := model.LabelValue("integrations/" + sh.cfg.Name())
35
key, _ := sh.cfg.Identifier(sh.cfg.globals)
36
37
group := &targetgroup.Group{
38
Labels: model.LabelSet{
39
model.InstanceLabel: model.LabelValue(key),
40
model.JobLabel: integrationNameValue,
41
"agent_hostname": model.LabelValue(sh.cfg.globals.AgentIdentifier),
42
43
// Meta labels that can be used during SD.
44
"__meta_agent_integration_name": model.LabelValue(sh.cfg.Name()),
45
"__meta_agent_integration_instance": model.LabelValue(sh.cfg.Name()),
46
"__meta_agent_integration_autoscrape": model.LabelValue(metricsutils.BoolToString(*sh.cfg.Common.Autoscrape.Enable)),
47
},
48
Source: fmt.Sprintf("%s/%s", sh.cfg.Name(), sh.cfg.Name()),
49
}
50
51
for _, lbl := range sh.cfg.Common.ExtraLabels {
52
group.Labels[model.LabelName(lbl.Name)] = model.LabelValue(lbl.Value)
53
}
54
55
for _, t := range sh.cfg.SnmpTargets {
56
labelSet := model.LabelSet{
57
model.AddressLabel: model.LabelValue(ep.Host),
58
model.MetricsPathLabel: model.LabelValue(path.Join(ep.Prefix, "metrics")),
59
"snmp_target": model.LabelValue(t.Target),
60
"__param_target": model.LabelValue(t.Target),
61
}
62
63
if t.Module != "" {
64
labelSet = labelSet.Merge(model.LabelSet{
65
"__param_module": model.LabelValue(t.Module),
66
})
67
}
68
69
if t.WalkParams != "" {
70
labelSet = labelSet.Merge(model.LabelSet{
71
"__param_walk_params": model.LabelValue(t.WalkParams),
72
})
73
}
74
75
group.Targets = append(group.Targets, labelSet)
76
}
77
78
return []*targetgroup.Group{group}
79
}
80
81
func (sh *snmpHandler) ScrapeConfigs(sd discovery.Configs) []*autoscrape.ScrapeConfig {
82
if !*sh.cfg.Common.Autoscrape.Enable {
83
return nil
84
}
85
name := sh.cfg.Name()
86
cfg := config.DefaultScrapeConfig
87
cfg.JobName = fmt.Sprintf("%s/%s", name, name)
88
cfg.Scheme = sh.cfg.globals.AgentBaseURL.Scheme
89
cfg.ServiceDiscoveryConfigs = sd
90
cfg.ScrapeInterval = sh.cfg.Common.Autoscrape.ScrapeInterval
91
cfg.ScrapeTimeout = sh.cfg.Common.Autoscrape.ScrapeTimeout
92
cfg.RelabelConfigs = sh.cfg.Common.Autoscrape.RelabelConfigs
93
cfg.MetricRelabelConfigs = sh.cfg.Common.Autoscrape.MetricRelabelConfigs
94
95
return []*autoscrape.ScrapeConfig{{
96
Instance: sh.cfg.Common.Autoscrape.MetricsInstance,
97
Config: cfg,
98
}}
99
}
100
101
func (sh *snmpHandler) Handler(prefix string) (http.Handler, error) {
102
r := mux.NewRouter()
103
r.Handle(path.Join(prefix, "metrics"), sh.createHandler(sh.cfg.SnmpTargets))
104
105
return r, nil
106
}
107
108
// Static typecheck tests
109
var (
110
_ integrations.Integration = (*snmpHandler)(nil)
111
_ integrations.HTTPIntegration = (*snmpHandler)(nil)
112
_ integrations.MetricsIntegration = (*snmpHandler)(nil)
113
)
114
115
func (sh *snmpHandler) RunIntegration(ctx context.Context) error {
116
<-ctx.Done()
117
return nil
118
}
119
120
func (sh *snmpHandler) createHandler(targets []SNMPTarget) http.HandlerFunc {
121
snmpTargets := make(map[string]SNMPTarget)
122
for _, target := range targets {
123
snmpTargets[target.Name] = target
124
}
125
126
return func(w http.ResponseWriter, r *http.Request) {
127
logger := sh.log
128
query := r.URL.Query()
129
targetName := query.Get("target")
130
131
var target string
132
if len(query["target"]) != 1 || targetName == "" {
133
http.Error(w, "'target' parameter must be specified once", 400)
134
return
135
}
136
137
t, ok := snmpTargets[targetName]
138
if ok {
139
target = t.Target
140
} else {
141
target = targetName
142
}
143
144
var moduleName string
145
if query.Has("module") {
146
if len(query["module"]) > 1 {
147
http.Error(w, "'module' parameter must only be specified once", 400)
148
return
149
}
150
moduleName = query.Get("module")
151
} else {
152
moduleName = t.Module
153
}
154
155
if moduleName == "" {
156
moduleName = "if_mib"
157
}
158
159
module, ok := (*sh.modules)[moduleName]
160
if !ok {
161
http.Error(w, fmt.Sprintf("Unknown module '%s'", moduleName), 400)
162
return
163
}
164
165
// override module connection details with custom walk params if provided
166
var walkParams string
167
if query.Has("walk_params") {
168
if len(query["walk_params"]) > 1 {
169
http.Error(w, "'walk_params' parameter must only be specified once", 400)
170
return
171
}
172
walkParams = query.Get("walk_params")
173
} else {
174
walkParams = t.WalkParams
175
}
176
177
if walkParams != "" {
178
if wp, ok := sh.cfg.WalkParams[walkParams]; ok {
179
// module.WalkParams = wp
180
if wp.Version != 0 {
181
module.WalkParams.Version = wp.Version
182
}
183
if wp.MaxRepetitions != 0 {
184
module.WalkParams.MaxRepetitions = wp.MaxRepetitions
185
}
186
if wp.Retries != 0 {
187
module.WalkParams.Retries = wp.Retries
188
}
189
if wp.Timeout != 0 {
190
module.WalkParams.Timeout = wp.Timeout
191
}
192
module.WalkParams.Auth = wp.Auth
193
} else {
194
http.Error(w, fmt.Sprintf("Unknown walk_params '%s'", walkParams), 400)
195
return
196
}
197
logger = log.With(logger, "module", moduleName, "target", target, "walk_params", walkParams)
198
} else {
199
logger = log.With(logger, "module", moduleName, "target", target)
200
}
201
level.Debug(logger).Log("msg", "Starting scrape")
202
203
start := time.Now()
204
registry := prometheus.NewRegistry()
205
c := collector.New(r.Context(), target, module, logger)
206
registry.MustRegister(c)
207
// Delegate http serving to Prometheus client library, which will call collector.Collect.
208
h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
209
h.ServeHTTP(w, r)
210
211
duration := time.Since(start).Seconds()
212
level.Debug(logger).Log("msg", "Finished scrape", "duration_seconds", duration)
213
}
214
}
215
216
func (sh *snmpHandler) handler(w http.ResponseWriter, r *http.Request) {
217
logger := sh.log
218
219
query := r.URL.Query()
220
221
target := query.Get("target")
222
if len(query["target"]) != 1 || target == "" {
223
http.Error(w, "'target' parameter must be specified once", 400)
224
return
225
}
226
227
moduleName := query.Get("module")
228
if len(query["module"]) > 1 {
229
http.Error(w, "'module' parameter must only be specified once", 400)
230
return
231
}
232
if moduleName == "" {
233
moduleName = "if_mib"
234
}
235
236
module, ok := (*sh.modules)[moduleName]
237
if !ok {
238
http.Error(w, fmt.Sprintf("Unknown module '%s'", moduleName), 400)
239
return
240
}
241
242
// override module connection details with custom walk params if provided
243
walkParams := query.Get("walk_params")
244
if len(query["walk_params"]) > 1 {
245
http.Error(w, "'walk_params' parameter must only be specified once", 400)
246
return
247
}
248
249
if walkParams != "" {
250
if wp, ok := sh.cfg.WalkParams[walkParams]; ok {
251
// module.WalkParams = wp
252
if wp.Version != 0 {
253
module.WalkParams.Version = wp.Version
254
}
255
if wp.MaxRepetitions != 0 {
256
module.WalkParams.MaxRepetitions = wp.MaxRepetitions
257
}
258
if wp.Retries != 0 {
259
module.WalkParams.Retries = wp.Retries
260
}
261
if wp.Timeout != 0 {
262
module.WalkParams.Timeout = wp.Timeout
263
}
264
module.WalkParams.Auth = wp.Auth
265
} else {
266
http.Error(w, fmt.Sprintf("Unknown walk_params '%s'", walkParams), 400)
267
return
268
}
269
logger = log.With(logger, "module", moduleName, "target", target, "walk_params", walkParams)
270
} else {
271
logger = log.With(logger, "module", moduleName, "target", target)
272
}
273
level.Debug(logger).Log("msg", "Starting scrape")
274
275
start := time.Now()
276
registry := prometheus.NewRegistry()
277
c := collector.New(r.Context(), target, module, logger)
278
registry.MustRegister(c)
279
// Delegate http serving to Prometheus client library, which will call collector.Collect.
280
h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
281
h.ServeHTTP(w, r)
282
duration := time.Since(start).Seconds()
283
level.Debug(logger).Log("msg", "Finished scrape", "duration_seconds", duration)
284
}
285
286
func (sh snmpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
287
sh.handler(w, r)
288
}
289
290