Просмотр исходного кода

feat(alerting): converter for db model to notification

bergquist 9 лет назад
Родитель
Сommit
9a8416416d

+ 2 - 1
pkg/models/alert_notifications.go

@@ -38,7 +38,8 @@ type UpdateAlertNotificationCommand struct {
 
 type GetAlertNotificationQuery struct {
 	Name  string
-	ID    int64
+	Id    int64
+	Ids   []int64
 	OrgID int64
 
 	Result []*AlertNotification

+ 113 - 0
pkg/services/alerting/notifier.go

@@ -1 +1,114 @@
 package alerting
+
+import (
+	"github.com/grafana/grafana/pkg/components/simplejson"
+	"github.com/grafana/grafana/pkg/log"
+	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/services/alerting/alertstates"
+)
+
+type Notifier struct {
+	log log.Logger
+}
+
+func NewNotifier() *Notifier {
+	return &Notifier{
+		log: log.New("alerting.notifier"),
+	}
+}
+
+func (n *Notifier) Notify(alertResult AlertResult) {
+	notifiers := getNotifiers(alertResult.AlertJob.Rule.OrgId, alertResult.AlertJob.Rule.NotificationGroups)
+
+	for _, notifier := range notifiers {
+		warn := alertResult.State == alertstates.Warn && notifier.SendWarning
+		crit := alertResult.State == alertstates.Critical && notifier.SendCritical
+
+		if warn || crit {
+			n.log.Info("Sending notification", "state", alertResult.State, "type", notifier.Type)
+			go notifier.Notifierr.Notify(alertResult)
+		}
+	}
+
+}
+
+type Notification struct {
+	Name         string
+	Type         string
+	SendWarning  bool
+	SendCritical bool
+
+	Notifierr Notifierr
+}
+
+type EmailNotifier struct {
+	To   string
+	From string
+}
+
+func (this EmailNotifier) Notify(alertResult AlertResult) {
+	//bus.dispath to notification package in grafana
+}
+
+type WebhookNotifier struct {
+	Url          string
+	AuthUser     string
+	AuthPassword string
+}
+
+func (this WebhookNotifier) Notify(alertResult AlertResult) {
+	//bus.dispath to notification package in grafana
+}
+
+type Notifierr interface {
+	Notify(alertResult AlertResult)
+}
+
+func getNotifiers(orgId int64, notificationGroups []int64) []*Notification {
+	var notifications []*m.AlertNotification
+
+	for _, notificationId := range notificationGroups {
+		query := m.GetAlertNotificationQuery{
+			OrgID: orgId,
+			Id:    notificationId,
+		}
+
+		notifications = append(notifications, query.Result...)
+	}
+
+	var result []*Notification
+
+	for _, notification := range notifications {
+		not, err := NewNotificationFromDBModel(notification)
+		if err == nil {
+			result = append(result, not)
+		}
+	}
+
+	return result
+}
+
+func NewNotificationFromDBModel(model *m.AlertNotification) (*Notification, error) {
+	return &Notification{
+		Name:         model.Name,
+		Type:         model.Type,
+		Notifierr:    createNotifier(model.Type, model.Settings),
+		SendCritical: !model.Settings.Get("ignoreCrit").MustBool(),
+		SendWarning:  !model.Settings.Get("ignoreWarn").MustBool(),
+	}, nil
+}
+
+var createNotifier = func(notificationType string, settings *simplejson.Json) Notifierr {
+	if notificationType == "email" {
+		return &EmailNotifier{
+			To:   settings.Get("to").MustString(),
+			From: settings.Get("from").MustString(),
+		}
+	}
+
+	return &WebhookNotifier{
+		Url:          settings.Get("url").MustString(),
+		AuthUser:     settings.Get("user").MustString(),
+		AuthPassword: settings.Get("password").MustString(),
+	}
+}

+ 68 - 0
pkg/services/alerting/notifier_test.go

@@ -0,0 +1,68 @@
+package alerting
+
+import (
+	"testing"
+
+	"reflect"
+
+	"github.com/grafana/grafana/pkg/components/simplejson"
+	m "github.com/grafana/grafana/pkg/models"
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestAlertNotificationExtraction(t *testing.T) {
+
+	Convey("Parsing alert notification from settings", t, func() {
+		Convey("Parsing email notification from settings", func() {
+			json := `
+            {
+                "from": "alerting@grafana.org",
+                "to": "ops@grafana.org"
+            }`
+
+			settingsJSON, _ := simplejson.NewJson([]byte(json))
+			model := &m.AlertNotification{
+				Name:     "ops",
+				Type:     "email",
+				Settings: settingsJSON,
+			}
+
+			not, err := NewNotificationFromDBModel(model)
+
+			So(err, ShouldBeNil)
+			So(not.Name, ShouldEqual, "ops")
+			So(not.Type, ShouldEqual, "email")
+			So(reflect.TypeOf(not.Notifierr).Elem().String(), ShouldEqual, "alerting.EmailNotifier")
+
+			email := not.Notifierr.(*EmailNotifier)
+			So(email.To, ShouldEqual, "ops@grafana.org")
+			So(email.From, ShouldEqual, "alerting@grafana.org")
+		})
+
+		Convey("Parsing webhook notification from settings", func() {
+			json := `
+            {
+                "url": "http://localhost:3000",
+                "username": "username",
+                "password": "password"
+            }`
+
+			settingsJSON, _ := simplejson.NewJson([]byte(json))
+			model := &m.AlertNotification{
+				Name:     "slack",
+				Type:     "webhook",
+				Settings: settingsJSON,
+			}
+
+			not, err := NewNotificationFromDBModel(model)
+
+			So(err, ShouldBeNil)
+			So(not.Name, ShouldEqual, "slack")
+			So(not.Type, ShouldEqual, "webhook")
+			So(reflect.TypeOf(not.Notifierr).Elem().String(), ShouldEqual, "alerting.WebhookNotifier")
+
+			webhook := not.Notifierr.(*WebhookNotifier)
+			So(webhook.Url, ShouldEqual, "http://localhost:3000")
+		})
+	})
+}

+ 36 - 11
pkg/services/sqlstore/alert_notification.go

@@ -3,6 +3,7 @@ package sqlstore
 import (
 	"bytes"
 	"fmt"
+	"strconv"
 	"time"
 
 	"github.com/go-xorm/xorm"
@@ -43,6 +44,25 @@ func getAlertNotifications(query *m.GetAlertNotificationQuery, sess *xorm.Sessio
 		params = append(params, query.Name)
 	}
 
+	if query.Id != 0 {
+		sql.WriteString(` AND alert_notification.id = ?`)
+		params = append(params, strconv.Itoa(int(query.Id)))
+	}
+
+	if len(query.Ids) > 0 {
+		sql.WriteString(` AND (`)
+
+		for i, id := range query.Ids {
+			if i != 0 {
+				sql.WriteString(` OR`)
+			}
+			sql.WriteString(` alert_notification.id = ?`)
+			params = append(params, id)
+		}
+
+		sql.WriteString(`)`)
+	}
+
 	var result []*m.AlertNotification
 	if err := sess.Sql(sql.String(), params...).Find(&result); err != nil {
 		return err
@@ -71,15 +91,16 @@ func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error
 			Type:     cmd.Type,
 			Created:  time.Now(),
 			Settings: cmd.Settings,
+			Updated:  time.Now(),
 		}
 
-		id, err := sess.Insert(alertNotification)
+		_, err = sess.Insert(alertNotification)
 
 		if err != nil {
 			return err
 		}
 
-		alertNotification.Id = id
+		//alertNotification.Id = int(id)
 		cmd.Result = alertNotification
 		return nil
 	})
@@ -87,30 +108,34 @@ func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error
 
 func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
 	return inTransaction(func(sess *xorm.Session) (err error) {
-		alertNotification := &m.AlertNotification{}
-
-		var has bool
-		has, err = sess.Id(cmd.Id).Get(alertNotification)
+		current := &m.AlertNotification{}
+		_, err = sess.Id(cmd.Id).Get(current)
 
 		if err != nil {
 			return err
 		}
 
-		if !has {
-			return fmt.Errorf("Alert notification does not exist")
-		}
-
+		alertNotification := &m.AlertNotification{}
+		alertNotification.Id = cmd.Id
+		alertNotification.OrgId = cmd.OrgID
 		alertNotification.Name = cmd.Name
 		alertNotification.Type = cmd.Type
 		alertNotification.Settings = cmd.Settings
 		alertNotification.Updated = time.Now()
+		alertNotification.Created = current.Created
 
-		_, err = sess.Id(alertNotification.Id).Cols("name", "type", "settings", "updated").Update(alertNotification)
+		var affected int64
+		//affected, err = sess.Id(alertNotification.Id).Cols("name", "type", "settings", "updated").Update(alertNotification)
+		affected, err = sess.Id(alertNotification.Id).Update(alertNotification)
 
 		if err != nil {
 			return err
 		}
 
+		if affected == 0 {
+			return fmt.Errorf("Could not find alert notification")
+		}
+
 		cmd.Result = alertNotification
 		return nil
 	})

+ 39 - 17
pkg/services/sqlstore/alert_notification_test.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"testing"
 
+	"github.com/grafana/grafana/pkg/components/simplejson"
 	m "github.com/grafana/grafana/pkg/models"
 	. "github.com/smartystreets/goconvey/convey"
 )
@@ -27,40 +28,61 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
 
 		Convey("Can save Alert Notification", func() {
 			cmd := &m.CreateAlertNotificationCommand{
-				Name: "ops",
-				Type: "email",
+				Name:     "ops",
+				Type:     "email",
+				OrgID:    1,
+				Settings: simplejson.New(),
 			}
 
 			err = CreateAlertNotificationCommand(cmd)
 			So(err, ShouldBeNil)
 			So(cmd.Result.Id, ShouldNotEqual, 0)
+			So(cmd.Result.OrgId, ShouldNotEqual, 0)
+			So(cmd.Result.Type, ShouldEqual, "email")
 
 			Convey("Cannot save Alert Notification with the same name", func() {
 				err = CreateAlertNotificationCommand(cmd)
 				So(err, ShouldNotBeNil)
 			})
 
-			Convey("Cannot update alert notification that does not exist", func() {
+			Convey("Can update alert notification", func() {
 				newCmd := &m.UpdateAlertNotificationCommand{
-					Name:  "NewName",
-					Type:  cmd.Result.Type,
-					OrgID: cmd.Result.OrgId,
-					Id:    1337,
+					Name:     "NewName",
+					Type:     "webhook",
+					OrgID:    cmd.Result.OrgId,
+					Settings: simplejson.New(),
+					Id:       cmd.Result.Id,
 				}
-				err = UpdateAlertNotification(newCmd)
-				So(err, ShouldNotBeNil)
+				err := UpdateAlertNotification(newCmd)
+				So(err, ShouldBeNil)
+				So(newCmd.Result.Name, ShouldEqual, "NewName")
 			})
+		})
 
-			Convey("Can update alert notification", func() {
-				newCmd := &m.UpdateAlertNotificationCommand{
-					Name:  "NewName",
-					Type:  cmd.Result.Type,
-					OrgID: cmd.Result.OrgId,
-					Id:    cmd.Result.Id,
+		Convey("Can search using an array of ids", func() {
+			So(CreateAlertNotificationCommand(&m.CreateAlertNotificationCommand{
+				Name:     "ops2",
+				Type:     "email",
+				OrgID:    1,
+				Settings: simplejson.New(),
+			}), ShouldBeNil)
+
+			So(CreateAlertNotificationCommand(&m.CreateAlertNotificationCommand{
+				Name:     "slack",
+				Type:     "webhook",
+				OrgID:    1,
+				Settings: simplejson.New(),
+			}), ShouldBeNil)
+
+			Convey("search", func() {
+				query := &m.GetAlertNotificationQuery{
+					Ids:   []int64{1, 2, 3},
+					OrgID: 1,
 				}
-				err = UpdateAlertNotification(newCmd)
+
+				err := AlertNotificationQuery(query)
 				So(err, ShouldBeNil)
-				So(newCmd.Result.Name, ShouldEqual, "NewName")
+				So(len(query.Result), ShouldEqual, 2)
 			})
 		})
 	})