AlertingNG: Modify queries and transform endpoint to get datasource UIDs (#30297)

* Pass skipCache from context

* Use macaron Params instead of ParamsEscape for UIDs

* Modify queries and transform to get datasource UIDs

* Update github.com/grafana/grafana-plugin-sdk-go to v0.83.0
This commit is contained in:
Sofia Papagiannaki
2021-01-15 18:33:50 +02:00
committed by GitHub
parent edb7f2280b
commit 2b15581339
9 changed files with 128 additions and 104 deletions
+8 -8
View File
@@ -31,7 +31,7 @@ func (ng *AlertNG) registerAPIEndpoints() {
// 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); err != nil {
if err := ng.validateCondition(dto.Condition, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
@@ -54,14 +54,14 @@ func (ng *AlertNG) conditionEvalEndpoint(c *models.ReqContext, dto evalAlertCond
// alertDefinitionEvalEndpoint handles GET /api/alert-definitions/eval/:alertDefinitionUID.
func (ng *AlertNG) alertDefinitionEvalEndpoint(c *models.ReqContext) response.Response {
alertDefinitionUID := c.ParamsEscape(":alertDefinitionUID")
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); err != nil {
if err := ng.validateCondition(*condition, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
@@ -87,7 +87,7 @@ func (ng *AlertNG) alertDefinitionEvalEndpoint(c *models.ReqContext) response.Re
// getAlertDefinitionEndpoint handles GET /api/alert-definitions/:alertDefinitionUID.
func (ng *AlertNG) getAlertDefinitionEndpoint(c *models.ReqContext) response.Response {
alertDefinitionUID := c.ParamsEscape(":alertDefinitionUID")
alertDefinitionUID := c.Params(":alertDefinitionUID")
query := getAlertDefinitionByUIDQuery{
UID: alertDefinitionUID,
@@ -103,7 +103,7 @@ func (ng *AlertNG) getAlertDefinitionEndpoint(c *models.ReqContext) response.Res
// deleteAlertDefinitionEndpoint handles DELETE /api/alert-definitions/:alertDefinitionUID.
func (ng *AlertNG) deleteAlertDefinitionEndpoint(c *models.ReqContext) response.Response {
alertDefinitionUID := c.ParamsEscape(":alertDefinitionUID")
alertDefinitionUID := c.Params(":alertDefinitionUID")
cmd := deleteAlertDefinitionByUIDCommand{
UID: alertDefinitionUID,
@@ -119,10 +119,10 @@ func (ng *AlertNG) deleteAlertDefinitionEndpoint(c *models.ReqContext) response.
// updateAlertDefinitionEndpoint handles PUT /api/alert-definitions/:alertDefinitionUID.
func (ng *AlertNG) updateAlertDefinitionEndpoint(c *models.ReqContext, cmd updateAlertDefinitionCommand) response.Response {
cmd.UID = c.ParamsEscape(":alertDefinitionUID")
cmd.UID = c.Params(":alertDefinitionUID")
cmd.OrgID = c.SignedInUser.OrgId
if err := ng.validateCondition(cmd.Condition, c.SignedInUser); err != nil {
if err := ng.validateCondition(cmd.Condition, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
@@ -137,7 +137,7 @@ func (ng *AlertNG) updateAlertDefinitionEndpoint(c *models.ReqContext, cmd updat
func (ng *AlertNG) createAlertDefinitionEndpoint(c *models.ReqContext, cmd saveAlertDefinitionCommand) response.Response {
cmd.OrgID = c.SignedInUser.OrgId
if err := ng.validateCondition(cmd.Condition, c.SignedInUser); err != nil {
if err := ng.validateCondition(cmd.Condition, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
+13 -13
View File
@@ -68,12 +68,12 @@ type AlertQuery struct {
// RelativeTimeRange is the relative Start and End of the query as sent by the frontend.
RelativeTimeRange RelativeTimeRange `json:"relativeTimeRange"`
DatasourceID int64 `json:"-"`
DatasourceUID string `json:"-"`
// JSON is the raw JSON query and includes the above properties as well as custom properties.
Model json.RawMessage `json:"model"`
modelProps map[string]interface{} `json:"-"`
modelProps map[string]interface{}
}
func (aq *AlertQuery) setModelProps() error {
@@ -102,20 +102,20 @@ func (aq *AlertQuery) setDatasource() error {
}
if dsName == expr.DatasourceName {
aq.DatasourceID = expr.DatasourceID
aq.modelProps["datasourceId"] = expr.DatasourceID
aq.DatasourceUID = expr.DatasourceUID
aq.modelProps["datasourceUid"] = expr.DatasourceUID
return nil
}
i, ok := aq.modelProps["datasourceId"]
i, ok := aq.modelProps["datasourceUid"]
if !ok {
return fmt.Errorf("failed to get datasourceId from query model")
return fmt.Errorf("failed to get datasourceUid from query model")
}
dsID, ok := i.(float64)
dsUID, ok := i.(string)
if !ok {
return fmt.Errorf("failed to cast datasourceId to float64: %v", i)
return fmt.Errorf("failed to cast datasourceUid to string: %v", i)
}
aq.DatasourceID = int64(dsID)
aq.DatasourceUID = dsUID
return nil
}
@@ -125,7 +125,7 @@ func (aq *AlertQuery) IsExpression() (bool, error) {
if err != nil {
return false, err
}
return aq.DatasourceID == expr.DatasourceID, nil
return aq.DatasourceUID == expr.DatasourceUID, nil
}
// setMaxDatapoints sets the model maxDataPoints if it's missing or invalid
@@ -206,12 +206,12 @@ func (aq *AlertQuery) getIntervalDuration() (time.Duration, error) {
}
// GetDatasource returns the query datasource identifier.
func (aq *AlertQuery) GetDatasource() (int64, error) {
func (aq *AlertQuery) GetDatasource() (string, error) {
err := aq.setDatasource()
if err != nil {
return 0, err
return "", err
}
return aq.DatasourceID, nil
return aq.DatasourceUID, nil
}
func (aq *AlertQuery) getModel() ([]byte, error) {
+60 -59
View File
@@ -13,14 +13,14 @@ import (
func TestAlertQuery(t *testing.T) {
testCases := []struct {
desc string
alertQuery AlertQuery
expectedIsExpression bool
expectedDatasource string
expectedDatasourceID int64
expectedMaxPoints int64
expectedIntervalMS int64
err error
desc string
alertQuery AlertQuery
expectedIsExpression bool
expectedDatasource string
expectedDatasourceUID string
expectedMaxPoints int64
expectedIntervalMS int64
err error
}{
{
desc: "given an expression query",
@@ -32,11 +32,11 @@ func TestAlertQuery(t *testing.T) {
"extraParam": "some text"
}`),
},
expectedIsExpression: true,
expectedDatasource: expr.DatasourceName,
expectedDatasourceID: int64(expr.DatasourceID),
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: true,
expectedDatasource: expr.DatasourceName,
expectedDatasourceUID: expr.DatasourceUID,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query",
@@ -44,16 +44,16 @@ func TestAlertQuery(t *testing.T) {
RefID: "A",
Model: json.RawMessage(`{
"datasource": "my datasource",
"datasourceId": 1,
"datasourceUid": "000000001",
"queryType": "metricQuery",
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceID: 1,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with valid maxDataPoints",
@@ -61,17 +61,17 @@ func TestAlertQuery(t *testing.T) {
RefID: "A",
Model: json.RawMessage(`{
"datasource": "my datasource",
"datasourceId": 1,
"datasourceUid": "000000001",
"queryType": "metricQuery",
"maxDataPoints": 200,
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceID: 1,
expectedMaxPoints: 200,
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceUID: "000000001",
expectedMaxPoints: 200,
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with invalid maxDataPoints",
@@ -79,17 +79,17 @@ func TestAlertQuery(t *testing.T) {
RefID: "A",
Model: json.RawMessage(`{
"datasource": "my datasource",
"datasourceId": 1,
"datasourceUid": "000000001",
"queryType": "metricQuery",
"maxDataPoints": "invalid",
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceID: 1,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with zero maxDataPoints",
@@ -97,17 +97,17 @@ func TestAlertQuery(t *testing.T) {
RefID: "A",
Model: json.RawMessage(`{
"datasource": "my datasource",
"datasourceId": 1,
"datasourceUid": "000000001",
"queryType": "metricQuery",
"maxDataPoints": 0,
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceID: 1,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with valid intervalMs",
@@ -115,17 +115,17 @@ func TestAlertQuery(t *testing.T) {
RefID: "A",
Model: json.RawMessage(`{
"datasource": "my datasource",
"datasourceId": 1,
"datasourceUid": "000000001",
"queryType": "metricQuery",
"intervalMs": 2000,
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceID: 1,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: 2000,
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: 2000,
},
{
desc: "given a query with invalid intervalMs",
@@ -133,17 +133,17 @@ func TestAlertQuery(t *testing.T) {
RefID: "A",
Model: json.RawMessage(`{
"datasource": "my datasource",
"datasourceId": 1,
"datasourceUid": "000000001",
"queryType": "metricQuery",
"intervalMs": "invalid",
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceID: 1,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with invalid intervalMs",
@@ -151,17 +151,17 @@ func TestAlertQuery(t *testing.T) {
RefID: "A",
Model: json.RawMessage(`{
"datasource": "my datasource",
"datasourceId": 1,
"datasourceUid": "000000001",
"queryType": "metricQuery",
"intervalMs": 0,
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceID: 1,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedDatasource: "my datasource",
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
}
@@ -176,7 +176,7 @@ func TestAlertQuery(t *testing.T) {
t.Run("can set datasource for expression", func(t *testing.T) {
err := tc.alertQuery.setDatasource()
require.NoError(t, err)
require.Equal(t, tc.expectedDatasourceID, tc.alertQuery.DatasourceID)
require.Equal(t, tc.expectedDatasourceUID, tc.alertQuery.DatasourceUID)
})
t.Run("can set queryType for expression", func(t *testing.T) {
@@ -204,17 +204,18 @@ func TestAlertQuery(t *testing.T) {
err = json.Unmarshal(blob, &model)
require.NoError(t, err)
fmt.Printf(">>>>>>> %+v %+v\n", tc.alertQuery, model)
i, ok := model["datasource"]
require.True(t, ok)
datasource, ok := i.(string)
require.True(t, ok)
require.Equal(t, tc.expectedDatasource, datasource)
i, ok = model["datasourceId"]
i, ok = model["datasourceUid"]
require.True(t, ok)
datasourceID, ok := i.(float64)
datasourceUID, ok := i.(string)
require.True(t, ok)
require.Equal(t, tc.expectedDatasourceID, int64(datasourceID))
require.Equal(t, tc.expectedDatasourceUID, datasourceUID)
i, ok = model["maxDataPoints"]
require.True(t, ok)
+9 -6
View File
@@ -4,7 +4,6 @@ import (
"fmt"
"time"
"github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
)
@@ -35,7 +34,7 @@ func (ng *AlertNG) validateAlertDefinition(alertDefinition *AlertDefinition, req
}
// validateCondition validates that condition queries refer to existing datasources
func (ng *AlertNG) validateCondition(c eval.Condition, user *models.SignedInUser) error {
func (ng *AlertNG) validateCondition(c eval.Condition, user *models.SignedInUser, skipCache bool) error {
var refID string
if len(c.QueriesAndExpressions) == 0 {
@@ -47,18 +46,22 @@ func (ng *AlertNG) validateCondition(c eval.Condition, user *models.SignedInUser
refID = c.RefID
}
datasourceID, err := query.GetDatasource()
datasourceUID, err := query.GetDatasource()
if err != nil {
return err
}
if datasourceID == expr.DatasourceID {
isExpression, err := query.IsExpression()
if err != nil {
return err
}
if isExpression {
continue
}
_, err = ng.DatasourceCache.GetDatasource(datasourceID, user, false)
_, err = ng.DatasourceCache.GetDatasourceByUID(datasourceUID, user, skipCache)
if err != nil {
return err
return fmt.Errorf("failed to get datasource: %s: %w", datasourceUID, err)
}
}