diff --git a/alerting/provider/custom/custom.go b/alerting/provider/custom/custom.go index ad942138..78c625e7 100644 --- a/alerting/provider/custom/custom.go +++ b/alerting/provider/custom/custom.go @@ -16,11 +16,19 @@ 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"` +} + +var DefaultPlaceholderValues = map[string]map[string]string{ + "ALERT_TRIGGERED_OR_RESOLVED": map[string]string{ + "triggered": "TRIGGERED", + "resolved": "RESOLVED", + }, } // IsValid returns whether the provider's configuration is valid @@ -33,10 +41,28 @@ func (provider *AlertProvider) ToCustomAlertProvider(service *core.Service, aler return provider } +// GetPlaceholderValue returns the Placeholder value +func (provider *AlertProvider) GetPlaceholderValue(name, status string) string { + if _, ok := provider.Placeholders[name]; ok { + if val, ok := provider.Placeholders[name][status]; ok { + return val + } + } else { + if _, ok := DefaultPlaceholderValues[name]; ok { + if val, ok := DefaultPlaceholderValues[name][status]; ok { + return val + } + } + } + + return "" +} + 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 +71,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.GetPlaceholderValue("ALERT_TRIGGERED_OR_RESOLVED", "resolved")) } else { - body = strings.ReplaceAll(body, "[ALERT_TRIGGERED_OR_RESOLVED]", "TRIGGERED") + body = strings.ReplaceAll(body, "[ALERT_TRIGGERED_OR_RESOLVED]", provider.GetPlaceholderValue("ALERT_TRIGGERED_OR_RESOLVED", "triggered")) } } if strings.Contains(providerURL, "[ALERT_DESCRIPTION]") { @@ -58,9 +84,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.GetPlaceholderValue("ALERT_TRIGGERED_OR_RESOLVED", "resolved")) } else { - providerURL = strings.ReplaceAll(providerURL, "[ALERT_TRIGGERED_OR_RESOLVED]", "TRIGGERED") + providerURL = strings.ReplaceAll(providerURL, "[ALERT_TRIGGERED_OR_RESOLVED]", provider.GetPlaceholderValue("ALERT_TRIGGERED_OR_RESOLVED", "triggered")) } } if len(method) == 0 { diff --git a/alerting/provider/custom/custom_test.go b/alerting/provider/custom/custom_test.go index bcd5f669..8118fad8 100644 --- a/alerting/provider/custom/custom_test.go +++ b/alerting/provider/custom/custom_test.go @@ -68,3 +68,28 @@ 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)) + } +} diff --git a/config/config_test.go b/config/config_test.go index 5f5f295a..d948f800 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -344,6 +344,10 @@ alerting: access-key: "1" originator: "31619191918" recipients: "31619191919" + placeholders: + ALERT_TRIGGERED_OR_RESOLVED: + triggered: "partial_outage" + resolved: "operational" services: - name: twinnation url: https://twinnation.org/health