Alerting: Adds support for multiple URLs in Alertmanager notifier (#24196)

* Alerting: Adds support for multiple URLs in Alertmanager notifier

Adds support for multiple URLs in Alertmanager notifier following
alertmanager documentation for high availability setup.
Update the documentation for alertmanager notifier.

Closes #24195

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
Co-authored-by: bergquist <carl.bergquist@gmail.com>
This commit is contained in:
Victor Coutellier
2020-05-20 08:49:53 +02:00
committed by GitHub
parent 50b2f26d80
commit 3a0f2dc160
3 changed files with 61 additions and 22 deletions

View File

@@ -3,6 +3,7 @@ package notifiers
import (
"context"
"regexp"
"strings"
"time"
"github.com/grafana/grafana/pkg/bus"
@@ -20,17 +21,20 @@ func init() {
Factory: NewAlertmanagerNotifier,
OptionsTemplate: `
<h3 class="page-heading">Alertmanager settings</h3>
<div class="gf-form">
<span class="gf-form-label width-10">Url</span>
<input type="text" required class="gf-form-input max-width-26" ng-model="ctrl.model.settings.url" placeholder="http://localhost:9093"></input>
<div class="gf-form max-width-30">
<span class="gf-form-label width-10">Url(s)</span>
<input type="text" required class="gf-form-input max-width-30" ng-model="ctrl.model.settings.url" placeholder="http://localhost:9093"></input>
<info-popover mode="right-absolute">
As specified in Alertmanager documentation, do not specify a load balancer here. Enter all your Alertmanager URLs comma-separated.
</info-popover>
</div>
<div class="gf-form">
<div class="gf-form max-width-30">
<span class="gf-form-label width-10">Basic Auth User</span>
<input type="text" class="gf-form-input max-width-26" ng-model="ctrl.model.settings.basicAuthUser" placeholder=""></input>
<input type="text" class="gf-form-input max-width-30" ng-model="ctrl.model.settings.basicAuthUser" placeholder=""></input>
</div>
<div class="gf-form">
<div class="gf-form max-width-30">
<span class="gf-form-label width-10">Basic Auth Password</span>
<input type="text" class="gf-form-input max-width-26" ng-model="ctrl.model.settings.basicAuthPassword" placeholder=""></input>
<input type="text" class="gf-form-input max-width-30" ng-model="ctrl.model.settings.basicAuthPassword" placeholder=""></input>
</div>
</div>
`,
@@ -39,10 +43,18 @@ func init() {
// NewAlertmanagerNotifier returns a new Alertmanager notifier
func NewAlertmanagerNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
urlString := model.Settings.Get("url").MustString()
if urlString == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
}
var url []string
for _, u := range strings.Split(urlString, ",") {
u = strings.TrimSpace(u)
if u != "" {
url = append(url, u)
}
}
basicAuthUser := model.Settings.Get("basicAuthUser").MustString()
basicAuthPassword := model.Settings.Get("basicAuthPassword").MustString()
@@ -58,7 +70,7 @@ func NewAlertmanagerNotifier(model *models.AlertNotification) (alerting.Notifier
// AlertmanagerNotifier sends alert notifications to the alert manager
type AlertmanagerNotifier struct {
NotifierBase
URL string
URL []string
BasicAuthUser string
BasicAuthPassword string
log log.Logger
@@ -153,17 +165,19 @@ func (am *AlertmanagerNotifier) Notify(evalContext *alerting.EvalContext) error
bodyJSON := simplejson.NewFromAny(alerts)
body, _ := bodyJSON.MarshalJSON()
cmd := &models.SendWebhookSync{
Url: am.URL + "/api/v1/alerts",
User: am.BasicAuthUser,
Password: am.BasicAuthPassword,
HttpMethod: "POST",
Body: string(body),
}
for _, url := range am.URL {
cmd := &models.SendWebhookSync{
Url: strings.TrimSuffix(url, "/") + "/api/v1/alerts",
User: am.BasicAuthUser,
Password: am.BasicAuthPassword,
HttpMethod: "POST",
Body: string(body),
}
if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
am.log.Error("Failed to send alertmanager", "error", err, "alertmanager", am.Name)
return err
if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
am.log.Error("Failed to send alertmanager", "error", err, "alertmanager", am.Name, "url", url)
return err
}
}
return nil

View File

@@ -97,7 +97,7 @@ func TestAlertmanagerNotifier(t *testing.T) {
})
Convey("from settings", func() {
json := `{ "url": "http://127.0.0.1:9093/" }`
json := `{ "url": "http://127.0.0.1:9093/", "basicAuthUser": "user", "basicAuthPassword": "password" }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
model := &models.AlertNotification{
@@ -110,7 +110,26 @@ func TestAlertmanagerNotifier(t *testing.T) {
alertmanagerNotifier := not.(*AlertmanagerNotifier)
So(err, ShouldBeNil)
So(alertmanagerNotifier.URL, ShouldEqual, "http://127.0.0.1:9093/")
So(alertmanagerNotifier.BasicAuthUser, ShouldEqual, "user")
So(alertmanagerNotifier.BasicAuthPassword, ShouldEqual, "password")
So(alertmanagerNotifier.URL, ShouldResemble, []string{"http://127.0.0.1:9093/"})
})
Convey("from settings with multiple alertmanager", func() {
json := `{ "url": "http://alertmanager1:9093,http://alertmanager2:9093" }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
model := &models.AlertNotification{
Name: "alertmanager",
Type: "alertmanager",
Settings: settingsJSON,
}
not, err := NewAlertmanagerNotifier(model)
alertmanagerNotifier := not.(*AlertmanagerNotifier)
So(err, ShouldBeNil)
So(alertmanagerNotifier.URL, ShouldResemble, []string{"http://alertmanager1:9093", "http://alertmanager2:9093"})
})
})
})