Sfoglia il codice sorgente

feat(api): adds endpoint for mass pausing alerts

ref #6589
bergquist 9 anni fa
parent
commit
fb6aa0e026

+ 68 - 4
pkg/api/alerting.go

@@ -259,10 +259,11 @@ func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) R
 
 //POST /api/alerts/:alertId/pause
 func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response {
+	alertId := c.ParamsInt64("alertId")
 	cmd := models.PauseAlertCommand{
-		OrgId:   c.OrgId,
-		AlertId: c.ParamsInt64("alertId"),
-		Paused:  dto.Paused,
+		OrgId:    c.OrgId,
+		AlertIds: []int64{alertId},
+		Paused:   dto.Paused,
 	}
 
 	if err := bus.Dispatch(&cmd); err != nil {
@@ -277,10 +278,73 @@ func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response {
 	}
 
 	result := map[string]interface{}{
-		"alertId": cmd.AlertId,
+		"alertId": alertId,
 		"state":   response,
 		"message": "alert " + pausedState,
 	}
 
 	return Json(200, result)
 }
+
+func existInSlice(slice []int64, value int64) bool {
+	for _, v := range slice {
+		if v == value {
+			return true
+		}
+	}
+	return false
+}
+
+//POST /api/alerts/pause
+func PauseAlerts(c *middleware.Context, dto dtos.PauseAlertsCommand) Response {
+	cmd := &models.GetAllAlertsQuery{}
+	if err := bus.Dispatch(cmd); err != nil {
+		return ApiError(500, "", err)
+	}
+
+	var alertsToUpdate []int64
+	skipFilter := len(dto.DataSourceIds) == 0
+	for _, alert := range cmd.Result {
+		if skipFilter {
+			alertsToUpdate = append(alertsToUpdate, alert.Id)
+			continue
+		}
+
+		alert, err := alerting.NewRuleFromDBAlert(alert)
+		if err != nil {
+			return ApiError(500, "", err)
+		}
+
+		for _, v := range alert.Conditions {
+			id, exist := v.GetDatsourceId()
+			if exist && existInSlice(dto.DataSourceIds, *id) {
+				alertsToUpdate = append(alertsToUpdate, alert.Id)
+			}
+		}
+	}
+
+	updateCmd := models.PauseAlertCommand{
+		OrgId:    c.OrgId,
+		AlertIds: alertsToUpdate,
+		Paused:   dto.Paused,
+	}
+
+	if err := bus.Dispatch(&updateCmd); err != nil {
+		return ApiError(500, "", err)
+	}
+
+	var response models.AlertStateType = models.AlertStatePending
+	pausedState := "un paused"
+	if updateCmd.Paused {
+		response = models.AlertStatePaused
+		pausedState = "paused"
+	}
+
+	result := map[string]interface{}{
+		"state":          response,
+		"message":        "alert " + pausedState,
+		"alertsAffected": updateCmd.ResultCount,
+	}
+
+	return Json(200, result)
+}

+ 11 - 0
pkg/api/alerting_test.go

@@ -0,0 +1,11 @@
+package api
+
+import (
+	"testing"
+
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestAlertingApi(t *testing.T) {
+	Convey("", func() {})
+}

+ 1 - 0
pkg/api/api.go

@@ -256,6 +256,7 @@ func Register(r *macaron.Macaron) {
 		r.Group("/alerts", func() {
 			r.Post("/test", bind(dtos.AlertTestCommand{}), wrap(AlertTest))
 			r.Post("/:alertId/pause", bind(dtos.PauseAlertCommand{}), wrap(PauseAlert), reqEditorRole)
+			r.Post("/pause", bind(dtos.PauseAlertsCommand{}), wrap(PauseAlerts), reqGrafanaAdmin)
 			r.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert))
 			r.Get("/", wrap(GetAlerts))
 			r.Get("/states-for-dashboard", wrap(GetAlertStatesForDashboard))

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

@@ -64,3 +64,8 @@ type PauseAlertCommand struct {
 	AlertId int64 `json:"alertId"`
 	Paused  bool  `json:"paused"`
 }
+
+type PauseAlertsCommand struct {
+	DataSourceIds []int64 `json:"datasourceId"`
+	Paused        bool    `json:"paused"`
+}

+ 4 - 3
pkg/models/alert.go

@@ -132,9 +132,10 @@ type SaveAlertsCommand struct {
 }
 
 type PauseAlertCommand struct {
-	OrgId   int64
-	AlertId int64
-	Paused  bool
+	OrgId       int64
+	AlertIds    []int64
+	ResultCount int64
+	Paused      bool
 }
 
 type SetAlertStateCommand struct {

+ 4 - 0
pkg/services/alerting/conditions/query.go

@@ -34,6 +34,10 @@ type AlertQuery struct {
 	To           string
 }
 
+func (c *QueryCondition) GetDatsourceId() (datasourceId *int64, exist bool) {
+	return &c.Query.DatasourceId, true
+}
+
 func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.ConditionResult, error) {
 	timeRange := tsdb.NewTimeRange(c.Query.From, c.Query.To)
 

+ 1 - 0
pkg/services/alerting/interfaces.go

@@ -30,4 +30,5 @@ type ConditionResult struct {
 
 type Condition interface {
 	Eval(result *EvalContext) (*ConditionResult, error)
+	GetDatsourceId() (datasourceId *int64, exist bool)
 }

+ 22 - 13
pkg/services/sqlstore/alert.go

@@ -5,6 +5,8 @@ import (
 	"fmt"
 	"time"
 
+	"strings"
+
 	"github.com/go-xorm/xorm"
 	"github.com/grafana/grafana/pkg/bus"
 	m "github.com/grafana/grafana/pkg/models"
@@ -246,25 +248,32 @@ func SetAlertState(cmd *m.SetAlertStateCommand) error {
 
 func PauseAlertRule(cmd *m.PauseAlertCommand) error {
 	return inTransaction(func(sess *xorm.Session) error {
-		alert := m.Alert{}
-
-		has, err := x.Where("id = ? AND org_id=?", cmd.AlertId, cmd.OrgId).Get(&alert)
-
-		if err != nil {
-			return err
-		} else if !has {
-			return fmt.Errorf("Could not find alert")
+		var buffer bytes.Buffer
+		params := make([]interface{}, 0)
+		buffer.WriteString(`UPDATE alert SET state = ?`)
+
+		alertIdCount := len(cmd.AlertIds)
+		if alertIdCount == 1 {
+			buffer.WriteString(` WHERE id = ?`)
+		} else if alertIdCount > 1 {
+			buffer.WriteString(` WHERE id IN (?` + strings.Repeat(",?", len(cmd.AlertIds)-1) + `)`)
 		}
 
-		var newState m.AlertStateType
 		if cmd.Paused {
-			newState = m.AlertStatePaused
+			params = append(params, string(m.AlertStatePaused))
 		} else {
-			newState = m.AlertStatePending
+			params = append(params, string(m.AlertStatePending))
 		}
-		alert.State = newState
 
-		sess.Id(alert.Id).Update(&alert)
+		for _, v := range cmd.AlertIds {
+			params = append(params, v)
+		}
+
+		res, err := sess.Exec(buffer.String(), params...)
+		if err != nil {
+			return err
+		}
+		cmd.ResultCount, _ = res.RowsAffected()
 		return nil
 	})
 }

+ 0 - 18
pkg/services/sqlstore/alert_heartbeat_test.go

@@ -1,18 +0,0 @@
-package sqlstore
-
-import (
-	"testing"
-
-	//	m "github.com/grafana/grafana/pkg/models"
-	. "github.com/smartystreets/goconvey/convey"
-)
-
-func TestAlertingHeartbeatDataAccess(t *testing.T) {
-
-	Convey("Testing Alerting data access", t, func() {
-		InitTestDB(t)
-		//send heartbeat from server 1
-		//send heartbeat from server 2
-
-	})
-}