mirror of
https://github.com/prometheus/alertmanager
synced 2025-02-18 19:46:54 +00:00
Implement opsgenie_api_key_file (#2728)
Signed-off-by: Jan-Otto Kröpke <joe@adorsys.de>
This commit is contained in:
parent
b9ce1d1e99
commit
186362cef0
@ -308,6 +308,10 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
return fmt.Errorf("at most one of slack_api_url & slack_api_url_file must be configured")
|
||||
}
|
||||
|
||||
if c.Global.OpsGenieAPIKey != "" && len(c.Global.OpsGenieAPIKeyFile) > 0 {
|
||||
return fmt.Errorf("at most one of opsgenie_api_key & opsgenie_api_key_file must be configured")
|
||||
}
|
||||
|
||||
names := map[string]struct{}{}
|
||||
|
||||
for _, rcv := range c.Receivers {
|
||||
@ -393,11 +397,12 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
if !strings.HasSuffix(ogc.APIURL.Path, "/") {
|
||||
ogc.APIURL.Path += "/"
|
||||
}
|
||||
if ogc.APIKey == "" {
|
||||
if c.Global.OpsGenieAPIKey == "" {
|
||||
return fmt.Errorf("no global OpsGenie API Key set")
|
||||
if ogc.APIKey == "" && len(ogc.APIKeyFile) == 0 {
|
||||
if c.Global.OpsGenieAPIKey == "" && len(c.Global.OpsGenieAPIKeyFile) == 0 {
|
||||
return fmt.Errorf("no global OpsGenie API Key set either inline or in a file")
|
||||
}
|
||||
ogc.APIKey = c.Global.OpsGenieAPIKey
|
||||
ogc.APIKeyFile = c.Global.OpsGenieAPIKeyFile
|
||||
}
|
||||
}
|
||||
for _, wcc := range rcv.WechatConfigs {
|
||||
@ -636,24 +641,25 @@ type GlobalConfig struct {
|
||||
|
||||
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
|
||||
|
||||
SMTPFrom string `yaml:"smtp_from,omitempty" json:"smtp_from,omitempty"`
|
||||
SMTPHello string `yaml:"smtp_hello,omitempty" json:"smtp_hello,omitempty"`
|
||||
SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"`
|
||||
SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"`
|
||||
SMTPAuthPassword Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"`
|
||||
SMTPAuthSecret Secret `yaml:"smtp_auth_secret,omitempty" json:"smtp_auth_secret,omitempty"`
|
||||
SMTPAuthIdentity string `yaml:"smtp_auth_identity,omitempty" json:"smtp_auth_identity,omitempty"`
|
||||
SMTPRequireTLS bool `yaml:"smtp_require_tls" json:"smtp_require_tls,omitempty"`
|
||||
SlackAPIURL *SecretURL `yaml:"slack_api_url,omitempty" json:"slack_api_url,omitempty"`
|
||||
SlackAPIURLFile string `yaml:"slack_api_url_file,omitempty" json:"slack_api_url_file,omitempty"`
|
||||
PagerdutyURL *URL `yaml:"pagerduty_url,omitempty" json:"pagerduty_url,omitempty"`
|
||||
OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"`
|
||||
OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"`
|
||||
WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"`
|
||||
WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"`
|
||||
WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"`
|
||||
VictorOpsAPIURL *URL `yaml:"victorops_api_url,omitempty" json:"victorops_api_url,omitempty"`
|
||||
VictorOpsAPIKey Secret `yaml:"victorops_api_key,omitempty" json:"victorops_api_key,omitempty"`
|
||||
SMTPFrom string `yaml:"smtp_from,omitempty" json:"smtp_from,omitempty"`
|
||||
SMTPHello string `yaml:"smtp_hello,omitempty" json:"smtp_hello,omitempty"`
|
||||
SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"`
|
||||
SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"`
|
||||
SMTPAuthPassword Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"`
|
||||
SMTPAuthSecret Secret `yaml:"smtp_auth_secret,omitempty" json:"smtp_auth_secret,omitempty"`
|
||||
SMTPAuthIdentity string `yaml:"smtp_auth_identity,omitempty" json:"smtp_auth_identity,omitempty"`
|
||||
SMTPRequireTLS bool `yaml:"smtp_require_tls" json:"smtp_require_tls,omitempty"`
|
||||
SlackAPIURL *SecretURL `yaml:"slack_api_url,omitempty" json:"slack_api_url,omitempty"`
|
||||
SlackAPIURLFile string `yaml:"slack_api_url_file,omitempty" json:"slack_api_url_file,omitempty"`
|
||||
PagerdutyURL *URL `yaml:"pagerduty_url,omitempty" json:"pagerduty_url,omitempty"`
|
||||
OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"`
|
||||
OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"`
|
||||
OpsGenieAPIKeyFile string `yaml:"opsgenie_api_key_file,omitempty" json:"opsgenie_api_key_file,omitempty"`
|
||||
WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"`
|
||||
WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"`
|
||||
WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"`
|
||||
VictorOpsAPIURL *URL `yaml:"victorops_api_url,omitempty" json:"victorops_api_url,omitempty"`
|
||||
VictorOpsAPIKey Secret `yaml:"victorops_api_key,omitempty" json:"victorops_api_key,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface for GlobalConfig.
|
||||
|
@ -952,13 +952,38 @@ func TestOpsGenieDefaultAPIKey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpsGenieDefaultAPIKeyFile(t *testing.T) {
|
||||
conf, err := LoadFile("testdata/conf.opsgenie-default-apikey-file.yml")
|
||||
if err != nil {
|
||||
t.Fatalf("Error parsing %s: %s", "testdata/conf.opsgenie-default-apikey-file.yml", err)
|
||||
}
|
||||
|
||||
var defaultKey = conf.Global.OpsGenieAPIKeyFile
|
||||
if defaultKey != conf.Receivers[0].OpsGenieConfigs[0].APIKeyFile {
|
||||
t.Fatalf("Invalid OpsGenie key_file: %s\nExpected: %s", conf.Receivers[0].OpsGenieConfigs[0].APIKeyFile, defaultKey)
|
||||
}
|
||||
if defaultKey == conf.Receivers[1].OpsGenieConfigs[0].APIKeyFile {
|
||||
t.Errorf("Invalid OpsGenie key_file: %s\nExpected: %s", conf.Receivers[0].OpsGenieConfigs[0].APIKeyFile, "/override_file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpsGenieBothAPIKeyAndFile(t *testing.T) {
|
||||
_, err := LoadFile("testdata/conf.opsgenie-both-file-and-apikey.yml")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected an error parsing %s: %s", "testdata/conf.opsgenie-both-file-and-apikey.yml", err)
|
||||
}
|
||||
if err.Error() != "at most one of opsgenie_api_key & opsgenie_api_key_file must be configured" {
|
||||
t.Errorf("Expected: %s\nGot: %s", "at most one of opsgenie_api_key & opsgenie_api_key_file must be configured", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpsGenieNoAPIKey(t *testing.T) {
|
||||
_, err := LoadFile("testdata/conf.opsgenie-no-apikey.yml")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected an error parsing %s: %s", "testdata/conf.opsgenie-no-apikey.yml", err)
|
||||
}
|
||||
if err.Error() != "no global OpsGenie API Key set" {
|
||||
t.Errorf("Expected: %s\nGot: %s", "no global OpsGenie API Key set", err.Error())
|
||||
if err.Error() != "no global OpsGenie API Key set either inline or in a file" {
|
||||
t.Errorf("Expected: %s\nGot: %s", "no global OpsGenie API Key set either inline or in a file", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -456,6 +456,7 @@ type OpsGenieConfig struct {
|
||||
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
|
||||
|
||||
APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"`
|
||||
APIKeyFile string `yaml:"api_key_file,omitempty" json:"api_key_file,omitempty"`
|
||||
APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"`
|
||||
Message string `yaml:"message,omitempty" json:"message,omitempty"`
|
||||
Description string `yaml:"description,omitempty" json:"description,omitempty"`
|
||||
@ -480,6 +481,10 @@ func (c *OpsGenieConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
|
||||
return err
|
||||
}
|
||||
|
||||
if c.APIURL != nil && len(c.APIKeyFile) > 0 {
|
||||
return fmt.Errorf("at most one of api_key & api_key_file must be configured")
|
||||
}
|
||||
|
||||
for _, r := range c.Responders {
|
||||
if r.ID == "" && r.Username == "" && r.Name == "" {
|
||||
return errors.Errorf("OpsGenieConfig responder %v has to have at least one of id, username or name specified", r)
|
||||
|
27
config/testdata/conf.opsgenie-both-file-and-apikey.yml
vendored
Normal file
27
config/testdata/conf.opsgenie-both-file-and-apikey.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
global:
|
||||
opsgenie_api_key: asd132
|
||||
opsgenie_api_key_file: '/global_file'
|
||||
|
||||
route:
|
||||
group_by: ['alertname', 'cluster', 'service']
|
||||
group_wait: 30s
|
||||
group_interval: 5m
|
||||
repeat_interval: 3h
|
||||
receiver: escalation-Y-opsgenie
|
||||
routes:
|
||||
- match:
|
||||
service: foo
|
||||
receiver: team-X-opsgenie
|
||||
|
||||
receivers:
|
||||
- name: 'team-X-opsgenie'
|
||||
opsgenie_configs:
|
||||
- responders:
|
||||
- name: 'team-X'
|
||||
type: 'team'
|
||||
- name: 'escalation-Y-opsgenie'
|
||||
opsgenie_configs:
|
||||
- responders:
|
||||
- name: 'escalation-Y'
|
||||
type: 'escalation'
|
||||
api_key: qwe456
|
26
config/testdata/conf.opsgenie-default-apikey-file.yml
vendored
Normal file
26
config/testdata/conf.opsgenie-default-apikey-file.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
global:
|
||||
opsgenie_api_key_file: '/global_file'
|
||||
|
||||
route:
|
||||
group_by: ['alertname', 'cluster', 'service']
|
||||
group_wait: 30s
|
||||
group_interval: 5m
|
||||
repeat_interval: 3h
|
||||
receiver: escalation-Y-opsgenie
|
||||
routes:
|
||||
- match:
|
||||
service: foo
|
||||
receiver: team-X-opsgenie
|
||||
|
||||
receivers:
|
||||
- name: 'team-X-opsgenie'
|
||||
opsgenie_configs:
|
||||
- responders:
|
||||
- name: 'team-X'
|
||||
type: 'team'
|
||||
- name: 'escalation-Y-opsgenie'
|
||||
opsgenie_configs:
|
||||
- responders:
|
||||
- name: 'escalation-Y'
|
||||
type: 'escalation'
|
||||
api_key_file: /override_file
|
@ -86,6 +86,7 @@ global:
|
||||
[ victorops_api_url: <string> | default = "https://alert.victorops.com/integrations/generic/20131114/alert/" ]
|
||||
[ pagerduty_url: <string> | default = "https://events.pagerduty.com/v2/enqueue" ]
|
||||
[ opsgenie_api_key: <secret> ]
|
||||
[ opsgenie_api_key_file: <filepath> ]
|
||||
[ opsgenie_api_url: <string> | default = "https://api.opsgenie.com/" ]
|
||||
[ wechat_api_url: <string> | default = "https://qyapi.weixin.qq.com/cgi-bin/" ]
|
||||
[ wechat_api_secret: <secret> ]
|
||||
@ -506,6 +507,9 @@ OpsGenie notifications are sent via the [OpsGenie API](https://docs.opsgenie.com
|
||||
# The API key to use when talking to the OpsGenie API.
|
||||
[ api_key: <secret> | default = global.opsgenie_api_key ]
|
||||
|
||||
# The filepath to API key to use when talking to the OpsGenie API. Conflicts with api_key.
|
||||
[ api_key_file: <filepath> | default = global.opsgenie_api_key_file ]
|
||||
|
||||
# The host to send OpsGenie API requests to.
|
||||
[ api_url: <string> | default = global.opsgenie_api_url ]
|
||||
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -255,7 +256,16 @@ func (n *Notifier) createRequests(ctx context.Context, as ...*types.Alert) ([]*h
|
||||
}
|
||||
}
|
||||
|
||||
apiKey := tmpl(string(n.conf.APIKey))
|
||||
var apiKey string
|
||||
if n.conf.APIKey != "" {
|
||||
apiKey = tmpl(string(n.conf.APIKey))
|
||||
} else {
|
||||
content, err := ioutil.ReadFile(n.conf.APIKeyFile)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "read key_file error")
|
||||
}
|
||||
apiKey = tmpl(string(content))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "templating error")
|
||||
|
@ -69,6 +69,31 @@ func TestOpsGenieRedactedURL(t *testing.T) {
|
||||
test.AssertNotifyLeaksNoSecret(t, ctx, notifier, key)
|
||||
}
|
||||
|
||||
func TestGettingOpsGegineApikeyFromFile(t *testing.T) {
|
||||
ctx, u, fn := test.GetContextWithCancelingURL()
|
||||
defer fn()
|
||||
|
||||
key := "key"
|
||||
|
||||
f, err := ioutil.TempFile("", "opsgenie_test")
|
||||
require.NoError(t, err, "creating temp file failed")
|
||||
_, err = f.WriteString(key)
|
||||
require.NoError(t, err, "writing to temp file failed")
|
||||
|
||||
notifier, err := New(
|
||||
&config.OpsGenieConfig{
|
||||
APIURL: &config.URL{URL: u},
|
||||
APIKeyFile: f.Name(),
|
||||
HTTPConfig: &commoncfg.HTTPClientConfig{},
|
||||
},
|
||||
test.CreateTmpl(t),
|
||||
log.NewNopLogger(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
test.AssertNotifyLeaksNoSecret(t, ctx, notifier, key)
|
||||
}
|
||||
|
||||
func TestOpsGenie(t *testing.T) {
|
||||
u, err := url.Parse("https://opsgenie/api")
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user