Expressions: Fixes the issue showing expressions editor (#62510)

* Use suggested value for uid

* update the snapshot

* use __expr__

* replace all -100 with __expr__

* update snapshot

* more changes

* revert redundant change

* Use expr.DatasourceUID where it's possible

* generate files
This commit is contained in:
ismail simsek
2023-01-31 18:50:10 +01:00
committed by GitHub
parent fdb1a47ca2
commit 91221bc436
54 changed files with 259 additions and 242 deletions

View File

@@ -23,7 +23,7 @@ apiVersion: 1
# # evaluation - should be obtained via the API # # evaluation - should be obtained via the API
# data: # data:
# - refId: A # - refId: A
# datasourceUid: "-100" # datasourceUid: "__expr__"
# model: # model:
# conditions: # conditions:
# - evaluator: # - evaluator:
@@ -40,7 +40,7 @@ apiVersion: 1
# type: query # type: query
# datasource: # datasource:
# type: __expr__ # type: __expr__
# uid: "-100" # uid: "__expr__"
# expression: 1==0 # expression: 1==0
# intervalMs: 1000 # intervalMs: 1000
# maxDataPoints: 43200 # maxDataPoints: 43200

View File

@@ -69,7 +69,7 @@ groups:
# evaluation - should be obtained trough the API # evaluation - should be obtained trough the API
data: data:
- refId: A - refId: A
datasourceUid: '-100' datasourceUid: '__expr__'
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -86,7 +86,7 @@ groups:
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: '-100' uid: '__expr__'
expression: 1==0 expression: 1==0
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200

View File

@@ -282,7 +282,7 @@ resource "grafana_rule_group" "my_rule_group" {
// The query was configured to obtain data from the last 60 seconds. Let's alert on the average value of that series using a Reduce stage. // The query was configured to obtain data from the last 60 seconds. Let's alert on the average value of that series using a Reduce stage.
data { data {
datasource_uid = "-100" datasource_uid = "__expr__"
// You can also create a rule in the UI, then GET that rule to obtain the JSON. // You can also create a rule in the UI, then GET that rule to obtain the JSON.
// This can be helpful when using more complex reduce expressions. // This can be helpful when using more complex reduce expressions.
model = <<EOT model = <<EOT
@@ -298,7 +298,7 @@ EOT
// Now, let's use a math expression as our threshold. // Now, let's use a math expression as our threshold.
// We want to alert when the value of stage "B" above exceeds 70. // We want to alert when the value of stage "B" above exceeds 70.
data { data {
datasource_uid = "-100" datasource_uid = "__expr__"
ref_id = "C" ref_id = "C"
relative_time_range { relative_time_range {
from = 0 from = 0

View File

@@ -993,8 +993,8 @@ Status: Accepted
**Properties** **Properties**
| Name | Type | Go type | Required | Default | Description | Example | | Name | Type | Go type | Required | Default | Description | Example |
| --------------------------------------------------------- | ----------------------------------------- | ------------------- | :------: | ------- | -------------------------------------------------------------------------------------------------- | ------- | | --------------------------------------------------------- | ----------------------------------------- | ------------------- | :------: | ------- | ------------------------------------------------------------------------------------------------------ | ------- |
| datasourceUid | string | `string` | | | Grafana data source unique identifier; it should be '-100' for a Server Side Expression operation. | | | datasourceUid | string | `string` | | | Grafana data source unique identifier; it should be '**expr**' for a Server Side Expression operation. | |
| model | [interface{}](#interface) | `interface{}` | | | JSON is the raw JSON query and includes the above properties as well as custom properties. | | | model | [interface{}](#interface) | `interface{}` | | | JSON is the raw JSON query and includes the above properties as well as custom properties. | |
| queryType | string | `string` | | | QueryType is an optional identifier for the type of query. | | queryType | string | `string` | | | QueryType is an optional identifier for the type of query. |
| It can be used to distinguish different types of queries. | | | It can be used to distinguish different types of queries. | |
@@ -1175,10 +1175,10 @@ Status: Accepted
**Properties** **Properties**
| Name | Type | Go type | Required | Default | Description | Example | | Name | Type | Go type | Required | Default | Description | Example |
| ------------ | ---------------------------- | ------------------- | :------: | ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------ | ---------------------------- | ------------------- | :------: | ------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| annotations | map of string | `map[string]string` | | | | `{"runbook_url":"https://supercoolrunbook.com/page/13"}` | | annotations | map of string | `map[string]string` | | | | `{"runbook_url":"https://supercoolrunbook.com/page/13"}` |
| condition | string | `string` | ✓ | | | `A` | | condition | string | `string` | ✓ | | | `A` |
| data | [][alertquery](#alert-query) | `[]*AlertQuery` | ✓ | | | `[{"datasourceUid":"-100","model":{"conditions":[{"evaluator":{"params":[0,0],"type":"gt"},"operator":{"type":"and"},"query":{"params":[]},"reducer":{"params":[],"type":"avg"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1 == 1","hide":false,"intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"},"queryType":"","refId":"A","relativeTimeRange":{"from":0,"to":0}}]` | | data | [][alertquery](#alert-query) | `[]*AlertQuery` | ✓ | | | `[{"datasourceUid":"__expr__","model":{"conditions":[{"evaluator":{"params":[0,0],"type":"gt"},"operator":{"type":"and"},"query":{"params":[]},"reducer":{"params":[],"type":"avg"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1 == 1","hide":false,"intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"},"queryType":"","refId":"A","relativeTimeRange":{"from":0,"to":0}}]` |
| execErrState | string | `string` | ✓ | | | | | execErrState | string | `string` | ✓ | | | |
| folderUID | string | `string` | ✓ | | | `project_x` | | folderUID | string | `string` | ✓ | | | `project_x` |
| for | [Duration](#duration) | `Duration` | ✓ | | | | | for | [Duration](#duration) | `Duration` | ✓ | | | |

View File

@@ -2,30 +2,30 @@ import { lastValueFrom, merge, Observable, of } from 'rxjs';
import { catchError, switchMap } from 'rxjs/operators'; import { catchError, switchMap } from 'rxjs/operators';
import { import {
DataSourceApi, DataFrame,
dataFrameToJSON,
DataQuery,
DataQueryRequest, DataQueryRequest,
DataQueryResponse, DataQueryResponse,
DataSourceApi,
DataSourceInstanceSettings, DataSourceInstanceSettings,
DataQuery,
DataSourceJsonData, DataSourceJsonData,
ScopedVars,
makeClassES5Compatible,
DataFrame,
parseLiveChannelAddress,
getDataSourceRef,
DataSourceRef, DataSourceRef,
dataFrameToJSON, getDataSourceRef,
makeClassES5Compatible,
parseLiveChannelAddress,
ScopedVars,
} from '@grafana/data'; } from '@grafana/data';
import { config } from '../config'; import { config } from '../config';
import { import {
BackendSrvRequest,
FetchResponse,
getBackendSrv, getBackendSrv,
getDataSourceSrv, getDataSourceSrv,
getGrafanaLiveSrv, getGrafanaLiveSrv,
StreamingFrameOptions,
StreamingFrameAction, StreamingFrameAction,
BackendSrvRequest, StreamingFrameOptions,
FetchResponse,
} from '../services'; } from '../services';
import { BackendDataSourceResponse, toDataQueryResponse } from './queryResponse'; import { BackendDataSourceResponse, toDataQueryResponse } from './queryResponse';

View File

@@ -8,6 +8,7 @@ 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"
@@ -737,7 +738,7 @@ func insertTestRule(t *testing.T, sqlStore db.DB, foderOrgID int64, folderUID st
Data: []alertQuery{ Data: []alertQuery{
{ {
RefID: "A", RefID: "A",
DatasourceUID: "-100", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"

View File

@@ -11,6 +11,7 @@ import (
alertingModels "github.com/grafana/alerting/alerting/models" alertingModels "github.com/grafana/alerting/alerting/models"
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"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"
@@ -571,7 +572,7 @@ func withClassicConditionSingleQuery() func(r *ngmodels.AlertRule) {
RefID: "B", RefID: "B",
QueryType: "", QueryType: "",
RelativeTimeRange: ngmodels.RelativeTimeRange{From: ngmodels.Duration(0), To: ngmodels.Duration(0)}, RelativeTimeRange: ngmodels.RelativeTimeRange{From: ngmodels.Duration(0), To: ngmodels.Duration(0)},
DatasourceUID: "-100", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(fmt.Sprintf(classicConditionsModel, "A", "B")), Model: json.RawMessage(fmt.Sprintf(classicConditionsModel, "A", "B")),
}, },
} }
@@ -600,21 +601,21 @@ func withExpressionsMultiQuery() func(r *ngmodels.AlertRule) {
RefID: "C", RefID: "C",
QueryType: "", QueryType: "",
RelativeTimeRange: ngmodels.RelativeTimeRange{From: ngmodels.Duration(0), To: ngmodels.Duration(0)}, RelativeTimeRange: ngmodels.RelativeTimeRange{From: ngmodels.Duration(0), To: ngmodels.Duration(0)},
DatasourceUID: "-100", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(fmt.Sprintf(reduceLastExpressionModel, "A", "C")), Model: json.RawMessage(fmt.Sprintf(reduceLastExpressionModel, "A", "C")),
}, },
{ {
RefID: "D", RefID: "D",
QueryType: "", QueryType: "",
RelativeTimeRange: ngmodels.RelativeTimeRange{From: ngmodels.Duration(0), To: ngmodels.Duration(0)}, RelativeTimeRange: ngmodels.RelativeTimeRange{From: ngmodels.Duration(0), To: ngmodels.Duration(0)},
DatasourceUID: "-100", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(fmt.Sprintf(reduceLastExpressionModel, "B", "D")), Model: json.RawMessage(fmt.Sprintf(reduceLastExpressionModel, "B", "D")),
}, },
{ {
RefID: "E", RefID: "E",
QueryType: "", QueryType: "",
RelativeTimeRange: ngmodels.RelativeTimeRange{From: ngmodels.Duration(0), To: ngmodels.Duration(0)}, RelativeTimeRange: ngmodels.RelativeTimeRange{From: ngmodels.Duration(0), To: ngmodels.Duration(0)},
DatasourceUID: "-100", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(fmt.Sprintf(mathExpressionModel, "A", "B", "E")), Model: json.RawMessage(fmt.Sprintf(mathExpressionModel, "A", "B", "E")),
}, },
} }

View File

@@ -38,7 +38,7 @@ const classicConditionsModel = `
}], }],
"datasource": { "datasource": {
"type": "__expr__", "type": "__expr__",
"uid": "-100" "uid": "__expr__"
}, },
"hide": false, "hide": false,
"intervalMs": 1000, "intervalMs": 1000,

View File

@@ -480,7 +480,7 @@ func TestProvisioningApi(t *testing.T) {
insertRule(t, sut, createTestAlertRule("rule1", 1)) insertRule(t, sut, createTestAlertRule("rule1", 1))
insertRule(t, sut, createTestAlertRule("rule2", 1)) insertRule(t, sut, createTestAlertRule("rule2", 1))
expectedResponse := `{"apiVersion":1,"groups":[{"orgId":1,"name":"my-cool-group","folder":"Folder Title","interval":"1m","rules":[{"uid":"rule1","title":"rule1","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"-100"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false},{"uid":"rule2","title":"rule2","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"-100"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]}]}` expectedResponse := `{"apiVersion":1,"groups":[{"orgId":1,"name":"my-cool-group","folder":"Folder Title","interval":"1m","rules":[{"uid":"rule1","title":"rule1","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false},{"uid":"rule2","title":"rule2","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]}]}`
response := sut.RouteGetAlertRuleGroupExport(&rc, "folder-uid", "my-cool-group") response := sut.RouteGetAlertRuleGroupExport(&rc, "folder-uid", "my-cool-group")
@@ -495,7 +495,11 @@ func TestProvisioningApi(t *testing.T) {
insertRule(t, sut, createTestAlertRule("rule2", 1)) insertRule(t, sut, createTestAlertRule("rule2", 1))
rc.Context.Req.Header.Add("Accept", "application/yaml") rc.Context.Req.Header.Add("Accept", "application/yaml")
expectedResponse := "apiVersion: 1\ngroups:\n - orgId: 1\n name: my-cool-group\n folder: Folder Title\n interval: 1m\n rules:\n - uid: rule1\n title: rule1\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: \"-100\"\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n - uid: rule2\n title: rule2\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: \"-100\"\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n" expectedResponse := "apiVersion: 1\ngroups:\n - orgId: 1\n name: my-cool-group\n folder" +
": Folder Title\n interval: 1m\n rules:\n - uid: rule1\n title: rule1\n" +
" condition: A\n data:\n - refId: A\n datasourceUid" +
": \"\"\n model:\n conditions:\n - evaluator:\n" +
" params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: __expr__\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n - uid: rule2\n title: rule2\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: __expr__\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n"
response := sut.RouteGetAlertRuleGroupExport(&rc, "folder-uid", "my-cool-group") response := sut.RouteGetAlertRuleGroupExport(&rc, "folder-uid", "my-cool-group")
@@ -607,7 +611,7 @@ func TestProvisioningApi(t *testing.T) {
rc := createTestRequestCtx() rc := createTestRequestCtx()
insertRule(t, sut, createTestAlertRule("rule1", 1)) insertRule(t, sut, createTestAlertRule("rule1", 1))
expectedResponse := `{"apiVersion":1,"groups":[{"orgId":1,"name":"my-cool-group","folder":"Folder Title","interval":"1m","rules":[{"uid":"rule1","title":"rule1","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"-100"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]}]}` expectedResponse := `{"apiVersion":1,"groups":[{"orgId":1,"name":"my-cool-group","folder":"Folder Title","interval":"1m","rules":[{"uid":"rule1","title":"rule1","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]}]}`
response := sut.RouteGetAlertRuleExport(&rc, "rule1") response := sut.RouteGetAlertRuleExport(&rc, "rule1")
@@ -621,7 +625,7 @@ func TestProvisioningApi(t *testing.T) {
insertRule(t, sut, createTestAlertRule("rule1", 1)) insertRule(t, sut, createTestAlertRule("rule1", 1))
rc.Context.Req.Header.Add("Accept", "application/yaml") rc.Context.Req.Header.Add("Accept", "application/yaml")
expectedResponse := "apiVersion: 1\ngroups:\n - orgId: 1\n name: my-cool-group\n folder: Folder Title\n interval: 1m\n rules:\n - uid: rule1\n title: rule1\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: \"-100\"\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n" expectedResponse := "apiVersion: 1\ngroups:\n - orgId: 1\n name: my-cool-group\n folder: Folder Title\n interval: 1m\n rules:\n - uid: rule1\n title: rule1\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: __expr__\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n"
response := sut.RouteGetAlertRuleExport(&rc, "rule1") response := sut.RouteGetAlertRuleExport(&rc, "rule1")
@@ -725,7 +729,7 @@ func TestProvisioningApi(t *testing.T) {
insertRule(t, sut, createTestAlertRuleWithFolderAndGroup("rule2", 1, "folder-uid", "groupb")) insertRule(t, sut, createTestAlertRuleWithFolderAndGroup("rule2", 1, "folder-uid", "groupb"))
insertRule(t, sut, createTestAlertRuleWithFolderAndGroup("rule3", 1, "folder-uid2", "groupb")) insertRule(t, sut, createTestAlertRuleWithFolderAndGroup("rule3", 1, "folder-uid2", "groupb"))
expectedResponse := `{"apiVersion":1,"groups":[{"orgId":1,"name":"groupa","folder":"Folder Title","interval":"1m","rules":[{"uid":"rule1","title":"rule1","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"-100"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]},{"orgId":1,"name":"groupb","folder":"Folder Title","interval":"1m","rules":[{"uid":"rule2","title":"rule2","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"-100"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]},{"orgId":1,"name":"groupb","folder":"Folder Title2","interval":"1m","rules":[{"uid":"rule3","title":"rule3","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"-100"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]}]}` expectedResponse := `{"apiVersion":1,"groups":[{"orgId":1,"name":"groupa","folder":"Folder Title","interval":"1m","rules":[{"uid":"rule1","title":"rule1","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]},{"orgId":1,"name":"groupb","folder":"Folder Title","interval":"1m","rules":[{"uid":"rule2","title":"rule2","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]},{"orgId":1,"name":"groupb","folder":"Folder Title2","interval":"1m","rules":[{"uid":"rule3","title":"rule3","condition":"A","data":[{"refId":"A","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"","model":{"conditions":[{"evaluator":{"params":[3],"type":"gt"},"operator":{"type":"and"},"query":{"params":["A"]},"reducer":{"type":"last"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1==0","intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}],"noDataState":"OK","execErrState":"OK","for":"0s","isPaused":false}]}]}`
response := sut.RouteGetAlertRulesExport(&rc) response := sut.RouteGetAlertRulesExport(&rc)
@@ -741,7 +745,7 @@ func TestProvisioningApi(t *testing.T) {
insertRule(t, sut, createTestAlertRuleWithFolderAndGroup("rule3", 1, "folder-uid2", "groupb")) insertRule(t, sut, createTestAlertRuleWithFolderAndGroup("rule3", 1, "folder-uid2", "groupb"))
rc.Context.Req.Header.Add("Accept", "application/yaml") rc.Context.Req.Header.Add("Accept", "application/yaml")
expectedResponse := "apiVersion: 1\ngroups:\n - orgId: 1\n name: groupa\n folder: Folder Title\n interval: 1m\n rules:\n - uid: rule1\n title: rule1\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: \"-100\"\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n - orgId: 1\n name: groupb\n folder: Folder Title\n interval: 1m\n rules:\n - uid: rule2\n title: rule2\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: \"-100\"\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n - orgId: 1\n name: groupb\n folder: Folder Title2\n interval: 1m\n rules:\n - uid: rule3\n title: rule3\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: \"-100\"\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n" expectedResponse := "apiVersion: 1\ngroups:\n - orgId: 1\n name: groupa\n folder: Folder Title\n interval: 1m\n rules:\n - uid: rule1\n title: rule1\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: __expr__\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n - orgId: 1\n name: groupb\n folder: Folder Title\n interval: 1m\n rules:\n - uid: rule2\n title: rule2\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: __expr__\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n - orgId: 1\n name: groupb\n folder: Folder Title2\n interval: 1m\n rules:\n - uid: rule3\n title: rule3\n condition: A\n data:\n - refId: A\n datasourceUid: \"\"\n model:\n conditions:\n - evaluator:\n params:\n - 3\n type: gt\n operator:\n type: and\n query:\n params:\n - A\n reducer:\n type: last\n type: query\n datasource:\n type: __expr__\n uid: __expr__\n expression: 1==0\n intervalMs: 1000\n maxDataPoints: 43200\n refId: A\n type: math\n noDataState: OK\n execErrState: OK\n for: 0s\n isPaused: false\n"
response := sut.RouteGetAlertRulesExport(&rc) response := sut.RouteGetAlertRulesExport(&rc)
@@ -1034,7 +1038,7 @@ var testModel = `
], ],
"datasource": { "datasource": {
"type": "__expr__", "type": "__expr__",
"uid": "-100" "uid": "__expr__"
}, },
"expression": "1==0", "expression": "1==0",
"intervalMs": 1000, "intervalMs": 1000,

View File

@@ -236,7 +236,9 @@ func (api *API) authorize(method, path string) web.Handler {
// authorizeDatasourceAccessForRule checks that user has access to all data sources declared by the rule // authorizeDatasourceAccessForRule checks that user has access to all data sources declared by the rule
func authorizeDatasourceAccessForRule(rule *ngmodels.AlertRule, evaluator func(evaluator ac.Evaluator) bool) bool { func authorizeDatasourceAccessForRule(rule *ngmodels.AlertRule, evaluator func(evaluator ac.Evaluator) bool) bool {
for _, query := range rule.Data { for _, query := range rule.Data {
if query.QueryType == expr.DatasourceType || query.DatasourceUID == expr.OldDatasourceUID { if query.QueryType == expr.DatasourceType || query.DatasourceUID == expr.DatasourceUID || query.
DatasourceUID == expr.
OldDatasourceUID {
continue continue
} }
if !evaluator(ac.EvalPermission(datasources.ActionQuery, datasources.ScopeProvider.GetResourceScopeUID(query.DatasourceUID))) { if !evaluator(ac.EvalPermission(datasources.ActionQuery, datasources.ScopeProvider.GetResourceScopeUID(query.DatasourceUID))) {

View File

@@ -401,7 +401,7 @@ func TestCheckDatasourcePermissionsForRule(t *testing.T) {
expressionByType := models.GenerateAlertQuery() expressionByType := models.GenerateAlertQuery()
expressionByType.QueryType = expr.DatasourceType expressionByType.QueryType = expr.DatasourceType
expressionByUID := models.GenerateAlertQuery() expressionByUID := models.GenerateAlertQuery()
expressionByUID.DatasourceUID = expr.OldDatasourceUID expressionByUID.DatasourceUID = expr.DatasourceUID
var data []models.AlertQuery var data []models.AlertQuery
var scopes []string var scopes []string

View File

@@ -32,7 +32,7 @@
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "query", "expression": "query",
"hide": false, "hide": false,
@@ -50,7 +50,7 @@
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "$reduced > 10", "expression": "$reduced > 10",
"hide": false, "hide": false,
@@ -95,7 +95,7 @@
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "$A", "expression": "$A",
"intervalMs": 2000, "intervalMs": 2000,

View File

@@ -39,7 +39,7 @@
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "query", "expression": "query",
"hide": false, "hide": false,
@@ -57,7 +57,7 @@
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "$reduced > 10", "expression": "$reduced > 10",
"hide": false, "hide": false,
@@ -102,7 +102,7 @@
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "$A", "expression": "$A",
"intervalMs": 2000, "intervalMs": 2000,

View File

@@ -98,7 +98,7 @@ content-type: application/json
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "query", "expression": "query",
"hide": false, "hide": false,
@@ -116,7 +116,7 @@ content-type: application/json
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "$reduced > 10", "expression": "$reduced > 10",
"hide": false, "hide": false,
@@ -184,7 +184,7 @@ content-type: application/json
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "query", "expression": "query",
"hide": false, "hide": false,
@@ -202,7 +202,7 @@ content-type: application/json
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "$reduced > 42", "expression": "$reduced > 42",
"hide": false, "hide": false,
@@ -283,7 +283,7 @@ Content-Type: application/json
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "query", "expression": "query",
"hide": false, "hide": false,
@@ -301,7 +301,7 @@ Content-Type: application/json
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "$reduced > 42", "expression": "$reduced > 42",
"hide": false, "hide": false,

View File

@@ -9,7 +9,7 @@
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"type": "math", "type": "math",
"expression": "2 + 2 > 1" "expression": "2 + 2 > 1"

View File

@@ -15,7 +15,7 @@ content-type: application/json
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"type":"math", "type":"math",
"expression":"1 < 2" "expression":"1 < 2"
@@ -56,7 +56,7 @@ content-type: application/json
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "$A", "expression": "$A",
"intervalMs": 2000, "intervalMs": 2000,
@@ -113,7 +113,7 @@ content-type: application/json
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"type":"math", "type":"math",
"expression":"1 < 2" "expression":"1 < 2"
@@ -121,7 +121,7 @@ content-type: application/json
} }
] ]
} }
}} }
### grafana recipient - lotex payload ### grafana recipient - lotex payload
POST http://admin:admin@localhost:3000/api/v1/rule/test/{{grafanaRecipient}} POST http://admin:admin@localhost:3000/api/v1/rule/test/{{grafanaRecipient}}

View File

@@ -99,7 +99,7 @@
"AlertQuery": { "AlertQuery": {
"properties": { "properties": {
"datasourceUid": { "datasourceUid": {
"description": "Grafana data source unique identifier; it should be '-100' for a Server Side Expression operation.", "description": "Grafana data source unique identifier; it should be '__expr__' for a Server Side Expression operation.",
"type": "string" "type": "string"
}, },
"model": { "model": {
@@ -2212,7 +2212,7 @@
"data": { "data": {
"example": [ "example": [
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -3284,7 +3284,6 @@
"type": "object" "type": "object"
}, },
"URL": { "URL": {
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
"properties": { "properties": {
"ForceQuery": { "ForceQuery": {
"type": "boolean" "type": "boolean"
@@ -3320,7 +3319,7 @@
"$ref": "#/definitions/Userinfo" "$ref": "#/definitions/Userinfo"
} }
}, },
"title": "A URL represents a parsed URL (technically, a URI reference).", "title": "URL is a custom URL type that allows validation at configuration load time.",
"type": "object" "type": "object"
}, },
"Userinfo": { "Userinfo": {
@@ -3497,6 +3496,7 @@
"type": "object" "type": "object"
}, },
"alertGroup": { "alertGroup": {
"description": "AlertGroup alert group",
"properties": { "properties": {
"alerts": { "alerts": {
"description": "alerts", "description": "alerts",
@@ -3624,6 +3624,7 @@
"type": "object" "type": "object"
}, },
"gettableAlert": { "gettableAlert": {
"description": "GettableAlert gettable alert",
"properties": { "properties": {
"annotations": { "annotations": {
"$ref": "#/definitions/labelSet" "$ref": "#/definitions/labelSet"
@@ -3685,7 +3686,6 @@
"type": "array" "type": "array"
}, },
"gettableSilence": { "gettableSilence": {
"description": "GettableSilence gettable silence",
"properties": { "properties": {
"comment": { "comment": {
"description": "comment", "description": "comment",
@@ -3734,6 +3734,7 @@
"type": "object" "type": "object"
}, },
"gettableSilences": { "gettableSilences": {
"description": "GettableSilences gettable silences",
"items": { "items": {
"$ref": "#/definitions/gettableSilence" "$ref": "#/definitions/gettableSilence"
}, },

View File

@@ -118,7 +118,7 @@ type ProvisionedAlertRule struct {
// example: A // example: A
Condition string `json:"condition"` Condition string `json:"condition"`
// required: true // required: true
// example: [{"refId":"A","queryType":"","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"-100","model":{"conditions":[{"evaluator":{"params":[0,0],"type":"gt"},"operator":{"type":"and"},"query":{"params":[]},"reducer":{"params":[],"type":"avg"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1 == 1","hide":false,"intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}] // example: [{"refId":"A","queryType":"","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"__expr__","model":{"conditions":[{"evaluator":{"params":[0,0],"type":"gt"},"operator":{"type":"and"},"query":{"params":[]},"reducer":{"params":[],"type":"avg"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"1 == 1","hide":false,"intervalMs":1000,"maxDataPoints":43200,"refId":"A","type":"math"}}]
Data []models.AlertQuery `json:"data"` Data []models.AlertQuery `json:"data"`
// readonly: true // readonly: true
Updated time.Time `json:"updated,omitempty"` Updated time.Time `json:"updated,omitempty"`

View File

@@ -99,7 +99,7 @@
"AlertQuery": { "AlertQuery": {
"properties": { "properties": {
"datasourceUid": { "datasourceUid": {
"description": "Grafana data source unique identifier; it should be '-100' for a Server Side Expression operation.", "description": "Grafana data source unique identifier; it should be '__expr__' for a Server Side Expression operation.",
"type": "string" "type": "string"
}, },
"model": { "model": {
@@ -2212,7 +2212,7 @@
"data": { "data": {
"example": [ "example": [
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -3284,7 +3284,6 @@
"type": "object" "type": "object"
}, },
"URL": { "URL": {
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
"properties": { "properties": {
"ForceQuery": { "ForceQuery": {
"type": "boolean" "type": "boolean"
@@ -3320,7 +3319,7 @@
"$ref": "#/definitions/Userinfo" "$ref": "#/definitions/Userinfo"
} }
}, },
"title": "A URL represents a parsed URL (technically, a URI reference).", "title": "URL is a custom URL type that allows validation at configuration load time.",
"type": "object" "type": "object"
}, },
"Userinfo": { "Userinfo": {
@@ -3497,7 +3496,6 @@
"type": "object" "type": "object"
}, },
"alertGroup": { "alertGroup": {
"description": "AlertGroup alert group",
"properties": { "properties": {
"alerts": { "alerts": {
"description": "alerts", "description": "alerts",
@@ -3742,6 +3740,7 @@
"type": "array" "type": "array"
}, },
"integration": { "integration": {
"description": "Integration integration",
"properties": { "properties": {
"lastNotifyAttempt": { "lastNotifyAttempt": {
"description": "A timestamp indicating the last attempt to deliver a notification regardless of the outcome.\nFormat: date-time", "description": "A timestamp indicating the last attempt to deliver a notification regardless of the outcome.\nFormat: date-time",
@@ -3885,7 +3884,6 @@
"type": "array" "type": "array"
}, },
"postableSilence": { "postableSilence": {
"description": "PostableSilence postable silence",
"properties": { "properties": {
"comment": { "comment": {
"description": "comment", "description": "comment",
@@ -3923,6 +3921,7 @@
"type": "object" "type": "object"
}, },
"receiver": { "receiver": {
"description": "Receiver receiver",
"properties": { "properties": {
"active": { "active": {
"description": "active", "description": "active",

View File

@@ -2711,7 +2711,7 @@
"title": "AlertQuery represents a single query associated with an alert definition.", "title": "AlertQuery represents a single query associated with an alert definition.",
"properties": { "properties": {
"datasourceUid": { "datasourceUid": {
"description": "Grafana data source unique identifier; it should be '-100' for a Server Side Expression operation.", "description": "Grafana data source unique identifier; it should be '__expr__' for a Server Side Expression operation.",
"type": "string" "type": "string"
}, },
"model": { "model": {
@@ -4843,7 +4843,7 @@
}, },
"example": [ "example": [
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -5899,9 +5899,8 @@
} }
}, },
"URL": { "URL": {
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
"type": "object", "type": "object",
"title": "A URL represents a parsed URL (technically, a URI reference).", "title": "URL is a custom URL type that allows validation at configuration load time.",
"properties": { "properties": {
"ForceQuery": { "ForceQuery": {
"type": "boolean" "type": "boolean"
@@ -6112,7 +6111,6 @@
} }
}, },
"alertGroup": { "alertGroup": {
"description": "AlertGroup alert group",
"type": "object", "type": "object",
"required": [ "required": [
"alerts", "alerts",
@@ -6363,6 +6361,7 @@
"$ref": "#/definitions/gettableSilences" "$ref": "#/definitions/gettableSilences"
}, },
"integration": { "integration": {
"description": "Integration integration",
"type": "object", "type": "object",
"required": [ "required": [
"name", "name",
@@ -6507,7 +6506,6 @@
} }
}, },
"postableSilence": { "postableSilence": {
"description": "PostableSilence postable silence",
"type": "object", "type": "object",
"required": [ "required": [
"comment", "comment",
@@ -6546,6 +6544,7 @@
"$ref": "#/definitions/postableSilence" "$ref": "#/definitions/postableSilence"
}, },
"receiver": { "receiver": {
"description": "Receiver receiver",
"type": "object", "type": "object",
"required": [ "required": [
"active", "active",

View File

@@ -88,7 +88,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"`
// Grafana data source unique identifier; it should be '-100' for a Server Side Expression operation. // Grafana data source unique identifier; it should be '__expr__' for a Server Side Expression operation.
DatasourceUID string `json:"datasourceUid"` 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.

View File

@@ -7,6 +7,7 @@ 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"
) )
@@ -29,7 +30,7 @@ func TestAlertQuery(t *testing.T) {
"queryType": "metricQuery", "queryType": "metricQuery",
"extraParam": "some text" "extraParam": "some text"
}`), }`),
DatasourceUID: "-100", DatasourceUID: expr.DatasourceUID,
}, },
expectedIsExpression: true, expectedIsExpression: true,
expectedMaxPoints: int64(defaultMaxDataPoints), expectedMaxPoints: int64(defaultMaxDataPoints),

View File

@@ -300,7 +300,7 @@ func CreateClassicConditionExpression(refID string, inputRefID string, reducer s
return AlertQuery{ return AlertQuery{
RefID: refID, RefID: refID,
QueryType: expr.DatasourceType, QueryType: expr.DatasourceType,
DatasourceUID: expr.OldDatasourceUID, DatasourceUID: expr.DatasourceUID,
// the format corresponds to model `ClassicConditionJSON` in /pkg/expr/classic/classic.go // the format corresponds to model `ClassicConditionJSON` in /pkg/expr/classic/classic.go
Model: json.RawMessage(fmt.Sprintf(` Model: json.RawMessage(fmt.Sprintf(`
{ {
@@ -334,7 +334,7 @@ func CreateClassicConditionExpression(refID string, inputRefID string, reducer s
} }
} }
] ]
}`, refID, inputRefID, operation, threshold, reducer, expr.OldDatasourceUID, expr.DatasourceType)), }`, refID, inputRefID, operation, threshold, reducer, expr.DatasourceUID, expr.DatasourceType)),
} }
} }

View File

@@ -7,6 +7,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/expr"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db"
@@ -371,7 +372,7 @@ func createTestRule(title string, groupTitle string, orgID int64) models.AlertRu
{ {
RefID: "A", RefID: "A",
Model: json.RawMessage("{}"), Model: json.RawMessage("{}"),
DatasourceUID: "-100", DatasourceUID: expr.DatasourceUID,
RelativeTimeRange: models.RelativeTimeRange{ RelativeTimeRange: models.RelativeTimeRange{
From: models.Duration(60), From: models.Duration(60),
To: models.Duration(0), To: models.Duration(0),

View File

@@ -719,13 +719,13 @@ func withQueryForState(t *testing.T, evalResult eval.State) models.AlertRuleMuta
switch evalResult { switch evalResult {
case eval.Normal: case eval.Normal:
expression = `{ expression = `{
"datasourceUid": "-100", "datasourceUid": "__expr__",
"type":"math", "type":"math",
"expression":"2 + 1 < 1" "expression":"2 + 1 < 1"
}` }`
case eval.Pending, eval.Alerting: case eval.Pending, eval.Alerting:
expression = `{ expression = `{
"datasourceUid": "-100", "datasourceUid": "__expr__",
"type":"math", "type":"math",
"expression":"2 + 2 > 1" "expression":"2 + 2 > 1"
}` }`
@@ -734,7 +734,7 @@ func withQueryForState(t *testing.T, evalResult eval.State) models.AlertRuleMuta
} }
case eval.Error: case eval.Error:
expression = `{ expression = `{
"datasourceUid": "-100", "datasourceUid": "__expr__",
"type":"math", "type":"math",
"expression":"$A" "expression":"$A"
}` }`
@@ -746,7 +746,7 @@ func withQueryForState(t *testing.T, evalResult eval.State) models.AlertRuleMuta
rule.Condition = "A" rule.Condition = "A"
rule.Data = []models.AlertQuery{ rule.Data = []models.AlertQuery{
{ {
DatasourceUID: "-100", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(expression), Model: json.RawMessage(expression),
RelativeTimeRange: models.RelativeTimeRange{ RelativeTimeRange: models.RelativeTimeRange{
From: models.Duration(5 * time.Hour), From: models.Duration(5 * time.Hour),

View File

@@ -139,7 +139,7 @@ func CreateTestAlertRuleWithLabels(t testing.TB, ctx context.Context, dbstore *s
Data: []models.AlertQuery{ Data: []models.AlertQuery{
{ {
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"datasourceUid": "-100", "datasourceUid": "__expr__",
"type":"math", "type":"math",
"expression":"2 + 2 > 1" "expression":"2 + 2 > 1"
}`), }`),

View File

@@ -31,7 +31,7 @@ groups:
relativeTimeRange: relativeTimeRange:
from: 0 from: 0
to: 0 to: 0
datasourceUID: "-100" datasourceUid: "__expr__"
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -49,7 +49,7 @@ groups:
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: "-100" uid: "__expr__"
hide: false hide: false
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200

View File

@@ -30,7 +30,7 @@ groups:
relativeTimeRange: relativeTimeRange:
from: 0 from: 0
to: 0 to: 0
datasourceUID: "-100" datasourceUid: "__expr__"
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -48,7 +48,7 @@ groups:
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: "-100" uid: "__expr__"
hide: false hide: false
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200

View File

@@ -30,7 +30,7 @@ groups:
relativeTimeRange: relativeTimeRange:
from: 0 from: 0
to: 0 to: 0
datasourceUID: "-100" datasourceUid: "__expr__"
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -48,7 +48,7 @@ groups:
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: "-100" uid: "__expr__"
hide: false hide: false
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200

View File

@@ -30,7 +30,7 @@ groups:
relativeTimeRange: relativeTimeRange:
from: 0 from: 0
to: 0 to: 0
datasourceUID: "-100" datasourceUid: "__expr__"
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -48,7 +48,7 @@ groups:
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: "-100" uid: "__expr__"
hide: false hide: false
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200

View File

@@ -30,7 +30,7 @@ groups:
relativeTimeRange: relativeTimeRange:
from: 0 from: 0
to: 0 to: 0
datasourceUID: "-100" datasourceUid: "__expr__"
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -48,7 +48,7 @@ groups:
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: "-100" uid: "__expr__"
hide: false hide: false
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200
@@ -84,7 +84,7 @@ groups:
relativeTimeRange: relativeTimeRange:
from: 0 from: 0
to: 0 to: 0
datasourceUID: "-100" datasourceUid: "__expr__"
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -102,7 +102,7 @@ groups:
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: "-100" uid: "__expr__"
hide: false hide: false
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200

View File

@@ -30,7 +30,7 @@ apiVersion: 1
relativeTimeRange: relativeTimeRange:
from: 0 from: 0
to: 0 to: 0
datasourceUID: "-100" datasourceUid: "__expr__"
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -48,7 +48,7 @@ apiVersion: 1
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: "-100" uid: "__expr__"
hide: false hide: false
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200

View File

@@ -41,7 +41,7 @@
"from": 0, "from": 0,
"to": 0 "to": 0
}, },
"datasourceUID": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -70,7 +70,7 @@
], ],
"datasource": { "datasource": {
"type": "__expr__", "type": "__expr__",
"uid": "-100" "uid": "__expr__"
}, },
"hide": false, "hide": false,
"intervalMs": 1000, "intervalMs": 1000,

View File

@@ -30,7 +30,7 @@ groups:
relativeTimeRange: relativeTimeRange:
from: 0 from: 0
to: 0 to: 0
datasourceUID: "-100" datasourceUid: "__expr__"
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -48,7 +48,7 @@ groups:
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: "-100" uid: "__expr__"
hide: false hide: false
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200

View File

@@ -30,7 +30,7 @@ groups:
relativeTimeRange: relativeTimeRange:
from: 0 from: 0
to: 0 to: 0
datasourceUID: "-100" datasourceUid: "__expr__"
model: model:
conditions: conditions:
- evaluator: - evaluator:
@@ -48,7 +48,7 @@ groups:
type: query type: query
datasource: datasource:
type: __expr__ type: __expr__
uid: "-100" uid: "__expr__"
hide: false hide: false
intervalMs: 1000 intervalMs: 1000
maxDataPoints: 43200 maxDataPoints: 43200

View File

@@ -467,7 +467,7 @@ func (c *fakePluginClient) QueryData(ctx context.Context, req *backend.QueryData
c.req = req c.req = req
// If an expression query ends up getting directly queried, we want it to return an error in our test. // If an expression query ends up getting directly queried, we want it to return an error in our test.
if req.PluginContext.PluginID == "__expr__" { if req.PluginContext.PluginID == expr.DatasourceUID {
return nil, errors.New("cant query an expression datasource") return nil, errors.New("cant query an expression datasource")
} }

View File

@@ -171,7 +171,7 @@ func migrateAlertRuleQueries(data []alertQuery) ([]alertQuery, error) {
result := make([]alertQuery, 0, len(data)) result := make([]alertQuery, 0, len(data))
for _, d := range data { for _, d := range data {
// queries that are expression are not relevant, skip them. // queries that are expression are not relevant, skip them.
if d.DatasourceUID == expr.OldDatasourceUID { if d.DatasourceUID == expr.DatasourceType {
result = append(result, d) result = append(result, d)
continue continue
} }

View File

@@ -7,6 +7,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@@ -187,7 +188,7 @@ func transConditions(set dashAlertSettings, orgID int64, dsUIDMap dsUIDLookup) (
ccAlertQuery := alertQuery{ ccAlertQuery := alertQuery{
RefID: ccRefID, RefID: ccRefID,
Model: exprModelJSON, Model: exprModelJSON,
DatasourceUID: "-100", DatasourceUID: expr.DatasourceUID,
} }
newCond.Data = append(newCond.Data, ccAlertQuery) newCond.Data = append(newCond.Data, ccAlertQuery)

View File

@@ -10,6 +10,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/expr"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -253,7 +254,7 @@ func TestIntegrationAdminConfiguration_SendingToExternalAlertmanagers(t *testing
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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -274,7 +275,7 @@ func TestIntegrationAdminConfiguration_SendingToExternalAlertmanagers(t *testing
_ = postRequest(t, ruleURL, buf.String(), http.StatusAccepted) _ = postRequest(t, ruleURL, buf.String(), http.StatusAccepted)
} }
//Eventually, our Alertmanagers should receiver the alert. // Eventually, our Alertmanagers should receiver the alert.
{ {
require.Eventually(t, func() bool { require.Eventually(t, func() bool {
return fakeAM1.AlertsCount() == 1 && fakeAM2.AlertsCount() == 1 return fakeAM1.AlertsCount() == 1 && fakeAM2.AlertsCount() == 1

View File

@@ -12,6 +12,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/expr"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -508,7 +509,7 @@ func TestIntegrationAlertAndGroupsQuery(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -649,7 +650,7 @@ func TestIntegrationRulerAccess(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -752,7 +753,7 @@ func TestIntegrationDeleteFolderWithRules(t *testing.T) {
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "2 + 3 > 1", "expression": "2 + 3 > 1",
"intervalMs": 1000, "intervalMs": 1000,
@@ -907,7 +908,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -937,7 +938,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -967,7 +968,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -998,7 +999,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -1058,7 +1059,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -1117,7 +1118,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -1137,7 +1138,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -1208,7 +1209,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
"from":18000, "from":18000,
"to":10800 "to":10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model":{ "model":{
"expression":"2 + 3 \u003e 1", "expression":"2 + 3 \u003e 1",
"intervalMs":1000, "intervalMs":1000,
@@ -1244,7 +1245,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
"from":18000, "from":18000,
"to":10800 "to":10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model":{ "model":{
"expression":"2 + 3 \u003e 1", "expression":"2 + 3 \u003e 1",
"intervalMs":1000, "intervalMs":1000,
@@ -1302,7 +1303,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 < 1" "expression": "2 + 3 < 1"
@@ -1375,7 +1376,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 < 1" "expression": "2 + 3 < 1"
@@ -1409,7 +1410,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -1483,7 +1484,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 < 1" "expression": "2 + 3 < 1"
@@ -1551,7 +1552,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
"from":18000, "from":18000,
"to":10800 "to":10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model":{ "model":{
"expression":"2 + 3 \u003C 1", "expression":"2 + 3 \u003C 1",
"intervalMs":1000, "intervalMs":1000,
@@ -1600,7 +1601,7 @@ func TestIntegrationAlertRuleCRUD(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 < 1" "expression": "2 + 3 < 1"
@@ -1660,7 +1661,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
"from":18000, "from":18000,
"to":10800 "to":10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model":{ "model":{
"expression":"2 + 3 \u003C 1", "expression":"2 + 3 \u003C 1",
"intervalMs":1000, "intervalMs":1000,
@@ -1745,7 +1746,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
"from":18000, "from":18000,
"to":10800 "to":10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model":{ "model":{
"expression":"2 + 3 \u003C 1", "expression":"2 + 3 \u003C 1",
"intervalMs":1000, "intervalMs":1000,
@@ -1957,7 +1958,7 @@ func TestIntegrationQuota(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -1992,7 +1993,7 @@ func TestIntegrationQuota(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 4 > 1" "expression": "2 + 4 > 1"
@@ -2051,7 +2052,7 @@ func TestIntegrationQuota(t *testing.T) {
"from":18000, "from":18000,
"to":10800 "to":10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model":{ "model":{
"expression":"2 + 4 \u003E 1", "expression":"2 + 4 \u003E 1",
"intervalMs":1000, "intervalMs":1000,
@@ -2122,7 +2123,7 @@ func TestIntegrationEval(t *testing.T) {
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model": { "model": {
"type":"math", "type":"math",
"expression":"1 < 2" "expression":"1 < 2"
@@ -2186,7 +2187,7 @@ func TestIntegrationEval(t *testing.T) {
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"type":"math", "type":"math",
"expression":"1 > 2" "expression":"1 > 2"
@@ -2250,7 +2251,7 @@ func TestIntegrationEval(t *testing.T) {
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"type":"math", "type":"math",
"expression":"1 > 2" "expression":"1 > 2"
@@ -2351,7 +2352,7 @@ func TestIntegrationEval(t *testing.T) {
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"type":"math", "type":"math",
"expression":"1 < 2" "expression":"1 < 2"
@@ -2408,7 +2409,7 @@ func TestIntegrationEval(t *testing.T) {
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"type":"math", "type":"math",
"expression":"1 > 2" "expression":"1 > 2"

View File

@@ -220,14 +220,14 @@
}, },
{ {
"refId": "B", "refId": "B",
"datasourceUid": "-100", "datasourceUid": "__expr__",
"queryType": "", "queryType": "",
"model": { "model": {
"refId": "B", "refId": "B",
"hide": false, "hide": false,
"type": "reduce", "type": "reduce",
"datasource": { "datasource": {
"uid": "-100", "uid": "__expr__",
"type": "__expr__" "type": "__expr__"
}, },
"conditions": [ "conditions": [
@@ -261,14 +261,14 @@
}, },
{ {
"refId": "C", "refId": "C",
"datasourceUid": "-100", "datasourceUid": "__expr__",
"queryType": "", "queryType": "",
"model": { "model": {
"refId": "C", "refId": "C",
"hide": false, "hide": false,
"type": "threshold", "type": "threshold",
"datasource": { "datasource": {
"uid": "-100", "uid": "__expr__",
"type": "__expr__" "type": "__expr__"
}, },
"conditions": [ "conditions": [

View File

@@ -17,6 +17,7 @@ import (
"time" "time"
"github.com/grafana/alerting/alerting/notifier/channels" "github.com/grafana/alerting/alerting/notifier/channels"
"github.com/grafana/grafana/pkg/expr"
"github.com/prometheus/alertmanager/template" "github.com/prometheus/alertmanager/template"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -979,7 +980,7 @@ func getRulesConfig(t *testing.T) string {
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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"

View File

@@ -11,6 +11,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/expr"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -104,7 +105,7 @@ func TestIntegrationPrometheusRules(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -124,7 +125,7 @@ func TestIntegrationPrometheusRules(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -180,7 +181,7 @@ func TestIntegrationPrometheusRules(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -237,7 +238,7 @@ func TestIntegrationPrometheusRules(t *testing.T) {
"rules": [{ "rules": [{
"state": "inactive", "state": "inactive",
"name": "AlwaysFiring", "name": "AlwaysFiring",
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]", "query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"__expr__\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
"duration": 10, "duration": 10,
"annotations": { "annotations": {
"annotation1": "val1" "annotation1": "val1"
@@ -252,7 +253,7 @@ func TestIntegrationPrometheusRules(t *testing.T) {
}, { }, {
"state": "inactive", "state": "inactive",
"name": "AlwaysFiringButSilenced", "name": "AlwaysFiringButSilenced",
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]", "query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"__expr__\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
"health": "ok", "health": "ok",
"type": "alerting", "type": "alerting",
"lastEvaluation": "0001-01-01T00:00:00Z", "lastEvaluation": "0001-01-01T00:00:00Z",
@@ -289,7 +290,7 @@ func TestIntegrationPrometheusRules(t *testing.T) {
"rules": [{ "rules": [{
"state": "inactive", "state": "inactive",
"name": "AlwaysFiring", "name": "AlwaysFiring",
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]", "query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"__expr__\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
"duration": 10, "duration": 10,
"annotations": { "annotations": {
"annotation1": "val1" "annotation1": "val1"
@@ -304,7 +305,7 @@ func TestIntegrationPrometheusRules(t *testing.T) {
}, { }, {
"state": "inactive", "state": "inactive",
"name": "AlwaysFiringButSilenced", "name": "AlwaysFiringButSilenced",
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]", "query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"__expr__\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
"health": "ok", "health": "ok",
"type": "alerting", "type": "alerting",
"lastEvaluation": "0001-01-01T00:00:00Z", "lastEvaluation": "0001-01-01T00:00:00Z",
@@ -371,7 +372,7 @@ func TestIntegrationPrometheusRulesFilterByDashboard(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -391,7 +392,7 @@ func TestIntegrationPrometheusRulesFilterByDashboard(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -434,7 +435,7 @@ func TestIntegrationPrometheusRulesFilterByDashboard(t *testing.T) {
"rules": [{ "rules": [{
"state": "inactive", "state": "inactive",
"name": "AlwaysFiring", "name": "AlwaysFiring",
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]", "query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"__expr__\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
"duration": 10, "duration": 10,
"annotations": { "annotations": {
"__dashboardUid__": "%s", "__dashboardUid__": "%s",
@@ -447,7 +448,7 @@ func TestIntegrationPrometheusRulesFilterByDashboard(t *testing.T) {
}, { }, {
"state": "inactive", "state": "inactive",
"name": "AlwaysFiringButSilenced", "name": "AlwaysFiringButSilenced",
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]", "query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"__expr__\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
"health": "ok", "health": "ok",
"type": "alerting", "type": "alerting",
"lastEvaluation": "0001-01-01T00:00:00Z", "lastEvaluation": "0001-01-01T00:00:00Z",
@@ -469,7 +470,7 @@ func TestIntegrationPrometheusRulesFilterByDashboard(t *testing.T) {
"rules": [{ "rules": [{
"state": "inactive", "state": "inactive",
"name": "AlwaysFiring", "name": "AlwaysFiring",
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]", "query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"__expr__\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
"duration": 10, "duration": 10,
"annotations": { "annotations": {
"__dashboardUid__": "%s", "__dashboardUid__": "%s",

View File

@@ -9,6 +9,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/expr"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -101,7 +102,7 @@ func TestIntegrationAlertRulePermissions(t *testing.T) {
"from":18000, "from":18000,
"to":10800 "to":10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model":{ "model":{
"expression":"2 + 3 \u003E 1", "expression":"2 + 3 \u003E 1",
"intervalMs":1000, "intervalMs":1000,
@@ -151,7 +152,7 @@ func TestIntegrationAlertRulePermissions(t *testing.T) {
"from":18000, "from":18000,
"to":10800 "to":10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model":{ "model":{
"expression":"2 + 3 \u003E 1", "expression":"2 + 3 \u003E 1",
"intervalMs":1000, "intervalMs":1000,
@@ -224,7 +225,7 @@ func TestIntegrationAlertRulePermissions(t *testing.T) {
"from":18000, "from":18000,
"to":10800 "to":10800
}, },
"datasourceUid":"-100", "datasourceUid":"__expr__",
"model":{ "model":{
"expression":"2 + 3 \u003E 1", "expression":"2 + 3 \u003E 1",
"intervalMs":1000, "intervalMs":1000,
@@ -297,7 +298,7 @@ func createRule(t *testing.T, client apiClient, folder string) {
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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -437,7 +438,7 @@ func TestIntegrationRulerRulesFilterByDashboard(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -457,7 +458,7 @@ func TestIntegrationRulerRulesFilterByDashboard(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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -499,7 +500,7 @@ func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) {
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "2 + 3 \u003e 1", "expression": "2 + 3 \u003e 1",
"intervalMs": 1000, "intervalMs": 1000,
@@ -532,7 +533,7 @@ func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) {
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "2 + 3 \u003e 1", "expression": "2 + 3 \u003e 1",
"intervalMs": 1000, "intervalMs": 1000,
@@ -577,7 +578,7 @@ func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) {
"from": 18000, "from": 18000,
"to": 10800 "to": 10800
}, },
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"expression": "2 + 3 \u003e 1", "expression": "2 + 3 \u003e 1",
"intervalMs": 1000, "intervalMs": 1000,
@@ -889,7 +890,7 @@ func newTestingRuleConfig(t *testing.T) apimodels.PostableRuleGroupConfig {
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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"
@@ -916,7 +917,7 @@ func newTestingRuleConfig(t *testing.T) apimodels.PostableRuleGroupConfig {
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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"

View File

@@ -10,6 +10,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/expr"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -105,7 +106,7 @@ func alertRuleGen() func() apimodels.PostableExtendedRuleNode {
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", DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{ Model: json.RawMessage(`{
"type": "math", "type": "math",
"expression": "2 + 3 > 1" "expression": "2 + 3 > 1"

View File

@@ -11176,7 +11176,7 @@
"title": "AlertQuery represents a single query associated with an alert definition.", "title": "AlertQuery represents a single query associated with an alert definition.",
"properties": { "properties": {
"datasourceUid": { "datasourceUid": {
"description": "Grafana data source unique identifier; it should be '-100' for a Server Side Expression operation.", "description": "Grafana data source unique identifier; it should be '__expr__' for a Server Side Expression operation.",
"type": "string" "type": "string"
}, },
"model": { "model": {
@@ -15886,7 +15886,7 @@
}, },
"example": [ "example": [
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -18056,9 +18056,8 @@
"type": "string" "type": "string"
}, },
"URL": { "URL": {
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
"type": "object", "type": "object",
"title": "A URL represents a parsed URL (technically, a URI reference).", "title": "URL is a custom URL type that allows validation at configuration load time.",
"properties": { "properties": {
"ForceQuery": { "ForceQuery": {
"type": "boolean" "type": "boolean"
@@ -18887,6 +18886,7 @@
} }
}, },
"alertGroup": { "alertGroup": {
"description": "AlertGroup alert group",
"type": "object", "type": "object",
"required": [ "required": [
"alerts", "alerts",
@@ -19014,6 +19014,7 @@
} }
}, },
"gettableAlert": { "gettableAlert": {
"description": "GettableAlert gettable alert",
"type": "object", "type": "object",
"required": [ "required": [
"labels", "labels",
@@ -19075,7 +19076,6 @@
} }
}, },
"gettableSilence": { "gettableSilence": {
"description": "GettableSilence gettable silence",
"type": "object", "type": "object",
"required": [ "required": [
"comment", "comment",
@@ -19124,6 +19124,7 @@
} }
}, },
"gettableSilences": { "gettableSilences": {
"description": "GettableSilences gettable silences",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/gettableSilence" "$ref": "#/definitions/gettableSilence"

View File

@@ -39,7 +39,7 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
}, },
}, },
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -64,7 +64,7 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
], ],
"datasource": { "datasource": {
"type": "__expr__", "type": "__expr__",
"uid": "-100", "uid": "__expr__",
}, },
"expression": "A", "expression": "A",
"hide": false, "hide": false,
@@ -76,7 +76,7 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
"refId": "B", "refId": "B",
}, },
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -103,7 +103,7 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
], ],
"datasource": { "datasource": {
"type": "__expr__", "type": "__expr__",
"uid": "-100", "uid": "__expr__",
}, },
"expression": "B", "expression": "B",
"hide": false, "hide": false,

View File

@@ -12,7 +12,7 @@ exports[`Query and expressions reducer should add a new expression 1`] = `
"refId": "A", "refId": "A",
}, },
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -141,7 +141,7 @@ exports[`Query and expressions reducer should rewire expressions 1`] = `
"refId": "A", "refId": "A",
}, },
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -187,7 +187,7 @@ exports[`Query and expressions reducer should set data queries 1`] = `
{ {
"queries": [ "queries": [
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -233,7 +233,7 @@ exports[`Query and expressions reducer should update an expression 1`] = `
{ {
"queries": [ "queries": [
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -287,7 +287,7 @@ exports[`Query and expressions reducer should update an expression refId and rew
"refId": "C", "refId": "C",
}, },
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -341,7 +341,7 @@ exports[`Query and expressions reducer should update expression type 1`] = `
"refId": "A", "refId": "A",
}, },
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {

View File

@@ -151,7 +151,7 @@ describe('Query and expressions reducer', () => {
const expressionQuery: AlertQuery = { const expressionQuery: AlertQuery = {
refId: 'B', refId: 'B',
queryType: 'expression', queryType: 'expression',
datasourceUid: '-100', datasourceUid: '__expr__',
relativeTimeRange: { from: 900, to: 1000 }, relativeTimeRange: { from: 900, to: 1000 },
model: { model: {
queryType: 'query', queryType: 'query',
@@ -166,7 +166,7 @@ describe('Query and expressions reducer', () => {
const expressionQuery2: AlertQuery = { const expressionQuery2: AlertQuery = {
refId: 'C', refId: 'C',
queryType: 'expression', queryType: 'expression',
datasourceUid: '-100', datasourceUid: '__expr__',
relativeTimeRange: { from: 1, to: 3 }, relativeTimeRange: { from: 1, to: 3 },
model: { model: {
queryType: 'query', queryType: 'query',
@@ -205,7 +205,7 @@ describe('Query and expressions reducer', () => {
queryType: 'query', queryType: 'query',
}, },
{ {
datasourceUid: '-100', datasourceUid: '__expr__',
relativeTimeRange: { from: 900, to: 1000 }, relativeTimeRange: { from: 900, to: 1000 },
model: { model: {
datasource: '__expr__', datasource: '__expr__',
@@ -219,7 +219,7 @@ describe('Query and expressions reducer', () => {
refId: 'B', refId: 'B',
}, },
{ {
datasourceUid: '-100', datasourceUid: '__expr__',
relativeTimeRange: { from: 900, to: 1000 }, relativeTimeRange: { from: 900, to: 1000 },
model: { model: {
datasource: '__expr__', datasource: '__expr__',
@@ -240,7 +240,7 @@ describe('Query and expressions reducer', () => {
const expressionQuery: AlertQuery = { const expressionQuery: AlertQuery = {
refId: 'B', refId: 'B',
queryType: 'expression', queryType: 'expression',
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
queryType: 'query', queryType: 'query',
datasource: '__expr__', datasource: '__expr__',
@@ -275,7 +275,7 @@ describe('Query and expressions reducer', () => {
queryType: 'query', queryType: 'query',
}, },
{ {
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
datasource: '__expr__', datasource: '__expr__',
expression: 'A', expression: 'A',

View File

@@ -25,7 +25,7 @@ describe('rule-editor', () => {
const classicCondition = { const classicCondition = {
refId: 'B', refId: 'B',
datasourceUid: '-100', datasourceUid: '__expr__',
queryType: '', queryType: '',
model: { model: {
refId: 'B', refId: 'B',
@@ -55,7 +55,7 @@ describe('rule-editor', () => {
const mathExpression = { const mathExpression = {
refId: 'B', refId: 'B',
datasourceUid: '-100', datasourceUid: '__expr__',
queryType: '', queryType: '',
model: { model: {
refId: 'B', refId: 'B',
@@ -68,7 +68,7 @@ describe('rule-editor', () => {
const reduceExpression = { const reduceExpression = {
refId: 'B', refId: 'B',
datasourceUid: '-100', datasourceUid: '__expr__',
queryType: '', queryType: '',
model: { model: {
refId: 'B', refId: 'B',
@@ -82,7 +82,7 @@ describe('rule-editor', () => {
const resampleExpression = { const resampleExpression = {
refId: 'A', refId: 'A',
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
refId: 'A', refId: 'A',
type: 'resample', type: 'resample',
@@ -101,14 +101,14 @@ describe('rule-editor', () => {
const thresholdExpression = { const thresholdExpression = {
refId: 'C', refId: 'C',
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
refId: 'C', refId: 'C',
type: 'threshold', type: 'threshold',
expression: 'B', expression: 'B',
datasource: { datasource: {
type: '__expr__', type: '__expr__',
uid: '-100', uid: '__expr__',
}, },
conditions: [ conditions: [
{ {
@@ -253,7 +253,7 @@ describe('getThresholdsForQueries', () => {
const classicCondition = { const classicCondition = {
refId: 'B', refId: 'B',
datasourceUid: '-100', datasourceUid: '__expr__',
queryType: '', queryType: '',
model: { model: {
refId: 'B', refId: 'B',
@@ -319,7 +319,7 @@ function createThresholdExample(thresholdType: string): AlertQuery[] {
const reduceExpression = { const reduceExpression = {
refId: 'B', refId: 'B',
datasourceUid: '-100', datasourceUid: '__expr__',
queryType: '', queryType: '',
model: { model: {
refId: 'B', refId: 'B',
@@ -333,7 +333,7 @@ function createThresholdExample(thresholdType: string): AlertQuery[] {
const thresholdExpression = { const thresholdExpression = {
refId: 'C', refId: 'C',
datasourceUid: '-100', datasourceUid: '__expr__',
queryType: '', queryType: '',
model: { model: {
refId: 'C', refId: 'C',

View File

@@ -102,7 +102,7 @@ const grafanaAlert = {
refId: 'B', refId: 'B',
queryType: '', queryType: '',
relativeTimeRange: { from: 0, to: 0 }, relativeTimeRange: { from: 0, to: 0 },
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
conditions: [ conditions: [
{ {

View File

@@ -12,7 +12,7 @@ describe('timeRange', () => {
const expressionQuery: AlertQuery = { const expressionQuery: AlertQuery = {
refId: 'B', refId: 'B',
queryType: 'expression', queryType: 'expression',
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
queryType: 'query', queryType: 'query',
datasource: '__expr__', datasource: '__expr__',
@@ -40,7 +40,7 @@ describe('timeRange', () => {
const expressionQuery: AlertQuery = { const expressionQuery: AlertQuery = {
refId: 'C', refId: 'C',
queryType: 'expression', queryType: 'expression',
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
queryType: 'query', queryType: 'query',
datasource: '__expr__', datasource: '__expr__',
@@ -80,7 +80,7 @@ describe('timeRange', () => {
const expressionQuery: AlertQuery = { const expressionQuery: AlertQuery = {
refId: 'B', refId: 'B',
queryType: 'expression', queryType: 'expression',
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
queryType: 'query', queryType: 'query',
datasource: '__expr__', datasource: '__expr__',
@@ -105,7 +105,7 @@ describe('timeRange', () => {
const expressionQuery: AlertQuery = { const expressionQuery: AlertQuery = {
refId: 'C', refId: 'C',
queryType: 'expression', queryType: 'expression',
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
queryType: 'query', queryType: 'query',
datasource: '__expr__', datasource: '__expr__',
@@ -142,7 +142,7 @@ describe('timeRange', () => {
const expressionQuery: AlertQuery = { const expressionQuery: AlertQuery = {
refId: 'B', refId: 'B',
queryType: 'expression', queryType: 'expression',
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
queryType: 'query', queryType: 'query',
datasource: '__expr__', datasource: '__expr__',
@@ -175,7 +175,7 @@ describe('timeRange', () => {
const expressionQuery: AlertQuery = { const expressionQuery: AlertQuery = {
refId: 'B', refId: 'B',
queryType: 'expression', queryType: 'expression',
datasourceUid: '-100', datasourceUid: '__expr__',
model: { model: {
queryType: 'query', queryType: 'query',
datasource: '__expr__', datasource: '__expr__',

View File

@@ -1,4 +1,4 @@
import { Observable, from, mergeMap } from 'rxjs'; import { from, mergeMap, Observable } from 'rxjs';
import { import {
DataQueryRequest, DataQueryRequest,
@@ -61,10 +61,9 @@ export class ExpressionDatasourceApi extends DataSourceWithBackend<ExpressionQue
} }
/** /**
* MATCHES a constant in DataSourceWithBackend, this should be '__expr__' * MATCHES a constant in DataSourceWithBackend
* @deprecated
*/ */
export const ExpressionDatasourceUID = '-100'; export const ExpressionDatasourceUID = '__expr__';
export const instanceSettings: DataSourceInstanceSettings = { export const instanceSettings: DataSourceInstanceSettings = {
id: -100, id: -100,

View File

@@ -2361,7 +2361,7 @@
"AlertQuery": { "AlertQuery": {
"properties": { "properties": {
"datasourceUid": { "datasourceUid": {
"description": "Grafana data source unique identifier; it should be '-100' for a Server Side Expression operation.", "description": "Grafana data source unique identifier; it should be '__expr__' for a Server Side Expression operation.",
"type": "string" "type": "string"
}, },
"model": { "model": {
@@ -7056,7 +7056,7 @@
"data": { "data": {
"example": [ "example": [
{ {
"datasourceUid": "-100", "datasourceUid": "__expr__",
"model": { "model": {
"conditions": [ "conditions": [
{ {
@@ -9241,7 +9241,6 @@
"type": "string" "type": "string"
}, },
"URL": { "URL": {
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
"properties": { "properties": {
"ForceQuery": { "ForceQuery": {
"type": "boolean" "type": "boolean"
@@ -9277,7 +9276,7 @@
"$ref": "#/components/schemas/Userinfo" "$ref": "#/components/schemas/Userinfo"
} }
}, },
"title": "A URL represents a parsed URL (technically, a URI reference).", "title": "URL is a custom URL type that allows validation at configuration load time.",
"type": "object" "type": "object"
}, },
"UpdateAlertNotificationCommand": { "UpdateAlertNotificationCommand": {
@@ -10072,6 +10071,7 @@
"type": "object" "type": "object"
}, },
"alertGroup": { "alertGroup": {
"description": "AlertGroup alert group",
"properties": { "properties": {
"alerts": { "alerts": {
"description": "alerts", "description": "alerts",
@@ -10199,6 +10199,7 @@
"type": "object" "type": "object"
}, },
"gettableAlert": { "gettableAlert": {
"description": "GettableAlert gettable alert",
"properties": { "properties": {
"annotations": { "annotations": {
"$ref": "#/components/schemas/labelSet" "$ref": "#/components/schemas/labelSet"
@@ -10260,7 +10261,6 @@
"type": "array" "type": "array"
}, },
"gettableSilence": { "gettableSilence": {
"description": "GettableSilence gettable silence",
"properties": { "properties": {
"comment": { "comment": {
"description": "comment", "description": "comment",
@@ -10309,6 +10309,7 @@
"type": "object" "type": "object"
}, },
"gettableSilences": { "gettableSilences": {
"description": "GettableSilences gettable silences",
"items": { "items": {
"$ref": "#/components/schemas/gettableSilence" "$ref": "#/components/schemas/gettableSilence"
}, },