diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index 460ad56e1ab..40b117835ec 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -252,33 +252,30 @@ func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) R return ApiSuccess("Test notification sent") } -func getAlertIdForRequest(c *middleware.Context) (int64, error) { - alertId := c.QueryInt64("alertId") - panelId := c.QueryInt64("panelId") - dashboardId := c.QueryInt64("dashboardId") - - if alertId == 0 && dashboardId == 0 && panelId == 0 { - return 0, fmt.Errorf("Missing alertId or dashboardId and panelId") +//POST /api/:alertId/pause +func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response { + cmd := models.PauseAlertCommand{ + OrgId: c.OrgId, + AlertId: c.ParamsInt64("alertId"), + Paused: dto.Paused, } - if alertId == 0 { - //fetch alertId - query := models.GetAlertsQuery{ - OrgId: c.OrgId, - DashboardId: dashboardId, - PanelId: panelId, - } - - if err := bus.Dispatch(&query); err != nil { - return 0, err - } - - if len(query.Result) != 1 { - return 0, fmt.Errorf("PanelId is not unique on dashboard") - } - - alertId = query.Result[0].Id + if err := bus.Dispatch(&cmd); err != nil { + return ApiError(500, "", err) } - return alertId, nil + var response models.AlertStateType = models.AlertStateNoData + pausedState := "un paused" + if cmd.Paused { + response = models.AlertStatePaused + pausedState = "paused" + } + + result := map[string]interface{}{ + "alertId": cmd.AlertId, + "state": response, + "message": "alert " + pausedState, + } + + return Json(200, result) } diff --git a/pkg/api/api.go b/pkg/api/api.go index deb29d730eb..5609536e213 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -252,6 +252,7 @@ func Register(r *macaron.Macaron) { r.Group("/alerts", func() { r.Post("/test", bind(dtos.AlertTestCommand{}), wrap(AlertTest)) + r.Post("/:alertId/pause", ValidateOrgAlert, bind(dtos.PauseAlertCommand{}), wrap(PauseAlert)) r.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert)) r.Get("/", wrap(GetAlerts)) r.Get("/states-for-dashboard", wrap(GetAlertStatesForDashboard)) diff --git a/pkg/api/dtos/alerting.go b/pkg/api/dtos/alerting.go index e024768cd5e..bf4d7f4353e 100644 --- a/pkg/api/dtos/alerting.go +++ b/pkg/api/dtos/alerting.go @@ -58,3 +58,8 @@ type NotificationTestCommand struct { Type string `json:"type"` Settings *simplejson.Json `json:"settings"` } + +type PauseAlertCommand struct { + AlertId int64 `json:"alertId"` + Paused bool `json:"paused"` +} diff --git a/pkg/models/alert.go b/pkg/models/alert.go index 938be8ddbd4..f50bb3193dc 100644 --- a/pkg/models/alert.go +++ b/pkg/models/alert.go @@ -101,6 +101,12 @@ type SaveAlertsCommand struct { Alerts []*Alert } +type PauseAlertCommand struct { + OrgId int64 + AlertId int64 + Paused bool +} + type SetAlertStateCommand struct { AlertId int64 OrgId int64 diff --git a/pkg/services/alerting/scheduler.go b/pkg/services/alerting/scheduler.go index 9d20796f3dc..b6ef1a63ff8 100644 --- a/pkg/services/alerting/scheduler.go +++ b/pkg/services/alerting/scheduler.go @@ -5,6 +5,7 @@ import ( "time" "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" ) type SchedulerImpl struct { @@ -48,7 +49,7 @@ func (s *SchedulerImpl) Tick(tickTime time.Time, execQueue chan *Job) { now := tickTime.Unix() for _, job := range s.jobs { - if job.Running { + if job.Running || job.Rule.State == models.AlertStatePaused { continue } diff --git a/pkg/services/sqlstore/alert.go b/pkg/services/sqlstore/alert.go index 61397017943..76ea268bc04 100644 --- a/pkg/services/sqlstore/alert.go +++ b/pkg/services/sqlstore/alert.go @@ -18,6 +18,7 @@ func init() { bus.AddHandler("sql", GetAllAlertQueryHandler) bus.AddHandler("sql", SetAlertState) bus.AddHandler("sql", GetAlertStatesForDashboard) + bus.AddHandler("sql", PauseAlertRule) } func GetAlertById(query *m.GetAlertByIdQuery) error { @@ -243,6 +244,29 @@ func SetAlertState(cmd *m.SetAlertStateCommand) error { }) } +func PauseAlertRule(cmd *m.PauseAlertCommand) error { + return inTransaction(func(sess *xorm.Session) error { + alert := m.Alert{} + + if has, err := sess.Id(cmd.AlertId).Get(&alert); err != nil { + return err + } else if !has { + return fmt.Errorf("Could not find alert") + } + + var newState m.AlertStateType + if cmd.Paused { + newState = m.AlertStatePaused + } else { + newState = m.AlertStateNoData + } + alert.State = newState + + sess.Id(alert.Id).Update(&alert) + return nil + }) +} + func GetAlertStatesForDashboard(query *m.GetAlertStatesForDashboardQuery) error { var rawSql = `SELECT id, diff --git a/public/app/features/alerting/alert_list_ctrl.ts b/public/app/features/alerting/alert_list_ctrl.ts index 4b429e961a7..b2287759a9b 100644 --- a/public/app/features/alerting/alert_list_ctrl.ts +++ b/public/app/features/alerting/alert_list_ctrl.ts @@ -23,7 +23,7 @@ export class AlertListCtrl { }; /** @ngInject */ - constructor(private backendSrv, private $location) { + constructor(private backendSrv, private $location, private $scope) { var params = $location.search(); this.filters.state = params.state || null; this.loadAlerts(); @@ -43,6 +43,19 @@ export class AlertListCtrl { }); } + pauseAlertRule(alertId: any) { + var alert = _.find(this.alerts, {id: alertId}); + + var payload = { + paused: alert.state !== "paused" + }; + + this.backendSrv.post(`/api/alerts/${alert.id}/pause`, payload).then(result => { + alert.state = result.state; + alert.stateModel = alertDef.getStateDisplayModel(result.state); + }); + } + openHowTo() { appEvents.emit('show-modal', { src: 'public/app/features/alerting/partials/alert_howto.html', diff --git a/public/app/features/alerting/partials/alert_list.html b/public/app/features/alerting/partials/alert_list.html index a8678bc4cdc..685aa1f2db8 100644 --- a/public/app/features/alerting/partials/alert_list.html +++ b/public/app/features/alerting/partials/alert_list.html @@ -29,7 +29,10 @@