The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/pkg/services/ngalert/api.go

177 lines
6.6 KiB

package ngalert
import (
"github.com/go-macaron/binding"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/util"
)
func (ng *AlertNG) registerAPIEndpoints() {
ng.RouteRegister.Group("/api/alert-definitions", func(alertDefinitions routing.RouteRegister) {
alertDefinitions.Get("", middleware.ReqSignedIn, routing.Wrap(ng.listAlertDefinitions))
alertDefinitions.Get("/eval/:alertDefinitionUID", ng.validateOrgAlertDefinition, routing.Wrap(ng.alertDefinitionEvalEndpoint))
alertDefinitions.Post("/eval", middleware.ReqSignedIn, binding.Bind(evalAlertConditionCommand{}), routing.Wrap(ng.conditionEvalEndpoint))
alertDefinitions.Get("/:alertDefinitionUID", ng.validateOrgAlertDefinition, routing.Wrap(ng.getAlertDefinitionEndpoint))
alertDefinitions.Delete("/:alertDefinitionUID", ng.validateOrgAlertDefinition, routing.Wrap(ng.deleteAlertDefinitionEndpoint))
alertDefinitions.Post("/", middleware.ReqSignedIn, binding.Bind(saveAlertDefinitionCommand{}), routing.Wrap(ng.createAlertDefinitionEndpoint))
alertDefinitions.Put("/:alertDefinitionUID", ng.validateOrgAlertDefinition, binding.Bind(updateAlertDefinitionCommand{}), routing.Wrap(ng.updateAlertDefinitionEndpoint))
})
ng.RouteRegister.Group("/api/ngalert/", func(schedulerRouter routing.RouteRegister) {
schedulerRouter.Post("/pause", routing.Wrap(ng.pauseScheduler))
schedulerRouter.Post("/unpause", routing.Wrap(ng.unpauseScheduler))
}, middleware.ReqOrgAdmin)
}
// conditionEvalEndpoint handles POST /api/alert-definitions/eval.
func (ng *AlertNG) conditionEvalEndpoint(c *models.ReqContext, dto evalAlertConditionCommand) response.Response {
if err := ng.validateCondition(dto.Condition, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
evalResults, err := eval.ConditionEval(&dto.Condition, timeNow())
if err != nil {
return response.Error(400, "Failed to evaluate conditions", err)
}
frame := evalResults.AsDataFrame()
df := tsdb.NewDecodedDataFrames([]*data.Frame{&frame})
instances, err := df.Encoded()
if err != nil {
return response.Error(400, "Failed to encode result dataframes", err)
}
return response.JSON(200, util.DynMap{
"instances": instances,
})
}
// alertDefinitionEvalEndpoint handles GET /api/alert-definitions/eval/:alertDefinitionUID.
func (ng *AlertNG) alertDefinitionEvalEndpoint(c *models.ReqContext) response.Response {
alertDefinitionUID := c.Params(":alertDefinitionUID")
condition, err := ng.LoadAlertCondition(alertDefinitionUID, c.SignedInUser.OrgId)
if err != nil {
return response.Error(400, "Failed to load alert definition conditions", err)
}
if err := ng.validateCondition(*condition, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
evalResults, err := eval.ConditionEval(condition, timeNow())
if err != nil {
return response.Error(400, "Failed to evaluate alert", err)
}
frame := evalResults.AsDataFrame()
df := tsdb.NewDecodedDataFrames([]*data.Frame{&frame})
if err != nil {
return response.Error(400, "Failed to instantiate Dataframes from the decoded frames", err)
}
instances, err := df.Encoded()
if err != nil {
return response.Error(400, "Failed to encode result dataframes", err)
}
return response.JSON(200, util.DynMap{
"instances": instances,
})
}
// getAlertDefinitionEndpoint handles GET /api/alert-definitions/:alertDefinitionUID.
func (ng *AlertNG) getAlertDefinitionEndpoint(c *models.ReqContext) response.Response {
alertDefinitionUID := c.Params(":alertDefinitionUID")
query := getAlertDefinitionByUIDQuery{
UID: alertDefinitionUID,
OrgID: c.SignedInUser.OrgId,
}
if err := ng.getAlertDefinitionByUID(&query); err != nil {
return response.Error(500, "Failed to get alert definition", err)
}
return response.JSON(200, &query.Result)
}
// deleteAlertDefinitionEndpoint handles DELETE /api/alert-definitions/:alertDefinitionUID.
func (ng *AlertNG) deleteAlertDefinitionEndpoint(c *models.ReqContext) response.Response {
alertDefinitionUID := c.Params(":alertDefinitionUID")
cmd := deleteAlertDefinitionByUIDCommand{
UID: alertDefinitionUID,
OrgID: c.SignedInUser.OrgId,
}
if err := ng.deleteAlertDefinitionByUID(&cmd); err != nil {
return response.Error(500, "Failed to delete alert definition", err)
}
return response.Success("Alert definition deleted")
}
// updateAlertDefinitionEndpoint handles PUT /api/alert-definitions/:alertDefinitionUID.
func (ng *AlertNG) updateAlertDefinitionEndpoint(c *models.ReqContext, cmd updateAlertDefinitionCommand) response.Response {
cmd.UID = c.Params(":alertDefinitionUID")
cmd.OrgID = c.SignedInUser.OrgId
if err := ng.validateCondition(cmd.Condition, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
if err := ng.updateAlertDefinition(&cmd); err != nil {
return response.Error(500, "Failed to update alert definition", err)
}
return response.JSON(200, cmd.Result)
}
// createAlertDefinitionEndpoint handles POST /api/alert-definitions.
func (ng *AlertNG) createAlertDefinitionEndpoint(c *models.ReqContext, cmd saveAlertDefinitionCommand) response.Response {
cmd.OrgID = c.SignedInUser.OrgId
if err := ng.validateCondition(cmd.Condition, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
if err := ng.saveAlertDefinition(&cmd); err != nil {
return response.Error(500, "Failed to create alert definition", err)
}
return response.JSON(200, cmd.Result)
}
// listAlertDefinitions handles GET /api/alert-definitions.
func (ng *AlertNG) listAlertDefinitions(c *models.ReqContext) response.Response {
query := listAlertDefinitionsQuery{OrgID: c.SignedInUser.OrgId}
if err := ng.getOrgAlertDefinitions(&query); err != nil {
return response.Error(500, "Failed to list alert definitions", err)
}
return response.JSON(200, util.DynMap{"results": query.Result})
}
func (ng *AlertNG) pauseScheduler() response.Response {
err := ng.schedule.pause()
if err != nil {
return response.Error(500, "Failed to pause scheduler", err)
}
return response.JSON(200, util.DynMap{"message": "alert definition scheduler paused"})
}
func (ng *AlertNG) unpauseScheduler() response.Response {
err := ng.schedule.unpause()
if err != nil {
return response.Error(500, "Failed to unpause scheduler", err)
}
return response.JSON(200, util.DynMap{"message": "alert definition scheduler unpaused"})
}