fix(alerting): Resolve PagerDuty issue with bad payload when alert description has " in it

This commit is contained in:
TwiN 2022-10-20 15:47:07 -04:00
parent 490610ccfd
commit 6ddf1258e5
2 changed files with 32 additions and 18 deletions

View File

@ -53,7 +53,7 @@ func (provider *AlertProvider) IsValid() bool {
// //
// Relevant: https://developer.pagerduty.com/docs/events-api-v2/trigger-events/ // Relevant: https://developer.pagerduty.com/docs/events-api-v2/trigger-events/
func (provider *AlertProvider) Send(endpoint *core.Endpoint, alert *alert.Alert, result *core.Result, resolved bool) error { func (provider *AlertProvider) Send(endpoint *core.Endpoint, alert *alert.Alert, result *core.Result, resolved bool) error {
buffer := bytes.NewBuffer([]byte(provider.buildRequestBody(endpoint, alert, result, resolved))) buffer := bytes.NewBuffer(provider.buildRequestBody(endpoint, alert, result, resolved))
request, err := http.NewRequest(http.MethodPost, restAPIURL, buffer) request, err := http.NewRequest(http.MethodPost, restAPIURL, buffer)
if err != nil { if err != nil {
return err return err
@ -87,8 +87,21 @@ func (provider *AlertProvider) Send(endpoint *core.Endpoint, alert *alert.Alert,
return nil return nil
} }
type Body struct {
RoutingKey string `json:"routing_key"`
DedupKey string `json:"dedup_key"`
EventAction string `json:"event_action"`
Payload Payload `json:"payload"`
}
type Payload struct {
Summary string `json:"summary"`
Source string `json:"source"`
Severity string `json:"severity"`
}
// buildRequestBody builds the request body for the provider // buildRequestBody builds the request body for the provider
func (provider *AlertProvider) buildRequestBody(endpoint *core.Endpoint, alert *alert.Alert, result *core.Result, resolved bool) string { func (provider *AlertProvider) buildRequestBody(endpoint *core.Endpoint, alert *alert.Alert, result *core.Result, resolved bool) []byte {
var message, eventAction, resolveKey string var message, eventAction, resolveKey string
if resolved { if resolved {
message = fmt.Sprintf("RESOLVED: %s - %s", endpoint.DisplayName(), alert.GetDescription()) message = fmt.Sprintf("RESOLVED: %s - %s", endpoint.DisplayName(), alert.GetDescription())
@ -99,16 +112,17 @@ func (provider *AlertProvider) buildRequestBody(endpoint *core.Endpoint, alert *
eventAction = "trigger" eventAction = "trigger"
resolveKey = "" resolveKey = ""
} }
return fmt.Sprintf(`{ body, _ := json.Marshal(Body{
"routing_key": "%s", RoutingKey: provider.getIntegrationKeyForGroup(endpoint.Group),
"dedup_key": "%s", DedupKey: resolveKey,
"event_action": "%s", EventAction: eventAction,
"payload": { Payload: Payload{
"summary": "%s", Summary: message,
"source": "%s", Source: "Gatus",
"severity": "critical" Severity: "critical",
} },
}`, provider.getIntegrationKeyForGroup(endpoint.Group), resolveKey, eventAction, message, endpoint.Name) })
return body
} }
// getIntegrationKeyForGroup returns the appropriate pagerduty integration key for a given group // getIntegrationKeyForGroup returns the appropriate pagerduty integration key for a given group

View File

@ -149,24 +149,24 @@ func TestAlertProvider_buildRequestBody(t *testing.T) {
Provider: AlertProvider{IntegrationKey: "00000000000000000000000000000000"}, Provider: AlertProvider{IntegrationKey: "00000000000000000000000000000000"},
Alert: alert.Alert{Description: &description}, Alert: alert.Alert{Description: &description},
Resolved: false, Resolved: false,
ExpectedBody: "{\n \"routing_key\": \"00000000000000000000000000000000\",\n \"dedup_key\": \"\",\n \"event_action\": \"trigger\",\n \"payload\": {\n \"summary\": \"TRIGGERED: - test\",\n \"source\": \"\",\n \"severity\": \"critical\"\n }\n}", ExpectedBody: "{\"routing_key\":\"00000000000000000000000000000000\",\"dedup_key\":\"\",\"event_action\":\"trigger\",\"payload\":{\"summary\":\"TRIGGERED: endpoint-name - test\",\"source\":\"Gatus\",\"severity\":\"critical\"}}",
}, },
{ {
Name: "resolved", Name: "resolved",
Provider: AlertProvider{IntegrationKey: "00000000000000000000000000000000"}, Provider: AlertProvider{IntegrationKey: "00000000000000000000000000000000"},
Alert: alert.Alert{Description: &description, ResolveKey: "key"}, Alert: alert.Alert{Description: &description, ResolveKey: "key"},
Resolved: true, Resolved: true,
ExpectedBody: "{\n \"routing_key\": \"00000000000000000000000000000000\",\n \"dedup_key\": \"key\",\n \"event_action\": \"resolve\",\n \"payload\": {\n \"summary\": \"RESOLVED: - test\",\n \"source\": \"\",\n \"severity\": \"critical\"\n }\n}", ExpectedBody: "{\"routing_key\":\"00000000000000000000000000000000\",\"dedup_key\":\"key\",\"event_action\":\"resolve\",\"payload\":{\"summary\":\"RESOLVED: endpoint-name - test\",\"source\":\"Gatus\",\"severity\":\"critical\"}}",
}, },
} }
for _, scenario := range scenarios { for _, scenario := range scenarios {
t.Run(scenario.Name, func(t *testing.T) { t.Run(scenario.Name, func(t *testing.T) {
body := scenario.Provider.buildRequestBody(&core.Endpoint{}, &scenario.Alert, &core.Result{}, scenario.Resolved) body := scenario.Provider.buildRequestBody(&core.Endpoint{Name: "endpoint-name"}, &scenario.Alert, &core.Result{}, scenario.Resolved)
if body != scenario.ExpectedBody { if string(body) != scenario.ExpectedBody {
t.Errorf("expected %s, got %s", scenario.ExpectedBody, body) t.Errorf("expected:\n%s\ngot:\n%s", scenario.ExpectedBody, body)
} }
out := make(map[string]interface{}) out := make(map[string]interface{})
if err := json.Unmarshal([]byte(body), &out); err != nil { if err := json.Unmarshal(body, &out); err != nil {
t.Error("expected body to be valid JSON, got error:", err.Error()) t.Error("expected body to be valid JSON, got error:", err.Error())
} }
}) })