From fac7b8551a098edbac0f624c6546c3049e58b6a3 Mon Sep 17 00:00:00 2001 From: TwinProduction Date: Thu, 24 Sep 2020 19:52:59 -0400 Subject: [PATCH] Start working on implementing common provider interface --- config/config.go | 108 ++++++++++++++++++++++++++++++++++-------- config/config_test.go | 45 ++++++++++++++++-- watchdog/alerting.go | 9 ++-- 3 files changed, 133 insertions(+), 29 deletions(-) diff --git a/config/config.go b/config/config.go index c18e71ee..60f82ed3 100644 --- a/config/config.go +++ b/config/config.go @@ -3,6 +3,7 @@ package config import ( "errors" "github.com/TwinProduction/gatus/alerting" + "github.com/TwinProduction/gatus/alerting/provider" "github.com/TwinProduction/gatus/core" "gopkg.in/yaml.v2" "io/ioutil" @@ -99,26 +100,95 @@ func validateAlertingConfig(config *Config) { log.Printf("[config][validateAlertingConfig] Alerting is not configured") return } + alertTypes := []core.AlertType{ + core.SlackAlert, + core.TwilioAlert, + core.PagerDutyAlert, + core.CustomAlert, + } var validProviders, invalidProviders []core.AlertType - if config.Alerting.Slack != nil && config.Alerting.Slack.IsValid() { - validProviders = append(validProviders, core.SlackAlert) - } else { - invalidProviders = append(invalidProviders, core.SlackAlert) - } - if config.Alerting.Twilio != nil && config.Alerting.Twilio.IsValid() { - validProviders = append(validProviders, core.TwilioAlert) - } else { - invalidProviders = append(invalidProviders, core.TwilioAlert) - } - if config.Alerting.PagerDuty != nil && config.Alerting.PagerDuty.IsValid() { - validProviders = append(validProviders, core.PagerDutyAlert) - } else { - invalidProviders = append(invalidProviders, core.PagerDutyAlert) - } - if config.Alerting.Custom != nil && config.Alerting.Custom.IsValid() { - validProviders = append(validProviders, core.CustomAlert) - } else { - invalidProviders = append(invalidProviders, core.CustomAlert) + for _, alertType := range alertTypes { + alertProvider := GetAlertingProviderByAlertType(config, alertType) + if alertProvider != nil { + if alertProvider.IsValid() { + validProviders = append(validProviders, alertType) + } else { + log.Printf("[config][validateAlertingConfig] Ignoring provider=%s because configuration is invalid", alertType) + invalidProviders = append(invalidProviders, alertType) + } + } else { + invalidProviders = append(invalidProviders, alertType) + } } + //if config.Alerting.Slack != nil { + // if config.Alerting.Slack.IsValid() { + // validProviders = append(validProviders, core.SlackAlert) + // } else { + // log.Printf("[config][validateAlertingConfig] Ignoring provider=%s because configuration is invalid", core.SlackAlert) + // invalidProviders = append(invalidProviders, core.SlackAlert) + // } + //} else { + // invalidProviders = append(invalidProviders, core.SlackAlert) + //} + //if config.Alerting.Twilio != nil { + // if config.Alerting.Twilio.IsValid() { + // validProviders = append(validProviders, core.TwilioAlert) + // } else { + // log.Printf("[config][validateAlertingConfig] Ignoring provider=%s because configuration is invalid", core.TwilioAlert) + // invalidProviders = append(invalidProviders, core.TwilioAlert) + // } + //} else { + // invalidProviders = append(invalidProviders, core.TwilioAlert) + //} + //if config.Alerting.PagerDuty != nil { + // if config.Alerting.PagerDuty.IsValid() { + // validProviders = append(validProviders, core.PagerDutyAlert) + // } else { + // log.Printf("[config][validateAlertingConfig] Ignoring provider=%s because configuration is invalid", core.PagerDutyAlert) + // invalidProviders = append(invalidProviders, core.PagerDutyAlert) + // } + //} else { + // invalidProviders = append(invalidProviders, core.PagerDutyAlert) + //} + //if config.Alerting.Custom != nil { + // if config.Alerting.Custom.IsValid() { + // validProviders = append(validProviders, core.CustomAlert) + // } else { + // log.Printf("[config][validateAlertingConfig] Ignoring provider=%s because configuration is invalid", core.CustomAlert) + // invalidProviders = append(invalidProviders, core.CustomAlert) + // } + //} else { + // invalidProviders = append(invalidProviders, core.CustomAlert) + //} log.Printf("[config][validateAlertingConfig] configuredProviders=%s; ignoredProviders=%s", validProviders, invalidProviders) } + +func GetAlertingProviderByAlertType(config *Config, alertType core.AlertType) provider.AlertProvider { + switch alertType { + case core.SlackAlert: + if config.Alerting.Slack == nil { + // Since we're returning an interface, we need to explicitly return nil, even if the provider itself is nil + return nil + } + return config.Alerting.Slack + case core.TwilioAlert: + if config.Alerting.Twilio == nil { + // Since we're returning an interface, we need to explicitly return nil, even if the provider itself is nil + return nil + } + return config.Alerting.Twilio + case core.PagerDutyAlert: + if config.Alerting.PagerDuty == nil { + // Since we're returning an interface, we need to explicitly return nil, even if the provider itself is nil + return nil + } + return config.Alerting.PagerDuty + case core.CustomAlert: + if config.Alerting.Custom == nil { + // Since we're returning an interface, we need to explicitly return nil, even if the provider itself is nil + return nil + } + return config.Alerting.Custom + } + return nil +} diff --git a/config/config_test.go b/config/config_test.go index 847d16f5..20f9e95c 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,7 +1,6 @@ package config import ( - "fmt" "github.com/TwinProduction/gatus/core" "testing" "time" @@ -36,7 +35,6 @@ services: if config.Services[1].Url != "https://api.github.com/healthz" { t.Errorf("URL should have been %s", "https://api.github.com/healthz") } - fmt.Println(config.Services[0].Interval) if config.Services[0].Interval != 15*time.Second { t.Errorf("Interval should have been %s", 15*time.Second) } @@ -123,6 +121,8 @@ func TestParseAndValidateConfigBytesWithAlerting(t *testing.T) { alerting: slack: webhook-url: "http://example.com" + pagerduty: + integration-key: "00000000000000000000000000000000" services: - name: twinnation url: https://twinnation.org/actuator/health @@ -144,10 +144,19 @@ services: t.Error("Metrics should've been false by default") } if config.Alerting == nil { - t.Fatal("config.AlertingConfig shouldn't have been nil") + t.Fatal("config.Alerting shouldn't have been nil") + } + if config.Alerting.Slack == nil || !config.Alerting.Slack.IsValid() { + t.Fatal("Slack alerting config should've been valid") } if config.Alerting.Slack.WebhookUrl != "http://example.com" { - t.Errorf("Slack webhook should've been %s, but was %s", "http://example.com", config.Alerting.Slack) + t.Errorf("Slack webhook should've been %s, but was %s", "http://example.com", config.Alerting.Slack.WebhookUrl) + } + if config.Alerting.PagerDuty == nil || !config.Alerting.PagerDuty.IsValid() { + t.Fatal("PagerDuty alerting config should've been valid") + } + if config.Alerting.PagerDuty.IntegrationKey != "00000000000000000000000000000000" { + t.Errorf("PagerDuty integration key should've been %s, but was %s", "00000000000000000000000000000000", config.Alerting.PagerDuty.IntegrationKey) } if len(config.Services) != 1 { t.Error("There should've been 1 service") @@ -180,3 +189,31 @@ services: t.Errorf("The type of the alert should've been %s, but it was %s", "Healthcheck failed 7 times in a row", config.Services[0].Alerts[0].Description) } } + +func TestParseAndValidateConfigBytesWithInvalidPagerDutyAlertingConfig(t *testing.T) { + config, err := parseAndValidateConfigBytes([]byte(` +alerting: + pagerduty: + integration-key: "INVALID_KEY" +services: + - name: twinnation + url: https://twinnation.org/actuator/health + conditions: + - "[STATUS] == 200" +`)) + if err != nil { + t.Error("No error should've been returned") + } + if config == nil { + t.Fatal("Config shouldn't have been nil") + } + if config.Alerting == nil { + t.Fatal("config.Alerting shouldn't have been nil") + } + if config.Alerting.PagerDuty == nil { + t.Fatal("PagerDuty alerting config shouldn't have been nil") + } + if config.Alerting.PagerDuty.IsValid() { + t.Fatal("PagerDuty alerting config should've been invalid") + } +} diff --git a/watchdog/alerting.go b/watchdog/alerting.go index 00774f79..3952a15a 100644 --- a/watchdog/alerting.go +++ b/watchdog/alerting.go @@ -37,6 +37,8 @@ func handleAlertsToTrigger(service *core.Service, result *core.Result, cfg *conf continue } var alertProvider *custom.AlertProvider + // TODO: leverage provider.AlertingProvider interface and config.GetAlertingProviderByAlertType(cfg, alert.Type) + // TODO: to support all types of alerts without having to explicitly define them here and in handleAlertsToResolve() if alert.Type == core.SlackAlert { if cfg.Alerting.Slack != nil && cfg.Alerting.Slack.IsValid() { log.Printf("[watchdog][handleAlertsToTrigger] Sending Slack alert because alert with description='%s' has been triggered", alert.Description) @@ -128,12 +130,7 @@ func handleAlertsToResolve(service *core.Service, result *core.Result, cfg *conf } else if alert.Type == core.CustomAlert { if cfg.Alerting.Custom != nil && cfg.Alerting.Custom.IsValid() { log.Printf("[watchdog][handleAlertsToResolve] Sending custom alert because alert with description='%s' has been resolved", alert.Description) - alertProvider = &custom.AlertProvider{ - Url: cfg.Alerting.Custom.Url, - Method: cfg.Alerting.Custom.Method, - Body: cfg.Alerting.Custom.Body, - Headers: cfg.Alerting.Custom.Headers, - } + alertProvider = cfg.Alerting.Custom } else { log.Printf("[watchdog][handleAlertsToResolve] Not sending custom alert despite being resolved, because the custom provider isn't configured properly") }