Alerting: introduce AlertQuery in definitions package (#63825)

* copy AlertQuery from ngmodels to the definition package
* replaces usages of ngmodels.AlertQuery in API models
* create a converter between models of AlertQuery
---------

Co-authored-by: Alex Moreno <alexander.moreno@grafana.com>
This commit is contained in:
Yuri Tseretyan 2023-03-27 11:55:13 -04:00 committed by GitHub
parent 36e8ca7f13
commit 52a0f59706
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 279 additions and 182 deletions

View File

@ -337,7 +337,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRuleGroup(c *contextmodel.ReqContext, f
}
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusOK, AlertRuleGroupToApi(g))
return response.JSON(http.StatusOK, ApiAlertRuleGroupFromAlertRuleGroup(g))
}
// RouteGetAlertRulesExport retrieves all alert rules in a format compatible with file provisioning.
@ -403,7 +403,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRuleExport(c *contextmodel.ReqContext,
func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *contextmodel.ReqContext, ag definitions.AlertRuleGroup, folderUID string, group string) response.Response {
ag.FolderUID = folderUID
ag.Title = group
groupModel, err := AlertRuleGroupFromApi(ag)
groupModel, err := AlertRuleGroupFromApiAlertRuleGroup(ag)
if err != nil {
ErrResp(http.StatusBadRequest, err, "")
}

View File

@ -1021,13 +1021,13 @@ func createTestAlertRule(title string, orgID int64) definitions.ProvisionedAlert
OrgID: orgID,
Title: title,
Condition: "A",
Data: []models.AlertQuery{
Data: []definitions.AlertQuery{
{
RefID: "A",
Model: json.RawMessage(testModel),
RelativeTimeRange: models.RelativeTimeRange{
From: models.Duration(60),
To: models.Duration(0),
RelativeTimeRange: definitions.RelativeTimeRange{
From: definitions.Duration(60),
To: definitions.Duration(0),
},
},
},

View File

@ -448,7 +448,7 @@ func toGettableExtendedRuleNode(r ngmodels.AlertRule, namespaceID int64, provena
OrgID: r.OrgID,
Title: r.Title,
Condition: r.Condition,
Data: r.Data,
Data: ApiAlertQueriesFromAlertQueries(r.Data),
Updated: r.Updated,
IntervalSeconds: r.IntervalSeconds,
Version: r.Version,

View File

@ -76,10 +76,11 @@ func validateRuleNode(
}
}
if len(ruleNode.GrafanaManagedAlert.Data) != 0 {
queries := AlertQueriesFromApiAlertQueries(ruleNode.GrafanaManagedAlert.Data)
if len(queries) != 0 {
cond := ngmodels.Condition{
Condition: ruleNode.GrafanaManagedAlert.Condition,
Data: ruleNode.GrafanaManagedAlert.Data,
Data: queries,
}
if err = conditionValidator(cond); err != nil {
return nil, fmt.Errorf("failed to validate condition of alert rule %s: %w", ruleNode.GrafanaManagedAlert.Title, err)
@ -90,7 +91,7 @@ func validateRuleNode(
OrgID: orgId,
Title: ruleNode.GrafanaManagedAlert.Title,
Condition: ruleNode.GrafanaManagedAlert.Condition,
Data: ruleNode.GrafanaManagedAlert.Data,
Data: queries,
UID: ruleNode.GrafanaManagedAlert.UID,
IntervalSeconds: intervalSeconds,
NamespaceUID: namespace.UID,

View File

@ -56,11 +56,11 @@ func validRule() apimodels.PostableExtendedRuleNode {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: fmt.Sprintf("TEST-ALERT-%d", rand.Int63()),
Condition: "A",
Data: []models.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
QueryType: "TEST",
RelativeTimeRange: models.RelativeTimeRange{
RelativeTimeRange: apimodels.RelativeTimeRange{
From: 10,
To: 0,
},
@ -248,7 +248,7 @@ func TestValidateRuleNode_NoUID(t *testing.T) {
require.Equal(t, orgId, alert.OrgID)
require.Equal(t, api.GrafanaManagedAlert.Title, alert.Title)
require.Equal(t, api.GrafanaManagedAlert.Condition, alert.Condition)
require.Equal(t, api.GrafanaManagedAlert.Data, alert.Data)
require.Equal(t, AlertQueriesFromApiAlertQueries(api.GrafanaManagedAlert.Data), alert.Data)
require.Equal(t, time.Time{}, alert.Updated)
require.Equal(t, int64(interval.Seconds()), alert.IntervalSeconds)
require.Equal(t, int64(0), alert.Version)
@ -411,7 +411,7 @@ func TestValidateRuleNodeFailures_NoUID(t *testing.T) {
name: "fail if there are not data (empty)",
rule: func() *apimodels.PostableExtendedRuleNode {
r := validRule()
r.GrafanaManagedAlert.Data = make([]models.AlertQuery, 0, 1)
r.GrafanaManagedAlert.Data = make([]apimodels.AlertQuery, 0, 1)
return &r
},
},
@ -535,7 +535,7 @@ func TestValidateRuleNode_UID(t *testing.T) {
r.GrafanaManagedAlert.Condition = ""
r.GrafanaManagedAlert.Data = nil
if rand.Int63()%2 == 0 {
r.GrafanaManagedAlert.Data = make([]models.AlertQuery, 0)
r.GrafanaManagedAlert.Data = make([]apimodels.AlertQuery, 0)
}
return &r
},
@ -630,7 +630,7 @@ func TestValidateRuleNodeFailures_UID(t *testing.T) {
name: "fail if there are not data (empty) but condition is set",
rule: func() *apimodels.PostableExtendedRuleNode {
r := validRule()
r.GrafanaManagedAlert.Data = make([]models.AlertQuery, 0, 1)
r.GrafanaManagedAlert.Data = make([]apimodels.AlertQuery, 0, 1)
r.GrafanaManagedAlert.Condition = "A"
return &r
},

View File

@ -40,7 +40,9 @@ func (srv TestingApiSrv) RouteTestGrafanaRuleConfig(c *contextmodel.ReqContext,
return errorToResponse(backendTypeDoesNotMatchPayloadTypeError(apimodels.GrafanaBackend, body.Type().String()))
}
if !authorizeDatasourceAccessForRule(&ngmodels.AlertRule{Data: body.GrafanaManagedCondition.Data}, func(evaluator accesscontrol.Evaluator) bool {
queries := AlertQueriesFromApiAlertQueries(body.GrafanaManagedCondition.Data)
if !authorizeDatasourceAccessForRule(&ngmodels.AlertRule{Data: queries}, func(evaluator accesscontrol.Evaluator) bool {
return accesscontrol.HasAccess(srv.accessControl, c)(accesscontrol.ReqSignedIn, evaluator)
}) {
return errorToResponse(fmt.Errorf("%w to query one or many data sources used by the rule", ErrAuthorization))
@ -48,7 +50,7 @@ func (srv TestingApiSrv) RouteTestGrafanaRuleConfig(c *contextmodel.ReqContext,
evalCond := ngmodels.Condition{
Condition: body.GrafanaManagedCondition.Condition,
Data: body.GrafanaManagedCondition.Data,
Data: queries,
}
ctx := eval.Context(c.Req.Context(), c.SignedInUser)
@ -112,7 +114,8 @@ func (srv TestingApiSrv) RouteTestRuleConfig(c *contextmodel.ReqContext, body ap
}
func (srv TestingApiSrv) RouteEvalQueries(c *contextmodel.ReqContext, cmd apimodels.EvalQueriesPayload) response.Response {
if !authorizeDatasourceAccessForRule(&ngmodels.AlertRule{Data: cmd.Data}, func(evaluator accesscontrol.Evaluator) bool {
queries := AlertQueriesFromApiAlertQueries(cmd.Data)
if !authorizeDatasourceAccessForRule(&ngmodels.AlertRule{Data: queries}, func(evaluator accesscontrol.Evaluator) bool {
return accesscontrol.HasAccess(srv.accessControl, c)(accesscontrol.ReqSignedIn, evaluator)
}) {
return ErrResp(http.StatusUnauthorized, fmt.Errorf("%w to query one or many data sources used by the rule", ErrAuthorization), "")
@ -120,7 +123,7 @@ func (srv TestingApiSrv) RouteEvalQueries(c *contextmodel.ReqContext, cmd apimod
cond := ngmodels.Condition{
Condition: "",
Data: cmd.Data,
Data: queries,
}
if len(cmd.Data) > 0 {
cond.Condition = cmd.Data[0].RefID
@ -169,7 +172,8 @@ func (srv TestingApiSrv) BacktestAlertRule(c *contextmodel.ReqContext, cmd apimo
return ErrResp(400, err, "")
}
if !authorizeDatasourceAccessForRule(&ngmodels.AlertRule{Data: cmd.Data}, func(evaluator accesscontrol.Evaluator) bool {
queries := AlertQueriesFromApiAlertQueries(cmd.Data)
if !authorizeDatasourceAccessForRule(&ngmodels.AlertRule{Data: queries}, func(evaluator accesscontrol.Evaluator) bool {
return accesscontrol.HasAccess(srv.accessControl, c)(accesscontrol.ReqSignedIn, evaluator)
}) {
return errorToResponse(fmt.Errorf("%w to query one or many data sources used by the rule", ErrAuthorization))
@ -190,7 +194,7 @@ func (srv TestingApiSrv) BacktestAlertRule(c *contextmodel.ReqContext, cmd apimo
UID: "backtesting-" + util.GenerateShortUID(),
OrgID: c.OrgID,
Condition: cmd.Condition,
Data: cmd.Data,
Data: queries,
IntervalSeconds: intervalSeconds,
NoDataState: noDataState,
For: forInterval,

View File

@ -47,7 +47,7 @@ func TestRouteTestGrafanaRuleConfig(t *testing.T) {
Expr: "",
GrafanaManagedCondition: &definitions.EvalAlertConditionCommand{
Condition: data1.RefID,
Data: []models.AlertQuery{data1, data2},
Data: ApiAlertQueriesFromAlertQueries([]models.AlertQuery{data1, data2}),
Now: time.Time{},
},
})
@ -83,7 +83,7 @@ func TestRouteTestGrafanaRuleConfig(t *testing.T) {
Expr: "",
GrafanaManagedCondition: &definitions.EvalAlertConditionCommand{
Condition: data1.RefID,
Data: []models.AlertQuery{data1, data2},
Data: ApiAlertQueriesFromAlertQueries([]models.AlertQuery{data1, data2}),
Now: currentTime,
},
})
@ -124,7 +124,7 @@ func TestRouteTestGrafanaRuleConfig(t *testing.T) {
Expr: "",
GrafanaManagedCondition: &definitions.EvalAlertConditionCommand{
Condition: data1.RefID,
Data: []models.AlertQuery{data1},
Data: ApiAlertQueriesFromAlertQueries([]models.AlertQuery{data1}),
Now: currentTime,
},
})
@ -138,7 +138,7 @@ func TestRouteTestGrafanaRuleConfig(t *testing.T) {
Expr: "",
GrafanaManagedCondition: &definitions.EvalAlertConditionCommand{
Condition: data1.RefID,
Data: []models.AlertQuery{data1},
Data: ApiAlertQueriesFromAlertQueries([]models.AlertQuery{data1}),
Now: currentTime,
},
})
@ -174,7 +174,7 @@ func TestRouteEvalQueries(t *testing.T) {
}
response := srv.RouteEvalQueries(rc, definitions.EvalQueriesPayload{
Data: []models.AlertQuery{data1, data2},
Data: ApiAlertQueriesFromAlertQueries([]models.AlertQuery{data1, data2}),
Now: time.Time{},
})
@ -211,7 +211,7 @@ func TestRouteEvalQueries(t *testing.T) {
srv := createTestingApiSrv(ds, ac, eval_mocks.NewEvaluatorFactory(evaluator))
response := srv.RouteEvalQueries(rc, definitions.EvalQueriesPayload{
Data: []models.AlertQuery{data1, data2},
Data: ApiAlertQueriesFromAlertQueries([]models.AlertQuery{data1, data2}),
Now: currentTime,
})
@ -256,7 +256,7 @@ func TestRouteEvalQueries(t *testing.T) {
srv := createTestingApiSrv(ds, ac, eval_mocks.NewEvaluatorFactory(evaluator))
response := srv.RouteEvalQueries(rc, definitions.EvalQueriesPayload{
Data: []models.AlertQuery{data1},
Data: ApiAlertQueriesFromAlertQueries([]models.AlertQuery{data1}),
Now: currentTime,
})
@ -266,7 +266,7 @@ func TestRouteEvalQueries(t *testing.T) {
rc.IsSignedIn = true
response = srv.RouteEvalQueries(rc, definitions.EvalQueriesPayload{
Data: []models.AlertQuery{data1},
Data: ApiAlertQueriesFromAlertQueries([]models.AlertQuery{data1}),
Now: currentTime,
})

View File

@ -19,7 +19,7 @@ func AlertRuleFromProvisionedAlertRule(a definitions.ProvisionedAlertRule) (mode
RuleGroup: a.RuleGroup,
Title: a.Title,
Condition: a.Condition,
Data: a.Data,
Data: AlertQueriesFromApiAlertQueries(a.Data),
Updated: a.Updated,
NoDataState: models.NoDataState(a.NoDataState), // TODO there must be a validation
ExecErrState: models.ExecutionErrorState(a.ExecErrState), // TODO there must be a validation
@ -41,7 +41,7 @@ func ProvisionedAlertRuleFromAlertRule(rule models.AlertRule, provenance models.
Title: rule.Title,
For: model.Duration(rule.For),
Condition: rule.Condition,
Data: rule.Data,
Data: ApiAlertQueriesFromAlertQueries(rule.Data),
Updated: rule.Updated,
NoDataState: definitions.NoDataState(rule.NoDataState), // TODO there may be a validation
ExecErrState: definitions.ExecutionErrorState(rule.ExecErrState), // TODO there may be a validation
@ -61,7 +61,43 @@ func ProvisionedAlertRuleFromAlertRules(rules []*models.AlertRule) definitions.P
return result
}
func AlertRuleGroupFromApi(a definitions.AlertRuleGroup) (models.AlertRuleGroup, error) {
// AlertQueriesFromApiAlertQueries converts a collection of definitions.AlertQuery to collection of models.AlertQuery
func AlertQueriesFromApiAlertQueries(queries []definitions.AlertQuery) []models.AlertQuery {
result := make([]models.AlertQuery, 0, len(queries))
for _, q := range queries {
result = append(result, models.AlertQuery{
RefID: q.RefID,
QueryType: q.QueryType,
RelativeTimeRange: models.RelativeTimeRange{
From: models.Duration(q.RelativeTimeRange.From),
To: models.Duration(q.RelativeTimeRange.To),
},
DatasourceUID: q.DatasourceUID,
Model: q.Model,
})
}
return result
}
// ApiAlertQueriesFromAlertQueries converts a collection of models.AlertQuery to collection of definitions.AlertQuery
func ApiAlertQueriesFromAlertQueries(queries []models.AlertQuery) []definitions.AlertQuery {
result := make([]definitions.AlertQuery, 0, len(queries))
for _, q := range queries {
result = append(result, definitions.AlertQuery{
RefID: q.RefID,
QueryType: q.QueryType,
RelativeTimeRange: definitions.RelativeTimeRange{
From: definitions.Duration(q.RelativeTimeRange.From),
To: definitions.Duration(q.RelativeTimeRange.To),
},
DatasourceUID: q.DatasourceUID,
Model: q.Model,
})
}
return result
}
func AlertRuleGroupFromApiAlertRuleGroup(a definitions.AlertRuleGroup) (models.AlertRuleGroup, error) {
ruleGroup := models.AlertRuleGroup{
Title: a.Title,
FolderUID: a.FolderUID,
@ -77,7 +113,7 @@ func AlertRuleGroupFromApi(a definitions.AlertRuleGroup) (models.AlertRuleGroup,
return ruleGroup, nil
}
func AlertRuleGroupToApi(d models.AlertRuleGroup) definitions.AlertRuleGroup {
func ApiAlertRuleGroupFromAlertRuleGroup(d models.AlertRuleGroup) definitions.AlertRuleGroup {
rules := make([]definitions.ProvisionedAlertRule, 0, len(d.Rules))
for i := range d.Rules {
rules = append(rules, ProvisionedAlertRuleFromAlertRule(d.Rules[i], d.Provenance))

View File

@ -15,7 +15,7 @@ func TestToModel(t *testing.T) {
FolderUID: "123",
Interval: 10,
}
tm, err := AlertRuleGroupFromApi(ruleGroup)
tm, err := AlertRuleGroupFromApiAlertRuleGroup(ruleGroup)
require.NoError(t, err)
require.Nil(t, tm.Rules)
})
@ -30,7 +30,7 @@ func TestToModel(t *testing.T) {
},
},
}
tm, err := AlertRuleGroupFromApi(ruleGroup)
tm, err := AlertRuleGroupFromApiAlertRuleGroup(ruleGroup)
require.NoError(t, err)
require.Len(t, tm.Rules, 1)
})

View File

@ -6,8 +6,6 @@ import (
"time"
"github.com/prometheus/common/model"
"github.com/grafana/grafana/pkg/services/ngalert/models"
)
// swagger:route Get /api/ruler/grafana/api/v1/rules ruler RouteGetGrafanaRulesConfig
@ -370,7 +368,7 @@ const (
type PostableGrafanaRule struct {
Title string `json:"title" yaml:"title"`
Condition string `json:"condition" yaml:"condition"`
Data []models.AlertQuery `json:"data" yaml:"data"`
Data []AlertQuery `json:"data" yaml:"data"`
UID string `json:"uid" yaml:"uid"`
NoDataState NoDataState `json:"no_data_state" yaml:"no_data_state"`
ExecErrState ExecutionErrorState `json:"exec_err_state" yaml:"exec_err_state"`
@ -383,7 +381,7 @@ type GettableGrafanaRule struct {
OrgID int64 `json:"orgId" yaml:"orgId"`
Title string `json:"title" yaml:"title"`
Condition string `json:"condition" yaml:"condition"`
Data []models.AlertQuery `json:"data" yaml:"data"`
Data []AlertQuery `json:"data" yaml:"data"`
Updated time.Time `json:"updated" yaml:"updated"`
IntervalSeconds int64 `json:"intervalSeconds" yaml:"intervalSeconds"`
Version int64 `json:"version" yaml:"version"`
@ -396,3 +394,70 @@ type GettableGrafanaRule struct {
Provenance Provenance `json:"provenance,omitempty" yaml:"provenance,omitempty"`
IsPaused bool `json:"is_paused" yaml:"is_paused"`
}
// AlertQuery represents a single query associated with an alert definition.
type AlertQuery struct {
// RefID is the unique identifier of the query, set by the frontend call.
RefID string `json:"refId"`
// QueryType is an optional identifier for the type of query.
// It can be used to distinguish different types of queries.
QueryType string `json:"queryType"`
// RelativeTimeRange is the relative Start and End of the query as sent by the frontend.
RelativeTimeRange RelativeTimeRange `json:"relativeTimeRange"`
// Grafana data source unique identifier; it should be '__expr__' for a Server Side Expression operation.
DatasourceUID string `json:"datasourceUid"`
// JSON is the raw JSON query and includes the above properties as well as custom properties.
Model json.RawMessage `json:"model"`
}
// RelativeTimeRange is the per query start and end time
// for requests.
type RelativeTimeRange struct {
From Duration `json:"from" yaml:"from"`
To Duration `json:"to" yaml:"to"`
}
// Duration is a type used for marshalling durations.
type Duration time.Duration
func (d Duration) String() string {
return time.Duration(d).String()
}
func (d Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Duration(d).Seconds())
}
func (d *Duration) UnmarshalJSON(b []byte) error {
var v interface{}
if err := json.Unmarshal(b, &v); err != nil {
return err
}
switch value := v.(type) {
case float64:
*d = Duration(time.Duration(value) * time.Second)
return nil
default:
return fmt.Errorf("invalid duration %v", v)
}
}
func (d Duration) MarshalYAML() (interface{}, error) {
return time.Duration(d).Seconds(), nil
}
func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
var v interface{}
if err := unmarshal(&v); err != nil {
return err
}
switch value := v.(type) {
case int:
*d = Duration(time.Duration(value) * time.Second)
return nil
default:
return fmt.Errorf("invalid duration %v", v)
}
}

View File

@ -4,15 +4,13 @@ import (
"encoding/json"
"fmt"
"time"
"github.com/grafana/grafana/pkg/services/ngalert/models"
)
// EvalAlertConditionCommand is the command for evaluating a condition
type EvalAlertConditionCommand struct {
Condition string `json:"condition"`
Data []models.AlertQuery `json:"data"` // TODO yuri. Create API model for AlertQuery
Now time.Time `json:"now"`
Condition string `json:"condition"`
Data []AlertQuery `json:"data"`
Now time.Time `json:"now"`
}
func (cmd *EvalAlertConditionCommand) UnmarshalJSON(b []byte) error {

View File

@ -5,7 +5,6 @@ import (
"github.com/prometheus/common/model"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/provisioning/alerting/file"
)
@ -119,7 +118,7 @@ type ProvisionedAlertRule struct {
Condition string `json:"condition"`
// required: true
// 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 []AlertQuery `json:"data"`
// readonly: true
Updated time.Time `json:"updated,omitempty"`
// required: true

View File

@ -10,8 +10,6 @@ import (
"github.com/prometheus/alertmanager/config"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/promql"
"github.com/grafana/grafana/pkg/services/ngalert/models"
)
// swagger:route Post /api/v1/rule/test/grafana testing RouteTestRuleGrafanaConfig
@ -95,8 +93,8 @@ type EvalQueriesRequest struct {
// swagger:model
type EvalQueriesPayload struct {
Data []models.AlertQuery `json:"data"`
Now time.Time `json:"now"`
Data []AlertQuery `json:"data"`
Now time.Time `json:"now"`
}
func (p *TestRulePayload) UnmarshalJSON(b []byte) error {
@ -187,9 +185,9 @@ type BacktestConfig struct {
To time.Time `json:"to"`
Interval model.Duration `json:"interval,omitempty"`
Condition string `json:"condition"`
Data []models.AlertQuery `json:"data"` // TODO yuri. Create API model for AlertQuery
For model.Duration `json:"for,omitempty"`
Condition string `json:"condition"`
Data []AlertQuery `json:"data"`
For model.Duration `json:"for,omitempty"`
Title string `json:"title"`
Labels map[string]string `json:"labels,omitempty"`

View File

@ -5,8 +5,6 @@ import (
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/ngalert/models"
)
func TestRulePayloadMarshaling(t *testing.T) {
@ -24,7 +22,7 @@ func TestRulePayloadMarshaling(t *testing.T) {
{
desc: "success grafana",
input: func() TestRulePayload {
data := models.AlertQuery{}
data := AlertQuery{}
// hack around that the struct embeds the json message inside of it as well
raw, _ := json.Marshal(data)
@ -33,7 +31,7 @@ func TestRulePayloadMarshaling(t *testing.T) {
return TestRulePayload{
GrafanaManagedCondition: &EvalAlertConditionCommand{
Condition: "placeholder",
Data: []models.AlertQuery{data},
Data: []AlertQuery{data},
},
}
}(),

View File

@ -247,12 +247,12 @@ func TestIntegrationAdminConfiguration_SendingToExternalAlertmanagers(t *testing
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{

View File

@ -503,12 +503,12 @@ func TestIntegrationAlertAndGroupsQuery(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -644,12 +644,12 @@ func TestIntegrationRulerAccess(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: fmt.Sprintf("AlwaysFiring %d", i),
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -886,7 +886,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
},
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Data: []ngmodels.AlertQuery{},
Data: []apimodels.AlertQuery{},
},
},
expectedMessage: "invalid rule specification at index [0]: invalid alert rule: no queries or expressions are found",
@ -903,12 +903,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -933,12 +933,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: getLongString(t, ngstore.AlertRuleMaxTitleLength+1),
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -963,12 +963,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -994,12 +994,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1024,12 +1024,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: "unknown",
Model: json.RawMessage(`{
@ -1054,12 +1054,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "B",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1113,12 +1113,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1133,12 +1133,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiringButSilenced",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1300,12 +1300,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
UID: "unknown",
Title: "AlwaysNormal",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1373,12 +1373,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
UID: ruleUID,
Title: "AlwaysNormal",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1407,12 +1407,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
UID: ruleUID,
Title: "AlwaysAlerting",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1481,12 +1481,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
UID: ruleUID, // Including the UID in the payload makes the endpoint update the existing rule.
Title: "AlwaysNormal",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1599,12 +1599,12 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
UID: ruleUID, // Including the UID in the payload makes the endpoint update the existing rule.
Title: "AlwaysNormal",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1958,12 +1958,12 @@ func TestIntegrationQuota(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "One more alert rule",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -1993,12 +1993,12 @@ func TestIntegrationQuota(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "Updated alert rule",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{

View File

@ -53,8 +53,7 @@ func TestBacktesting(t *testing.T) {
require.Truef(t, ok, "The data file does not contain a field `query`")
for _, query := range queryRequest.Data {
isExpr, _ := query.IsExpression()
if isExpr {
if query.DatasourceUID == "__expr__" {
continue
}
t.Logf("Creating a new test data source with UID %s", query.DatasourceUID)

View File

@ -32,7 +32,6 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/org"
@ -981,12 +980,12 @@ func getRulesConfig(t *testing.T) string {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: alertName,
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{

View File

@ -98,12 +98,12 @@ func TestIntegrationPrometheusRules(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -118,12 +118,12 @@ func TestIntegrationPrometheusRules(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiringButSilenced",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -174,12 +174,12 @@ func TestIntegrationPrometheusRules(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "NeverCreated",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -365,12 +365,12 @@ func TestIntegrationPrometheusRulesFilterByDashboard(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -385,12 +385,12 @@ func TestIntegrationPrometheusRulesFilterByDashboard(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiringButSilenced",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{

View File

@ -294,12 +294,12 @@ func createRule(t *testing.T, client apiClient, folder string) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: fmt.Sprintf("rule under folder %s", folder),
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -434,12 +434,12 @@ func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -454,12 +454,12 @@ func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiringButSilenced",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -889,12 +889,12 @@ func newTestingRuleConfig(t *testing.T) apimodels.PostableRuleGroupConfig {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{
@ -916,12 +916,12 @@ func newTestingRuleConfig(t *testing.T) apimodels.PostableRuleGroupConfig {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "AlwaysFiring2",
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{

View File

@ -99,12 +99,12 @@ func alertRuleGen() func() apimodels.PostableExtendedRuleNode {
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: fmt.Sprintf("rule-%s", util.GenerateShortUID()),
Condition: "A",
Data: []ngmodels.AlertQuery{
Data: []apimodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(time.Duration(5) * time.Hour),
To: apimodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: expr.DatasourceUID,
Model: json.RawMessage(`{