Alerting/Expr: New SSE Request/QueryType, alerting move data source UID (#33282)

This commit is contained in:
Kyle Brandt
2021-04-23 16:52:32 +02:00
committed by GitHub
parent 659ea20c3c
commit 5e818146de
19 changed files with 179 additions and 248 deletions
@@ -14,9 +14,8 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "000000002",
"model": {
"datasource": "gdev-prometheus",
"datasourceUid": "000000002",
"expr": "http_request_duration_microseconds_count",
"hide": false,
"interval": "",
@@ -33,9 +32,8 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasource": "__expr__",
"datasourceUid": "-100",
"expression": "query",
"hide": false,
"intervalMs": 1000,
@@ -52,9 +50,8 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasource": "__expr__",
"datasourceUid": "-100",
"expression": "$reduced > 10",
"hide": false,
"intervalMs": 1000,
@@ -80,10 +77,9 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "000000004",
"model": {
"alias": "just-testing",
"datasource": "gdev-testdata",
"datasourceUid": "000000004",
"intervalMs": 1000,
"maxDataPoints": 100,
"orgId": 0,
@@ -99,9 +95,8 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasource": "__expr__",
"datasourceUid": "__expr__",
"expression": "$A",
"intervalMs": 2000,
"maxDataPoints": 200,
@@ -21,9 +21,8 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "000000002",
"model": {
"datasource": "gdev-prometheus",
"datasourceUid": "000000002",
"expr": "http_request_duration_microseconds_count",
"hide": false,
"interval": "",
@@ -40,9 +39,8 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasource": "__expr__",
"datasourceUid": "-100",
"expression": "query",
"hide": false,
"intervalMs": 1000,
@@ -59,9 +57,8 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasource": "__expr__",
"datasourceUid": "-100",
"expression": "$reduced > 10",
"hide": false,
"intervalMs": 1000,
@@ -87,10 +84,9 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "000000004",
"model": {
"alias": "just-testing",
"datasource": "gdev-testdata",
"datasourceUid": "000000004",
"intervalMs": 1000,
"maxDataPoints": 100,
"orgId": 0,
@@ -106,9 +102,8 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasource": "__expr__",
"datasourceUid": "__expr__",
"expression": "$A",
"intervalMs": 2000,
"maxDataPoints": 200,
@@ -76,8 +76,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "000000002",
"model": {
"datasourceUid": "000000002",
"expr": "http_request_duration_microseconds_count",
"hide": false,
"interval": "",
@@ -94,8 +94,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "query",
"hide": false,
"intervalMs": 1000,
@@ -112,8 +112,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "$reduced > 10",
"hide": false,
"intervalMs": 1000,
@@ -158,8 +158,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "000000002",
"model": {
"datasourceUid": "000000002",
"expr": "http_request_duration_microseconds_count",
"hide": false,
"interval": "",
@@ -176,8 +176,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "query",
"hide": false,
"intervalMs": 1000,
@@ -194,8 +194,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "$reduced > 42",
"hide": false,
"intervalMs": 1000,
@@ -80,9 +80,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "000000002",
"model": {
"datasource": "gdev-prometheus",
"datasourceUid": "000000002",
"expr": "http_request_duration_microseconds_count",
"hide": false,
"interval": "",
@@ -99,8 +98,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "query",
"hide": false,
"intervalMs": 1000,
@@ -117,8 +116,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "$reduced > 10",
"hide": false,
"intervalMs": 1000,
@@ -167,8 +166,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "000000002",
"model": {
"datasourceUid": "000000002",
"expr": "http_request_duration_microseconds_count",
"hide": false,
"interval": "",
@@ -185,8 +184,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "query",
"hide": false,
"intervalMs": 1000,
@@ -203,8 +202,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "$reduced > 42",
"hide": false,
"intervalMs": 1000,
@@ -266,8 +265,8 @@ Content-Type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "000000002",
"model": {
"datasourceUid": "000000002",
"expr": "http_request_duration_microseconds_count",
"hide": false,
"interval": "",
@@ -284,8 +283,8 @@ Content-Type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "query",
"hide": false,
"intervalMs": 1000,
@@ -302,8 +301,8 @@ Content-Type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "$reduced > 42",
"hide": false,
"intervalMs": 1000,
@@ -9,8 +9,8 @@
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasource": "__expr__",
"type": "math",
"expression": "2 + 2 > 1"
}
+4 -4
View File
@@ -15,8 +15,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"type":"math",
"expression":"1 < 2"
}
@@ -39,8 +39,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "000000004",
"model": {
"datasourceUid": "000000004",
"intervalMs": 1000,
"maxDataPoints": 100,
"orgId": 0,
@@ -56,8 +56,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"expression": "$A",
"intervalMs": 2000,
"maxDataPoints": 200,
@@ -113,8 +113,8 @@ content-type: application/json
"from": 18000,
"to": 10800
},
"datasourceUid": "-100",
"model": {
"datasourceUid": "-100",
"type":"math",
"expression":"1 < 2"
}
+12 -11
View File
@@ -102,13 +102,10 @@ type AlertExecCtx struct {
Ctx context.Context
}
// GetQueryDataRequest validates the condition and creates a backend.QueryDataRequest from it.
func GetQueryDataRequest(ctx AlertExecCtx, data []models.AlertQuery, now time.Time) (*backend.QueryDataRequest, error) {
queryDataReq := &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
OrgID: ctx.OrgID,
},
Queries: []backend.DataQuery{},
// GetExprRequest validates the condition and creates a expr.Request from it.
func GetExprRequest(ctx AlertExecCtx, data []models.AlertQuery, now time.Time) (*expr.Request, error) {
req := &expr.Request{
OrgId: ctx.OrgID,
}
for i := range data {
@@ -127,16 +124,20 @@ func GetQueryDataRequest(ctx AlertExecCtx, data []models.AlertQuery, now time.Ti
return nil, fmt.Errorf("failed to retrieve maxDatapoints from the model: %w", err)
}
queryDataReq.Queries = append(queryDataReq.Queries, backend.DataQuery{
req.Queries = append(req.Queries, expr.Query{
TimeRange: expr.TimeRange{
From: q.RelativeTimeRange.ToTimeRange(now).From,
To: q.RelativeTimeRange.ToTimeRange(now).To,
},
DatasourceUID: q.DatasourceUID,
JSON: model,
Interval: interval,
RefID: q.RefID,
MaxDataPoints: maxDatapoints,
QueryType: q.QueryType,
TimeRange: q.RelativeTimeRange.ToTimeRange(now),
})
}
return queryDataReq, nil
return req, nil
}
func executeCondition(ctx AlertExecCtx, c *models.Condition, now time.Time, dataService *tsdb.Service) (*ExecutionResults, error) {
@@ -165,7 +166,7 @@ func executeCondition(ctx AlertExecCtx, c *models.Condition, now time.Time, data
}
func executeQueriesAndExpressions(ctx AlertExecCtx, data []models.AlertQuery, now time.Time, dataService *tsdb.Service) (*backend.QueryDataResponse, error) {
queryDataReq, err := GetQueryDataRequest(ctx, data, now)
queryDataReq, err := GetExprRequest(ctx, data, now)
if err != nil {
return nil, err
}
+2 -41
View File
@@ -68,7 +68,7 @@ type AlertQuery struct {
// RelativeTimeRange is the relative Start and End of the query as sent by the frontend.
RelativeTimeRange RelativeTimeRange `json:"relativeTimeRange"`
DatasourceUID string `json:"-"`
DatasourceUID string `json:"datasourceUid"`
// JSON is the raw JSON query and includes the above properties as well as custom properties.
Model json.RawMessage `json:"model"`
@@ -86,34 +86,8 @@ func (aq *AlertQuery) setModelProps() error {
return nil
}
// setDatasource sets DatasourceUID.
// If it's an expression sets DefaultExprDatasourceUID.
func (aq *AlertQuery) setDatasource() error {
if aq.modelProps == nil {
err := aq.setModelProps()
if err != nil {
return err
}
}
i, ok := aq.modelProps["datasourceUid"]
if !ok {
return fmt.Errorf("failed to get datasourceUid from query model")
}
dsUID, ok := i.(string)
if !ok {
return fmt.Errorf("failed to cast datasourceUid to string: %v", i)
}
aq.DatasourceUID = dsUID
return nil
}
// IsExpression returns true if the alert query is an expression.
func (aq *AlertQuery) IsExpression() (bool, error) {
err := aq.setDatasource()
if err != nil {
return false, err
}
return aq.DatasourceUID == expr.DatasourceUID, nil
}
@@ -196,20 +170,11 @@ func (aq *AlertQuery) GetIntervalDuration() (time.Duration, error) {
// GetDatasource returns the query datasource identifier.
func (aq *AlertQuery) GetDatasource() (string, error) {
err := aq.setDatasource()
if err != nil {
return "", err
}
return aq.DatasourceUID, nil
}
func (aq *AlertQuery) GetModel() ([]byte, error) {
err := aq.setDatasource()
if err != nil {
return nil, err
}
err = aq.setMaxDatapoints()
err := aq.setMaxDatapoints()
if err != nil {
return nil, err
}
@@ -250,10 +215,6 @@ func (aq *AlertQuery) setQueryType() error {
// PreSave sets query's properties.
// It should be called before being saved.
func (aq *AlertQuery) PreSave() error {
if err := aq.setDatasource(); err != nil {
return fmt.Errorf("failed to set datasource to query model: %w", err)
}
if err := aq.setQueryType(); err != nil {
return fmt.Errorf("failed to set query type to query model: %w", err)
}
+33 -62
View File
@@ -6,147 +6,130 @@ import (
"testing"
"time"
"github.com/grafana/grafana/pkg/expr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAlertQuery(t *testing.T) {
testCases := []struct {
desc string
alertQuery AlertQuery
expectedIsExpression bool
expectedDatasource string
expectedDatasourceUID string
expectedMaxPoints int64
expectedIntervalMS int64
err error
desc string
alertQuery AlertQuery
expectedIsExpression bool
expectedDatasource string
expectedMaxPoints int64
expectedIntervalMS int64
err error
}{
{
desc: "given an expression query",
alertQuery: AlertQuery{
RefID: "A",
Model: json.RawMessage(`{
"datasourceUid": "-100",
"queryType": "metricQuery",
"extraParam": "some text"
}`),
DatasourceUID: "-100",
},
expectedIsExpression: true,
expectedDatasourceUID: expr.DatasourceUID,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: true,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query",
alertQuery: AlertQuery{
RefID: "A",
Model: json.RawMessage(`{
"datasourceUid": "000000001",
"queryType": "metricQuery",
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with valid maxDataPoints",
alertQuery: AlertQuery{
RefID: "A",
Model: json.RawMessage(`{
"datasourceUid": "000000001",
"queryType": "metricQuery",
"maxDataPoints": 200,
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasourceUID: "000000001",
expectedMaxPoints: 200,
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedMaxPoints: 200,
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with invalid maxDataPoints",
alertQuery: AlertQuery{
RefID: "A",
Model: json.RawMessage(`{
"datasourceUid": "000000001",
"queryType": "metricQuery",
"maxDataPoints": "invalid",
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with zero maxDataPoints",
alertQuery: AlertQuery{
RefID: "A",
Model: json.RawMessage(`{
"datasourceUid": "000000001",
"queryType": "metricQuery",
"maxDataPoints": 0,
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with valid intervalMs",
alertQuery: AlertQuery{
RefID: "A",
Model: json.RawMessage(`{
"datasourceUid": "000000001",
"queryType": "metricQuery",
"intervalMs": 2000,
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: 2000,
expectedIsExpression: false,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: 2000,
},
{
desc: "given a query with invalid intervalMs",
alertQuery: AlertQuery{
RefID: "A",
Model: json.RawMessage(`{
"datasourceUid": "000000001",
"queryType": "metricQuery",
"intervalMs": "invalid",
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
{
desc: "given a query with invalid intervalMs",
alertQuery: AlertQuery{
RefID: "A",
Model: json.RawMessage(`{
"datasourceUid": "000000001",
"queryType": "metricQuery",
"intervalMs": 0,
"extraParam": "some text"
}`),
},
expectedIsExpression: false,
expectedDatasourceUID: "000000001",
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
expectedIsExpression: false,
expectedMaxPoints: int64(defaultMaxDataPoints),
expectedIntervalMS: int64(defaultIntervalMS),
},
}
@@ -158,12 +141,6 @@ func TestAlertQuery(t *testing.T) {
assert.Equal(t, tc.expectedIsExpression, isExpression)
})
t.Run("can set datasource for expression", func(t *testing.T) {
err := tc.alertQuery.setDatasource()
require.NoError(t, err)
require.Equal(t, tc.expectedDatasourceUID, tc.alertQuery.DatasourceUID)
})
t.Run("can set queryType for expression", func(t *testing.T) {
err := tc.alertQuery.setQueryType()
require.NoError(t, err)
@@ -189,13 +166,7 @@ func TestAlertQuery(t *testing.T) {
err = json.Unmarshal(blob, &model)
require.NoError(t, err)
i, ok := model["datasourceUid"]
require.True(t, ok)
datasourceUID, ok := i.(string)
require.True(t, ok)
require.Equal(t, tc.expectedDatasourceUID, datasourceUID)
i, ok = model["maxDataPoints"]
i, ok := model["maxDataPoints"]
require.True(t, ok)
maxDataPoints, ok := i.(float64)
require.True(t, ok)