diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index 6a9e5ba22..c6ce558db 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -268,7 +268,7 @@ func reloadConfig(filename string, rls ...Reloadable) (err error) { if err != nil { return err } - acfg := &config.AlertmanagersConfig{ + acfg := &config.AlertmanagerConfig{ Scheme: u.Scheme, PathPrefix: u.Path, Timeout: cfg.notifierTimeout, @@ -284,7 +284,7 @@ func reloadConfig(filename string, rls ...Reloadable) (err error) { }, }, } - conf.AlertingConfig.AlertmanagersConfigs = append(conf.AlertingConfig.AlertmanagersConfigs, acfg) + conf.AlertingConfig.AlertmanagerConfigs = append(conf.AlertingConfig.AlertmanagerConfigs, acfg) } failed := false diff --git a/config/config.go b/config/config.go index c3cec1aef..da961d189 100644 --- a/config/config.go +++ b/config/config.go @@ -88,7 +88,7 @@ var ( } // DefaultAlertmanagersConfig is the default alertmanager configuration. - DefaultAlertmanagersConfig = AlertmanagersConfig{ + DefaultAlertmanagersConfig = AlertmanagerConfig{ Scheme: "http", Timeout: 10 * time.Second, } @@ -220,27 +220,33 @@ func resolveFilepaths(baseDir string, cfg *Config) { cfg.RuleFiles[i] = join(rf) } - for _, cfg := range cfg.ScrapeConfigs { - scfg := &cfg.HTTPClientConfig - + clientPaths := func(scfg *HTTPClientConfig) { scfg.BearerTokenFile = join(scfg.BearerTokenFile) scfg.TLSConfig.CAFile = join(scfg.TLSConfig.CAFile) scfg.TLSConfig.CertFile = join(scfg.TLSConfig.CertFile) scfg.TLSConfig.KeyFile = join(scfg.TLSConfig.KeyFile) - - for _, kcfg := range cfg.ServiceDiscoveryConfig.KubernetesSDConfigs { + } + sdPaths := func(cfg *ServiceDiscoveryConfig) { + for _, kcfg := range cfg.KubernetesSDConfigs { kcfg.BearerTokenFile = join(kcfg.BearerTokenFile) kcfg.TLSConfig.CAFile = join(kcfg.TLSConfig.CAFile) kcfg.TLSConfig.CertFile = join(kcfg.TLSConfig.CertFile) kcfg.TLSConfig.KeyFile = join(kcfg.TLSConfig.KeyFile) } - - for _, mcfg := range cfg.ServiceDiscoveryConfig.MarathonSDConfigs { + for _, mcfg := range cfg.MarathonSDConfigs { mcfg.TLSConfig.CAFile = join(mcfg.TLSConfig.CAFile) mcfg.TLSConfig.CertFile = join(mcfg.TLSConfig.CertFile) mcfg.TLSConfig.KeyFile = join(mcfg.TLSConfig.KeyFile) } + } + for _, cfg := range cfg.ScrapeConfigs { + clientPaths(&cfg.HTTPClientConfig) + sdPaths(&cfg.ServiceDiscoveryConfig) + } + for _, cfg := range cfg.AlertingConfig.AlertmanagerConfigs { + clientPaths(&cfg.HTTPClientConfig) + sdPaths(&cfg.ServiceDiscoveryConfig) } } @@ -442,7 +448,7 @@ func (c *ServiceDiscoveryConfig) UnmarshalYAML(unmarshal func(interface{}) error if err := unmarshal((*plain)(c)); err != nil { return err } - if err := checkOverflow(c.XXX, "TLS config"); err != nil { + if err := checkOverflow(c.XXX, "service discovery config"); err != nil { return err } return nil @@ -465,6 +471,16 @@ type HTTPClientConfig struct { XXX map[string]interface{} `yaml:",inline"` } +func (c *HTTPClientConfig) validate() error { + if len(c.BearerToken) > 0 && len(c.BearerTokenFile) > 0 { + return fmt.Errorf("at most one of bearer_token & bearer_token_file must be configured") + } + if c.BasicAuth != nil && (len(c.BearerToken) > 0 || len(c.BearerTokenFile) > 0) { + return fmt.Errorf("at most one of basic_auth, bearer_token & bearer_token_file must be configured") + } + return nil +} + // ScrapeConfig configures a scraping unit for Prometheus. type ScrapeConfig struct { // The job name to which the job label is set by default. @@ -511,14 +527,12 @@ func (c *ScrapeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { if len(c.JobName) == 0 { return fmt.Errorf("job_name is empty") } + // The UnmarshalYAML method of HTTPClientConfig is not being called because it's not a pointer. // We cannot make it a pointer as the parser panics for inlined pointer structs. // Thus we just do its validation here. - if len(c.HTTPClientConfig.BearerToken) > 0 && len(c.HTTPClientConfig.BearerTokenFile) > 0 { - return fmt.Errorf("at most one of bearer_token & bearer_token_file must be configured") - } - if c.HTTPClientConfig.BasicAuth != nil && (len(c.HTTPClientConfig.BearerToken) > 0 || len(c.HTTPClientConfig.BearerTokenFile) > 0) { - return fmt.Errorf("at most one of basic_auth, bearer_token & bearer_token_file must be configured") + if err := c.HTTPClientConfig.validate(); err != nil { + return err } // Check for users putting URLs in target groups. @@ -536,8 +550,8 @@ func (c *ScrapeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { // AlertingConfig configures alerting and alertmanager related configs type AlertingConfig struct { - AlertRelabelConfigs []*RelabelConfig `yaml:"alert_relabel_configs,omitempty"` - AlertmanagersConfigs []*AlertmanagersConfig `yaml:"alertmanagers,omitempty"` + AlertRelabelConfigs []*RelabelConfig `yaml:"alert_relabel_configs,omitempty"` + AlertmanagerConfigs []*AlertmanagerConfig `yaml:"alertmanagers,omitempty"` // Catches all undefined fields and must be empty after parsing. XXX map[string]interface{} `yaml:",inline"` @@ -559,7 +573,7 @@ func (c *AlertingConfig) UnmarshalYAML(unmarshal func(interface{}) error) error } // AlertmanagersConfig configures how Alertmanagers can be discovered and communicated with. -type AlertmanagersConfig struct { +type AlertmanagerConfig struct { // We cannot do proper Go type embedding below as the parser will then parse // values arbitrarily into the overflow maps of further-down types. @@ -581,23 +595,21 @@ type AlertmanagersConfig struct { } // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (c *AlertmanagersConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (c *AlertmanagerConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { *c = DefaultAlertmanagersConfig - type plain AlertmanagersConfig + type plain AlertmanagerConfig if err := unmarshal((*plain)(c)); err != nil { return err } if err := checkOverflow(c.XXX, "alertmanager config"); err != nil { return err } + // The UnmarshalYAML method of HTTPClientConfig is not being called because it's not a pointer. // We cannot make it a pointer as the parser panics for inlined pointer structs. // Thus we just do its validation here. - if len(c.HTTPClientConfig.BearerToken) > 0 && len(c.HTTPClientConfig.BearerTokenFile) > 0 { - return fmt.Errorf("at most one of bearer_token & bearer_token_file must be configured") - } - if c.HTTPClientConfig.BasicAuth != nil && (len(c.HTTPClientConfig.BearerToken) > 0 || len(c.HTTPClientConfig.BearerTokenFile) > 0) { - return fmt.Errorf("at most one of basic_auth, bearer_token & bearer_token_file must be configured") + if err := c.HTTPClientConfig.validate(); err != nil { + return err } // Check for users putting URLs in target groups. diff --git a/config/config_test.go b/config/config_test.go index 973095410..66837ef58 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -403,7 +403,7 @@ var expectedConf = &Config{ }, }, AlertingConfig: AlertingConfig{ - AlertmanagersConfigs: []*AlertmanagersConfig{ + AlertmanagerConfigs: []*AlertmanagerConfig{ { Scheme: "https", Timeout: 10 * time.Second, diff --git a/notifier/notifier.go b/notifier/notifier.go index b17b8e51d..3098637eb 100644 --- a/notifier/notifier.go +++ b/notifier/notifier.go @@ -149,7 +149,7 @@ func (n *Notifier) ApplyConfig(conf *config.Config) error { amSets := []*alertmanagerSet{} ctx, cancel := context.WithCancel(n.ctx) - for _, cfg := range conf.AlertingConfig.AlertmanagersConfigs { + for _, cfg := range conf.AlertingConfig.AlertmanagerConfigs { ams, err := newAlertmanagerSet(cfg) if err != nil { return err @@ -300,8 +300,8 @@ func (n *Notifier) Alertmanagers() []string { return res } -// sendAll sends the alerts to all configured Alertmanagers at concurrently. -// It returns the number of sends that have failed and true if all failed. +// sendAll sends the alerts to all configured Alertmanagers concurrently. +// It returns true if the alerts could be sent successfully to at least on Alertmanager. func (n *Notifier) sendAll(alerts ...*model.Alert) bool { begin := time.Now() @@ -380,8 +380,7 @@ func (n *Notifier) Collect(ch chan<- prometheus.Metric) { ch <- n.queueCapacity } -// alertmanager holds all necessary information to send alerts -// to an Alertmanager endpoint. +// alertmanager holds Alertmanager endpoint information. type alertmanager struct { plainURL string // test injection hook labels model.LabelSet @@ -419,14 +418,14 @@ func (a alertmanager) send(ctx context.Context, c *http.Client, b []byte) error // discovery definitions that have a common configuration on how alerts should be sent. type alertmanagerSet struct { ts *discovery.TargetSet - cfg *config.AlertmanagersConfig + cfg *config.AlertmanagerConfig client *http.Client mtx sync.RWMutex ams []alertmanager } -func newAlertmanagerSet(cfg *config.AlertmanagersConfig) (*alertmanagerSet, error) { +func newAlertmanagerSet(cfg *config.AlertmanagerConfig) (*alertmanagerSet, error) { client, err := retrieval.NewHTTPClient(cfg.HTTPClientConfig) if err != nil { return nil, err @@ -477,7 +476,7 @@ func postPath(pre string) string { // alertmanagersFromGroup extracts a list of alertmanagers from a target group and an associcated // AlertmanagerConfig. -func alertmanagerFromGroup(tg *config.TargetGroup, cfg *config.AlertmanagersConfig) ([]alertmanager, error) { +func alertmanagerFromGroup(tg *config.TargetGroup, cfg *config.AlertmanagerConfig) ([]alertmanager, error) { var res []alertmanager for _, lset := range tg.Targets { diff --git a/notifier/notifier_test.go b/notifier/notifier_test.go index 7664ee3fe..fdc86de53 100644 --- a/notifier/notifier_test.go +++ b/notifier/notifier_test.go @@ -153,7 +153,7 @@ func TestHandlerSendAll(t *testing.T) { {plainURL: server1.URL}, {plainURL: server2.URL}, }, - cfg: &config.AlertmanagersConfig{ + cfg: &config.AlertmanagerConfig{ Timeout: time.Second, }, }) @@ -314,7 +314,7 @@ func TestHandlerQueueing(t *testing.T) { ams: []alertmanager{ {plainURL: server.URL}, }, - cfg: &config.AlertmanagersConfig{ + cfg: &config.AlertmanagerConfig{ Timeout: time.Second, }, })