From a6bc0039e986cd79af21c2ef657f5eef31bf4a10 Mon Sep 17 00:00:00 2001 From: TwinProduction Date: Tue, 5 Oct 2021 20:40:44 -0400 Subject: [PATCH] Rename integrations to overrides --- README.md | 31 ++-- alerting/provider/pagerduty/pagerduty.go | 58 +++---- alerting/provider/pagerduty/pagerduty_test.go | 149 ++++++++++++------ 3 files changed, 151 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index 34bc07ec..a2bfef4a 100644 --- a/README.md +++ b/README.md @@ -412,14 +412,14 @@ services: #### Configuring PagerDuty alerts -| Parameter | Description | Default | -|:---------------------------------------- |:----------------------------------------------------------------------------- |:-------------- | -| `alerting.pagerduty` | Configuration for alerts of type `pagerduty` | `{}` | -| `alerting.pagerduty.integration-key` | PagerDuty Events API v2 integration key. | `""` | -| `alerting.pagerduty.default-alert` | Default alert configuration.
See [Setting a default alert](#setting-a-default-alert) | N/A | -| `alerting.pagerduty.integrations` | Pagerduty integrations per team configurations | `[]` | -| `alerting.pagerduty.integrations[].integration-key` | Pagerduty integrationkey for a perticular team | `""` | -| `alerting.pagerduty.integrations[].group` | the group that the integration key belongs to | `""` | +| Parameter | Description | Default | +|:------------------------------------------------------ |:----------------------------------------------------------------------------- |:-------------- | +| `alerting.pagerduty` | Configuration for alerts of type `pagerduty` | `{}` | +| `alerting.pagerduty.integration-key` | PagerDuty Events API v2 integration key | `""` | +| `alerting.pagerduty.default-alert` | Default alert configuration.
See [Setting a default alert](#setting-a-default-alert) | N/A | +| `alerting.pagerduty.overrides` | List of overrides that may be prioritized over the default configuration | `[]` | +| `alerting.pagerduty.overrides[].group` | Service group for which the configuration will be overridden by this configuration | `""` | +| `alerting.pagerduty.overrides[].integration-key` | PagerDuty Events API v2 integration key | `""` | It is highly recommended to set `services[].alerts[].send-on-resolved` to `true` for alerts of type `pagerduty`, because unlike other alerts, the operation resulting from setting said @@ -427,18 +427,20 @@ parameter to `true` will not create another incident, but mark the incident as r PagerDuty instead. Behavior: -- Team integration have priority over the general integration -- If no team integration is provided it will defaults to the general pagerduty integration -- If no team integration and no general integration were provided it defaults to the first team integration provided +- By default, `alerting.pagerduty.integration-key` is used as the integration key +- If there is a `services[].group` matching the value of `alerting.pagerduty.overrides[].group`, it will take precedence over `alerting.pagerduty.integration-key` ```yaml alerting: pagerduty: integration-key: "********************************" - intergrations: - - integration-key: "********************************" - group: "core" + # You can also add group-specific integration keys, which will + # override the integration key above for the specified groups + overrides: + - group: "core" + integration-key: "********************************" + services: - name: website @@ -455,6 +457,7 @@ services: success-threshold: 5 send-on-resolved: true description: "healthcheck failed" + - name: back-end group: core url: "https://example.org/" diff --git a/alerting/provider/pagerduty/pagerduty.go b/alerting/provider/pagerduty/pagerduty.go index 5318a879..afeba036 100644 --- a/alerting/provider/pagerduty/pagerduty.go +++ b/alerting/provider/pagerduty/pagerduty.go @@ -13,11 +13,6 @@ const ( restAPIURL = "https://events.pagerduty.com/v2/enqueue" ) -type Integrations struct { - IntegrationKey string `yaml:"integration-key"` - Group string `yaml:"group"` -} - // AlertProvider is the configuration necessary for sending an alert using PagerDuty type AlertProvider struct { IntegrationKey string `yaml:"integration-key"` @@ -25,42 +20,34 @@ type AlertProvider struct { // DefaultAlert is the default alert configuration to use for services with an alert of the appropriate type DefaultAlert *alert.Alert `yaml:"default-alert"` - Integrations []Integrations `yaml:"integrations"` + // Overrides is a list of Override that may be prioritized over the default configuration + Overrides []Override `yaml:"overrides"` +} + +// Override is a case under which the default integration is overridden +type Override struct { + Group string `yaml:"group"` + IntegrationKey string `yaml:"integration-key"` } // IsValid returns whether the provider's configuration is valid func (provider *AlertProvider) IsValid() bool { registeredGroups := make(map[string]bool) - if provider.Integrations != nil { - for _, integration := range provider.Integrations { - if isAlreadyRegistered := registeredGroups[integration.Group]; isAlreadyRegistered || integration.Group == "" || len(integration.IntegrationKey) != 32 { + if provider.Overrides != nil { + for _, override := range provider.Overrides { + if isAlreadyRegistered := registeredGroups[override.Group]; isAlreadyRegistered || override.Group == "" || len(override.IntegrationKey) != 32 { return false } - registeredGroups[integration.Group] = true + registeredGroups[override.Group] = true } } - return len(provider.IntegrationKey) == 32 || provider.Integrations != nil -} - -// GetPagerDutyIntegrationKey returns the appropriate pagerduty integration key -func (provider *AlertProvider) GetPagerDutyIntegrationKey(group string) string { - if provider.Integrations != nil { - for _, integration := range provider.Integrations { - if group == integration.Group { - return integration.IntegrationKey - } - } - } - if provider.IntegrationKey != "" { - return provider.IntegrationKey - } - return "" + // Either the default integration key has the right length, or there are overrides who are properly configured. + return len(provider.IntegrationKey) == 32 || len(provider.Overrides) != 0 } // ToCustomAlertProvider converts the provider into a custom.AlertProvider // // relevant: https://developer.pagerduty.com/docs/events-api-v2/trigger-events/ - func (provider *AlertProvider) ToCustomAlertProvider(service *core.Service, alert *alert.Alert, _ *core.Result, resolved bool) *custom.AlertProvider { var message, eventAction, resolveKey string if resolved { @@ -84,13 +71,28 @@ func (provider *AlertProvider) ToCustomAlertProvider(service *core.Service, aler "source": "%s", "severity": "critical" } -}`, provider.GetPagerDutyIntegrationKey(service.Group), resolveKey, eventAction, message, service.Name), +}`, provider.getPagerDutyIntegrationKeyForGroup(service.Group), resolveKey, eventAction, message, service.Name), Headers: map[string]string{ "Content-Type": "application/json", }, } } +// getPagerDutyIntegrationKeyForGroup returns the appropriate pagerduty integration key for a given group +func (provider *AlertProvider) getPagerDutyIntegrationKeyForGroup(group string) string { + if provider.Overrides != nil { + for _, override := range provider.Overrides { + if group == override.Group { + return override.IntegrationKey + } + } + } + if provider.IntegrationKey != "" { + return provider.IntegrationKey + } + return "" +} + // GetDefaultAlert returns the provider's default alert configuration func (provider AlertProvider) GetDefaultAlert() *alert.Alert { return provider.DefaultAlert diff --git a/alerting/provider/pagerduty/pagerduty_test.go b/alerting/provider/pagerduty/pagerduty_test.go index c4b09c00..a4a86af5 100644 --- a/alerting/provider/pagerduty/pagerduty_test.go +++ b/alerting/provider/pagerduty/pagerduty_test.go @@ -10,7 +10,7 @@ import ( "github.com/TwinProduction/gatus/v3/core" ) -func TestAlertDefaultProvider_IsValid(t *testing.T) { +func TestAlertProvider_IsValid(t *testing.T) { invalidProvider := AlertProvider{IntegrationKey: ""} if invalidProvider.IsValid() { t.Error("provider shouldn't have been valid") @@ -20,41 +20,39 @@ func TestAlertDefaultProvider_IsValid(t *testing.T) { t.Error("provider should've been valid") } } -func TestAlertPerGroupProvider_IsValid(t *testing.T) { - invalidGroup := Integrations{ - IntegrationKey: "00000000000000000000000000000000", - Group: "", + +func TestAlertProvider_IsValidWithOverride(t *testing.T) { + providerWithInvalidOverrideGroup := AlertProvider{ + Overrides: []Override{ + { + IntegrationKey: "00000000000000000000000000000000", + Group: "", + }, + }, } - integrations := []Integrations{} - integrations = append(integrations, invalidGroup) - invalidProviderGroupNameError := AlertProvider{ - Integrations: integrations, - } - if invalidProviderGroupNameError.IsValid() { + if providerWithInvalidOverrideGroup.IsValid() { t.Error("provider Group shouldn't have been valid") } - invalidIntegrationKey := Integrations{ - IntegrationKey: "", - Group: "group", + providerWithInvalidOverrideIntegrationKey := AlertProvider{ + Overrides: []Override{ + { + IntegrationKey: "", + Group: "group", + }, + }, } - integrations = []Integrations{} - integrations = append(integrations, invalidIntegrationKey) - invalidProviderIntegrationKey := AlertProvider{ - Integrations: integrations, - } - if invalidProviderIntegrationKey.IsValid() { + if providerWithInvalidOverrideIntegrationKey.IsValid() { t.Error("provider integration key shouldn't have been valid") } - validIntegration := Integrations{ - IntegrationKey: "00000000000000000000000000000000", - Group: "group", + providerWithValidOverride := AlertProvider{ + Overrides: []Override{ + { + IntegrationKey: "00000000000000000000000000000000", + Group: "group", + }, + }, } - integrations = []Integrations{} - integrations = append(integrations, validIntegration) - validProvider := AlertProvider{ - Integrations: integrations, - } - if !validProvider.IsValid() { + if !providerWithValidOverride.IsValid() { t.Error("provider should've been valid") } } @@ -81,16 +79,15 @@ func TestAlertProvider_ToCustomAlertProviderWithResolvedAlert(t *testing.T) { } } -func TestAlertPerGroupProvider_ToCustomAlertProviderWithResolvedAlert(t *testing.T) { - validIntegration := Integrations{ - IntegrationKey: "00000000000000000000000000000000", - Group: "group", - } - integrations := []Integrations{} - integrations = append(integrations, validIntegration) +func TestAlertProvider_ToCustomAlertProviderWithResolvedAlertAndOverride(t *testing.T) { provider := AlertProvider{ IntegrationKey: "", - Integrations: integrations, + Overrides: []Override{ + { + IntegrationKey: "00000000000000000000000000000000", + Group: "group", + }, + }, } customAlertProvider := provider.ToCustomAlertProvider(&core.Service{}, &alert.Alert{}, &core.Result{}, true) if customAlertProvider == nil { @@ -134,16 +131,15 @@ func TestAlertProvider_ToCustomAlertProviderWithTriggeredAlert(t *testing.T) { } } -func TestAlertPerGroupProvider_ToCustomAlertProviderWithTriggeredAlert(t *testing.T) { - validIntegration := Integrations{ - IntegrationKey: "00000000000000000000000000000000", - Group: "group", - } - integrations := []Integrations{} - integrations = append(integrations, validIntegration) +func TestAlertProvider_ToCustomAlertProviderWithTriggeredAlertAndOverride(t *testing.T) { provider := AlertProvider{ IntegrationKey: "", - Integrations: integrations, + Overrides: []Override{ + { + IntegrationKey: "00000000000000000000000000000000", + Group: "group", + }, + }, } customAlertProvider := provider.ToCustomAlertProvider(&core.Service{}, &alert.Alert{}, &core.Result{}, false) if customAlertProvider == nil { @@ -164,3 +160,66 @@ func TestAlertPerGroupProvider_ToCustomAlertProviderWithTriggeredAlert(t *testin t.Error("expected body to be valid JSON, got error:", err.Error()) } } + +func TestAlertProvider_getPagerDutyIntegrationKey(t *testing.T) { + scenarios := []struct { + Name string + Provider AlertProvider + InputGroup string + ExpectedOutput string + }{ + { + Name: "provider-no-override-specify-no-group-should-default", + Provider: AlertProvider{ + IntegrationKey: "00000000000000000000000000000001", + Overrides: nil, + }, + InputGroup: "", + ExpectedOutput: "00000000000000000000000000000001", + }, + { + Name: "provider-no-override-specify-group-should-default", + Provider: AlertProvider{ + IntegrationKey: "00000000000000000000000000000001", + Overrides: nil, + }, + InputGroup: "group", + ExpectedOutput: "00000000000000000000000000000001", + }, + { + Name: "provider-with-override-specify-no-group-should-default", + Provider: AlertProvider{ + IntegrationKey: "00000000000000000000000000000001", + Overrides: []Override{ + { + Group: "group", + IntegrationKey: "00000000000000000000000000000002", + }, + }, + }, + InputGroup: "", + ExpectedOutput: "00000000000000000000000000000001", + }, + { + Name: "provider-with-override-specify-group-should-override", + Provider: AlertProvider{ + IntegrationKey: "00000000000000000000000000000001", + Overrides: []Override{ + { + Group: "group", + IntegrationKey: "00000000000000000000000000000002", + }, + }, + }, + InputGroup: "group", + ExpectedOutput: "00000000000000000000000000000002", + }, + } + for _, scenario := range scenarios { + t.Run(scenario.Name, func(t *testing.T) { + if output := scenario.Provider.getPagerDutyIntegrationKeyForGroup(scenario.InputGroup); output != scenario.ExpectedOutput { + t.Errorf("expected %s, got %s", scenario.ExpectedOutput, output) + } + }) + } +}