Add support for PagerDuty API v2 (#1054)
This commit is contained in:
parent
4ee40f97e6
commit
5db8055bab
|
@ -156,7 +156,7 @@ receivers:
|
|||
email_configs:
|
||||
- to: 'team-X+alerts-critical@example.org'
|
||||
pagerduty_configs:
|
||||
- service_key: <team-X-key>
|
||||
- routing_key: <team-X-key>
|
||||
|
||||
- name: 'team-Y-mails'
|
||||
email_configs:
|
||||
|
@ -164,11 +164,11 @@ receivers:
|
|||
|
||||
- name: 'team-Y-pager'
|
||||
pagerduty_configs:
|
||||
- service_key: <team-Y-key>
|
||||
- routing_key: <team-Y-key>
|
||||
|
||||
- name: 'team-DB-pager'
|
||||
pagerduty_configs:
|
||||
- service_key: <team-DB-key>
|
||||
- routing_key: <team-DB-key>
|
||||
```
|
||||
|
||||
## Amtool
|
||||
|
|
|
@ -298,7 +298,7 @@ var DefaultGlobalConfig = GlobalConfig{
|
|||
ResolveTimeout: model.Duration(5 * time.Minute),
|
||||
|
||||
SMTPRequireTLS: true,
|
||||
PagerdutyURL: "https://events.pagerduty.com/generic/2010-04-15/create_event.json",
|
||||
PagerdutyURL: "https://events.pagerduty.com/v2/enqueue",
|
||||
HipchatURL: "https://api.hipchat.com/",
|
||||
OpsGenieAPIHost: "https://api.opsgenie.com/",
|
||||
VictorOpsAPIURL: "https://alert.victorops.com/integrations/generic/20131114/alert/",
|
||||
|
|
|
@ -283,7 +283,7 @@ func TestEmptyFieldsAndRegex(t *testing.T) {
|
|||
HipchatURL: "https://hipchat.foobar.org/",
|
||||
SlackAPIURL: "mysecret",
|
||||
SMTPRequireTLS: true,
|
||||
PagerdutyURL: "https://events.pagerduty.com/generic/2010-04-15/create_event.json",
|
||||
PagerdutyURL: "https://events.pagerduty.com/v2/enqueue",
|
||||
OpsGenieAPIHost: "https://api.opsgenie.com/",
|
||||
VictorOpsAPIURL: "https://alert.victorops.com/integrations/generic/20131114/alert/",
|
||||
},
|
||||
|
|
|
@ -178,12 +178,16 @@ func (c *EmailConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
type PagerdutyConfig struct {
|
||||
NotifierConfig `yaml:",inline" json:",inline"`
|
||||
|
||||
ServiceKey Secret `yaml:"service_key,omitempty" json:"service_key,omitempty"`
|
||||
ServiceKey Secret `yaml:"service_key,omitempty" json"service_key,omitempty"`
|
||||
RoutingKey Secret `yaml:"routing_key,omitempty" json:"routing_key,omitempty"`
|
||||
URL string `yaml:"url,omitempty" json:"url,omitempty"`
|
||||
Client string `yaml:"client,omitempty" json:"client,omitempty"`
|
||||
ClientURL string `yaml:"client_url,omitempty" json:"client_url,omitempty"`
|
||||
Description string `yaml:"description,omitempty" json:"description,omitempty"`
|
||||
Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"`
|
||||
Severity string `yaml:"severity,omitempty" json:"severity,omitempty"`
|
||||
Component string `yaml:"component,omitempty" json:"component,omitempty"`
|
||||
Group string `yaml:"group,omitempty" json:"group,omitempty"`
|
||||
|
||||
// Catches all undefined fields and must be empty after parsing.
|
||||
XXX map[string]interface{} `yaml:",inline" json:"-"`
|
||||
|
@ -196,8 +200,8 @@ func (c *PagerdutyConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
|
|||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.ServiceKey == "" {
|
||||
return fmt.Errorf("missing service key in PagerDuty config")
|
||||
if c.RoutingKey == "" && c.ServiceKey == "" {
|
||||
return fmt.Errorf("missing service or routing key in PagerDuty config")
|
||||
}
|
||||
return checkOverflow(c.XXX, "pagerduty config")
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ service_key: ''
|
|||
var cfg PagerdutyConfig
|
||||
err := yaml.Unmarshal([]byte(in), &cfg)
|
||||
|
||||
expected := "missing service key in PagerDuty config"
|
||||
expected := "missing service or routing key in PagerDuty config"
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("no error returned, expected:\n%v", expected)
|
||||
|
|
|
@ -108,7 +108,7 @@ receivers:
|
|||
email_configs:
|
||||
- to: 'team-X+alerts-critical@example.org'
|
||||
pagerduty_configs:
|
||||
- service_key: "mysecret"
|
||||
- routing_key: "mysecret"
|
||||
|
||||
- name: 'team-Y-mails'
|
||||
email_configs:
|
||||
|
@ -116,11 +116,11 @@ receivers:
|
|||
|
||||
- name: 'team-Y-pager'
|
||||
pagerduty_configs:
|
||||
- service_key: "mysecret"
|
||||
- routing_key: "mysecret"
|
||||
|
||||
- name: 'team-DB-pager'
|
||||
pagerduty_configs:
|
||||
- service_key: "mysecret"
|
||||
- routing_key: "mysecret"
|
||||
- name: 'team-X-hipchat'
|
||||
hipchat_configs:
|
||||
- auth_token: "mysecret"
|
||||
|
|
146
notify/impl.go
146
notify/impl.go
|
@ -438,18 +438,116 @@ const (
|
|||
)
|
||||
|
||||
type pagerDutyMessage struct {
|
||||
ServiceKey string `json:"service_key"`
|
||||
IncidentKey string `json:"incident_key"`
|
||||
EventType string `json:"event_type"`
|
||||
Description string `json:"description"`
|
||||
RoutingKey string `json:"routing_key,omitempty"`
|
||||
ServiceKey string `json:"service_key,omitempty"`
|
||||
DedupKey string `json:"dedup_key,omitempty"`
|
||||
IncidentKey string `json:"incident_key,omitempty"`
|
||||
EventType string `json:"event_type,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
EventAction string `json:"event_action"`
|
||||
Payload *pagerDutyPayload `json:"payload"`
|
||||
Client string `json:"client,omitempty"`
|
||||
ClientURL string `json:"client_url,omitempty"`
|
||||
Details map[string]string `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
type pagerDutyPayload struct {
|
||||
Summary string `json:"summary"`
|
||||
Source string `json:"source"`
|
||||
Severity string `json:"severity"`
|
||||
Timestamp string `json:"timestamp,omitempty"`
|
||||
Component string `json:"component,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
CustomDetails map[string]string `json:"custom_details,omitempty"`
|
||||
}
|
||||
|
||||
func (n *PagerDuty) notifyV1(ctx context.Context, eventType string, key string, tmpl func(string) string, details map[string]string, as ...*types.Alert) (bool, error) {
|
||||
|
||||
msg := &pagerDutyMessage{}
|
||||
|
||||
var err error
|
||||
|
||||
level.Info(n.logger).Log("msg", "PagerDuty v1 API will no longer be supported: https://v2.developer.pagerduty.com/v2/docs/api-v2-frequently-asked-questions")
|
||||
msg.ServiceKey = string(n.conf.ServiceKey)
|
||||
msg.EventType = eventType
|
||||
msg.IncidentKey = hashKey(key)
|
||||
msg.Description = tmpl(n.conf.Description)
|
||||
msg.Details = details
|
||||
n.conf.URL = "https://events.pagerduty.com/generic/2010-04-15/create_event.json"
|
||||
|
||||
if eventType == pagerDutyEventTrigger {
|
||||
msg.Client = tmpl(n.conf.Client)
|
||||
msg.ClientURL = tmpl(n.conf.ClientURL)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(msg); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := ctxhttp.Post(ctx, http.DefaultClient, n.conf.URL, contentTypeJSON, &buf)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return n.retryV1(resp.StatusCode)
|
||||
}
|
||||
|
||||
func (n *PagerDuty) notifyV2(ctx context.Context, eventType string, key string, tmpl func(string) string, details map[string]string, as ...*types.Alert) (bool, error) {
|
||||
|
||||
var err error
|
||||
|
||||
msg := &pagerDutyMessage{}
|
||||
|
||||
if n.conf.Severity == "" {
|
||||
n.conf.Severity = "error"
|
||||
}
|
||||
msg.RoutingKey = string(n.conf.RoutingKey)
|
||||
msg.EventAction = eventType
|
||||
msg.DedupKey = hashKey(key)
|
||||
if eventType == pagerDutyEventTrigger {
|
||||
msgpayload := &pagerDutyPayload{
|
||||
Summary: tmpl(n.conf.Description),
|
||||
Source: n.conf.Client,
|
||||
Severity: n.conf.Severity,
|
||||
CustomDetails: details,
|
||||
Component: n.conf.Component,
|
||||
Group: n.conf.Group,
|
||||
}
|
||||
msg.Payload = msgpayload
|
||||
}
|
||||
|
||||
if eventType == pagerDutyEventTrigger {
|
||||
msg.Client = tmpl(n.conf.Client)
|
||||
msg.ClientURL = tmpl(n.conf.ClientURL)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(msg); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
resp, err := ctxhttp.Post(ctx, http.DefaultClient, n.conf.URL, contentTypeJSON, &buf)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return n.retryV2(resp.StatusCode)
|
||||
}
|
||||
|
||||
// Notify implements the Notifier interface.
|
||||
//
|
||||
// http://developer.pagerduty.com/documentation/integration/events/trigger
|
||||
// https://v2.developer.pagerduty.com/docs/events-api-v2
|
||||
func (n *PagerDuty) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
|
||||
key, ok := GroupKey(ctx)
|
||||
if !ok {
|
||||
|
@ -474,36 +572,17 @@ func (n *PagerDuty) Notify(ctx context.Context, as ...*types.Alert) (bool, error
|
|||
details[k] = tmpl(v)
|
||||
}
|
||||
|
||||
msg := &pagerDutyMessage{
|
||||
ServiceKey: tmpl(string(n.conf.ServiceKey)),
|
||||
EventType: eventType,
|
||||
IncidentKey: hashKey(key),
|
||||
Description: tmpl(n.conf.Description),
|
||||
Details: details,
|
||||
}
|
||||
if eventType == pagerDutyEventTrigger {
|
||||
msg.Client = tmpl(n.conf.Client)
|
||||
msg.ClientURL = tmpl(n.conf.ClientURL)
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(msg); err != nil {
|
||||
return false, err
|
||||
if n.conf.ServiceKey != "" {
|
||||
return n.notifyV1(ctx, eventType, key, tmpl, details, as...)
|
||||
}
|
||||
|
||||
resp, err := ctxhttp.Post(ctx, http.DefaultClient, n.conf.URL, contentTypeJSON, &buf)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return n.retry(resp.StatusCode)
|
||||
return n.notifyV2(ctx, eventType, key, tmpl, details, as...)
|
||||
}
|
||||
|
||||
func (n *PagerDuty) retry(statusCode int) (bool, error) {
|
||||
func (n *PagerDuty) retryV1(statusCode int) (bool, error) {
|
||||
// Retrying can solve the issue on 403 (rate limiting) and 5xx response codes.
|
||||
// 2xx response codes indicate a successful request.
|
||||
// https://v2.developer.pagerduty.com/docs/trigger-events
|
||||
|
@ -514,6 +593,17 @@ func (n *PagerDuty) retry(statusCode int) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (n *PagerDuty) retryV2(statusCode int) (bool, error) {
|
||||
// Retrying can solve the issue on 429 (rate limiting) and 5xx response codes.
|
||||
// 2xx response codes indicate a successful request.
|
||||
// https://v2.developer.pagerduty.com/docs/events-api-v2#api-response-codes--retry-logic
|
||||
if statusCode/100 != 2 {
|
||||
return (statusCode == 429 || statusCode/100 == 5), fmt.Errorf("unexpected status code %v", statusCode)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Slack implements a Notifier for Slack notifications.
|
||||
type Slack struct {
|
||||
conf *config.SlackConfig
|
||||
|
|
Loading…
Reference in New Issue