diff --git a/pkg/services/ngalert/api/api_configuration.go b/pkg/services/ngalert/api/api_configuration.go index c8f1c3e17d8..294cad0f8bd 100644 --- a/pkg/services/ngalert/api/api_configuration.go +++ b/pkg/services/ngalert/api/api_configuration.go @@ -143,3 +143,22 @@ func (srv ConfigSrv) externalAlertmanagers(ctx context.Context, orgID int64) ([] } return alertmanagers, nil } + +func (srv ConfigSrv) RouteGetAlertingStatus(c *models.ReqContext) response.Response { + sendsAlertsTo := ngmodels.InternalAlertmanager + + cfg, err := srv.store.GetAdminConfiguration(c.OrgID) + if err != nil && !errors.Is(err, store.ErrNoAdminConfiguration) { + msg := "failed to fetch configuration from the database" + srv.log.Error(msg, "err", err) + return ErrResp(http.StatusInternalServerError, err, msg) + } + if cfg != nil { + sendsAlertsTo = cfg.SendAlertsTo + } + + resp := apimodels.AlertingStatus{ + AlertmanagersChoice: apimodels.AlertmanagersChoice(sendsAlertsTo.String()), + } + return response.JSON(http.StatusOK, resp) +} diff --git a/pkg/services/ngalert/api/authorization.go b/pkg/services/ngalert/api/authorization.go index b8f115a85b8..fda64e2b049 100644 --- a/pkg/services/ngalert/api/authorization.go +++ b/pkg/services/ngalert/api/authorization.go @@ -172,6 +172,16 @@ func (api *API) authorize(method, path string) web.Handler { case http.MethodPost + "/api/alertmanager/{DatasourceUID}/config/api/v1/receivers/test": eval = ac.EvalPermission(ac.ActionAlertingNotificationsExternalRead, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID"))) + case http.MethodGet + "/api/v1/ngalert": + // let user with any alerting permission access this API + eval = ac.EvalAny( + ac.EvalPermission(ac.ActionAlertingInstanceRead), + ac.EvalPermission(ac.ActionAlertingInstancesExternalRead), + ac.EvalPermission(ac.ActionAlertingRuleRead), + ac.EvalPermission(ac.ActionAlertingRuleExternalRead), + ac.EvalPermission(ac.ActionAlertingNotificationsRead), + ac.EvalPermission(ac.ActionAlertingNotificationsExternalRead), + ) // Raw Alertmanager Config Paths case http.MethodDelete + "/api/v1/ngalert/admin_config", http.MethodGet + "/api/v1/ngalert/admin_config", diff --git a/pkg/services/ngalert/api/authorization_test.go b/pkg/services/ngalert/api/authorization_test.go index 84b6bb06d46..d8b67290309 100644 --- a/pkg/services/ngalert/api/authorization_test.go +++ b/pkg/services/ngalert/api/authorization_test.go @@ -49,7 +49,7 @@ func TestAuthorize(t *testing.T) { } paths[p] = methods } - require.Len(t, paths, 39) + require.Len(t, paths, 40) ac := acmock.New() api := &API{AccessControl: ac} diff --git a/pkg/services/ngalert/api/configuration.go b/pkg/services/ngalert/api/configuration.go index 070025e51ea..7bc382c92ab 100644 --- a/pkg/services/ngalert/api/configuration.go +++ b/pkg/services/ngalert/api/configuration.go @@ -32,3 +32,7 @@ func (f *ConfigurationApiHandler) handleRoutePostNGalertConfig(c *models.ReqCont func (f *ConfigurationApiHandler) handleRouteDeleteNGalertConfig(c *models.ReqContext) response.Response { return f.grafana.RouteDeleteNGalertConfig(c) } + +func (f *ConfigurationApiHandler) handleRouteGetStatus(c *models.ReqContext) response.Response { + return f.grafana.RouteGetAlertingStatus(c) +} diff --git a/pkg/services/ngalert/api/generated_base_api_configuration.go b/pkg/services/ngalert/api/generated_base_api_configuration.go index d4b1788082e..8a8912b96b5 100644 --- a/pkg/services/ngalert/api/generated_base_api_configuration.go +++ b/pkg/services/ngalert/api/generated_base_api_configuration.go @@ -22,6 +22,7 @@ type ConfigurationApi interface { RouteDeleteNGalertConfig(*models.ReqContext) response.Response RouteGetAlertmanagers(*models.ReqContext) response.Response RouteGetNGalertConfig(*models.ReqContext) response.Response + RouteGetStatus(*models.ReqContext) response.Response RoutePostNGalertConfig(*models.ReqContext) response.Response } @@ -34,6 +35,9 @@ func (f *ConfigurationApiHandler) RouteGetAlertmanagers(ctx *models.ReqContext) func (f *ConfigurationApiHandler) RouteGetNGalertConfig(ctx *models.ReqContext) response.Response { return f.handleRouteGetNGalertConfig(ctx) } +func (f *ConfigurationApiHandler) RouteGetStatus(ctx *models.ReqContext) response.Response { + return f.handleRouteGetStatus(ctx) +} func (f *ConfigurationApiHandler) RoutePostNGalertConfig(ctx *models.ReqContext) response.Response { // Parse Request Body conf := apimodels.PostableNGalertConfig{} @@ -75,6 +79,16 @@ func (api *API) RegisterConfigurationApiEndpoints(srv ConfigurationApi, m *metri m, ), ) + group.Get( + toMacaronPath("/api/v1/ngalert"), + api.authorize(http.MethodGet, "/api/v1/ngalert"), + metrics.Instrument( + http.MethodGet, + "/api/v1/ngalert", + srv.RouteGetStatus, + m, + ), + ) group.Post( toMacaronPath("/api/v1/ngalert/admin_config"), api.authorize(http.MethodPost, "/api/v1/ngalert/admin_config"), diff --git a/pkg/services/ngalert/api/tooling/api.json b/pkg/services/ngalert/api/tooling/api.json index 678528e37ff..77f1f835b18 100644 --- a/pkg/services/ngalert/api/tooling/api.json +++ b/pkg/services/ngalert/api/tooling/api.json @@ -232,6 +232,19 @@ ], "type": "object" }, + "AlertingStatus": { + "properties": { + "alertmanagersChoice": { + "enum": [ + "all", + "internal", + "external" + ], + "type": "string" + } + }, + "type": "object" + }, "ApiRuleNode": { "properties": { "alert": { diff --git a/pkg/services/ngalert/api/tooling/definitions/admin.go b/pkg/services/ngalert/api/tooling/definitions/admin.go index 1bcfac172b4..b1adcf83541 100644 --- a/pkg/services/ngalert/api/tooling/definitions/admin.go +++ b/pkg/services/ngalert/api/tooling/definitions/admin.go @@ -4,6 +4,16 @@ import ( v1 "github.com/prometheus/client_golang/api/prometheus/v1" ) +// swagger:route GET /api/v1/ngalert configuration RouteGetStatus +// +// Get the status of the alerting engine +// +// Produces: +// - application/json +// +// Responses: +// 200: AlertingStatus + // swagger:route GET /api/v1/ngalert/alertmanagers configuration RouteGetAlertmanagers // // Get the discovered and dropped Alertmanagers of the user's organization based on the specified configuration. @@ -81,3 +91,8 @@ type GettableAlertmanagers struct { Status string `json:"status"` Data v1.AlertManagersResult `json:"data"` } + +// swagger:model +type AlertingStatus struct { + AlertmanagersChoice AlertmanagersChoice `json:"alertmanagersChoice"` +} diff --git a/pkg/services/ngalert/api/tooling/post.json b/pkg/services/ngalert/api/tooling/post.json index 9bc9ba32816..0489e9d3963 100644 --- a/pkg/services/ngalert/api/tooling/post.json +++ b/pkg/services/ngalert/api/tooling/post.json @@ -232,6 +232,19 @@ ], "type": "object" }, + "AlertingStatus": { + "properties": { + "alertmanagersChoice": { + "enum": [ + "all", + "internal", + "external" + ], + "type": "string" + } + }, + "type": "object" + }, "ApiRuleNode": { "properties": { "alert": { @@ -5558,6 +5571,26 @@ ] } }, + "/api/v1/ngalert": { + "get": { + "description": "Get the status of the alerting engine", + "operationId": "RouteGetStatus", + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "AlertingStatus", + "schema": { + "$ref": "#/definitions/AlertingStatus" + } + } + }, + "tags": [ + "configuration" + ] + } + }, "/api/v1/provisioning/alert-rules": { "post": { "consumes": [ diff --git a/pkg/services/ngalert/api/tooling/spec.json b/pkg/services/ngalert/api/tooling/spec.json index e3b5c12c0e0..e525d4d6707 100644 --- a/pkg/services/ngalert/api/tooling/spec.json +++ b/pkg/services/ngalert/api/tooling/spec.json @@ -1757,6 +1757,26 @@ } } }, + "/api/v1/ngalert": { + "get": { + "description": "Get the status of the alerting engine", + "produces": [ + "application/json" + ], + "tags": [ + "configuration" + ], + "operationId": "RouteGetStatus", + "responses": { + "200": { + "description": "AlertingStatus", + "schema": { + "$ref": "#/definitions/AlertingStatus" + } + } + } + } + }, "/api/v1/provisioning/alert-rules": { "post": { "consumes": [ @@ -2733,6 +2753,19 @@ } } }, + "AlertingStatus": { + "type": "object", + "properties": { + "alertmanagersChoice": { + "type": "string", + "enum": [ + "all", + "internal", + "external" + ] + } + } + }, "ApiRuleNode": { "type": "object", "properties": {