From 6ddf1258e57331723ffc53948f06f9d591f32689 Mon Sep 17 00:00:00 2001 From: TwiN Date: Thu, 20 Oct 2022 15:47:07 -0400 Subject: [PATCH] fix(alerting): Resolve PagerDuty issue with bad payload when alert description has `"` in it --- alerting/provider/pagerduty/pagerduty.go | 38 +++++++++++++------ alerting/provider/pagerduty/pagerduty_test.go | 12 +++--- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/alerting/provider/pagerduty/pagerduty.go b/alerting/provider/pagerduty/pagerduty.go index 322dec28..1a6c34fa 100644 --- a/alerting/provider/pagerduty/pagerduty.go +++ b/alerting/provider/pagerduty/pagerduty.go @@ -53,7 +53,7 @@ func (provider *AlertProvider) IsValid() bool { // // 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 { - 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) if err != nil { return err @@ -87,8 +87,21 @@ func (provider *AlertProvider) Send(endpoint *core.Endpoint, alert *alert.Alert, 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 -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 if resolved { message = fmt.Sprintf("RESOLVED: %s - %s", endpoint.DisplayName(), alert.GetDescription()) @@ -99,16 +112,17 @@ func (provider *AlertProvider) buildRequestBody(endpoint *core.Endpoint, alert * eventAction = "trigger" resolveKey = "" } - return fmt.Sprintf(`{ - "routing_key": "%s", - "dedup_key": "%s", - "event_action": "%s", - "payload": { - "summary": "%s", - "source": "%s", - "severity": "critical" - } -}`, provider.getIntegrationKeyForGroup(endpoint.Group), resolveKey, eventAction, message, endpoint.Name) + body, _ := json.Marshal(Body{ + RoutingKey: provider.getIntegrationKeyForGroup(endpoint.Group), + DedupKey: resolveKey, + EventAction: eventAction, + Payload: Payload{ + Summary: message, + Source: "Gatus", + Severity: "critical", + }, + }) + return body } // getIntegrationKeyForGroup returns the appropriate pagerduty integration key for a given group diff --git a/alerting/provider/pagerduty/pagerduty_test.go b/alerting/provider/pagerduty/pagerduty_test.go index 71ea7549..2362ffbf 100644 --- a/alerting/provider/pagerduty/pagerduty_test.go +++ b/alerting/provider/pagerduty/pagerduty_test.go @@ -149,24 +149,24 @@ func TestAlertProvider_buildRequestBody(t *testing.T) { Provider: AlertProvider{IntegrationKey: "00000000000000000000000000000000"}, Alert: alert.Alert{Description: &description}, 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", Provider: AlertProvider{IntegrationKey: "00000000000000000000000000000000"}, Alert: alert.Alert{Description: &description, ResolveKey: "key"}, 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 { t.Run(scenario.Name, func(t *testing.T) { - body := scenario.Provider.buildRequestBody(&core.Endpoint{}, &scenario.Alert, &core.Result{}, scenario.Resolved) - if body != scenario.ExpectedBody { - t.Errorf("expected %s, got %s", scenario.ExpectedBody, body) + body := scenario.Provider.buildRequestBody(&core.Endpoint{Name: "endpoint-name"}, &scenario.Alert, &core.Result{}, scenario.Resolved) + if string(body) != scenario.ExpectedBody { + t.Errorf("expected:\n%s\ngot:\n%s", scenario.ExpectedBody, body) } 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()) } })