diff --git a/alerting/provider/custom/custom.go b/alerting/provider/custom/custom.go index ad942138..d2c8e768 100644 --- a/alerting/provider/custom/custom.go +++ b/alerting/provider/custom/custom.go @@ -16,11 +16,12 @@ import ( // AlertProvider is the configuration necessary for sending an alert using a custom HTTP request // Technically, all alert providers should be reachable using the custom alert provider type AlertProvider struct { - URL string `yaml:"url"` - Method string `yaml:"method,omitempty"` - Insecure bool `yaml:"insecure,omitempty"` - Body string `yaml:"body,omitempty"` - Headers map[string]string `yaml:"headers,omitempty"` + URL string `yaml:"url"` + Method string `yaml:"method,omitempty"` + Insecure bool `yaml:"insecure,omitempty"` + Body string `yaml:"body,omitempty"` + Headers map[string]string `yaml:"headers,omitempty"` + Placeholders map[string]map[string]string `yaml:"placeholders,omitempty"` } // IsValid returns whether the provider's configuration is valid @@ -33,10 +34,31 @@ func (provider *AlertProvider) ToCustomAlertProvider(service *core.Service, aler return provider } +// GetPlaceholderValue returns the Placeholder value for ALERT_TRIGGERED_OR_RESOLVED if configured +func (provider *AlertProvider) GetAlertStatePlaceholderValue(resolved bool) string { + status := "triggered" + if resolved { + status = "resolved" + } + + if _, ok := provider.Placeholders["ALERT_TRIGGERED_OR_RESOLVED"]; ok { + if val, ok := provider.Placeholders["ALERT_TRIGGERED_OR_RESOLVED"][status]; ok { + return val + } + } + + if resolved { + return "RESOLVED" + } + + return "TRIGGERED" +} + func (provider *AlertProvider) buildHTTPRequest(serviceName, alertDescription string, resolved bool) *http.Request { body := provider.Body providerURL := provider.URL method := provider.Method + if strings.Contains(body, "[ALERT_DESCRIPTION]") { body = strings.ReplaceAll(body, "[ALERT_DESCRIPTION]", alertDescription) } @@ -45,9 +67,9 @@ func (provider *AlertProvider) buildHTTPRequest(serviceName, alertDescription st } if strings.Contains(body, "[ALERT_TRIGGERED_OR_RESOLVED]") { if resolved { - body = strings.ReplaceAll(body, "[ALERT_TRIGGERED_OR_RESOLVED]", "RESOLVED") + body = strings.ReplaceAll(body, "[ALERT_TRIGGERED_OR_RESOLVED]", provider.GetAlertStatePlaceholderValue(true)) } else { - body = strings.ReplaceAll(body, "[ALERT_TRIGGERED_OR_RESOLVED]", "TRIGGERED") + body = strings.ReplaceAll(body, "[ALERT_TRIGGERED_OR_RESOLVED]", provider.GetAlertStatePlaceholderValue(false)) } } if strings.Contains(providerURL, "[ALERT_DESCRIPTION]") { @@ -58,9 +80,9 @@ func (provider *AlertProvider) buildHTTPRequest(serviceName, alertDescription st } if strings.Contains(providerURL, "[ALERT_TRIGGERED_OR_RESOLVED]") { if resolved { - providerURL = strings.ReplaceAll(providerURL, "[ALERT_TRIGGERED_OR_RESOLVED]", "RESOLVED") + providerURL = strings.ReplaceAll(providerURL, "[ALERT_TRIGGERED_OR_RESOLVED]", provider.GetAlertStatePlaceholderValue(true)) } else { - providerURL = strings.ReplaceAll(providerURL, "[ALERT_TRIGGERED_OR_RESOLVED]", "TRIGGERED") + providerURL = strings.ReplaceAll(providerURL, "[ALERT_TRIGGERED_OR_RESOLVED]", provider.GetAlertStatePlaceholderValue(false)) } } if len(method) == 0 { diff --git a/alerting/provider/custom/custom_test.go b/alerting/provider/custom/custom_test.go index bcd5f669..4c09b282 100644 --- a/alerting/provider/custom/custom_test.go +++ b/alerting/provider/custom/custom_test.go @@ -68,3 +68,45 @@ func TestAlertProvider_ToCustomAlertProvider(t *testing.T) { t.Error("customAlertProvider should've been equal to customAlertProvider") } } + +func TestAlertProvider_buildHTTPRequestWithCustomPlaceholder(t *testing.T) { + const ( + ExpectedURL = "http://example.com/service-name?event=MYTEST&description=alert-description" + ExpectedBody = "service-name,alert-description,MYTEST" + ) + customAlertProvider := &AlertProvider{ + URL: "http://example.com/[SERVICE_NAME]?event=[ALERT_TRIGGERED_OR_RESOLVED]&description=[ALERT_DESCRIPTION]", + Body: "[SERVICE_NAME],[ALERT_DESCRIPTION],[ALERT_TRIGGERED_OR_RESOLVED]", + Headers: nil, + Placeholders: map[string]map[string]string{ + "ALERT_TRIGGERED_OR_RESOLVED": { + "resolved": "MYTEST", + }, + }, + } + request := customAlertProvider.buildHTTPRequest("service-name", "alert-description", true) + if request.URL.String() != ExpectedURL { + t.Error("expected URL to be", ExpectedURL, "was", request.URL.String()) + } + body, _ := ioutil.ReadAll(request.Body) + if string(body) != ExpectedBody { + t.Error("expected body to be", ExpectedBody, "was", string(body)) + } +} + +func TestAlertProvider_GetAlertStatePlaceholderValueDefaults(t *testing.T) { + customAlertProvider := &AlertProvider{ + URL: "http://example.com/[SERVICE_NAME]?event=[ALERT_TRIGGERED_OR_RESOLVED]&description=[ALERT_DESCRIPTION]", + Body: "[SERVICE_NAME],[ALERT_DESCRIPTION],[ALERT_TRIGGERED_OR_RESOLVED]", + Headers: nil, + Placeholders: nil, + } + + if customAlertProvider.GetAlertStatePlaceholderValue(true) != "RESOLVED" { + t.Error("expected here actually RESOLVED") + } + + if customAlertProvider.GetAlertStatePlaceholderValue(false) != "TRIGGERED" { + t.Error("expected here actually TRIGGERED") + } +} diff --git a/config/config_test.go b/config/config_test.go index 5f5f295a..538309fe 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -344,6 +344,11 @@ alerting: access-key: "1" originator: "31619191918" recipients: "31619191919" + custom: + placeholders: + ALERT_TRIGGERED_OR_RESOLVED: + triggered: "partial_outage" + resolved: "operational" services: - name: twinnation url: https://twinnation.org/health @@ -396,6 +401,12 @@ services: if config.Alerting.Messagebird.Recipients != "31619191919" { t.Errorf("Messagebird to recipients should've been %s, but was %s", "31619191919", config.Alerting.Messagebird.Recipients) } + if config.Alerting.Custom == nil { + t.Fatal("config.Alerting. Custom shouldn't have been nil") + } + if config.Alerting.Custom.Placeholders == nil { + t.Fatal("config.Alerting.Custom.Placeholders shouldn't have been nil") + } if len(config.Services) != 1 { t.Error("There should've been 1 service") }