github.com/netdata/go.d.plugin@v0.58.1/modules/snmp/snmp.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package snmp
     4  
     5  import (
     6  	_ "embed"
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/netdata/go.d.plugin/agent/module"
    11  
    12  	"github.com/gosnmp/gosnmp"
    13  )
    14  
    15  const (
    16  	defaultUpdateEvery = 10
    17  	defaultHostname    = "127.0.0.1"
    18  	defaultCommunity   = "public"
    19  	defaultVersion     = gosnmp.Version2c
    20  	defaultPort        = 161
    21  	defaultRetries     = 1
    22  	defaultTimeout     = defaultUpdateEvery
    23  	defaultMaxOIDs     = 60
    24  )
    25  
    26  //go:embed "config_schema.json"
    27  var configSchema string
    28  
    29  func init() {
    30  	module.Register("snmp", module.Creator{
    31  		JobConfigSchema: configSchema,
    32  		Defaults: module.Defaults{
    33  			UpdateEvery: defaultUpdateEvery,
    34  		},
    35  		Create: func() module.Module { return New() },
    36  	})
    37  }
    38  
    39  func New() *SNMP {
    40  	return &SNMP{
    41  		Config: Config{
    42  			Hostname:  defaultHostname,
    43  			Community: defaultCommunity,
    44  			Options: Options{
    45  				Port:    defaultPort,
    46  				Retries: defaultRetries,
    47  				Timeout: defaultUpdateEvery,
    48  				Version: defaultVersion.String(),
    49  				MaxOIDs: defaultMaxOIDs,
    50  			},
    51  		},
    52  	}
    53  }
    54  
    55  type (
    56  	Config struct {
    57  		UpdateEvery int           `yaml:"update_every"`
    58  		Hostname    string        `yaml:"hostname"`
    59  		Community   string        `yaml:"community"`
    60  		User        User          `yaml:"user"`
    61  		Options     Options       `yaml:"options"`
    62  		ChartsInput []ChartConfig `yaml:"charts"`
    63  	}
    64  	User struct {
    65  		Name          string `yaml:"name"`
    66  		SecurityLevel string `yaml:"level"`
    67  		AuthProto     string `yaml:"auth_proto"`
    68  		AuthKey       string `yaml:"auth_key"`
    69  		PrivProto     string `yaml:"priv_proto"`
    70  		PrivKey       string `yaml:"priv_key"`
    71  	}
    72  	Options struct {
    73  		Port    int    `yaml:"port"`
    74  		Retries int    `yaml:"retries"`
    75  		Timeout int    `yaml:"timeout"`
    76  		Version string `yaml:"version"`
    77  		MaxOIDs int    `yaml:"max_request_size"`
    78  	}
    79  	ChartConfig struct {
    80  		ID         string            `yaml:"id"`
    81  		Title      string            `yaml:"title"`
    82  		Units      string            `yaml:"units"`
    83  		Family     string            `yaml:"family"`
    84  		Type       string            `yaml:"type"`
    85  		Priority   int               `yaml:"priority"`
    86  		IndexRange []int             `yaml:"multiply_range"`
    87  		Dimensions []DimensionConfig `yaml:"dimensions"`
    88  	}
    89  	DimensionConfig struct {
    90  		OID        string `yaml:"oid"`
    91  		Name       string `yaml:"name"`
    92  		Algorithm  string `yaml:"algorithm"`
    93  		Multiplier int    `yaml:"multiplier"`
    94  		Divisor    int    `yaml:"divisor"`
    95  	}
    96  )
    97  
    98  type SNMP struct {
    99  	module.Base
   100  	Config `yaml:",inline"`
   101  
   102  	charts     *module.Charts
   103  	snmpClient gosnmp.Handler
   104  	oids       []string
   105  }
   106  
   107  func (s *SNMP) Init() bool {
   108  	err := s.validateConfig()
   109  	if err != nil {
   110  		s.Errorf("config validation: %v", err)
   111  		return false
   112  	}
   113  
   114  	snmpClient, err := s.initSNMPClient()
   115  	if err != nil {
   116  		s.Errorf("SNMP client initialization: %v", err)
   117  		return false
   118  	}
   119  
   120  	s.Info(snmpClientConnInfo(snmpClient))
   121  
   122  	err = snmpClient.Connect()
   123  	if err != nil {
   124  		s.Errorf("SNMP client connect: %v", err)
   125  		return false
   126  	}
   127  	s.snmpClient = snmpClient
   128  
   129  	charts, err := newCharts(s.ChartsInput)
   130  	if err != nil {
   131  		s.Errorf("Population of charts failed: %v", err)
   132  		return false
   133  	}
   134  	s.charts = charts
   135  
   136  	s.oids = s.initOIDs()
   137  
   138  	return true
   139  }
   140  
   141  func (s *SNMP) Check() bool {
   142  	return len(s.Collect()) > 0
   143  }
   144  
   145  func (s *SNMP) Charts() *module.Charts {
   146  	return s.charts
   147  }
   148  
   149  func (s *SNMP) Collect() map[string]int64 {
   150  	mx, err := s.collect()
   151  	if err != nil {
   152  		s.Error(err)
   153  	}
   154  
   155  	if len(mx) == 0 {
   156  		return nil
   157  	}
   158  	return mx
   159  }
   160  
   161  func (s *SNMP) Cleanup() {
   162  	if s.snmpClient != nil {
   163  		_ = s.snmpClient.Close()
   164  	}
   165  }
   166  
   167  func snmpClientConnInfo(c gosnmp.Handler) string {
   168  	var info strings.Builder
   169  	info.WriteString(fmt.Sprintf("hostname=%s,port=%d,snmp_version=%s", c.Target(), c.Port(), c.Version()))
   170  	switch c.Version() {
   171  	case gosnmp.Version1, gosnmp.Version2c:
   172  		info.WriteString(fmt.Sprintf(",community=%s", c.Community()))
   173  	case gosnmp.Version3:
   174  		info.WriteString(fmt.Sprintf(",security_level=%d,%s", c.MsgFlags(), c.SecurityParameters().Description()))
   175  	}
   176  	return info.String()
   177  }