Bladeren bron

feat(notifications): make it possible to send test alert notifications

closes #5847
bergquist 9 jaren geleden
bovenliggende
commit
d11bc57c37

+ 16 - 0
pkg/api/alerting.go

@@ -214,6 +214,22 @@ func DeleteAlertNotification(c *middleware.Context) Response {
 	return ApiSuccess("Notification deleted")
 }
 
+//POST /api/alert-notifications/test
+func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) Response {
+	cmd := &alerting.NotificationTestCommand{
+		Name:     dto.Name,
+		Type:     dto.Type,
+		Severity: dto.Severity,
+		Settings: dto.Settings,
+	}
+
+	if err := bus.Dispatch(cmd); err != nil {
+		return ApiError(500, "Failed to send alert notifications", err)
+	}
+
+	return ApiSuccess("Test notification sent")
+}
+
 func GetAlertHistory(c *middleware.Context) Response {
 	alertId, err := getAlertIdForRequest(c)
 	if err != nil {

+ 1 - 0
pkg/api/api.go

@@ -259,6 +259,7 @@ func Register(r *macaron.Macaron) {
 		r.Get("/alert-notifications", wrap(GetAlertNotifications))
 
 		r.Group("/alert-notifications", func() {
+			r.Post("/test", bind(dtos.NotificationTestCommand{}), wrap(NotificationTest))
 			r.Post("/", bind(m.CreateAlertNotificationCommand{}), wrap(CreateAlertNotification))
 			r.Put("/:notificationId", bind(m.UpdateAlertNotificationCommand{}), wrap(UpdateAlertNotification))
 			r.Get("/:notificationId", wrap(GetAlertNotificationById))

+ 7 - 0
pkg/api/dtos/alerting.go

@@ -63,3 +63,10 @@ type AlertHistory struct {
 
 	Data *simplejson.Json `json:"data"`
 }
+
+type NotificationTestCommand struct {
+	Name     string           `json:"name"`
+	Type     string           `json:"type"`
+	Settings *simplejson.Json `json:"settings"`
+	Severity string           `json:"severity"`
+}

+ 4 - 1
pkg/services/alerting/notifier.go

@@ -46,6 +46,10 @@ func (n *RootNotifier) Notify(context *EvalContext) {
 		n.log.Error("Failed to upload alert panel image", "error", err)
 	}
 
+	n.sendNotifications(notifiers, context)
+}
+
+func (n *RootNotifier) sendNotifications(notifiers []Notifier, context *EvalContext) {
 	for _, notifier := range notifiers {
 		n.log.Info("Sending notification", "firing", context.Firing, "type", notifier.GetType())
 		go notifier.Notify(context)
@@ -53,7 +57,6 @@ func (n *RootNotifier) Notify(context *EvalContext) {
 }
 
 func (n *RootNotifier) uploadImage(context *EvalContext) error {
-
 	uploader, _ := imguploader.NewImageUploader()
 
 	imageUrl, err := context.GetImageUrl()

+ 93 - 0
pkg/services/alerting/test_notification.go

@@ -0,0 +1,93 @@
+package alerting
+
+import (
+	"github.com/grafana/grafana/pkg/bus"
+	"github.com/grafana/grafana/pkg/components/simplejson"
+	"github.com/grafana/grafana/pkg/log"
+	"github.com/grafana/grafana/pkg/models"
+)
+
+type NotificationTestCommand struct {
+	Severity string
+	Name     string
+	Type     string
+	Settings *simplejson.Json
+}
+
+func init() {
+	bus.AddHandler("alerting", handleNotificationTestCommand)
+
+}
+
+func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
+	notifier := NewRootNotifier()
+
+	model := &models.AlertNotification{
+		Name:     cmd.Name,
+		Type:     cmd.Type,
+		Settings: cmd.Settings,
+	}
+
+	notifiers, err := notifier.getNotifierFor(model)
+
+	if err != nil {
+		log.Error2("Failed to create notifier", "error", err.Error())
+		return err
+	}
+
+	severity := models.AlertSeverityType(cmd.Severity)
+	notifier.sendNotifications([]Notifier{notifiers}, createTestEvalContext(severity))
+
+	return nil
+}
+
+func createTestEvalContext(severity models.AlertSeverityType) *EvalContext {
+	state := models.AlertStateOK
+	firing := false
+	if severity == models.AlertSeverityCritical {
+		state = models.AlertStateCritical
+		firing = true
+	}
+	if severity == models.AlertSeverityWarning {
+		state = models.AlertStateWarning
+		firing = true
+	}
+
+	testRule := &Rule{
+		DashboardId: 1,
+		PanelId:     1,
+		Name:        "Test notification",
+		Message:     "Someone is testing the alert notification within grafana.",
+		State:       state,
+		Severity:    severity,
+	}
+
+	ctx := NewEvalContext(testRule)
+	ctx.ImagePublicUrl = "http://grafana.org/assets/img/blog/mixed_styles.png"
+
+	ctx.IsTestRun = true
+	ctx.Firing = firing
+	ctx.Error = nil
+	ctx.EvalMatches = evalMatchesBasedOnSeverity(severity)
+
+	return ctx
+}
+
+func evalMatchesBasedOnSeverity(severity models.AlertSeverityType) []*EvalMatch {
+	matches := make([]*EvalMatch, 0)
+	if severity == models.AlertSeverityOK {
+		return matches
+	}
+
+	matches = append(matches, &EvalMatch{
+		Metric: "High value",
+		Value:  100,
+	})
+
+	matches = append(matches, &EvalMatch{
+		Metric: "Higher Value",
+		Value:  200,
+	})
+
+	return matches
+}

+ 20 - 0
public/app/features/alerting/notification_edit_ctrl.ts

@@ -7,6 +7,8 @@ import config from 'app/core/config';
 
 export class AlertNotificationEditCtrl {
   model: any;
+  showTest: boolean = false;
+  testSeverity: string = "critical";
 
   /** @ngInject */
   constructor(private $routeParams, private backendSrv, private $scope, private $location) {
@@ -47,6 +49,24 @@ export class AlertNotificationEditCtrl {
   typeChanged() {
     this.model.settings = {};
   }
+
+  toggleTest() {
+    this.showTest = !this.showTest;
+  }
+
+  testNotification() {
+    var payload = {
+      name: this.model.name,
+      type: this.model.type,
+      settings: this.model.settings,
+      severity: this.testSeverity
+    };
+
+    this.backendSrv.post(`/api/alert-notifications/test`, payload)
+      .then(res => {
+        this.$scope.appEvent('alert-succes', ['Test notification sent', '']);
+      });
+  }
 }
 
 coreModule.controller('AlertNotificationEditCtrl', AlertNotificationEditCtrl);

+ 22 - 2
public/app/features/alerting/partials/notification_edit.html

@@ -60,7 +60,27 @@
 		</div>
 	</div>
 
-  <div class="gf-form-button-row">
-    <button ng-click="ctrl.save()" class="btn btn-success">Save</button>
+  <div class="gf-form-group">
+		<div class="gf-form-inline">
+			<div class="gf-form width-6">
+				<button ng-click="ctrl.save()" class="btn btn-success">Save</button>
+			</div>
+			<div class="gf-form width-8">
+				<button ng-click="ctrl.toggleTest()" class="btn btn-secondary">Test</button>
+			</div>
+
+			<div class="gf-form width-20" ng-show="ctrl.showTest">
+			  <span class="gf-form-label width-13">Severity for test notification</span>
+				<div class="gf-form-select-wrapper width-7">
+					<select class="gf-form-input"
+						ng-model="ctrl.testSeverity"
+						ng-options="t for t in ['critical', 'warning', 'ok']">
+					</select>
+				</div>
+			</div>
+			<div class="gf-form" ng-show="ctrl.showTest">
+				<button ng-click="ctrl.testNotification()" class="btn btn-secondary">Send</button>
+			</div>
+		</div>
   </div>
 </div>