Path: blob/main/pkg/integrations/v2/snmp_exporter/snmp.go
5414 views
package snmp_exporter12import (3"context"4"fmt"5"net/http"6"path"7"time"89"github.com/gorilla/mux"10"github.com/grafana/agent/pkg/integrations/v2"11"github.com/grafana/agent/pkg/integrations/v2/autoscrape"12"github.com/grafana/agent/pkg/integrations/v2/metricsutils"13"github.com/prometheus/common/model"14"github.com/prometheus/prometheus/config"15"github.com/prometheus/prometheus/discovery"16"github.com/prometheus/prometheus/discovery/targetgroup"1718"github.com/go-kit/log"19"github.com/go-kit/log/level"20"github.com/prometheus/client_golang/prometheus"21"github.com/prometheus/client_golang/prometheus/promhttp"22"github.com/prometheus/snmp_exporter/collector"23snmp_config "github.com/prometheus/snmp_exporter/config"24)2526type snmpHandler struct {27cfg *Config28modules *snmp_config.Config29log log.Logger30}3132func (sh *snmpHandler) Targets(ep integrations.Endpoint) []*targetgroup.Group {33integrationNameValue := model.LabelValue("integrations/" + sh.cfg.Name())34key, _ := sh.cfg.Identifier(sh.cfg.globals)3536group := &targetgroup.Group{37Labels: model.LabelSet{38model.InstanceLabel: model.LabelValue(key),39model.JobLabel: integrationNameValue,40"agent_hostname": model.LabelValue(sh.cfg.globals.AgentIdentifier),4142// Meta labels that can be used during SD.43"__meta_agent_integration_name": model.LabelValue(sh.cfg.Name()),44"__meta_agent_integration_instance": model.LabelValue(sh.cfg.Name()),45"__meta_agent_integration_autoscrape": model.LabelValue(metricsutils.BoolToString(*sh.cfg.Common.Autoscrape.Enable)),46},47Source: fmt.Sprintf("%s/%s", sh.cfg.Name(), sh.cfg.Name()),48}4950for _, lbl := range sh.cfg.Common.ExtraLabels {51group.Labels[model.LabelName(lbl.Name)] = model.LabelValue(lbl.Value)52}5354for _, t := range sh.cfg.SnmpTargets {55labelSet := model.LabelSet{56model.AddressLabel: model.LabelValue(ep.Host),57model.MetricsPathLabel: model.LabelValue(path.Join(ep.Prefix, "metrics")),58"snmp_target": model.LabelValue(t.Target),59"__param_target": model.LabelValue(t.Target),60}6162if t.Module != "" {63labelSet = labelSet.Merge(model.LabelSet{64"__param_module": model.LabelValue(t.Module),65})66}6768if t.WalkParams != "" {69labelSet = labelSet.Merge(model.LabelSet{70"__param_walk_params": model.LabelValue(t.WalkParams),71})72}7374group.Targets = append(group.Targets, labelSet)75}7677return []*targetgroup.Group{group}78}7980func (sh *snmpHandler) ScrapeConfigs(sd discovery.Configs) []*autoscrape.ScrapeConfig {81if !*sh.cfg.Common.Autoscrape.Enable {82return nil83}84name := sh.cfg.Name()85cfg := config.DefaultScrapeConfig86cfg.JobName = fmt.Sprintf("%s/%s", name, name)87cfg.Scheme = sh.cfg.globals.AgentBaseURL.Scheme88cfg.ServiceDiscoveryConfigs = sd89cfg.ScrapeInterval = sh.cfg.Common.Autoscrape.ScrapeInterval90cfg.ScrapeTimeout = sh.cfg.Common.Autoscrape.ScrapeTimeout91cfg.RelabelConfigs = sh.cfg.Common.Autoscrape.RelabelConfigs92cfg.MetricRelabelConfigs = sh.cfg.Common.Autoscrape.MetricRelabelConfigs9394return []*autoscrape.ScrapeConfig{{95Instance: sh.cfg.Common.Autoscrape.MetricsInstance,96Config: cfg,97}}98}99100func (sh *snmpHandler) Handler(prefix string) (http.Handler, error) {101r := mux.NewRouter()102r.Handle(path.Join(prefix, "metrics"), sh.createHandler(sh.cfg.SnmpTargets))103104return r, nil105}106107// Static typecheck tests108var (109_ integrations.Integration = (*snmpHandler)(nil)110_ integrations.HTTPIntegration = (*snmpHandler)(nil)111_ integrations.MetricsIntegration = (*snmpHandler)(nil)112)113114func (sh *snmpHandler) RunIntegration(ctx context.Context) error {115<-ctx.Done()116return nil117}118119func (sh *snmpHandler) createHandler(targets []SNMPTarget) http.HandlerFunc {120snmpTargets := make(map[string]SNMPTarget)121for _, target := range targets {122snmpTargets[target.Name] = target123}124125return func(w http.ResponseWriter, r *http.Request) {126logger := sh.log127query := r.URL.Query()128targetName := query.Get("target")129130var target string131if len(query["target"]) != 1 || targetName == "" {132http.Error(w, "'target' parameter must be specified once", 400)133return134}135136t, ok := snmpTargets[targetName]137if ok {138target = t.Target139} else {140target = targetName141}142143var moduleName string144if query.Has("module") {145if len(query["module"]) > 1 {146http.Error(w, "'module' parameter must only be specified once", 400)147return148}149moduleName = query.Get("module")150} else {151moduleName = t.Module152}153154if moduleName == "" {155moduleName = "if_mib"156}157158module, ok := (*sh.modules)[moduleName]159if !ok {160http.Error(w, fmt.Sprintf("Unknown module '%s'", moduleName), 400)161return162}163164// override module connection details with custom walk params if provided165var walkParams string166if query.Has("walk_params") {167if len(query["walk_params"]) > 1 {168http.Error(w, "'walk_params' parameter must only be specified once", 400)169return170}171walkParams = query.Get("walk_params")172} else {173walkParams = t.WalkParams174}175176if walkParams != "" {177if wp, ok := sh.cfg.WalkParams[walkParams]; ok {178// module.WalkParams = wp179if wp.Version != 0 {180module.WalkParams.Version = wp.Version181}182if wp.MaxRepetitions != 0 {183module.WalkParams.MaxRepetitions = wp.MaxRepetitions184}185if wp.Retries != 0 {186module.WalkParams.Retries = wp.Retries187}188if wp.Timeout != 0 {189module.WalkParams.Timeout = wp.Timeout190}191module.WalkParams.Auth = wp.Auth192} else {193http.Error(w, fmt.Sprintf("Unknown walk_params '%s'", walkParams), 400)194return195}196logger = log.With(logger, "module", moduleName, "target", target, "walk_params", walkParams)197} else {198logger = log.With(logger, "module", moduleName, "target", target)199}200level.Debug(logger).Log("msg", "Starting scrape")201202start := time.Now()203registry := prometheus.NewRegistry()204c := collector.New(r.Context(), target, module, logger)205registry.MustRegister(c)206// Delegate http serving to Prometheus client library, which will call collector.Collect.207h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})208h.ServeHTTP(w, r)209210duration := time.Since(start).Seconds()211level.Debug(logger).Log("msg", "Finished scrape", "duration_seconds", duration)212}213}214215func (sh *snmpHandler) handler(w http.ResponseWriter, r *http.Request) {216logger := sh.log217218query := r.URL.Query()219220target := query.Get("target")221if len(query["target"]) != 1 || target == "" {222http.Error(w, "'target' parameter must be specified once", 400)223return224}225226moduleName := query.Get("module")227if len(query["module"]) > 1 {228http.Error(w, "'module' parameter must only be specified once", 400)229return230}231if moduleName == "" {232moduleName = "if_mib"233}234235module, ok := (*sh.modules)[moduleName]236if !ok {237http.Error(w, fmt.Sprintf("Unknown module '%s'", moduleName), 400)238return239}240241// override module connection details with custom walk params if provided242walkParams := query.Get("walk_params")243if len(query["walk_params"]) > 1 {244http.Error(w, "'walk_params' parameter must only be specified once", 400)245return246}247248if walkParams != "" {249if wp, ok := sh.cfg.WalkParams[walkParams]; ok {250// module.WalkParams = wp251if wp.Version != 0 {252module.WalkParams.Version = wp.Version253}254if wp.MaxRepetitions != 0 {255module.WalkParams.MaxRepetitions = wp.MaxRepetitions256}257if wp.Retries != 0 {258module.WalkParams.Retries = wp.Retries259}260if wp.Timeout != 0 {261module.WalkParams.Timeout = wp.Timeout262}263module.WalkParams.Auth = wp.Auth264} else {265http.Error(w, fmt.Sprintf("Unknown walk_params '%s'", walkParams), 400)266return267}268logger = log.With(logger, "module", moduleName, "target", target, "walk_params", walkParams)269} else {270logger = log.With(logger, "module", moduleName, "target", target)271}272level.Debug(logger).Log("msg", "Starting scrape")273274start := time.Now()275registry := prometheus.NewRegistry()276c := collector.New(r.Context(), target, module, logger)277registry.MustRegister(c)278// Delegate http serving to Prometheus client library, which will call collector.Collect.279h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})280h.ServeHTTP(w, r)281duration := time.Since(start).Seconds()282level.Debug(logger).Log("msg", "Finished scrape", "duration_seconds", duration)283}284285func (sh snmpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {286sh.handler(w, r)287}288289290