From 0cbc14961ac7d87953efe0852363ceb7856cb865 Mon Sep 17 00:00:00 2001 From: Joe Blubaugh Date: Tue, 12 Jul 2022 15:01:31 +0800 Subject: [PATCH] Alerting: Disable /api/admin/pause-all-alerts with Unified Alerting (#51895) /api/admin/pause-all-alerts only takes effect for legacy alerts. This change returns a 403 if it's called when legacy alerting is disabled. Fixes #51729 --- pkg/api/alerting.go | 158 +++++++++++++++++++++------------------ pkg/api/alerting_test.go | 4 +- pkg/api/api.go | 5 +- 3 files changed, 93 insertions(+), 74 deletions(-) diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index 6e28c5c6558..d9d868f4e96 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -507,91 +507,107 @@ func (hs *HTTPServer) NotificationTest(c *models.ReqContext) response.Response { } // POST /api/alerts/:alertId/pause -func (hs *HTTPServer) PauseAlert(c *models.ReqContext) response.Response { - dto := dtos.PauseAlertCommand{} - if err := web.Bind(c.Req, &dto); err != nil { - return response.Error(http.StatusBadRequest, "bad request data", err) - } - alertID, err := strconv.ParseInt(web.Params(c.Req)[":alertId"], 10, 64) - if err != nil { - return response.Error(http.StatusBadRequest, "alertId is invalid", err) - } - result := make(map[string]interface{}) - result["alertId"] = alertID - - query := models.GetAlertByIdQuery{Id: alertID} - if err := hs.SQLStore.GetAlertById(c.Req.Context(), &query); err != nil { - return response.Error(500, "Get Alert failed", err) +func (hs *HTTPServer) PauseAlert(legacyAlertingEnabled *bool) func(c *models.ReqContext) response.Response { + if legacyAlertingEnabled == nil || !*legacyAlertingEnabled { + return func(_ *models.ReqContext) response.Response { + return response.Error(http.StatusBadRequest, "legacy alerting is disabled, so this call has no effect.", nil) + } } - guardian := guardian.New(c.Req.Context(), query.Result.DashboardId, c.OrgId, c.SignedInUser) - if canEdit, err := guardian.CanEdit(); err != nil || !canEdit { + return func(c *models.ReqContext) response.Response { + dto := dtos.PauseAlertCommand{} + if err := web.Bind(c.Req, &dto); err != nil { + return response.Error(http.StatusBadRequest, "bad request data", err) + } + alertID, err := strconv.ParseInt(web.Params(c.Req)[":alertId"], 10, 64) if err != nil { - return response.Error(500, "Error while checking permissions for Alert", err) + return response.Error(http.StatusBadRequest, "alertId is invalid", err) + } + result := make(map[string]interface{}) + result["alertId"] = alertID + + query := models.GetAlertByIdQuery{Id: alertID} + if err := hs.SQLStore.GetAlertById(c.Req.Context(), &query); err != nil { + return response.Error(500, "Get Alert failed", err) } - return response.Error(403, "Access denied to this dashboard and alert", nil) - } + guardian := guardian.New(c.Req.Context(), query.Result.DashboardId, c.OrgId, c.SignedInUser) + if canEdit, err := guardian.CanEdit(); err != nil || !canEdit { + if err != nil { + return response.Error(500, "Error while checking permissions for Alert", err) + } - // Alert state validation - if query.Result.State != models.AlertStatePaused && !dto.Paused { - result["state"] = "un-paused" - result["message"] = "Alert is already un-paused" - return response.JSON(http.StatusOK, result) - } else if query.Result.State == models.AlertStatePaused && dto.Paused { - result["state"] = models.AlertStatePaused - result["message"] = "Alert is already paused" + return response.Error(403, "Access denied to this dashboard and alert", nil) + } + + // Alert state validation + if query.Result.State != models.AlertStatePaused && !dto.Paused { + result["state"] = "un-paused" + result["message"] = "Alert is already un-paused" + return response.JSON(http.StatusOK, result) + } else if query.Result.State == models.AlertStatePaused && dto.Paused { + result["state"] = models.AlertStatePaused + result["message"] = "Alert is already paused" + return response.JSON(http.StatusOK, result) + } + + cmd := models.PauseAlertCommand{ + OrgId: c.OrgId, + AlertIds: []int64{alertID}, + Paused: dto.Paused, + } + + if err := hs.SQLStore.PauseAlert(c.Req.Context(), &cmd); err != nil { + return response.Error(500, "", err) + } + + resp := models.AlertStateUnknown + pausedState := "un-paused" + if cmd.Paused { + resp = models.AlertStatePaused + pausedState = "paused" + } + + result["state"] = resp + result["message"] = "Alert " + pausedState return response.JSON(http.StatusOK, result) } - - cmd := models.PauseAlertCommand{ - OrgId: c.OrgId, - AlertIds: []int64{alertID}, - Paused: dto.Paused, - } - - if err := hs.SQLStore.PauseAlert(c.Req.Context(), &cmd); err != nil { - return response.Error(500, "", err) - } - - resp := models.AlertStateUnknown - pausedState := "un-paused" - if cmd.Paused { - resp = models.AlertStatePaused - pausedState = "paused" - } - - result["state"] = resp - result["message"] = "Alert " + pausedState - return response.JSON(http.StatusOK, result) } // POST /api/admin/pause-all-alerts -func (hs *HTTPServer) PauseAllAlerts(c *models.ReqContext) response.Response { - dto := dtos.PauseAllAlertsCommand{} - if err := web.Bind(c.Req, &dto); err != nil { - return response.Error(http.StatusBadRequest, "bad request data", err) - } - updateCmd := models.PauseAllAlertCommand{ - Paused: dto.Paused, +func (hs *HTTPServer) PauseAllAlerts(legacyAlertingEnabled *bool) func(c *models.ReqContext) response.Response { + if legacyAlertingEnabled == nil || !*legacyAlertingEnabled { + return func(_ *models.ReqContext) response.Response { + return response.Error(http.StatusBadRequest, "legacy alerting is disabled, so this call has no effect.", nil) + } } - if err := hs.SQLStore.PauseAllAlerts(c.Req.Context(), &updateCmd); err != nil { - return response.Error(500, "Failed to pause alerts", err) - } + return func(c *models.ReqContext) response.Response { + dto := dtos.PauseAllAlertsCommand{} + if err := web.Bind(c.Req, &dto); err != nil { + return response.Error(http.StatusBadRequest, "bad request data", err) + } + updateCmd := models.PauseAllAlertCommand{ + Paused: dto.Paused, + } - resp := models.AlertStatePending - pausedState := "un paused" - if updateCmd.Paused { - resp = models.AlertStatePaused - pausedState = "paused" - } + if err := hs.SQLStore.PauseAllAlerts(c.Req.Context(), &updateCmd); err != nil { + return response.Error(500, "Failed to pause alerts", err) + } - result := map[string]interface{}{ - "state": resp, - "message": "alerts " + pausedState, - "alertsAffected": updateCmd.ResultCount, - } + resp := models.AlertStatePending + pausedState := "un paused" + if updateCmd.Paused { + resp = models.AlertStatePaused + pausedState = "paused" + } - return response.JSON(http.StatusOK, result) + result := map[string]interface{}{ + "state": resp, + "message": "alerts " + pausedState, + "alertsAffected": updateCmd.ResultCount, + } + + return response.JSON(http.StatusOK, result) + } } diff --git a/pkg/api/alerting_test.go b/pkg/api/alerting_test.go index f5f2ee9961b..70df8539ca6 100644 --- a/pkg/api/alerting_test.go +++ b/pkg/api/alerting_test.go @@ -145,7 +145,9 @@ func postAlertScenario(t *testing.T, hs *HTTPServer, desc string, url string, ro sc.context.OrgId = testOrgID sc.context.OrgRole = role - return hs.PauseAlert(c) + legacyAlertingEnabled := new(bool) + *legacyAlertingEnabled = true + return hs.PauseAlert(legacyAlertingEnabled)(c) }) sc.m.Post(routePattern, sc.defaultHandler) diff --git a/pkg/api/api.go b/pkg/api/api.go index 167a94fda63..4364d24ce3a 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/services/featuremgmt" publicdashboardsapi "github.com/grafana/grafana/pkg/services/publicdashboards/api" "github.com/grafana/grafana/pkg/services/serviceaccounts" + "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -460,7 +461,7 @@ func (hs *HTTPServer) registerRoutes() { apiRoute.Group("/alerts", func(alertsRoute routing.RouteRegister) { alertsRoute.Post("/test", routing.Wrap(hs.AlertTest)) - alertsRoute.Post("/:alertId/pause", reqEditorRole, routing.Wrap(hs.PauseAlert)) + alertsRoute.Post("/:alertId/pause", reqEditorRole, routing.Wrap(hs.PauseAlert(setting.AlertingEnabled))) alertsRoute.Get("/:alertId", hs.ValidateOrgAlert, routing.Wrap(hs.GetAlert)) alertsRoute.Get("/", routing.Wrap(hs.GetAlerts)) alertsRoute.Get("/states-for-dashboard", routing.Wrap(hs.GetAlertStatesForDashboard)) @@ -554,7 +555,7 @@ func (hs *HTTPServer) registerRoutes() { adminRoute.Get("/settings/features", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionSettingsRead)), hs.Features.HandleGetSettings) } adminRoute.Get("/stats", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionServerStatsRead)), routing.Wrap(hs.AdminGetStats)) - adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, routing.Wrap(hs.PauseAllAlerts)) + adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, routing.Wrap(hs.PauseAllAlerts(setting.AlertingEnabled))) if hs.ThumbService != nil && hs.Features.IsEnabled(featuremgmt.FlagDashboardPreviewsAdmin) { adminRoute.Post("/crawler/start", reqGrafanaAdmin, routing.Wrap(hs.ThumbService.StartCrawler))