Commit d11bc57c by bergquist

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

closes #5847
parent 4c5461d4
......@@ -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 {
......
......@@ -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))
......
......@@ -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"`
}
......@@ -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()
......
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
}
......@@ -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);
......
......@@ -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>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment