Skip to content

Commit

Permalink
feat(prom/exp/snmp): add support to pass multiple SNMP config files t…
Browse files Browse the repository at this point in the history
…o `prometheus.exporter.snmp`

Signed-off-by: hainenber <[email protected]>
  • Loading branch information
hainenber committed May 30, 2024
1 parent a89fa6c commit 2bcc1dd
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 35 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Main (unreleased)

- Added support for NS records to `discovery.dns`. (@djcode)

- Add support to pass multiple SNMP config files to `prometheus.exporter.snmp`. (@hainenber)

### Bugfixes

- Fixed an issue with `prometheus.scrape` in which targets that move from one
Expand Down
15 changes: 9 additions & 6 deletions docs/sources/reference/components/prometheus.exporter.snmp.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The `prometheus.exporter.snmp` component embeds

```alloy
prometheus.exporter.snmp "LABEL" {
config_file = SNMP_CONFIG_FILE_PATH
config_files = [SNMP_CONFIG_FILE_PATH_1, SNMP_CONFIG_FILE_PATH_2]
target "TARGET_NAME" {
address = TARGET_ADDRESS
Expand All @@ -30,14 +30,17 @@ prometheus.exporter.snmp "LABEL" {
The following arguments can be used to configure the exporter's behavior.
Omitted fields take their default values.

| Name | Type | Description | Default | Required |
| ------------- | -------------------- | ------------------------------------------------ | ------- | -------- |
| `config_file` | `string` | SNMP configuration file defining custom modules. | | no |
| `config` | `string` or `secret` | SNMP configuration as inline string. | | no |
| Name | Type | Description | Default | Required |
| ------------- | -------------------- | --------------------------------------------------------- | ------- | -------- |
| `config_file` | `string` | SNMP configuration file defining custom modules. | | no |
| `config_file` | `list(string)` | List of SNMP configuration files defining custom modules. | | no |
| `config` | `string` or `secret` | SNMP configuration as inline string. | | no |

The `config_file` argument points to a YAML file defining which snmp_exporter modules to use.
Refer to [snmp_exporter](https://github.com/prometheus/snmp_exporter#generating-configuration) for details on how to generate a configuration file.

The `config_files` argument consist of list of YAML files with content as described as above for `config_file`.

The `config` argument must be a YAML document as string defining which SNMP modules and auths to use.
`config` is typically loaded by using the exports of another component. For example,

Expand Down Expand Up @@ -109,7 +112,7 @@ from `prometheus.exporter.snmp`:

```alloy
prometheus.exporter.snmp "example" {
config_file = "snmp_modules.yml"
config_files = ["snmp_modules.yml"]
target "network_switch_1" {
address = "192.168.1.2"
Expand Down
10 changes: 6 additions & 4 deletions internal/component/prometheus/exporter/snmp/snmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ func (w WalkParams) Convert() map[string]snmp_config.WalkParams {

type Arguments struct {
ConfigFile string `alloy:"config_file,attr,optional"`
ConfigFiles []string `alloy:"config_files,attr,optional"`
Config alloytypes.OptionalSecret `alloy:"config,attr,optional"`
Targets TargetBlock `alloy:"target,block"`
WalkParams WalkParams `alloy:"walk_param,block,optional"`
Expand Down Expand Up @@ -141,9 +142,10 @@ func (a *Arguments) UnmarshalAlloy(f func(interface{}) error) error {
// Convert converts the component's Arguments to the integration's Config.
func (a *Arguments) Convert() *snmp_exporter.Config {
return &snmp_exporter.Config{
SnmpConfigFile: a.ConfigFile,
SnmpTargets: a.Targets.Convert(),
WalkParams: a.WalkParams.Convert(),
SnmpConfig: a.ConfigStruct,
SnmpConfigFile: a.ConfigFile,
SnmpConfigFiles: a.ConfigFiles,
SnmpTargets: a.Targets.Convert(),
WalkParams: a.WalkParams.Convert(),
SnmpConfig: a.ConfigStruct,
}
}
8 changes: 5 additions & 3 deletions internal/component/prometheus/exporter/snmp/snmp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,15 @@ func TestUnmarshalAlloy(t *testing.T) {

func TestConvertConfig(t *testing.T) {
args := Arguments{
ConfigFile: "modules.yml",
Targets: TargetBlock{{Name: "network_switch_1", Target: "192.168.1.2", Module: "if_mib"}},
WalkParams: WalkParams{{Name: "public", Retries: 2}},
ConfigFile: "modules.yml",
ConfigFiles: []string{"modules_1.yml", "modules_2.yml"},
Targets: TargetBlock{{Name: "network_switch_1", Target: "192.168.1.2", Module: "if_mib"}},
WalkParams: WalkParams{{Name: "public", Retries: 2}},
}

res := args.Convert()
require.Equal(t, "modules.yml", res.SnmpConfigFile)
require.Equal(t, []string{"modules_1.yml", "modules_2.yml"}, res.SnmpConfigFiles)
require.Equal(t, 1, len(res.SnmpTargets))
require.Equal(t, "network_switch_1", res.SnmpTargets[0].Name)
}
Expand Down
35 changes: 22 additions & 13 deletions internal/static/integrations/snmp_exporter/snmp_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"fmt"
"net/http"
"net/url"
"slices"
"strings"

"github.com/go-kit/log"
"github.com/grafana/alloy/internal/static/integrations"
Expand All @@ -19,10 +21,11 @@ import (

// DefaultConfig holds the default settings for the snmp_exporter integration.
var DefaultConfig = Config{
WalkParams: make(map[string]snmp_config.WalkParams),
SnmpConfigFile: "",
SnmpTargets: make([]SNMPTarget, 0),
SnmpConfig: snmp_config.Config{},
WalkParams: make(map[string]snmp_config.WalkParams),
SnmpConfigFile: "",
SnmpConfigFiles: []string{},
SnmpTargets: make([]SNMPTarget, 0),
SnmpConfig: snmp_config.Config{},
}

// SNMPTarget defines a target device to be used by the integration.
Expand All @@ -36,10 +39,11 @@ type SNMPTarget struct {

// Config configures the SNMP integration.
type Config struct {
WalkParams map[string]snmp_config.WalkParams `yaml:"walk_params,omitempty"`
SnmpConfigFile string `yaml:"config_file,omitempty"`
SnmpTargets []SNMPTarget `yaml:"snmp_targets"`
SnmpConfig snmp_config.Config `yaml:"snmp_config,omitempty"`
WalkParams map[string]snmp_config.WalkParams `yaml:"walk_params,omitempty"`
SnmpConfigFile string `yaml:"config_file,omitempty"`
SnmpConfigFiles []string `yaml:"config_files,omitempty"`
SnmpTargets []SNMPTarget `yaml:"snmp_targets"`
SnmpConfig snmp_config.Config `yaml:"snmp_config,omitempty"`
}

// UnmarshalYAML implements yaml.Unmarshaler for Config.
Expand Down Expand Up @@ -71,7 +75,8 @@ func init() {

// New creates a new snmp_exporter integration
func New(log log.Logger, c *Config) (integrations.Integration, error) {
snmpCfg, err := LoadSNMPConfig(c.SnmpConfigFile, &c.SnmpConfig)
snmpConfigFiles := c.SnmpConfigFiles
snmpCfg, err := LoadSNMPConfig(snmpConfigFiles, &c.SnmpConfig)
if err != nil {
return nil, err
}
Expand All @@ -97,12 +102,16 @@ func New(log log.Logger, c *Config) (integrations.Integration, error) {

// LoadSNMPConfig loads the SNMP configuration from the given file. If the file is empty, it will
// load the embedded configuration.
func LoadSNMPConfig(snmpConfigFile string, snmpCfg *snmp_config.Config) (*snmp_config.Config, error) {
func LoadSNMPConfig(snmpConfigFiles []string, snmpCfg *snmp_config.Config) (*snmp_config.Config, error) {
var err error
if snmpConfigFile != "" {
snmpCfg, err = snmp_config.LoadFile([]string{snmpConfigFile}, false)

// Remove empty string of default `snmpConfig`
validSnmpConfigFiles := slices.DeleteFunc(snmpConfigFiles, func(i string) bool { return i == "" })

if len(validSnmpConfigFiles) > 0 {
snmpCfg, err = snmp_config.LoadFile(validSnmpConfigFiles, false)
if err != nil {
return nil, fmt.Errorf("failed to load snmp config from file %v: %w", snmpConfigFile, err)
return nil, fmt.Errorf("failed to load snmp config from files %v: %w", strings.Join(snmpConfigFiles, " "), err)
}
} else {
if len(snmpCfg.Modules) == 0 && len(snmpCfg.Auths) == 0 { // If the user didn't specify a config, load the embedded config.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestLoadSNMPConfig(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg, err := LoadSNMPConfig(tt.cfg.SnmpConfigFile, &tt.cfg.SnmpConfig)
cfg, err := LoadSNMPConfig([]string{tt.cfg.SnmpConfigFile}, &tt.cfg.SnmpConfig)
require.NoError(t, err)

require.Equal(t, tt.expectedNumModules, len(cfg.Modules))
Expand Down
19 changes: 11 additions & 8 deletions internal/static/integrations/v2/snmp_exporter/snmp_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@ import (

// DefaultConfig holds the default settings for the snmp_exporter integration.
var DefaultConfig = Config{
WalkParams: make(map[string]snmp_config.WalkParams),
SnmpConfigFile: "",
WalkParams: make(map[string]snmp_config.WalkParams),
SnmpConfigFile: "",
SnmpConfigFiles: []string{},
}

// Config configures the SNMP integration.
type Config struct {
WalkParams map[string]snmp_config.WalkParams `yaml:"walk_params,omitempty"`
SnmpConfigFile string `yaml:"config_file,omitempty"`
SnmpTargets []snmp_exporter.SNMPTarget `yaml:"snmp_targets"`
SnmpConfig snmp_config.Config `yaml:"snmp_config,omitempty"`
Common common.MetricsConfig `yaml:",inline"`
WalkParams map[string]snmp_config.WalkParams `yaml:"walk_params,omitempty"`
SnmpConfigFile string `yaml:"config_file,omitempty"`
SnmpConfigFiles []string `yaml:"config_file,omitempty"`
SnmpTargets []snmp_exporter.SNMPTarget `yaml:"snmp_targets"`
SnmpConfig snmp_config.Config `yaml:"snmp_config,omitempty"`
Common common.MetricsConfig `yaml:",inline"`

globals integrations_v2.Globals
}
Expand All @@ -42,7 +44,8 @@ func (c *Config) Identifier(globals integrations_v2.Globals) (string, error) {

// NewIntegration creates a new SNMP integration.
func (c *Config) NewIntegration(log log.Logger, globals integrations_v2.Globals) (integrations_v2.Integration, error) {
snmpCfg, err := snmp_exporter.LoadSNMPConfig(c.SnmpConfigFile, &c.SnmpConfig)
snmpConfigFiles := append(c.SnmpConfigFiles, c.SnmpConfigFile)
snmpCfg, err := snmp_exporter.LoadSNMPConfig(snmpConfigFiles, &c.SnmpConfig)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 2bcc1dd

Please sign in to comment.