mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting/Expr: New SSE Request/QueryType, alerting move data source UID (#33282)
This commit is contained in:
parent
659ea20c3c
commit
5e818146de
@ -6,7 +6,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
||||||
"github.com/grafana/grafana/pkg/components/gtime"
|
"github.com/grafana/grafana/pkg/components/gtime"
|
||||||
"github.com/grafana/grafana/pkg/expr/mathexp"
|
"github.com/grafana/grafana/pkg/expr/mathexp"
|
||||||
)
|
)
|
||||||
@ -139,12 +138,12 @@ type ResampleCommand struct {
|
|||||||
VarToResample string
|
VarToResample string
|
||||||
Downsampler string
|
Downsampler string
|
||||||
Upsampler string
|
Upsampler string
|
||||||
TimeRange backend.TimeRange
|
TimeRange TimeRange
|
||||||
refID string
|
refID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResampleCommand creates a new ResampleCMD.
|
// NewResampleCommand creates a new ResampleCMD.
|
||||||
func NewResampleCommand(refID, rawWindow, varToResample string, downsampler string, upsampler string, tr backend.TimeRange) (*ResampleCommand, error) {
|
func NewResampleCommand(refID, rawWindow, varToResample string, downsampler string, upsampler string, tr TimeRange) (*ResampleCommand, error) {
|
||||||
// TODO: validate reducer here, before execution
|
// TODO: validate reducer here, before execution
|
||||||
window, err := gtime.ParseDuration(rawWindow)
|
window, err := gtime.ParseDuration(rawWindow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -218,7 +217,7 @@ func (gr *ResampleCommand) Execute(ctx context.Context, vars mathexp.Vars) (math
|
|||||||
if !ok {
|
if !ok {
|
||||||
return newRes, fmt.Errorf("can only resample type series, got type %v", val.Type())
|
return newRes, fmt.Errorf("can only resample type series, got type %v", val.Type())
|
||||||
}
|
}
|
||||||
num, err := series.Resample(gr.refID, gr.Window, gr.Downsampler, gr.Upsampler, gr.TimeRange)
|
num, err := series.Resample(gr.refID, gr.Window, gr.Downsampler, gr.Upsampler, gr.TimeRange.From, gr.TimeRange.To)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newRes, err
|
return newRes, err
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
||||||
"github.com/grafana/grafana/pkg/expr/mathexp"
|
"github.com/grafana/grafana/pkg/expr/mathexp"
|
||||||
|
|
||||||
"gonum.org/v1/gonum/graph"
|
"gonum.org/v1/gonum/graph"
|
||||||
@ -52,7 +51,7 @@ func (dp *DataPipeline) execute(c context.Context, s *Service) (mathexp.Vars, er
|
|||||||
|
|
||||||
// BuildPipeline builds a graph of the nodes, and returns the nodes in an
|
// BuildPipeline builds a graph of the nodes, and returns the nodes in an
|
||||||
// executable order.
|
// executable order.
|
||||||
func (s *Service) buildPipeline(req *backend.QueryDataRequest) (DataPipeline, error) {
|
func (s *Service) buildPipeline(req *Request) (DataPipeline, error) {
|
||||||
graph, err := s.buildDependencyGraph(req)
|
graph, err := s.buildDependencyGraph(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -67,7 +66,7 @@ func (s *Service) buildPipeline(req *backend.QueryDataRequest) (DataPipeline, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildDependencyGraph returns a dependency graph for a set of queries.
|
// buildDependencyGraph returns a dependency graph for a set of queries.
|
||||||
func (s *Service) buildDependencyGraph(req *backend.QueryDataRequest) (*simple.DirectedGraph, error) {
|
func (s *Service) buildDependencyGraph(req *Request) (*simple.DirectedGraph, error) {
|
||||||
graph, err := s.buildGraph(req)
|
graph, err := s.buildGraph(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -113,20 +112,26 @@ func buildNodeRegistry(g *simple.DirectedGraph) map[string]Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildGraph creates a new graph populated with nodes for every query.
|
// buildGraph creates a new graph populated with nodes for every query.
|
||||||
func (s *Service) buildGraph(req *backend.QueryDataRequest) (*simple.DirectedGraph, error) {
|
func (s *Service) buildGraph(req *Request) (*simple.DirectedGraph, error) {
|
||||||
dp := simple.NewDirectedGraph()
|
dp := simple.NewDirectedGraph()
|
||||||
|
|
||||||
for _, query := range req.Queries {
|
for _, query := range req.Queries {
|
||||||
rawQueryProp := make(map[string]interface{})
|
rawQueryProp := make(map[string]interface{})
|
||||||
err := json.Unmarshal(query.JSON, &rawQueryProp)
|
queryBytes, err := query.JSON.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
err = json.Unmarshal(queryBytes, &rawQueryProp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
rn := &rawNode{
|
rn := &rawNode{
|
||||||
Query: rawQueryProp,
|
Query: rawQueryProp,
|
||||||
RefID: query.RefID,
|
RefID: query.RefID,
|
||||||
TimeRange: query.TimeRange,
|
TimeRange: query.TimeRange,
|
||||||
QueryType: query.QueryType,
|
QueryType: query.QueryType,
|
||||||
|
DatasourceUID: query.DatasourceUID,
|
||||||
}
|
}
|
||||||
|
|
||||||
dsName, err := rn.GetDatasourceName()
|
dsName, err := rn.GetDatasourceName()
|
||||||
@ -134,17 +139,14 @@ func (s *Service) buildGraph(req *backend.QueryDataRequest) (*simple.DirectedGra
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dsUID, err := rn.GetDatasourceUid()
|
dsUID := rn.DatasourceUID
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var node graph.Node
|
var node graph.Node
|
||||||
switch {
|
switch {
|
||||||
case dsName == DatasourceName || dsUID == DatasourceUID:
|
case dsName == DatasourceName || dsUID == DatasourceUID:
|
||||||
node, err = buildCMDNode(dp, rn)
|
node, err = buildCMDNode(dp, rn)
|
||||||
default: // If it's not an expression query, it's a data source query.
|
default: // If it's not an expression query, it's a data source query.
|
||||||
node, err = s.buildDSNode(dp, rn, req.PluginContext.OrgID)
|
node, err = s.buildDSNode(dp, rn, req.OrgId)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -4,13 +4,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resample turns the Series into a Number based on the given reduction function
|
// Resample turns the Series into a Number based on the given reduction function
|
||||||
func (s Series) Resample(refID string, interval time.Duration, downsampler string, upsampler string, tr backend.TimeRange) (Series, error) {
|
func (s Series) Resample(refID string, interval time.Duration, downsampler string, upsampler string, from, to time.Time) (Series, error) {
|
||||||
newSeriesLength := int(float64(tr.To.Sub(tr.From).Nanoseconds()) / float64(interval.Nanoseconds()))
|
newSeriesLength := int(float64(to.Sub(from).Nanoseconds()) / float64(interval.Nanoseconds()))
|
||||||
if newSeriesLength <= 0 {
|
if newSeriesLength <= 0 {
|
||||||
return s, fmt.Errorf("the series cannot be sampled further; the time range is shorter than the interval")
|
return s, fmt.Errorf("the series cannot be sampled further; the time range is shorter than the interval")
|
||||||
}
|
}
|
||||||
@ -18,8 +17,8 @@ func (s Series) Resample(refID string, interval time.Duration, downsampler strin
|
|||||||
bookmark := 0
|
bookmark := 0
|
||||||
var lastSeen *float64
|
var lastSeen *float64
|
||||||
idx := 0
|
idx := 0
|
||||||
t := tr.From
|
t := from
|
||||||
for !t.After(tr.To) && idx <= newSeriesLength {
|
for !t.After(to) && idx <= newSeriesLength {
|
||||||
vals := make([]*float64, 0)
|
vals := make([]*float64, 0)
|
||||||
sIdx := bookmark
|
sIdx := bookmark
|
||||||
for {
|
for {
|
||||||
|
@ -276,7 +276,7 @@ func TestResampleSeries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
series, err := tt.seriesToResample.Resample("", tt.interval, tt.downsampler, tt.upsampler, tt.timeRange)
|
series, err := tt.seriesToResample.Resample("", tt.interval, tt.downsampler, tt.upsampler, tt.timeRange.From, tt.timeRange.To)
|
||||||
if tt.series.Frame == nil {
|
if tt.series.Frame == nil {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -21,10 +21,11 @@ type baseNode struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type rawNode struct {
|
type rawNode struct {
|
||||||
RefID string `json:"refId"`
|
RefID string `json:"refId"`
|
||||||
Query map[string]interface{}
|
Query map[string]interface{}
|
||||||
QueryType string
|
QueryType string
|
||||||
TimeRange backend.TimeRange
|
TimeRange TimeRange
|
||||||
|
DatasourceUID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rn *rawNode) GetDatasourceName() (string, error) {
|
func (rn *rawNode) GetDatasourceName() (string, error) {
|
||||||
@ -39,18 +40,6 @@ func (rn *rawNode) GetDatasourceName() (string, error) {
|
|||||||
return dsName, nil
|
return dsName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rn *rawNode) GetDatasourceUid() (string, error) {
|
|
||||||
rawDs, ok := rn.Query["datasourceUid"]
|
|
||||||
if !ok {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
dsUID, ok := rawDs.(string)
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("expected datasource identifier to be a string, got %T", rawDs)
|
|
||||||
}
|
|
||||||
return dsUID, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rn *rawNode) GetCommandType() (c CommandType, err error) {
|
func (rn *rawNode) GetCommandType() (c CommandType, err error) {
|
||||||
rawType, ok := rn.Query["type"]
|
rawType, ok := rn.Query["type"]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -144,7 +133,7 @@ type DSNode struct {
|
|||||||
|
|
||||||
orgID int64
|
orgID int64
|
||||||
queryType string
|
queryType string
|
||||||
timeRange backend.TimeRange
|
timeRange TimeRange
|
||||||
intervalMS int64
|
intervalMS int64
|
||||||
maxDP int64
|
maxDP int64
|
||||||
}
|
}
|
||||||
@ -182,15 +171,10 @@ func (s *Service) buildDSNode(dp *simple.DirectedGraph, rn *rawNode, orgID int64
|
|||||||
}
|
}
|
||||||
dsNode.datasourceID = int64(floatDsID)
|
dsNode.datasourceID = int64(floatDsID)
|
||||||
default:
|
default:
|
||||||
rawDsUID, ok := rn.Query["datasourceUid"]
|
if rn.DatasourceUID == "" {
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("neither datasourceId or datasourceUid in expression data source request for refId %v", rn.RefID)
|
return nil, fmt.Errorf("neither datasourceId or datasourceUid in expression data source request for refId %v", rn.RefID)
|
||||||
}
|
}
|
||||||
strDsUID, ok := rawDsUID.(string)
|
dsNode.datasourceUID = rn.DatasourceUID
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("expected datasourceUid to be a string, got type %T for refId %v", rawDsUID, rn.RefID)
|
|
||||||
}
|
|
||||||
dsNode.datasourceUID = strDsUID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var floatIntervalMS float64
|
var floatIntervalMS float64
|
||||||
@ -230,8 +214,11 @@ func (dn *DSNode) Execute(ctx context.Context, vars mathexp.Vars, s *Service) (m
|
|||||||
MaxDataPoints: dn.maxDP,
|
MaxDataPoints: dn.maxDP,
|
||||||
Interval: time.Duration(int64(time.Millisecond) * dn.intervalMS),
|
Interval: time.Duration(int64(time.Millisecond) * dn.intervalMS),
|
||||||
JSON: dn.query,
|
JSON: dn.query,
|
||||||
TimeRange: dn.timeRange,
|
TimeRange: backend.TimeRange{
|
||||||
QueryType: dn.queryType,
|
From: dn.timeRange.From,
|
||||||
|
To: dn.timeRange.To,
|
||||||
|
},
|
||||||
|
QueryType: dn.queryType,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ func (s *Service) isDisabled() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildPipeline builds a pipeline from a request.
|
// BuildPipeline builds a pipeline from a request.
|
||||||
func (s *Service) BuildPipeline(req *backend.QueryDataRequest) (DataPipeline, error) {
|
func (s *Service) BuildPipeline(req *Request) (DataPipeline, error) {
|
||||||
return s.buildPipeline(req)
|
return s.buildPipeline(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ func TestService(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
queries := []backend.DataQuery{
|
queries := []Query{
|
||||||
{
|
{
|
||||||
RefID: "A",
|
RefID: "A",
|
||||||
JSON: json.RawMessage(`{ "datasource": "test", "datasourceId": 1, "orgId": 1, "intervalMs": 1000, "maxDataPoints": 1000 }`),
|
JSON: json.RawMessage(`{ "datasource": "test", "datasourceId": 1, "orgId": 1, "intervalMs": 1000, "maxDataPoints": 1000 }`),
|
||||||
@ -52,7 +52,7 @@ func TestService(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &backend.QueryDataRequest{Queries: queries}
|
req := &Request{Queries: queries}
|
||||||
|
|
||||||
pl, err := s.BuildPipeline(req)
|
pl, err := s.BuildPipeline(req)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -36,11 +36,9 @@ func init() {
|
|||||||
|
|
||||||
// WrapTransformData creates and executes transform requests
|
// WrapTransformData creates and executes transform requests
|
||||||
func (s *Service) WrapTransformData(ctx context.Context, query plugins.DataQuery) (*backend.QueryDataResponse, error) {
|
func (s *Service) WrapTransformData(ctx context.Context, query plugins.DataQuery) (*backend.QueryDataResponse, error) {
|
||||||
sdkReq := &backend.QueryDataRequest{
|
req := Request{
|
||||||
PluginContext: backend.PluginContext{
|
OrgId: query.User.OrgId,
|
||||||
OrgID: query.User.OrgId,
|
Queries: []Query{},
|
||||||
},
|
|
||||||
Queries: []backend.DataQuery{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, q := range query.Queries {
|
for _, q := range query.Queries {
|
||||||
@ -48,24 +46,50 @@ func (s *Service) WrapTransformData(ctx context.Context, query plugins.DataQuery
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sdkReq.Queries = append(sdkReq.Queries, backend.DataQuery{
|
req.Queries = append(req.Queries, Query{
|
||||||
JSON: modelJSON,
|
JSON: modelJSON,
|
||||||
Interval: time.Duration(q.IntervalMS) * time.Millisecond,
|
Interval: time.Duration(q.IntervalMS) * time.Millisecond,
|
||||||
RefID: q.RefID,
|
RefID: q.RefID,
|
||||||
MaxDataPoints: q.MaxDataPoints,
|
MaxDataPoints: q.MaxDataPoints,
|
||||||
QueryType: q.QueryType,
|
QueryType: q.QueryType,
|
||||||
TimeRange: backend.TimeRange{
|
TimeRange: TimeRange{
|
||||||
From: query.TimeRange.GetFromAsTimeUTC(),
|
From: query.TimeRange.GetFromAsTimeUTC(),
|
||||||
To: query.TimeRange.GetToAsTimeUTC(),
|
To: query.TimeRange.GetToAsTimeUTC(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return s.TransformData(ctx, sdkReq)
|
return s.TransformData(ctx, &req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request is similar to plugins.DataQuery but with the Time Ranges is per Query.
|
||||||
|
type Request struct {
|
||||||
|
Headers map[string]string
|
||||||
|
Debug bool
|
||||||
|
OrgId int64
|
||||||
|
Queries []Query
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query is like plugins.DataSubQuery, but with a a time range, and only the UID
|
||||||
|
// for the data source. Also interval is a time.Duration.
|
||||||
|
type Query struct {
|
||||||
|
RefID string
|
||||||
|
TimeRange TimeRange
|
||||||
|
DatasourceUID string
|
||||||
|
JSON json.RawMessage
|
||||||
|
Interval time.Duration
|
||||||
|
QueryType string
|
||||||
|
MaxDataPoints int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeRange is a time.Time based TimeRange.
|
||||||
|
type TimeRange struct {
|
||||||
|
From time.Time
|
||||||
|
To time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransformData takes Queries which are either expressions nodes
|
// TransformData takes Queries which are either expressions nodes
|
||||||
// or are datasource requests.
|
// or are datasource requests.
|
||||||
func (s *Service) TransformData(ctx context.Context, req *backend.QueryDataRequest) (r *backend.QueryDataResponse, err error) {
|
func (s *Service) TransformData(ctx context.Context, req *Request) (r *backend.QueryDataResponse, err error) {
|
||||||
if s.isDisabled() {
|
if s.isDisabled() {
|
||||||
return nil, status.Error(codes.PermissionDenied, "Expressions are disabled")
|
return nil, status.Error(codes.PermissionDenied, "Expressions are disabled")
|
||||||
}
|
}
|
||||||
@ -116,7 +140,7 @@ func (s *Service) TransformData(ctx context.Context, req *backend.QueryDataReque
|
|||||||
return responses, nil
|
return responses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hiddenRefIDs(queries []backend.DataQuery) (map[string]struct{}, error) {
|
func hiddenRefIDs(queries []Query) (map[string]struct{}, error) {
|
||||||
hidden := make(map[string]struct{})
|
hidden := make(map[string]struct{})
|
||||||
|
|
||||||
for _, query := range queries {
|
for _, query := range queries {
|
||||||
|
@ -34,7 +34,7 @@ func DashboardAlertConditions(rawDCondJSON []byte, orgID int64) (*ngmodels.Condi
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
backendReq, err := eval.GetQueryDataRequest(eval.AlertExecCtx{ExpressionsEnabled: true}, ngCond.Data, time.Unix(500, 0))
|
backendReq, err := eval.GetExprRequest(eval.AlertExecCtx{ExpressionsEnabled: true}, ngCond.Data, time.Unix(500, 0))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -191,7 +191,6 @@ func (dc *dashConditionsJSON) GetNew(orgID int64) (*ngmodels.Condition, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
queryObj["datasource"] = getDsInfo.Result.Name
|
queryObj["datasource"] = getDsInfo.Result.Name
|
||||||
queryObj["datasourceUid"] = getDsInfo.Result.Uid
|
|
||||||
queryObj["refId"] = refID
|
queryObj["refId"] = refID
|
||||||
|
|
||||||
encodedObj, err := json.Marshal(queryObj)
|
encodedObj, err := json.Marshal(queryObj)
|
||||||
@ -211,7 +210,7 @@ func (dc *dashConditionsJSON) GetNew(orgID int64) (*ngmodels.Condition, error) {
|
|||||||
RefID: refID,
|
RefID: refID,
|
||||||
Model: encodedObj,
|
Model: encodedObj,
|
||||||
RelativeTimeRange: *rTR,
|
RelativeTimeRange: *rTR,
|
||||||
DatasourceUID: getDsInfo.Uid,
|
DatasourceUID: getDsInfo.Result.Uid,
|
||||||
}
|
}
|
||||||
ngCond.Data = append(ngCond.Data, alertQuery)
|
ngCond.Data = append(ngCond.Data, alertQuery)
|
||||||
}
|
}
|
||||||
@ -240,14 +239,12 @@ func (dc *dashConditionsJSON) GetNew(orgID int64) (*ngmodels.Condition, error) {
|
|||||||
ngCond.OrgID = orgID
|
ngCond.OrgID = orgID
|
||||||
|
|
||||||
exprModel := struct {
|
exprModel := struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
RefID string `json:"refId"`
|
RefID string `json:"refId"`
|
||||||
DatasourceUID string `json:"datasourceUid"`
|
Conditions []classic.ClassicConditionJSON `json:"conditions"`
|
||||||
Conditions []classic.ClassicConditionJSON `json:"conditions"`
|
|
||||||
}{
|
}{
|
||||||
"classic_conditions",
|
"classic_conditions",
|
||||||
ccRefID,
|
ccRefID,
|
||||||
expr.DatasourceUID,
|
|
||||||
conditions,
|
conditions,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,8 +254,9 @@ func (dc *dashConditionsJSON) GetNew(orgID int64) (*ngmodels.Condition, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ccAlertQuery := ngmodels.AlertQuery{
|
ccAlertQuery := ngmodels.AlertQuery{
|
||||||
RefID: ccRefID,
|
RefID: ccRefID,
|
||||||
Model: exprModelJSON,
|
Model: exprModelJSON,
|
||||||
|
DatasourceUID: expr.DatasourceUID,
|
||||||
}
|
}
|
||||||
|
|
||||||
ngCond.Data = append(ngCond.Data, ccAlertQuery)
|
ngCond.Data = append(ngCond.Data, ccAlertQuery)
|
||||||
|
@ -14,9 +14,8 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000002",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "gdev-prometheus",
|
|
||||||
"datasourceUid": "000000002",
|
|
||||||
"expr": "http_request_duration_microseconds_count",
|
"expr": "http_request_duration_microseconds_count",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"interval": "",
|
"interval": "",
|
||||||
@ -33,9 +32,8 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "__expr__",
|
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "query",
|
"expression": "query",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -52,9 +50,8 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "__expr__",
|
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "$reduced > 10",
|
"expression": "$reduced > 10",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -80,10 +77,9 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000004",
|
||||||
"model": {
|
"model": {
|
||||||
"alias": "just-testing",
|
"alias": "just-testing",
|
||||||
"datasource": "gdev-testdata",
|
|
||||||
"datasourceUid": "000000004",
|
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
"maxDataPoints": 100,
|
"maxDataPoints": 100,
|
||||||
"orgId": 0,
|
"orgId": 0,
|
||||||
@ -99,9 +95,8 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "__expr__",
|
|
||||||
"datasourceUid": "__expr__",
|
|
||||||
"expression": "$A",
|
"expression": "$A",
|
||||||
"intervalMs": 2000,
|
"intervalMs": 2000,
|
||||||
"maxDataPoints": 200,
|
"maxDataPoints": 200,
|
||||||
|
@ -21,9 +21,8 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000002",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "gdev-prometheus",
|
|
||||||
"datasourceUid": "000000002",
|
|
||||||
"expr": "http_request_duration_microseconds_count",
|
"expr": "http_request_duration_microseconds_count",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"interval": "",
|
"interval": "",
|
||||||
@ -40,9 +39,8 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "__expr__",
|
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "query",
|
"expression": "query",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -59,9 +57,8 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "__expr__",
|
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "$reduced > 10",
|
"expression": "$reduced > 10",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -87,10 +84,9 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000004",
|
||||||
"model": {
|
"model": {
|
||||||
"alias": "just-testing",
|
"alias": "just-testing",
|
||||||
"datasource": "gdev-testdata",
|
|
||||||
"datasourceUid": "000000004",
|
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
"maxDataPoints": 100,
|
"maxDataPoints": 100,
|
||||||
"orgId": 0,
|
"orgId": 0,
|
||||||
@ -106,9 +102,8 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "__expr__",
|
|
||||||
"datasourceUid": "__expr__",
|
|
||||||
"expression": "$A",
|
"expression": "$A",
|
||||||
"intervalMs": 2000,
|
"intervalMs": 2000,
|
||||||
"maxDataPoints": 200,
|
"maxDataPoints": 200,
|
||||||
|
@ -76,8 +76,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000002",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "000000002",
|
|
||||||
"expr": "http_request_duration_microseconds_count",
|
"expr": "http_request_duration_microseconds_count",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"interval": "",
|
"interval": "",
|
||||||
@ -94,8 +94,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "query",
|
"expression": "query",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -112,8 +112,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "$reduced > 10",
|
"expression": "$reduced > 10",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -158,8 +158,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000002",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "000000002",
|
|
||||||
"expr": "http_request_duration_microseconds_count",
|
"expr": "http_request_duration_microseconds_count",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"interval": "",
|
"interval": "",
|
||||||
@ -176,8 +176,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "query",
|
"expression": "query",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -194,8 +194,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "$reduced > 42",
|
"expression": "$reduced > 42",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
|
@ -80,9 +80,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000002",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "gdev-prometheus",
|
|
||||||
"datasourceUid": "000000002",
|
|
||||||
"expr": "http_request_duration_microseconds_count",
|
"expr": "http_request_duration_microseconds_count",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"interval": "",
|
"interval": "",
|
||||||
@ -99,8 +98,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "query",
|
"expression": "query",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -117,8 +116,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "$reduced > 10",
|
"expression": "$reduced > 10",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -167,8 +166,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000002",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "000000002",
|
|
||||||
"expr": "http_request_duration_microseconds_count",
|
"expr": "http_request_duration_microseconds_count",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"interval": "",
|
"interval": "",
|
||||||
@ -185,8 +184,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "query",
|
"expression": "query",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -203,8 +202,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "$reduced > 42",
|
"expression": "$reduced > 42",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -266,8 +265,8 @@ Content-Type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000002",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "000000002",
|
|
||||||
"expr": "http_request_duration_microseconds_count",
|
"expr": "http_request_duration_microseconds_count",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"interval": "",
|
"interval": "",
|
||||||
@ -284,8 +283,8 @@ Content-Type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "query",
|
"expression": "query",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
@ -302,8 +301,8 @@ Content-Type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "$reduced > 42",
|
"expression": "$reduced > 42",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasource": "__expr__",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 2 > 1"
|
"expression": "2 + 2 > 1"
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type":"math",
|
"type":"math",
|
||||||
"expression":"1 < 2"
|
"expression":"1 < 2"
|
||||||
}
|
}
|
||||||
@ -39,8 +39,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "000000004",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "000000004",
|
|
||||||
"intervalMs": 1000,
|
"intervalMs": 1000,
|
||||||
"maxDataPoints": 100,
|
"maxDataPoints": 100,
|
||||||
"orgId": 0,
|
"orgId": 0,
|
||||||
@ -56,8 +56,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"expression": "$A",
|
"expression": "$A",
|
||||||
"intervalMs": 2000,
|
"intervalMs": 2000,
|
||||||
"maxDataPoints": 200,
|
"maxDataPoints": 200,
|
||||||
@ -113,8 +113,8 @@ content-type: application/json
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type":"math",
|
"type":"math",
|
||||||
"expression":"1 < 2"
|
"expression":"1 < 2"
|
||||||
}
|
}
|
||||||
|
@ -102,13 +102,10 @@ type AlertExecCtx struct {
|
|||||||
Ctx context.Context
|
Ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetQueryDataRequest validates the condition and creates a backend.QueryDataRequest from it.
|
// GetExprRequest validates the condition and creates a expr.Request from it.
|
||||||
func GetQueryDataRequest(ctx AlertExecCtx, data []models.AlertQuery, now time.Time) (*backend.QueryDataRequest, error) {
|
func GetExprRequest(ctx AlertExecCtx, data []models.AlertQuery, now time.Time) (*expr.Request, error) {
|
||||||
queryDataReq := &backend.QueryDataRequest{
|
req := &expr.Request{
|
||||||
PluginContext: backend.PluginContext{
|
OrgId: ctx.OrgID,
|
||||||
OrgID: ctx.OrgID,
|
|
||||||
},
|
|
||||||
Queries: []backend.DataQuery{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range data {
|
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)
|
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,
|
JSON: model,
|
||||||
Interval: interval,
|
Interval: interval,
|
||||||
RefID: q.RefID,
|
RefID: q.RefID,
|
||||||
MaxDataPoints: maxDatapoints,
|
MaxDataPoints: maxDatapoints,
|
||||||
QueryType: q.QueryType,
|
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) {
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ type AlertQuery struct {
|
|||||||
// RelativeTimeRange is the relative Start and End of the query as sent by the frontend.
|
// RelativeTimeRange is the relative Start and End of the query as sent by the frontend.
|
||||||
RelativeTimeRange RelativeTimeRange `json:"relativeTimeRange"`
|
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.
|
// JSON is the raw JSON query and includes the above properties as well as custom properties.
|
||||||
Model json.RawMessage `json:"model"`
|
Model json.RawMessage `json:"model"`
|
||||||
@ -86,34 +86,8 @@ func (aq *AlertQuery) setModelProps() error {
|
|||||||
return nil
|
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.
|
// IsExpression returns true if the alert query is an expression.
|
||||||
func (aq *AlertQuery) IsExpression() (bool, error) {
|
func (aq *AlertQuery) IsExpression() (bool, error) {
|
||||||
err := aq.setDatasource()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return aq.DatasourceUID == expr.DatasourceUID, nil
|
return aq.DatasourceUID == expr.DatasourceUID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,20 +170,11 @@ func (aq *AlertQuery) GetIntervalDuration() (time.Duration, error) {
|
|||||||
|
|
||||||
// GetDatasource returns the query datasource identifier.
|
// GetDatasource returns the query datasource identifier.
|
||||||
func (aq *AlertQuery) GetDatasource() (string, error) {
|
func (aq *AlertQuery) GetDatasource() (string, error) {
|
||||||
err := aq.setDatasource()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return aq.DatasourceUID, nil
|
return aq.DatasourceUID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aq *AlertQuery) GetModel() ([]byte, error) {
|
func (aq *AlertQuery) GetModel() ([]byte, error) {
|
||||||
err := aq.setDatasource()
|
err := aq.setMaxDatapoints()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = aq.setMaxDatapoints()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -250,10 +215,6 @@ func (aq *AlertQuery) setQueryType() error {
|
|||||||
// PreSave sets query's properties.
|
// PreSave sets query's properties.
|
||||||
// It should be called before being saved.
|
// It should be called before being saved.
|
||||||
func (aq *AlertQuery) PreSave() error {
|
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 {
|
if err := aq.setQueryType(); err != nil {
|
||||||
return fmt.Errorf("failed to set query type to query model: %w", err)
|
return fmt.Errorf("failed to set query type to query model: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -6,147 +6,130 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/expr"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAlertQuery(t *testing.T) {
|
func TestAlertQuery(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
alertQuery AlertQuery
|
alertQuery AlertQuery
|
||||||
expectedIsExpression bool
|
expectedIsExpression bool
|
||||||
expectedDatasource string
|
expectedDatasource string
|
||||||
expectedDatasourceUID string
|
expectedMaxPoints int64
|
||||||
expectedMaxPoints int64
|
expectedIntervalMS int64
|
||||||
expectedIntervalMS int64
|
err error
|
||||||
err error
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "given an expression query",
|
desc: "given an expression query",
|
||||||
alertQuery: AlertQuery{
|
alertQuery: AlertQuery{
|
||||||
RefID: "A",
|
RefID: "A",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"queryType": "metricQuery",
|
"queryType": "metricQuery",
|
||||||
"extraParam": "some text"
|
"extraParam": "some text"
|
||||||
}`),
|
}`),
|
||||||
|
DatasourceUID: "-100",
|
||||||
},
|
},
|
||||||
expectedIsExpression: true,
|
expectedIsExpression: true,
|
||||||
expectedDatasourceUID: expr.DatasourceUID,
|
expectedMaxPoints: int64(defaultMaxDataPoints),
|
||||||
expectedMaxPoints: int64(defaultMaxDataPoints),
|
expectedIntervalMS: int64(defaultIntervalMS),
|
||||||
expectedIntervalMS: int64(defaultIntervalMS),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "given a query",
|
desc: "given a query",
|
||||||
alertQuery: AlertQuery{
|
alertQuery: AlertQuery{
|
||||||
RefID: "A",
|
RefID: "A",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "000000001",
|
|
||||||
"queryType": "metricQuery",
|
"queryType": "metricQuery",
|
||||||
"extraParam": "some text"
|
"extraParam": "some text"
|
||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedIsExpression: false,
|
expectedIsExpression: false,
|
||||||
expectedDatasourceUID: "000000001",
|
expectedMaxPoints: int64(defaultMaxDataPoints),
|
||||||
expectedMaxPoints: int64(defaultMaxDataPoints),
|
expectedIntervalMS: int64(defaultIntervalMS),
|
||||||
expectedIntervalMS: int64(defaultIntervalMS),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "given a query with valid maxDataPoints",
|
desc: "given a query with valid maxDataPoints",
|
||||||
alertQuery: AlertQuery{
|
alertQuery: AlertQuery{
|
||||||
RefID: "A",
|
RefID: "A",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "000000001",
|
|
||||||
"queryType": "metricQuery",
|
"queryType": "metricQuery",
|
||||||
"maxDataPoints": 200,
|
"maxDataPoints": 200,
|
||||||
"extraParam": "some text"
|
"extraParam": "some text"
|
||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedIsExpression: false,
|
expectedIsExpression: false,
|
||||||
expectedDatasourceUID: "000000001",
|
expectedMaxPoints: 200,
|
||||||
expectedMaxPoints: 200,
|
expectedIntervalMS: int64(defaultIntervalMS),
|
||||||
expectedIntervalMS: int64(defaultIntervalMS),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "given a query with invalid maxDataPoints",
|
desc: "given a query with invalid maxDataPoints",
|
||||||
alertQuery: AlertQuery{
|
alertQuery: AlertQuery{
|
||||||
RefID: "A",
|
RefID: "A",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "000000001",
|
|
||||||
"queryType": "metricQuery",
|
"queryType": "metricQuery",
|
||||||
"maxDataPoints": "invalid",
|
"maxDataPoints": "invalid",
|
||||||
"extraParam": "some text"
|
"extraParam": "some text"
|
||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedIsExpression: false,
|
expectedIsExpression: false,
|
||||||
expectedDatasourceUID: "000000001",
|
expectedMaxPoints: int64(defaultMaxDataPoints),
|
||||||
expectedMaxPoints: int64(defaultMaxDataPoints),
|
expectedIntervalMS: int64(defaultIntervalMS),
|
||||||
expectedIntervalMS: int64(defaultIntervalMS),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "given a query with zero maxDataPoints",
|
desc: "given a query with zero maxDataPoints",
|
||||||
alertQuery: AlertQuery{
|
alertQuery: AlertQuery{
|
||||||
RefID: "A",
|
RefID: "A",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "000000001",
|
|
||||||
"queryType": "metricQuery",
|
"queryType": "metricQuery",
|
||||||
"maxDataPoints": 0,
|
"maxDataPoints": 0,
|
||||||
"extraParam": "some text"
|
"extraParam": "some text"
|
||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedIsExpression: false,
|
expectedIsExpression: false,
|
||||||
expectedDatasourceUID: "000000001",
|
expectedMaxPoints: int64(defaultMaxDataPoints),
|
||||||
expectedMaxPoints: int64(defaultMaxDataPoints),
|
expectedIntervalMS: int64(defaultIntervalMS),
|
||||||
expectedIntervalMS: int64(defaultIntervalMS),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "given a query with valid intervalMs",
|
desc: "given a query with valid intervalMs",
|
||||||
alertQuery: AlertQuery{
|
alertQuery: AlertQuery{
|
||||||
RefID: "A",
|
RefID: "A",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "000000001",
|
|
||||||
"queryType": "metricQuery",
|
"queryType": "metricQuery",
|
||||||
"intervalMs": 2000,
|
"intervalMs": 2000,
|
||||||
"extraParam": "some text"
|
"extraParam": "some text"
|
||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedIsExpression: false,
|
expectedIsExpression: false,
|
||||||
expectedDatasourceUID: "000000001",
|
expectedMaxPoints: int64(defaultMaxDataPoints),
|
||||||
expectedMaxPoints: int64(defaultMaxDataPoints),
|
expectedIntervalMS: 2000,
|
||||||
expectedIntervalMS: 2000,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "given a query with invalid intervalMs",
|
desc: "given a query with invalid intervalMs",
|
||||||
alertQuery: AlertQuery{
|
alertQuery: AlertQuery{
|
||||||
RefID: "A",
|
RefID: "A",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "000000001",
|
|
||||||
"queryType": "metricQuery",
|
"queryType": "metricQuery",
|
||||||
"intervalMs": "invalid",
|
"intervalMs": "invalid",
|
||||||
"extraParam": "some text"
|
"extraParam": "some text"
|
||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedIsExpression: false,
|
expectedIsExpression: false,
|
||||||
expectedDatasourceUID: "000000001",
|
expectedMaxPoints: int64(defaultMaxDataPoints),
|
||||||
expectedMaxPoints: int64(defaultMaxDataPoints),
|
expectedIntervalMS: int64(defaultIntervalMS),
|
||||||
expectedIntervalMS: int64(defaultIntervalMS),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "given a query with invalid intervalMs",
|
desc: "given a query with invalid intervalMs",
|
||||||
alertQuery: AlertQuery{
|
alertQuery: AlertQuery{
|
||||||
RefID: "A",
|
RefID: "A",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "000000001",
|
|
||||||
"queryType": "metricQuery",
|
"queryType": "metricQuery",
|
||||||
"intervalMs": 0,
|
"intervalMs": 0,
|
||||||
"extraParam": "some text"
|
"extraParam": "some text"
|
||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedIsExpression: false,
|
expectedIsExpression: false,
|
||||||
expectedDatasourceUID: "000000001",
|
expectedMaxPoints: int64(defaultMaxDataPoints),
|
||||||
expectedMaxPoints: int64(defaultMaxDataPoints),
|
expectedIntervalMS: int64(defaultIntervalMS),
|
||||||
expectedIntervalMS: int64(defaultIntervalMS),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,12 +141,6 @@ func TestAlertQuery(t *testing.T) {
|
|||||||
assert.Equal(t, tc.expectedIsExpression, isExpression)
|
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) {
|
t.Run("can set queryType for expression", func(t *testing.T) {
|
||||||
err := tc.alertQuery.setQueryType()
|
err := tc.alertQuery.setQueryType()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -189,13 +166,7 @@ func TestAlertQuery(t *testing.T) {
|
|||||||
err = json.Unmarshal(blob, &model)
|
err = json.Unmarshal(blob, &model)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
i, ok := model["datasourceUid"]
|
i, ok := model["maxDataPoints"]
|
||||||
require.True(t, ok)
|
|
||||||
datasourceUID, ok := i.(string)
|
|
||||||
require.True(t, ok)
|
|
||||||
require.Equal(t, tc.expectedDatasourceUID, datasourceUID)
|
|
||||||
|
|
||||||
i, ok = model["maxDataPoints"]
|
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
maxDataPoints, ok := i.(float64)
|
maxDataPoints, ok := i.(float64)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
@ -90,8 +90,8 @@ func TestAlertAndGroupsQuery(t *testing.T) {
|
|||||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||||
},
|
},
|
||||||
|
DatasourceUID: "-100",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 3 > 1"
|
"expression": "2 + 3 > 1"
|
||||||
}`),
|
}`),
|
||||||
@ -208,8 +208,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||||
},
|
},
|
||||||
|
DatasourceUID: "-100",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 3 > 1"
|
"expression": "2 + 3 > 1"
|
||||||
}`),
|
}`),
|
||||||
@ -238,8 +238,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||||
},
|
},
|
||||||
|
DatasourceUID: "-100",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 3 > 1"
|
"expression": "2 + 3 > 1"
|
||||||
}`),
|
}`),
|
||||||
@ -268,8 +268,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||||
},
|
},
|
||||||
|
DatasourceUID: "-100",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 3 > 1"
|
"expression": "2 + 3 > 1"
|
||||||
}`),
|
}`),
|
||||||
@ -299,8 +299,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||||
},
|
},
|
||||||
|
DatasourceUID: "-100",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 3 > 1"
|
"expression": "2 + 3 > 1"
|
||||||
}`),
|
}`),
|
||||||
@ -368,8 +368,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||||
},
|
},
|
||||||
|
DatasourceUID: "-100",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 3 > 1"
|
"expression": "2 + 3 > 1"
|
||||||
}`),
|
}`),
|
||||||
@ -388,8 +388,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||||
},
|
},
|
||||||
|
DatasourceUID: "-100",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 3 > 1"
|
"expression": "2 + 3 > 1"
|
||||||
}`),
|
}`),
|
||||||
@ -474,8 +474,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from":18000,
|
"from":18000,
|
||||||
"to":10800
|
"to":10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid":"-100",
|
||||||
"model":{
|
"model":{
|
||||||
"datasourceUid":"-100",
|
|
||||||
"expression":"2 + 3 \u003e 1",
|
"expression":"2 + 3 \u003e 1",
|
||||||
"intervalMs":1000,
|
"intervalMs":1000,
|
||||||
"maxDataPoints":100,
|
"maxDataPoints":100,
|
||||||
@ -509,8 +509,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from":18000,
|
"from":18000,
|
||||||
"to":10800
|
"to":10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid":"-100",
|
||||||
"model":{
|
"model":{
|
||||||
"datasourceUid":"-100",
|
|
||||||
"expression":"2 + 3 \u003e 1",
|
"expression":"2 + 3 \u003e 1",
|
||||||
"intervalMs":1000,
|
"intervalMs":1000,
|
||||||
"maxDataPoints":100,
|
"maxDataPoints":100,
|
||||||
@ -567,8 +567,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||||
},
|
},
|
||||||
|
DatasourceUID: "-100",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 3 < 1"
|
"expression": "2 + 3 < 1"
|
||||||
}`),
|
}`),
|
||||||
@ -651,8 +651,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||||||
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||||||
},
|
},
|
||||||
|
DatasourceUID: "-100",
|
||||||
Model: json.RawMessage(`{
|
Model: json.RawMessage(`{
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"expression": "2 + 3 < 1"
|
"expression": "2 + 3 < 1"
|
||||||
}`),
|
}`),
|
||||||
@ -733,8 +733,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from":18000,
|
"from":18000,
|
||||||
"to":10800
|
"to":10800
|
||||||
},
|
},
|
||||||
"model":{
|
"datasourceUid":"-100",
|
||||||
"datasourceUid":"-100",
|
"model":{
|
||||||
"expression":"2 + 3 \u003C 1",
|
"expression":"2 + 3 \u003C 1",
|
||||||
"intervalMs":1000,
|
"intervalMs":1000,
|
||||||
"maxDataPoints":100,
|
"maxDataPoints":100,
|
||||||
@ -817,8 +817,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid":"-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type":"math",
|
"type":"math",
|
||||||
"expression":"1 < 2"
|
"expression":"1 < 2"
|
||||||
}
|
}
|
||||||
@ -868,8 +868,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type":"math",
|
"type":"math",
|
||||||
"expression":"1 > 2"
|
"expression":"1 > 2"
|
||||||
}
|
}
|
||||||
@ -919,8 +919,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type":"math",
|
"type":"math",
|
||||||
"expression":"1 > 2"
|
"expression":"1 > 2"
|
||||||
}
|
}
|
||||||
@ -946,8 +946,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "unknown",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "unknown"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -997,8 +997,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type":"math",
|
"type":"math",
|
||||||
"expression":"1 < 2"
|
"expression":"1 < 2"
|
||||||
}
|
}
|
||||||
@ -1050,8 +1050,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "-100",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "-100",
|
|
||||||
"type":"math",
|
"type":"math",
|
||||||
"expression":"1 > 2"
|
"expression":"1 > 2"
|
||||||
}
|
}
|
||||||
@ -1103,8 +1103,8 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
"from": 18000,
|
"from": 18000,
|
||||||
"to": 10800
|
"to": 10800
|
||||||
},
|
},
|
||||||
|
"datasourceUid": "unknown",
|
||||||
"model": {
|
"model": {
|
||||||
"datasourceUid": "unknown"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user