-
Notifications
You must be signed in to change notification settings - Fork 634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Split config of auth and modules #859
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Module and Auth Split Migration | ||
|
||
In [version 0.23.0](https://github.com/prometheus/snmp_exporter/releases/tag/v0.23.0) the configuration for the `snmp_epxorter` the configuration file format has changed. Configuration files for versions v0.22.0 and before will not work. The configuration was split from a flat list of modules to separate metric walking/mapping modules and authentication configuratoins. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/configuratoins/configurations/ |
||
|
||
This change necessitates migration of the generator config and `snmp_exporter` config to the new format. | ||
|
||
The complete `generator` format is [documented in generator/README.md#file-format](generator/README.md#file-format) | ||
|
||
The complete `snmp_exporter` format is [documented in /generator/FORMAT.md](/generator/FORMAT.md). | ||
|
||
## Examples | ||
|
||
A generator containing the following config: | ||
|
||
```yaml | ||
modules: | ||
sys_uptime: | ||
version: 2 | ||
walk: | ||
- sysUpTime | ||
auth: | ||
community: public | ||
``` | ||
|
||
Would now become: | ||
|
||
```yaml | ||
auths: | ||
public_v2: | ||
community: public | ||
version: 2 | ||
modules: | ||
sys_uptime: | ||
walk: | ||
- sysUpTime | ||
``` | ||
|
||
The newly generated `snmp_exporter` config would be: | ||
|
||
```yaml | ||
# WARNING: This file was auto-generated using snmp_exporter generator, manual changes will be lost. | ||
auths: | ||
public_v2: | ||
community: public | ||
security_level: noAuthNoPriv | ||
auth_protocol: MD5 | ||
priv_protocol: DES | ||
version: 2 | ||
modules: | ||
if_mib: | ||
get: | ||
- 1.3.6.1.2.1.1.3.0 | ||
metrics: | ||
- name: sysUpTime | ||
oid: 1.3.6.1.2.1.1.3 | ||
type: gauge | ||
help: The time (in hundredths of a second) since the network management portion | ||
of the system was last re-initialized. - 1.3.6.1.2.1.1.3 | ||
``` |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -14,6 +14,7 @@ | |||||
package config | ||||||
|
||||||
import ( | ||||||
"errors" | ||||||
"fmt" | ||||||
"os" | ||||||
"regexp" | ||||||
|
@@ -33,6 +34,9 @@ func LoadFile(filename string) (*Config, error) { | |||||
if err != nil { | ||||||
return nil, err | ||||||
} | ||||||
if cfg.Version != 2 { | ||||||
return cfg, ErrUnsupportedVersion | ||||||
} | ||||||
return cfg, nil | ||||||
} | ||||||
|
||||||
|
@@ -44,13 +48,12 @@ var ( | |||||
SecurityLevel: "noAuthNoPriv", | ||||||
AuthProtocol: "MD5", | ||||||
PrivProtocol: "DES", | ||||||
Version: 2, | ||||||
} | ||||||
DefaultWalkParams = WalkParams{ | ||||||
Version: 2, | ||||||
MaxRepetitions: 25, | ||||||
Retries: &defaultRetries, | ||||||
Timeout: time.Second * 5, | ||||||
Auth: DefaultAuth, | ||||||
UseUnconnectedUDPSocket: false, | ||||||
AllowNonIncreasingOIDs: false, | ||||||
} | ||||||
|
@@ -60,17 +63,21 @@ var ( | |||||
DefaultRegexpExtract = RegexpExtract{ | ||||||
Value: "$1", | ||||||
} | ||||||
|
||||||
ErrUnsupportedVersion = errors.New("unsupported config version") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a Go error, it shouldn't be this verbose. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will the user see it on CLI? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but basically no. That's the whole reason for the "Possible old config file" error. The user won't directly see this error. It's for internal |
||||||
) | ||||||
|
||||||
// Config for the snmp_exporter. | ||||||
type Config map[string]*Module | ||||||
type Config struct { | ||||||
Auths map[string]*Auth `yaml:"auths",omitempty"` | ||||||
Modules map[string]*Module `yaml:"modules",omitempty"` | ||||||
Version int `yaml:"version"` | ||||||
} | ||||||
|
||||||
type WalkParams struct { | ||||||
Version int `yaml:"version,omitempty"` | ||||||
MaxRepetitions uint32 `yaml:"max_repetitions,omitempty"` | ||||||
Retries *int `yaml:"retries,omitempty"` | ||||||
Timeout time.Duration `yaml:"timeout,omitempty"` | ||||||
Auth Auth `yaml:"auth,omitempty"` | ||||||
UseUnconnectedUDPSocket bool `yaml:"use_unconnected_udp_socket,omitempty"` | ||||||
AllowNonIncreasingOIDs bool `yaml:"allow_nonincreasing_oids,omitempty"` | ||||||
} | ||||||
|
@@ -90,43 +97,11 @@ func (c *Module) UnmarshalYAML(unmarshal func(interface{}) error) error { | |||||
if err := unmarshal((*plain)(c)); err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
wp := c.WalkParams | ||||||
|
||||||
if wp.Version < 1 || wp.Version > 3 { | ||||||
return fmt.Errorf("SNMP version must be 1, 2 or 3. Got: %d", wp.Version) | ||||||
} | ||||||
if wp.Version == 3 { | ||||||
switch wp.Auth.SecurityLevel { | ||||||
case "authPriv": | ||||||
if wp.Auth.PrivPassword == "" { | ||||||
return fmt.Errorf("priv password is missing, required for SNMPv3 with priv") | ||||||
} | ||||||
if wp.Auth.PrivProtocol != "DES" && wp.Auth.PrivProtocol != "AES" && wp.Auth.PrivProtocol != "AES192" && wp.Auth.PrivProtocol != "AES192C" && wp.Auth.PrivProtocol != "AES256" && wp.Auth.PrivProtocol != "AES256C" { | ||||||
return fmt.Errorf("priv protocol must be DES or AES") | ||||||
} | ||||||
fallthrough | ||||||
case "authNoPriv": | ||||||
if wp.Auth.Password == "" { | ||||||
return fmt.Errorf("auth password is missing, required for SNMPv3 with auth") | ||||||
} | ||||||
if wp.Auth.AuthProtocol != "MD5" && wp.Auth.AuthProtocol != "SHA" && wp.Auth.AuthProtocol != "SHA224" && wp.Auth.AuthProtocol != "SHA256" && wp.Auth.AuthProtocol != "SHA384" && wp.Auth.AuthProtocol != "SHA512" { | ||||||
return fmt.Errorf("auth protocol must be SHA or MD5") | ||||||
} | ||||||
fallthrough | ||||||
case "noAuthNoPriv": | ||||||
if wp.Auth.Username == "" { | ||||||
return fmt.Errorf("auth username is missing, required for SNMPv3") | ||||||
} | ||||||
default: | ||||||
return fmt.Errorf("security level must be one of authPriv, authNoPriv or noAuthNoPriv") | ||||||
} | ||||||
} | ||||||
return nil | ||||||
} | ||||||
|
||||||
// ConfigureSNMP sets the various version and auth settings. | ||||||
func (c WalkParams) ConfigureSNMP(g *gosnmp.GoSNMP) { | ||||||
func (c Auth) ConfigureSNMP(g *gosnmp.GoSNMP) { | ||||||
switch c.Version { | ||||||
case 1: | ||||||
g.Version = gosnmp.Version1 | ||||||
|
@@ -135,16 +110,16 @@ func (c WalkParams) ConfigureSNMP(g *gosnmp.GoSNMP) { | |||||
case 3: | ||||||
g.Version = gosnmp.Version3 | ||||||
} | ||||||
g.Community = string(c.Auth.Community) | ||||||
g.ContextName = c.Auth.ContextName | ||||||
g.Community = string(c.Community) | ||||||
g.ContextName = c.ContextName | ||||||
|
||||||
// v3 security settings. | ||||||
g.SecurityModel = gosnmp.UserSecurityModel | ||||||
usm := &gosnmp.UsmSecurityParameters{ | ||||||
UserName: c.Auth.Username, | ||||||
UserName: c.Username, | ||||||
} | ||||||
auth, priv := false, false | ||||||
switch c.Auth.SecurityLevel { | ||||||
switch c.SecurityLevel { | ||||||
case "noAuthNoPriv": | ||||||
g.MsgFlags = gosnmp.NoAuthNoPriv | ||||||
case "authNoPriv": | ||||||
|
@@ -156,8 +131,8 @@ func (c WalkParams) ConfigureSNMP(g *gosnmp.GoSNMP) { | |||||
priv = true | ||||||
} | ||||||
if auth { | ||||||
usm.AuthenticationPassphrase = string(c.Auth.Password) | ||||||
switch c.Auth.AuthProtocol { | ||||||
usm.AuthenticationPassphrase = string(c.Password) | ||||||
switch c.AuthProtocol { | ||||||
case "SHA": | ||||||
usm.AuthenticationProtocol = gosnmp.SHA | ||||||
case "SHA224": | ||||||
|
@@ -173,8 +148,8 @@ func (c WalkParams) ConfigureSNMP(g *gosnmp.GoSNMP) { | |||||
} | ||||||
} | ||||||
if priv { | ||||||
usm.PrivacyPassphrase = string(c.Auth.PrivPassword) | ||||||
switch c.Auth.PrivProtocol { | ||||||
usm.PrivacyPassphrase = string(c.PrivPassword) | ||||||
switch c.PrivProtocol { | ||||||
case "DES": | ||||||
usm.PrivacyProtocol = gosnmp.DES | ||||||
case "AES": | ||||||
|
@@ -261,6 +236,46 @@ type Auth struct { | |||||
PrivProtocol string `yaml:"priv_protocol,omitempty"` | ||||||
PrivPassword Secret `yaml:"priv_password,omitempty"` | ||||||
ContextName string `yaml:"context_name,omitempty"` | ||||||
Version int `yaml:"version,omitempty"` | ||||||
} | ||||||
|
||||||
func (c *Auth) UnmarshalYAML(unmarshal func(interface{}) error) error { | ||||||
*c = DefaultAuth | ||||||
type plain Auth | ||||||
if err := unmarshal((*plain)(c)); err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
if c.Version < 1 || c.Version > 3 { | ||||||
return fmt.Errorf("SNMP version must be 1, 2 or 3. Got: %d", c.Version) | ||||||
} | ||||||
if c.Version == 3 { | ||||||
switch c.SecurityLevel { | ||||||
case "authPriv": | ||||||
if c.PrivPassword == "" { | ||||||
return fmt.Errorf("priv password is missing, required for SNMPv3 with priv") | ||||||
} | ||||||
if c.PrivProtocol != "DES" && c.PrivProtocol != "AES" && c.PrivProtocol != "AES192" && c.PrivProtocol != "AES192C" && c.PrivProtocol != "AES256" && c.PrivProtocol != "AES256C" { | ||||||
return fmt.Errorf("priv protocol must be DES or AES") | ||||||
} | ||||||
fallthrough | ||||||
case "authNoPriv": | ||||||
if c.Password == "" { | ||||||
return fmt.Errorf("auth password is missing, required for SNMPv3 with auth") | ||||||
} | ||||||
if c.AuthProtocol != "MD5" && c.AuthProtocol != "SHA" && c.AuthProtocol != "SHA224" && c.AuthProtocol != "SHA256" && c.AuthProtocol != "SHA384" && c.AuthProtocol != "SHA512" { | ||||||
return fmt.Errorf("auth protocol must be SHA or MD5") | ||||||
} | ||||||
fallthrough | ||||||
case "noAuthNoPriv": | ||||||
if c.Username == "" { | ||||||
return fmt.Errorf("auth username is missing, required for SNMPv3") | ||||||
} | ||||||
default: | ||||||
return fmt.Errorf("security level must be one of authPriv, authNoPriv or noAuthNoPriv") | ||||||
} | ||||||
} | ||||||
return nil | ||||||
} | ||||||
|
||||||
type RegexpExtract struct { | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One question I would like this to answer is how to sequence the change if you need a different auth than
public_v2
. Is it safe to specify theauth
parameter with 0.22, then upgrade the exporter? Maybe this is obvious to experienced users of the exporter, but I'd rather make it explicit for the "someone else installed this 4 years ago and I need to keep it alive" target audience.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this is already explicitly stated on line 3 that the config format in 0.23.0 has changed.
In <= 0.22.0 there was no top level
modules:
key, just a bare list of modules.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reworded line 3 slightly.