feat(alerting): Add overrides for Mattermost (#292)
* add override support for mattermost * add documentation for override Mattermost webhooks * Apply suggestions from code review Co-authored-by: TwiN <twin@linux.com> * fix formatting Co-authored-by: Michael Engelhardt <me@mindcrime.dev> Co-authored-by: TwiN <twin@linux.com>
This commit is contained in:
		
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							| @ -487,12 +487,15 @@ endpoints: | ||||
| ``` | ||||
|  | ||||
| #### Configuring Mattermost alerts | ||||
| | Parameter                           | Description                                                                                 | Default       | | ||||
| |:------------------------------------|:--------------------------------------------------------------------------------------------|:--------------| | ||||
| | `alerting.mattermost`               | Configuration for alerts of type `mattermost`                                               | `{}`          | | ||||
| | `alerting.mattermost.webhook-url`   | Mattermost Webhook URL                                                                      | Required `""` | | ||||
| | `alerting.mattermost.client`        | Client configuration. <br />See [Client configuration](#client-configuration).              | `{}`          | | ||||
| | `alerting.mattermost.default-alert` | Default alert configuration. <br />See [Setting a default alert](#setting-a-default-alert). | N/A           | | ||||
| | Parameter                                     | Description                                                                                 | Default       | | ||||
| |:----------------------------------------------|:--------------------------------------------------------------------------------------------|:--------------| | ||||
| | `alerting.mattermost`                         | Configuration for alerts of type `mattermost`                                               | `{}`          | | ||||
| | `alerting.mattermost.webhook-url`             | Mattermost Webhook URL                                                                      | Required `""` | | ||||
| | `alerting.mattermost.client`                  | Client configuration. <br />See [Client configuration](#client-configuration).              | `{}`          | | ||||
| | `alerting.mattermost.default-alert`           | Default alert configuration. <br />See [Setting a default alert](#setting-a-default-alert). | N/A           | | ||||
| | `alerting.mattermost.overrides`               | List of overrides that may be prioritized over the default configuration                    | `[]`          | | ||||
| | `alerting.mattermost.overrides[].group`       | Endpoint group for which the configuration will be overridden by this configuration         | `""`          | | ||||
| | `alerting.mattermist.overrides[].webhook-url` | Mattermost Webhook URL                                                                      | `""`          | | ||||
|  | ||||
| ```yaml | ||||
| alerting: | ||||
|  | ||||
| @ -20,6 +20,15 @@ type AlertProvider struct { | ||||
|  | ||||
| 	// DefaultAlert is the default alert configuration to use for endpoints with an alert of the appropriate type | ||||
| 	DefaultAlert *alert.Alert `yaml:"default-alert,omitempty"` | ||||
|  | ||||
| 	// Overrides is a list of Override that may be prioritized over the default configuration | ||||
| 	Overrides []Override `yaml:"overrides,omitempty"` | ||||
| } | ||||
|  | ||||
| // Override is a case under which the default integration is overridden | ||||
| type Override struct { | ||||
| 	Group      string `yaml:"group"` | ||||
| 	WebhookURL string `yaml:"webhook-url"` | ||||
| } | ||||
|  | ||||
| // IsValid returns whether the provider's configuration is valid | ||||
| @ -27,13 +36,22 @@ func (provider *AlertProvider) IsValid() bool { | ||||
| 	if provider.ClientConfig == nil { | ||||
| 		provider.ClientConfig = client.GetDefaultConfig() | ||||
| 	} | ||||
| 	if provider.Overrides != nil { | ||||
| 		registeredGroups := make(map[string]bool) | ||||
| 		for _, override := range provider.Overrides { | ||||
| 			if isAlreadyRegistered := registeredGroups[override.Group]; isAlreadyRegistered || override.Group == "" || len(override.WebhookURL) == 0 { | ||||
| 				return false | ||||
| 			} | ||||
| 			registeredGroups[override.Group] = true | ||||
| 		} | ||||
| 	} | ||||
| 	return len(provider.WebhookURL) > 0 | ||||
| } | ||||
|  | ||||
| // Send an alert using the provider | ||||
| 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))) | ||||
| 	request, err := http.NewRequest(http.MethodPost, provider.WebhookURL, buffer) | ||||
| 	request, err := http.NewRequest(http.MethodPost, provider.getWebhookURLForGroup(endpoint.Group), buffer) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @ -101,6 +119,19 @@ func (provider *AlertProvider) buildRequestBody(endpoint *core.Endpoint, alert * | ||||
| }`, message, message, description, color, endpoint.URL, results) | ||||
| } | ||||
|  | ||||
|  | ||||
| // getWebhookURLForGroup returns the appropriate Webhook URL integration to for a given group | ||||
| func (provider *AlertProvider) getWebhookURLForGroup(group string) string { | ||||
| 	if provider.Overrides != nil { | ||||
| 		for _, override := range provider.Overrides { | ||||
| 			if group == override.Group { | ||||
| 				return override.WebhookURL | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return provider.WebhookURL | ||||
| } | ||||
|  | ||||
| // GetDefaultAlert returns the provider's default alert configuration | ||||
| func (provider AlertProvider) GetDefaultAlert() *alert.Alert { | ||||
| 	return provider.DefaultAlert | ||||
|  | ||||
| @ -22,6 +22,47 @@ func TestAlertProvider_IsValid(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestAlertProvider_IsValidWithOverride(t *testing.T) { | ||||
| 	providerWithInvalidOverrideGroup := AlertProvider{ | ||||
| 		Overrides: []Override{ | ||||
| 			{ | ||||
| 				WebhookURL: "http://example.com", | ||||
| 				Group:      "", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	if providerWithInvalidOverrideGroup.IsValid() { | ||||
| 		t.Error("provider Group shouldn't have been valid") | ||||
| 	} | ||||
|  | ||||
| 	providerWithInvalidOverrideWebHookUrl := AlertProvider{ | ||||
| 		Overrides: []Override{ | ||||
| 			{ | ||||
|  | ||||
| 				WebhookURL: "", | ||||
| 				Group:      "group", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	if providerWithInvalidOverrideWebHookUrl.IsValid() { | ||||
| 		t.Error("provider WebHookURL shoudn't have been valid") | ||||
| 	} | ||||
|  | ||||
| 	providerWithValidOverride := AlertProvider{ | ||||
| 		WebhookURL: "http://example.com", | ||||
| 		Overrides: []Override{ | ||||
| 			{ | ||||
| 				WebhookURL: "http://example.com", | ||||
| 				Group:      "group", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	if !providerWithValidOverride.IsValid() { | ||||
| 		t.Error("provider should've been valid") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestAlertProvider_Send(t *testing.T) { | ||||
| 	defer client.InjectHTTPClient(nil) | ||||
| 	firstDescription := "description-1" | ||||
| @ -156,3 +197,66 @@ func TestAlertProvider_GetDefaultAlert(t *testing.T) { | ||||
| 		t.Error("expected default alert to be nil") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestAlertProvider_getWebhookURLForGroup(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		Name           string | ||||
| 		Provider       AlertProvider | ||||
| 		InputGroup     string | ||||
| 		ExpectedOutput string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			Name: "provider-no-override-specify-no-group-should-default", | ||||
| 			Provider: AlertProvider{ | ||||
| 				WebhookURL: "http://example.com", | ||||
| 				Overrides:  nil, | ||||
| 			}, | ||||
| 			InputGroup:     "", | ||||
| 			ExpectedOutput: "http://example.com", | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "provider-no-override-specify-group-should-default", | ||||
| 			Provider: AlertProvider{ | ||||
| 				WebhookURL: "http://example.com", | ||||
| 				Overrides:  nil, | ||||
| 			}, | ||||
| 			InputGroup:     "group", | ||||
| 			ExpectedOutput: "http://example.com", | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "provider-with-override-specify-no-group-should-default", | ||||
| 			Provider: AlertProvider{ | ||||
| 				WebhookURL: "http://example.com", | ||||
| 				Overrides: []Override{ | ||||
| 					{ | ||||
| 						Group:      "group", | ||||
| 						WebhookURL: "http://example01.com", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			InputGroup:     "", | ||||
| 			ExpectedOutput: "http://example.com", | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "provider-with-override-specify-group-should-override", | ||||
| 			Provider: AlertProvider{ | ||||
| 				WebhookURL: "http://example.com", | ||||
| 				Overrides: []Override{ | ||||
| 					{ | ||||
| 						Group:      "group", | ||||
| 						WebhookURL: "http://example01.com", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			InputGroup:     "group", | ||||
| 			ExpectedOutput: "http://example01.com", | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.Name, func(t *testing.T) { | ||||
| 			if got := tt.Provider.getWebhookURLForGroup(tt.InputGroup); got != tt.ExpectedOutput { | ||||
| 				t.Errorf("AlertProvider.getToForGroup() = %v, want %v", got, tt.ExpectedOutput) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user