AlertingNG: base API implementation (#31824)
* AlertingNG: base API implementation * Pass the interface instead of the base impl * Ruler mock draft (WIP) * Update alerting-api dependency * Improve mock implementation
This commit is contained in:
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/schedule"
|
||||
@@ -38,6 +40,14 @@ type API struct {
|
||||
|
||||
// RegisterAPIEndpoints registers API handlers
|
||||
func (api *API) RegisterAPIEndpoints() {
|
||||
logger := log.New("ngalert.api")
|
||||
api.RegisterAlertmanagerApiEndpoints(AlertmanagerApiBase{log: logger})
|
||||
api.RegisterPermissionsApiEndpoints(PermissionsApiBase{log: logger})
|
||||
api.RegisterPrometheusApiEndpoints(PrometheusApiBase{log: logger})
|
||||
api.RegisterRulerApiEndpoints(RulerApiMock{log: logger})
|
||||
api.RegisterTestingApiEndpoints(TestingApiBase{log: logger})
|
||||
|
||||
// Legacy routes; they will be removed in v8
|
||||
api.RouteRegister.Group("/api/alert-definitions", func(alertDefinitions routing.RouteRegister) {
|
||||
alertDefinitions.Get("", middleware.ReqSignedIn, routing.Wrap(api.listAlertDefinitions))
|
||||
alertDefinitions.Get("/eval/:alertDefinitionUID", middleware.ReqSignedIn, api.validateOrgAlertDefinition, routing.Wrap(api.alertDefinitionEvalEndpoint))
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*Package api contains base API implementation of unified alerting
|
||||
*
|
||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
||||
*
|
||||
* Need to remove unused imports.
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-macaron/binding"
|
||||
apimodels "github.com/grafana/alerting-api/pkg/api"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type AlertmanagerApiService interface {
|
||||
RouteCreateSilence(*models.ReqContext, apimodels.SilenceBody) response.Response
|
||||
RouteDeleteAlertingConfig(*models.ReqContext) response.Response
|
||||
RouteDeleteSilence(*models.ReqContext) response.Response
|
||||
RouteGetAlertingConfig(*models.ReqContext) response.Response
|
||||
RouteGetAmAlertGroups(*models.ReqContext) response.Response
|
||||
RouteGetAmAlerts(*models.ReqContext) response.Response
|
||||
RouteGetSilence(*models.ReqContext) response.Response
|
||||
RouteGetSilences(*models.ReqContext) response.Response
|
||||
RoutePostAlertingConfig(*models.ReqContext, apimodels.UserConfig) response.Response
|
||||
RoutePostAmAlerts(*models.ReqContext, apimodels.PostableAlerts) response.Response
|
||||
}
|
||||
|
||||
type AlertmanagerApiBase struct {
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApiService) {
|
||||
api.RouteRegister.Group("", func(group routing.RouteRegister) {
|
||||
group.Post(toMacaronPath("/alertmanager/{DatasourceId}/api/v2/silences"), binding.Bind(apimodels.SilenceBody{}), routing.Wrap(srv.RouteCreateSilence))
|
||||
group.Delete(toMacaronPath("/alertmanager/{DatasourceId}/config/api/v1/alerts"), routing.Wrap(srv.RouteDeleteAlertingConfig))
|
||||
group.Delete(toMacaronPath("/alertmanager/{DatasourceId}/api/v2/silence/{SilenceId}"), routing.Wrap(srv.RouteDeleteSilence))
|
||||
group.Get(toMacaronPath("/alertmanager/{DatasourceId}/config/api/v1/alerts"), routing.Wrap(srv.RouteGetAlertingConfig))
|
||||
group.Get(toMacaronPath("/alertmanager/{DatasourceId}/api/v2/alerts/groups"), routing.Wrap(srv.RouteGetAmAlertGroups))
|
||||
group.Get(toMacaronPath("/alertmanager/{DatasourceId}/api/v2/alerts"), routing.Wrap(srv.RouteGetAmAlerts))
|
||||
group.Get(toMacaronPath("/alertmanager/{DatasourceId}/api/v2/silence/{SilenceId}"), routing.Wrap(srv.RouteGetSilence))
|
||||
group.Get(toMacaronPath("/alertmanager/{DatasourceId}/api/v2/silences"), routing.Wrap(srv.RouteGetSilences))
|
||||
group.Post(toMacaronPath("/alertmanager/{DatasourceId}/config/api/v1/alerts"), binding.Bind(apimodels.UserConfig{}), routing.Wrap(srv.RoutePostAlertingConfig))
|
||||
group.Post(toMacaronPath("/alertmanager/{DatasourceId}/api/v2/alerts"), binding.Bind(apimodels.PostableAlerts{}), routing.Wrap(srv.RoutePostAmAlerts))
|
||||
})
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteCreateSilence(c *models.ReqContext, body apimodels.SilenceBody) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteCreateSilence: ", "DatasourceId", datasourceId)
|
||||
base.log.Info("RouteCreateSilence: ", "body", body)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteDeleteAlertingConfig(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteDeleteAlertingConfig: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteDeleteSilence(c *models.ReqContext) response.Response {
|
||||
silenceId := c.Params(":SilenceId")
|
||||
base.log.Info("RouteDeleteSilence: ", "SilenceId", silenceId)
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteDeleteSilence: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetAlertingConfig(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetAlertingConfig: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetAmAlertGroups(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetAmAlertGroups: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetAmAlerts(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetAmAlerts: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetSilence(c *models.ReqContext) response.Response {
|
||||
silenceId := c.Params(":SilenceId")
|
||||
base.log.Info("RouteGetSilence: ", "SilenceId", silenceId)
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetSilence: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetSilences(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetSilences: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RoutePostAlertingConfig(c *models.ReqContext, body apimodels.UserConfig) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RoutePostAlertingConfig: ", "DatasourceId", datasourceId)
|
||||
base.log.Info("RoutePostAlertingConfig: ", "body", body)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RoutePostAmAlerts(c *models.ReqContext, body apimodels.PostableAlerts) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RoutePostAmAlerts: ", "DatasourceId", datasourceId)
|
||||
base.log.Info("RoutePostAmAlerts: ", "body", body)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*Package api contains base API implementation of unified alerting
|
||||
*
|
||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
||||
*
|
||||
* Need to remove unused imports.
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-macaron/binding"
|
||||
apimodels "github.com/grafana/alerting-api/pkg/api"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type PermissionsApiService interface {
|
||||
RouteGetNamespacePermissions(*models.ReqContext) response.Response
|
||||
RouteSetNamespacePermissions(*models.ReqContext, apimodels.Permissions) response.Response
|
||||
}
|
||||
|
||||
type PermissionsApiBase struct {
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (api *API) RegisterPermissionsApiEndpoints(srv PermissionsApiService) {
|
||||
api.RouteRegister.Group("", func(group routing.RouteRegister) {
|
||||
group.Get(toMacaronPath("/api/v1/namespace/{Namespace}/permissions"), routing.Wrap(srv.RouteGetNamespacePermissions))
|
||||
group.Post(toMacaronPath("/api/v1/namespace/{Namespace}/permissions"), binding.Bind(apimodels.Permissions{}), routing.Wrap(srv.RouteSetNamespacePermissions))
|
||||
})
|
||||
}
|
||||
|
||||
func (base PermissionsApiBase) RouteGetNamespacePermissions(c *models.ReqContext) response.Response {
|
||||
namespace := c.Params(":Namespace")
|
||||
base.log.Info("RouteGetNamespacePermissions: ", "Namespace", namespace)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base PermissionsApiBase) RouteSetNamespacePermissions(c *models.ReqContext, body apimodels.Permissions) response.Response {
|
||||
namespace := c.Params(":Namespace")
|
||||
base.log.Info("RouteSetNamespacePermissions: ", "Namespace", namespace)
|
||||
base.log.Info("RouteSetNamespacePermissions: ", "body", body)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*Package api contains base API implementation of unified alerting
|
||||
*
|
||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
||||
*
|
||||
* Need to remove unused imports.
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type PrometheusApiService interface {
|
||||
RouteGetAlertStatuses(*models.ReqContext) response.Response
|
||||
RouteGetRuleStatuses(*models.ReqContext) response.Response
|
||||
}
|
||||
|
||||
type PrometheusApiBase struct {
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (api *API) RegisterPrometheusApiEndpoints(srv PrometheusApiService) {
|
||||
api.RouteRegister.Group("", func(group routing.RouteRegister) {
|
||||
group.Get(toMacaronPath("/prometheus/{DatasourceId}/api/v1/alerts"), routing.Wrap(srv.RouteGetAlertStatuses))
|
||||
group.Get(toMacaronPath("/prometheus/{DatasourceId}/api/v1/rules"), routing.Wrap(srv.RouteGetRuleStatuses))
|
||||
})
|
||||
}
|
||||
|
||||
func (base PrometheusApiBase) RouteGetAlertStatuses(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetAlertStatuses: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base PrometheusApiBase) RouteGetRuleStatuses(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetRuleStatuses: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*Package api contains base API implementation of unified alerting
|
||||
*
|
||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
||||
*
|
||||
* Need to remove unused imports.
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-macaron/binding"
|
||||
apimodels "github.com/grafana/alerting-api/pkg/api"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type RulerApiService interface {
|
||||
RouteDeleteNamespaceRulesConfig(*models.ReqContext) response.Response
|
||||
RouteDeleteRuleGroupConfig(*models.ReqContext) response.Response
|
||||
RouteGetNamespaceRulesConfig(*models.ReqContext) response.Response
|
||||
RouteGetRulegGroupConfig(*models.ReqContext) response.Response
|
||||
RouteGetRulesConfig(*models.ReqContext) response.Response
|
||||
RoutePostNameRulesConfig(*models.ReqContext, apimodels.RuleGroupConfig) response.Response
|
||||
}
|
||||
|
||||
type RulerApiBase struct {
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (api *API) RegisterRulerApiEndpoints(srv RulerApiService) {
|
||||
api.RouteRegister.Group("", func(group routing.RouteRegister) {
|
||||
group.Delete(toMacaronPath("/ruler/{DatasourceId}/api/v1/rules/{Namespace}"), routing.Wrap(srv.RouteDeleteNamespaceRulesConfig))
|
||||
group.Delete(toMacaronPath("/ruler/{DatasourceId}/api/v1/rules/{Namespace}/{Groupname}"), routing.Wrap(srv.RouteDeleteRuleGroupConfig))
|
||||
group.Get(toMacaronPath("/ruler/{DatasourceId}/api/v1/rules/{Namespace}"), routing.Wrap(srv.RouteGetNamespaceRulesConfig))
|
||||
group.Get(toMacaronPath("/ruler/{DatasourceId}/api/v1/rules/{Namespace}/{Groupname}"), routing.Wrap(srv.RouteGetRulegGroupConfig))
|
||||
group.Get(toMacaronPath("/ruler/{DatasourceId}/api/v1/rules"), routing.Wrap(srv.RouteGetRulesConfig))
|
||||
group.Post(toMacaronPath("/ruler/{DatasourceId}/api/v1/rules/{Namespace}"), binding.Bind(apimodels.RuleGroupConfig{}), routing.Wrap(srv.RoutePostNameRulesConfig))
|
||||
})
|
||||
}
|
||||
|
||||
func (base RulerApiBase) RouteDeleteNamespaceRulesConfig(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteDeleteNamespaceRulesConfig: ", "DatasourceId", datasourceId)
|
||||
namespace := c.Params(":Namespace")
|
||||
base.log.Info("RouteDeleteNamespaceRulesConfig: ", "Namespace", namespace)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base RulerApiBase) RouteDeleteRuleGroupConfig(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteDeleteRuleGroupConfig: ", "DatasourceId", datasourceId)
|
||||
namespace := c.Params(":Namespace")
|
||||
base.log.Info("RouteDeleteRuleGroupConfig: ", "Namespace", namespace)
|
||||
groupname := c.Params(":Groupname")
|
||||
base.log.Info("RouteDeleteRuleGroupConfig: ", "Groupname", groupname)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base RulerApiBase) RouteGetNamespaceRulesConfig(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetNamespaceRulesConfig: ", "DatasourceId", datasourceId)
|
||||
namespace := c.Params(":Namespace")
|
||||
base.log.Info("RouteGetNamespaceRulesConfig: ", "Namespace", namespace)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base RulerApiBase) RouteGetRulegGroupConfig(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetRulegGroupConfig: ", "DatasourceId", datasourceId)
|
||||
namespace := c.Params(":Namespace")
|
||||
base.log.Info("RouteGetRulegGroupConfig: ", "Namespace", namespace)
|
||||
groupname := c.Params(":Groupname")
|
||||
base.log.Info("RouteGetRulegGroupConfig: ", "Groupname", groupname)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base RulerApiBase) RouteGetRulesConfig(c *models.ReqContext) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RouteGetRulesConfig: ", "DatasourceId", datasourceId)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base RulerApiBase) RoutePostNameRulesConfig(c *models.ReqContext, body apimodels.RuleGroupConfig) response.Response {
|
||||
datasourceId := c.Params(":DatasourceId")
|
||||
base.log.Info("RoutePostNameRulesConfig: ", "DatasourceId", datasourceId)
|
||||
namespace := c.Params(":Namespace")
|
||||
base.log.Info("RoutePostNameRulesConfig: ", "Namespace", namespace)
|
||||
base.log.Info("RoutePostNameRulesConfig: ", "body", body)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*Package api contains mock API implementation of unified alerting
|
||||
*
|
||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
||||
*
|
||||
* Need to remove unused imports.
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
apimodels "github.com/grafana/alerting-api/pkg/api"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
var prometheusAlert = []ngmodels.AlertQuery{
|
||||
{
|
||||
Model: json.RawMessage(`{
|
||||
"datasource": "gdev-prometheus",
|
||||
"datasourceUid": "000000002",
|
||||
"expr": "http_request_duration_microseconds_count",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
"intervalMs": 1000,
|
||||
"legendFormat": "",
|
||||
"maxDataPoints": 100,
|
||||
"refId": "query"
|
||||
}`),
|
||||
RefID: "query",
|
||||
RelativeTimeRange: ngmodels.RelativeTimeRange{
|
||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||
},
|
||||
},
|
||||
{
|
||||
Model: json.RawMessage(`{
|
||||
"datasource": "__expr__",
|
||||
"datasourceUid": "-100",
|
||||
"expression": "query",
|
||||
"hide": false,
|
||||
"intervalMs": 1000,
|
||||
"maxDataPoints": 100,
|
||||
"reducer": "mean",
|
||||
"refId": "reduced",
|
||||
"type": "reduce"
|
||||
}`),
|
||||
RefID: "reduced",
|
||||
RelativeTimeRange: ngmodels.RelativeTimeRange{
|
||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||
},
|
||||
},
|
||||
{
|
||||
Model: json.RawMessage(`{
|
||||
"datasource": "__expr__",
|
||||
"datasourceUid": "-100",
|
||||
"expression": "$reduced > 10",
|
||||
"hide": false,
|
||||
"intervalMs": 1000,
|
||||
"maxDataPoints": 100,
|
||||
"refId": "condition",
|
||||
"type": "math"
|
||||
}`),
|
||||
RefID: "condition",
|
||||
RelativeTimeRange: ngmodels.RelativeTimeRange{
|
||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var testAlert = []ngmodels.AlertQuery{
|
||||
{
|
||||
Model: json.RawMessage(`{
|
||||
"alias": "just-testing",
|
||||
"datasource": "000000004",
|
||||
"datasourceUid": "000000004",
|
||||
"intervalMs": 1000,
|
||||
"maxDataPoints": 100,
|
||||
"orgId": 0,
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "1,20,90,30,5,0"
|
||||
}`),
|
||||
RefID: "A",
|
||||
RelativeTimeRange: ngmodels.RelativeTimeRange{
|
||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||
},
|
||||
},
|
||||
{
|
||||
Model: json.RawMessage(`{
|
||||
"datasource": "__expr__",
|
||||
"datasourceUid": "__expr__",
|
||||
"expression": "$A",
|
||||
"intervalMs": 2000,
|
||||
"maxDataPoints": 200,
|
||||
"orgId": 0,
|
||||
"reducer": "mean",
|
||||
"refId": "B",
|
||||
"type": "reduce"
|
||||
}`),
|
||||
RefID: "B",
|
||||
RelativeTimeRange: ngmodels.RelativeTimeRange{
|
||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type RulerApiMock struct {
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (mock RulerApiMock) RouteDeleteNamespaceRulesConfig(c *models.ReqContext) response.Response {
|
||||
datasourceID := c.Params(":DatasourceId")
|
||||
mock.log.Info("RouteDeleteNamespaceRulesConfig: ", "DatasourceId", datasourceID)
|
||||
namespace := c.Params(":Namespace")
|
||||
mock.log.Info("RouteDeleteNamespaceRulesConfig: ", "Namespace", namespace)
|
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "namespace rules deleted"})
|
||||
}
|
||||
|
||||
func (mock RulerApiMock) RouteDeleteRuleGroupConfig(c *models.ReqContext) response.Response {
|
||||
datasourceID := c.Params(":DatasourceId")
|
||||
mock.log.Info("RouteDeleteRuleGroupConfig: ", "DatasourceId", datasourceID)
|
||||
namespace := c.Params(":Namespace")
|
||||
mock.log.Info("RouteDeleteRuleGroupConfig: ", "Namespace", namespace)
|
||||
groupname := c.Params(":Groupname")
|
||||
mock.log.Info("RouteDeleteRuleGroupConfig: ", "Groupname", groupname)
|
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "rule group deleted"})
|
||||
}
|
||||
|
||||
func (mock RulerApiMock) RouteGetNamespaceRulesConfig(c *models.ReqContext) response.Response {
|
||||
datasourceID := c.Params(":DatasourceId")
|
||||
mock.log.Info("RouteGetNamespaceRulesConfig: ", "DatasourceId", datasourceID)
|
||||
namespace := c.Params(":Namespace")
|
||||
mock.log.Info("RouteGetNamespaceRulesConfig: ", "Namespace", namespace)
|
||||
result := apimodels.NamespaceConfigResponse{
|
||||
namespace: []apimodels.RuleGroupConfig{
|
||||
{
|
||||
Name: "group1",
|
||||
Interval: 60,
|
||||
Rules: []apimodels.ExtendedRuleNode{
|
||||
{
|
||||
GrafanaManagedAlert: &apimodels.ExtendedUpsertAlertDefinitionCommand{
|
||||
NoDataState: apimodels.NoData,
|
||||
ExecutionErrorState: apimodels.AlertingErrState,
|
||||
UpdateAlertDefinitionCommand: ngmodels.UpdateAlertDefinitionCommand{
|
||||
UID: "UID",
|
||||
OrgID: 1,
|
||||
Title: "rule 1-1",
|
||||
Condition: "condition",
|
||||
Data: prometheusAlert,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
GrafanaManagedAlert: &apimodels.ExtendedUpsertAlertDefinitionCommand{
|
||||
NoDataState: apimodels.NoData,
|
||||
ExecutionErrorState: apimodels.AlertingErrState,
|
||||
UpdateAlertDefinitionCommand: ngmodels.UpdateAlertDefinitionCommand{
|
||||
UID: "UID",
|
||||
OrgID: 1,
|
||||
Title: "rule 1-2",
|
||||
Condition: "B",
|
||||
Data: testAlert,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return response.JSON(http.StatusAccepted, result)
|
||||
}
|
||||
|
||||
func (mock RulerApiMock) RouteGetRulegGroupConfig(c *models.ReqContext) response.Response {
|
||||
datasourceID := c.Params(":DatasourceId")
|
||||
mock.log.Info("RouteGetRulegGroupConfig: ", "DatasourceId", datasourceID)
|
||||
namespace := c.Params(":Namespace")
|
||||
mock.log.Info("RouteGetRulegGroupConfig: ", "Namespace", namespace)
|
||||
groupname := c.Params(":Groupname")
|
||||
mock.log.Info("RouteGetRulegGroupConfig: ", "Groupname", groupname)
|
||||
result := apimodels.RuleGroupConfigResponse{
|
||||
RuleGroupConfig: apimodels.RuleGroupConfig{
|
||||
Name: groupname,
|
||||
Interval: 60,
|
||||
Rules: []apimodels.ExtendedRuleNode{
|
||||
{
|
||||
GrafanaManagedAlert: &apimodels.ExtendedUpsertAlertDefinitionCommand{
|
||||
NoDataState: apimodels.NoData,
|
||||
ExecutionErrorState: apimodels.AlertingErrState,
|
||||
UpdateAlertDefinitionCommand: ngmodels.UpdateAlertDefinitionCommand{
|
||||
UID: "UID",
|
||||
OrgID: 1,
|
||||
Title: "something completely different",
|
||||
Condition: "A",
|
||||
Data: testAlert,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return response.JSON(http.StatusAccepted, result)
|
||||
}
|
||||
|
||||
func (mock RulerApiMock) RouteGetRulesConfig(c *models.ReqContext) response.Response {
|
||||
datasourceID := c.Params(":DatasourceId")
|
||||
mock.log.Info("RouteGetRulesConfig: ", "DatasourceId", datasourceID)
|
||||
result := apimodels.NamespaceConfigResponse{
|
||||
"namespace1": []apimodels.RuleGroupConfig{
|
||||
{
|
||||
Name: "group1",
|
||||
Interval: 60,
|
||||
Rules: []apimodels.ExtendedRuleNode{
|
||||
{
|
||||
GrafanaManagedAlert: &apimodels.ExtendedUpsertAlertDefinitionCommand{
|
||||
NoDataState: apimodels.NoData,
|
||||
ExecutionErrorState: apimodels.AlertingErrState,
|
||||
UpdateAlertDefinitionCommand: ngmodels.UpdateAlertDefinitionCommand{
|
||||
UID: "UID",
|
||||
OrgID: 1,
|
||||
Title: "rule 1-1",
|
||||
Condition: "A",
|
||||
Data: testAlert,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
GrafanaManagedAlert: &apimodels.ExtendedUpsertAlertDefinitionCommand{
|
||||
NoDataState: apimodels.NoData,
|
||||
ExecutionErrorState: apimodels.AlertingErrState,
|
||||
UpdateAlertDefinitionCommand: ngmodels.UpdateAlertDefinitionCommand{
|
||||
UID: "UID",
|
||||
OrgID: 1,
|
||||
Title: "rule 1-2",
|
||||
Condition: "A",
|
||||
Data: testAlert,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "group2",
|
||||
Interval: 60,
|
||||
Rules: []apimodels.ExtendedRuleNode{
|
||||
{
|
||||
GrafanaManagedAlert: &apimodels.ExtendedUpsertAlertDefinitionCommand{
|
||||
NoDataState: apimodels.NoData,
|
||||
ExecutionErrorState: apimodels.AlertingErrState,
|
||||
UpdateAlertDefinitionCommand: ngmodels.UpdateAlertDefinitionCommand{
|
||||
UID: "UID",
|
||||
OrgID: 1,
|
||||
Title: "rule 2-1",
|
||||
Condition: "A",
|
||||
Data: prometheusAlert,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
GrafanaManagedAlert: &apimodels.ExtendedUpsertAlertDefinitionCommand{
|
||||
NoDataState: apimodels.NoData,
|
||||
ExecutionErrorState: apimodels.AlertingErrState,
|
||||
UpdateAlertDefinitionCommand: ngmodels.UpdateAlertDefinitionCommand{
|
||||
UID: "UID",
|
||||
OrgID: 1,
|
||||
Title: "rule 2-2",
|
||||
Condition: "A",
|
||||
Data: testAlert,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return response.JSON(http.StatusAccepted, result)
|
||||
}
|
||||
|
||||
func (mock RulerApiMock) RoutePostNameRulesConfig(c *models.ReqContext, body apimodels.RuleGroupConfig) response.Response {
|
||||
datasourceID := c.Params(":DatasourceId")
|
||||
mock.log.Info("RoutePostNameRulesConfig: ", "DatasourceId", datasourceID)
|
||||
namespace := c.Params(":Namespace")
|
||||
mock.log.Info("RoutePostNameRulesConfig: ", "Namespace", namespace)
|
||||
mock.log.Info("RoutePostNameRulesConfig: ", "body", body)
|
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "namespace rules created"})
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*Package api contains base API implementation of unified alerting
|
||||
*
|
||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
||||
*
|
||||
* Need to remove unused imports.
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-macaron/binding"
|
||||
apimodels "github.com/grafana/alerting-api/pkg/api"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type TestingApiService interface {
|
||||
RouteTestReceiverConfig(*models.ReqContext, apimodels.ExtendedReceiver) response.Response
|
||||
RouteTestRuleConfig(*models.ReqContext, apimodels.TestRulePayload) response.Response
|
||||
}
|
||||
|
||||
type TestingApiBase struct {
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (api *API) RegisterTestingApiEndpoints(srv TestingApiService) {
|
||||
api.RouteRegister.Group("", func(group routing.RouteRegister) {
|
||||
group.Get(toMacaronPath("/api/v1/receiver/test"), binding.Bind(apimodels.ExtendedReceiver{}), routing.Wrap(srv.RouteTestReceiverConfig))
|
||||
group.Get(toMacaronPath("/api/v1/rule/test"), binding.Bind(apimodels.TestRulePayload{}), routing.Wrap(srv.RouteTestRuleConfig))
|
||||
})
|
||||
}
|
||||
|
||||
func (base TestingApiBase) RouteTestReceiverConfig(c *models.ReqContext, body apimodels.ExtendedReceiver) response.Response {
|
||||
base.log.Info("RouteTestReceiverConfig: ", "body", body)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base TestingApiBase) RouteTestRuleConfig(c *models.ReqContext, body apimodels.TestRulePayload) response.Response {
|
||||
base.log.Info("RouteTestRuleConfig: ", "body", body)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
swagger-codegen-api:
|
||||
swagger-codegen generate -v \
|
||||
-i https://grafana.github.io/alerting-api/post.json \
|
||||
-l go-server \
|
||||
-Dapis \
|
||||
-o ../ \
|
||||
--additional-properties packageName=api \
|
||||
-t ./templates \
|
||||
# --import-mappings eval.RelativeTimeRange="github.com/grafana/grafana/pkg/services/ngalert/eval" \
|
||||
# --type-mappings RelativeTimeRange=eval.RelativeTimeRange
|
||||
|
||||
copy-files:
|
||||
python move-and-rename.py
|
||||
|
||||
fix:
|
||||
sed -i -e 's/apimodels\.\[\]PostableAlert/apimodels.PostableAlerts/' ../go/*.go
|
||||
sed -i -e 's/apimodels\.\[\]UpdateDashboardAclCommand/apimodels.Permissions/' ../go/*.go
|
||||
goimports -w -v ../go/*.go
|
||||
rm ../go/*.go-e
|
||||
|
||||
clean:
|
||||
rm -rf ../go
|
||||
|
||||
all: swagger-codegen-api fix copy-files clean
|
||||
@@ -0,0 +1,7 @@
|
||||
import os
|
||||
path = '../go'
|
||||
files = os.listdir(path)
|
||||
dest_dir = "../"
|
||||
|
||||
for index, file in enumerate(files):
|
||||
os.rename(os.path.join(path, file), os.path.join(dest_dir, ''.join([file.split('.')[0], '_base.go'])))
|
||||
@@ -0,0 +1,38 @@
|
||||
{{>partial_header}}
|
||||
package {{packageName}}
|
||||
|
||||
{{#operations}}
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-macaron/binding"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
apimodels "github.com/grafana/alerting-api/pkg/api"
|
||||
)
|
||||
|
||||
type {{classname}}Service interface { {{#operation}}
|
||||
{{nickname}}(*models.ReqContext{{#bodyParams}}, apimodels.{{dataType}}{{/bodyParams}}) response.Response{{/operation}}
|
||||
}
|
||||
|
||||
type {{classname}}Base struct {
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (api *API) Register{{classname}}Endpoints(srv {{classname}}Service) {
|
||||
api.RouteRegister.Group("", func(group routing.RouteRegister){ {{#operations}}{{#operation}}
|
||||
group.{{httpMethod}}(toMacaronPath("{{{path}}}"){{#bodyParams}}, binding.Bind(apimodels.{{dataType}}{}){{/bodyParams}}, routing.Wrap(srv.{{nickname}})){{/operation}}{{/operations}}
|
||||
})
|
||||
}{{#operation}}
|
||||
|
||||
|
||||
func (base {{classname}}Base) {{nickname}}(c *models.ReqContext{{#bodyParams}}, {{paramName}} apimodels.{{dataType}}{{/bodyParams}}) response.Response { {{#pathParams}}
|
||||
{{paramName}} := c.Params(":{{baseName}}")
|
||||
base.log.Info("{{nickname}}: ", "{{baseName}}", {{paramName}}){{/pathParams}}{{#bodyParams}}
|
||||
base.log.Info("{{nickname}}: ", "{{baseName}}", {{paramName}}){{/bodyParams}}
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}{{/operation}}{{/operations}}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/*Package api contains base API implementation of unified alerting
|
||||
*
|
||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
||||
*
|
||||
* Need to remove unused imports.
|
||||
*/
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "group42",
|
||||
"interval": "10s",
|
||||
"rules": [
|
||||
{
|
||||
"expr": "",
|
||||
"grafana_alert": {
|
||||
"title": "something completely different",
|
||||
"condition": "A",
|
||||
"data": [
|
||||
{
|
||||
"refId": "A",
|
||||
"queryType": "",
|
||||
"relativeTimeRange": {
|
||||
"from": 18000,
|
||||
"to": 10800
|
||||
},
|
||||
"model": {
|
||||
"datasource": "__expr__",
|
||||
"type": "math",
|
||||
"expression": "2 + 2 > 1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"no_data_state": "NoData",
|
||||
"exec_err_state": "Alerting"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var searchRegex = regexp.MustCompile(`\{(\w+)\}`)
|
||||
|
||||
func toMacaronPath(path string) string {
|
||||
return string(searchRegex.ReplaceAllFunc([]byte(path), func(s []byte) []byte {
|
||||
m := string(s[1 : len(s)-1])
|
||||
return []byte(fmt.Sprintf(":%s", m))
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestToMacaronPath(t *testing.T) {
|
||||
testCases := []struct {
|
||||
inputPath string
|
||||
expectedOutputPath string
|
||||
}{
|
||||
{
|
||||
inputPath: "",
|
||||
expectedOutputPath: "",
|
||||
},
|
||||
{
|
||||
inputPath: "/ruler/{DatasourceId}/api/v1/rules/{Namespace}/{Groupname}",
|
||||
expectedOutputPath: "/ruler/:DatasourceId/api/v1/rules/:Namespace/:Groupname",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
outputPath := toMacaronPath(tc.inputPath)
|
||||
assert.Equal(t, tc.expectedOutputPath, outputPath)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user