From ecdf1888c4caf87be052ed113ba072b24a415d0c Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 19 Dec 2016 13:24:45 +0100 Subject: [PATCH] feat(alerting): removes pause per datasource --- pkg/api/alerting.go | 46 +---------------------- pkg/api/api.go | 2 +- pkg/api/dtos/alerting.go | 5 +-- pkg/metrics/metrics.go | 2 +- pkg/models/alert.go | 11 ++++++ pkg/services/alerting/conditions/query.go | 4 -- pkg/services/alerting/interfaces.go | 1 - pkg/services/alerting/result_handler.go | 4 ++ pkg/services/alerting/rule_test.go | 4 -- pkg/services/sqlstore/alert.go | 38 +++++++++++++++---- pkg/services/sqlstore/alert_test.go | 31 +++++++++++++++ 11 files changed, 83 insertions(+), 65 deletions(-) diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index d84151e5f45..f783e6e4229 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -287,20 +287,11 @@ func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response { } //POST /api/alerts/pause -func PauseAlerts(c *middleware.Context, dto dtos.PauseAlertsCommand) Response { - updateCmd := models.PauseAlertCommand{ - OrgId: c.OrgId, +func PauseAlerts(c *middleware.Context, dto dtos.PauseAllAlertsCommand) Response { + updateCmd := models.PauseAllAlertCommand{ Paused: dto.Paused, } - if len(dto.DataSourceIds) > 0 { - alertIdsToUpdate, err := getAlertIdsToUpdate(dto) - if err != nil { - return ApiError(500, "Failed to pause alerts", err) - } - updateCmd.AlertIds = alertIdsToUpdate - } - if err := bus.Dispatch(&updateCmd); err != nil { return ApiError(500, "Failed to pause alerts", err) } @@ -320,36 +311,3 @@ func PauseAlerts(c *middleware.Context, dto dtos.PauseAlertsCommand) Response { return Json(200, result) } - -func getAlertIdsToUpdate(pauseAlertCmd dtos.PauseAlertsCommand) ([]int64, error) { - cmd := &models.GetAllAlertsQuery{} - if err := bus.Dispatch(cmd); err != nil { - return nil, err - } - - var alertIdsToUpdate []int64 - for _, alert := range cmd.Result { - alert, err := alerting.NewRuleFromDBAlert(alert) - if err != nil { - return nil, err - } - - for _, condition := range alert.Conditions { - id, exist := condition.GetDatasourceId() - if exist && existInSlice(pauseAlertCmd.DataSourceIds, *id) { - alertIdsToUpdate = append(alertIdsToUpdate, alert.Id) - } - } - } - - return alertIdsToUpdate, nil -} - -func existInSlice(slice []int64, value int64) bool { - for _, v := range slice { - if v == value { - return true - } - } - return false -} diff --git a/pkg/api/api.go b/pkg/api/api.go index f7ec069b04e..4b142be1b1f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -256,7 +256,6 @@ 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)) @@ -290,6 +289,7 @@ func Register(r *macaron.Macaron) { r.Get("/users/:id/quotas", wrap(GetUserQuotas)) r.Put("/users/:id/quotas/:target", bind(m.UpdateUserQuotaCmd{}), wrap(UpdateUserQuota)) r.Get("/stats", AdminGetStats) + r.Post("/pause-all-alerts", bind(dtos.PauseAllAlertsCommand{}), wrap(PauseAlerts)) }, reqGrafanaAdmin) // rendering diff --git a/pkg/api/dtos/alerting.go b/pkg/api/dtos/alerting.go index c990b347aa3..f3d64f89524 100644 --- a/pkg/api/dtos/alerting.go +++ b/pkg/api/dtos/alerting.go @@ -65,7 +65,6 @@ type PauseAlertCommand struct { Paused bool `json:"paused"` } -type PauseAlertsCommand struct { - DataSourceIds []int64 `json:"datasourceId"` - Paused bool `json:"paused"` +type PauseAllAlertsCommand struct { + Paused bool `json:"paused"` } diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index f408aecba96..4dd2a7cedde 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -50,7 +50,7 @@ var ( // Timers M_DataSource_ProxyReq_Timer Timer - M_Alerting_Execution_Time Timer + M_Alerting_Execution_Time Timer // StatTotals M_Alerting_Active_Alerts Gauge diff --git a/pkg/models/alert.go b/pkg/models/alert.go index 3f7a5fb9c3f..13cae0715f7 100644 --- a/pkg/models/alert.go +++ b/pkg/models/alert.go @@ -3,6 +3,8 @@ package models import ( "time" + "fmt" + "github.com/grafana/grafana/pkg/components/simplejson" ) @@ -31,6 +33,10 @@ const ( ExecutionErrorKeepState ExecutionErrorOption = "keep_state" ) +var ( + ErrCannotChangeStateOnPausedAlert error = fmt.Errorf("Cannot change state on pause alert") +) + func (s AlertStateType) IsValid() bool { return s == AlertStateOK || s == AlertStateNoData || s == AlertStatePaused || s == AlertStatePending } @@ -138,6 +144,11 @@ type PauseAlertCommand struct { Paused bool } +type PauseAllAlertCommand struct { + ResultCount int64 + Paused bool +} + type SetAlertStateCommand struct { AlertId int64 OrgId int64 diff --git a/pkg/services/alerting/conditions/query.go b/pkg/services/alerting/conditions/query.go index ca6c5f8b5d5..d7e0a0c29e3 100644 --- a/pkg/services/alerting/conditions/query.go +++ b/pkg/services/alerting/conditions/query.go @@ -34,10 +34,6 @@ type AlertQuery struct { To string } -func (c *QueryCondition) GetDatasourceId() (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) diff --git a/pkg/services/alerting/interfaces.go b/pkg/services/alerting/interfaces.go index 32c78b1dd62..566fbdb2898 100644 --- a/pkg/services/alerting/interfaces.go +++ b/pkg/services/alerting/interfaces.go @@ -30,5 +30,4 @@ type ConditionResult struct { type Condition interface { Eval(result *EvalContext) (*ConditionResult, error) - GetDatasourceId() (datasourceId *int64, exist bool) } diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go index 2a7c6528b97..aab109088cb 100644 --- a/pkg/services/alerting/result_handler.go +++ b/pkg/services/alerting/result_handler.go @@ -86,6 +86,10 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error { } if err := bus.Dispatch(cmd); err != nil { + if err == m.ErrCannotChangeStateOnPausedAlert { + handler.log.Error("Cannot change state on alert thats pause", "error", err) + return err + } handler.log.Error("Failed to save state", "error", err) } diff --git a/pkg/services/alerting/rule_test.go b/pkg/services/alerting/rule_test.go index 426712fa9f2..f8761efcd90 100644 --- a/pkg/services/alerting/rule_test.go +++ b/pkg/services/alerting/rule_test.go @@ -14,10 +14,6 @@ func (f *FakeCondition) Eval(context *EvalContext) (*ConditionResult, error) { return &ConditionResult{}, nil } -func (c *FakeCondition) GetDatasourceId() (datasourceId *int64, exist bool) { - return nil, false -} - func TestAlertRuleModel(t *testing.T) { Convey("Testing alert rule", t, func() { diff --git a/pkg/services/sqlstore/alert.go b/pkg/services/sqlstore/alert.go index 819b5cf544d..1537a61dfa3 100644 --- a/pkg/services/sqlstore/alert.go +++ b/pkg/services/sqlstore/alert.go @@ -3,9 +3,8 @@ package sqlstore import ( "bytes" "fmt" - "time" - "strings" + "time" "github.com/go-xorm/xorm" "github.com/grafana/grafana/pkg/bus" @@ -21,6 +20,7 @@ func init() { bus.AddHandler("sql", SetAlertState) bus.AddHandler("sql", GetAlertStatesForDashboard) bus.AddHandler("sql", PauseAlertRule) + bus.AddHandler("sql", PauseAllAlertRule) } func GetAlertById(query *m.GetAlertByIdQuery) error { @@ -230,6 +230,10 @@ func SetAlertState(cmd *m.SetAlertStateCommand) error { return fmt.Errorf("Could not find alert") } + if alert.State == m.AlertStatePaused { + return m.ErrCannotChangeStateOnPausedAlert + } + alert.State = cmd.State alert.StateChanges += 1 alert.NewStateDate = time.Now() @@ -248,6 +252,10 @@ func SetAlertState(cmd *m.SetAlertStateCommand) error { func PauseAlertRule(cmd *m.PauseAlertCommand) error { return inTransaction(func(sess *xorm.Session) error { + if len(cmd.AlertIds) == 0 { + return fmt.Errorf("command contains no alertids") + } + var buffer bytes.Buffer params := make([]interface{}, 0) @@ -258,11 +266,9 @@ func PauseAlertRule(cmd *m.PauseAlertCommand) error { params = append(params, string(m.AlertStatePending)) } - if len(cmd.AlertIds) > 0 { - buffer.WriteString(` WHERE id IN (?` + strings.Repeat(",?", len(cmd.AlertIds)-1) + `)`) - for _, v := range cmd.AlertIds { - params = append(params, v) - } + buffer.WriteString(` WHERE id IN (?` + strings.Repeat(",?", len(cmd.AlertIds)-1) + `)`) + for _, v := range cmd.AlertIds { + params = append(params, v) } res, err := sess.Exec(buffer.String(), params...) @@ -274,6 +280,24 @@ func PauseAlertRule(cmd *m.PauseAlertCommand) error { }) } +func PauseAllAlertRule(cmd *m.PauseAllAlertCommand) error { + return inTransaction(func(sess *xorm.Session) error { + var newState string + if cmd.Paused { + newState = string(m.AlertStatePaused) + } else { + newState = string(m.AlertStatePending) + } + + res, err := sess.Exec(`UPDATE alert SET state = ?`, newState) + if err != nil { + return err + } + cmd.ResultCount, _ = res.RowsAffected() + return nil + }) +} + func GetAlertStatesForDashboard(query *m.GetAlertStatesForDashboardQuery) error { var rawSql = `SELECT id, diff --git a/pkg/services/sqlstore/alert_test.go b/pkg/services/sqlstore/alert_test.go index e22b1c48c47..0217def4772 100644 --- a/pkg/services/sqlstore/alert_test.go +++ b/pkg/services/sqlstore/alert_test.go @@ -39,6 +39,37 @@ func TestAlertingDataAccess(t *testing.T) { So(err, ShouldBeNil) }) + Convey("Can set new states", func() { + Convey("new state ok", func() { + cmd := &m.SetAlertStateCommand{ + AlertId: 1, + State: m.AlertStateOK, + } + + err = SetAlertState(cmd) + So(err, ShouldBeNil) + }) + + Convey("can pause alert", func() { + cmd := &m.PauseAllAlertCommand{ + Paused: true, + } + + err = PauseAllAlertRule(cmd) + So(err, ShouldBeNil) + + Convey("cannot updated paused alert", func() { + cmd := &m.SetAlertStateCommand{ + AlertId: 1, + State: m.AlertStateOK, + } + + err = SetAlertState(cmd) + So(err, ShouldNotBeNil) + }) + }) + }) + Convey("Can read properties", func() { alertQuery := m.GetAlertsQuery{DashboardId: testDash.Id, PanelId: 1, OrgId: 1} err2 := HandleAlertsQuery(&alertQuery)