AlertingNG: Edit Alert Definition (#30676)

* break out new and edit

* changed model to match new model in backend

* AlertingNG: API modifications (#30683)

* Fix API consistency

* Change eval alert definition to POST request

* Fix eval endpoint to accept custom now parameter

* Change JSON input property for create/update endpoints

* model adjustments

* set mixed datasource, fix put url

* update snapshots

* remove edit and add landing page

* remove snapshot tests ans snapshots

* wrap linkbutton in array

Co-authored-by: Sofia Papagiannaki <papagian@users.noreply.github.com>
Co-authored-by: Sofia Papagiannaki <sofia@grafana.com>
This commit is contained in:
Peter Holmberg
2021-02-04 09:13:02 +01:00
committed by GitHub
parent 21817055bd
commit aaf5710748
16 changed files with 287 additions and 471 deletions

View File

@@ -38,13 +38,24 @@ func (ng *AlertNG) registerAPIEndpoints() {
}
// conditionEvalEndpoint handles POST /api/alert-definitions/eval.
func (ng *AlertNG) conditionEvalEndpoint(c *models.ReqContext, dto evalAlertConditionCommand) response.Response {
if err := ng.validateCondition(dto.Condition, c.SignedInUser, c.SkipCache); err != nil {
func (ng *AlertNG) conditionEvalEndpoint(c *models.ReqContext, cmd evalAlertConditionCommand) response.Response {
evalCond := eval.Condition{
RefID: cmd.Condition,
OrgID: c.SignedInUser.OrgId,
QueriesAndExpressions: cmd.Data,
}
if err := ng.validateCondition(evalCond, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
now := cmd.Now
if now.IsZero() {
now = timeNow()
}
evaluator := eval.Evaluator{Cfg: ng.Cfg}
evalResults, err := evaluator.ConditionEval(&dto.Condition, timeNow())
evalResults, err := evaluator.ConditionEval(&evalCond, now)
if err != nil {
return response.Error(400, "Failed to evaluate conditions", err)
}
@@ -61,7 +72,7 @@ func (ng *AlertNG) conditionEvalEndpoint(c *models.ReqContext, dto evalAlertCond
})
}
// alertDefinitionEvalEndpoint handles GET /api/alert-definitions/eval/:alertDefinitionUID.
// alertDefinitionEvalEndpoint handles POST /api/alert-definitions/eval/:alertDefinitionUID.
func (ng *AlertNG) alertDefinitionEvalEndpoint(c *models.ReqContext) response.Response {
alertDefinitionUID := c.Params(":alertDefinitionUID")
@@ -132,7 +143,12 @@ func (ng *AlertNG) updateAlertDefinitionEndpoint(c *models.ReqContext, cmd updat
cmd.UID = c.Params(":alertDefinitionUID")
cmd.OrgID = c.SignedInUser.OrgId
if err := ng.validateCondition(cmd.Condition, c.SignedInUser, c.SkipCache); err != nil {
evalCond := eval.Condition{
RefID: cmd.Condition,
OrgID: c.SignedInUser.OrgId,
QueriesAndExpressions: cmd.Data,
}
if err := ng.validateCondition(evalCond, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}
@@ -147,7 +163,12 @@ func (ng *AlertNG) updateAlertDefinitionEndpoint(c *models.ReqContext, cmd updat
func (ng *AlertNG) createAlertDefinitionEndpoint(c *models.ReqContext, cmd saveAlertDefinitionCommand) response.Response {
cmd.OrgID = c.SignedInUser.OrgId
if err := ng.validateCondition(cmd.Condition, c.SignedInUser, c.SkipCache); err != nil {
evalCond := eval.Condition{
RefID: cmd.Condition,
OrgID: c.SignedInUser.OrgId,
QueriesAndExpressions: cmd.Data,
}
if err := ng.validateCondition(evalCond, c.SignedInUser, c.SkipCache); err != nil {
return response.Error(400, "invalid condition", err)
}

View File

@@ -57,23 +57,21 @@ func overrideAlertNGInRegistry(cfg *setting.Cfg) AlertNG {
func createTestAlertDefinition(t *testing.T, ng *AlertNG, intervalSeconds int64) *AlertDefinition {
cmd := saveAlertDefinitionCommand{
OrgID: 1,
Title: fmt.Sprintf("an alert definition %d", rand.Intn(1000)),
Condition: eval.Condition{
RefID: "A",
QueriesAndExpressions: []eval.AlertQuery{
{
Model: json.RawMessage(`{
OrgID: 1,
Title: fmt.Sprintf("an alert definition %d", rand.Intn(1000)),
Condition: "A",
Data: []eval.AlertQuery{
{
Model: json.RawMessage(`{
"datasource": "__expr__",
"type":"math",
"expression":"2 + 2 > 1"
}`),
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(5 * time.Hour),
To: eval.Duration(3 * time.Hour),
},
RefID: "A",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(5 * time.Hour),
To: eval.Duration(3 * time.Hour),
},
RefID: "A",
},
},
IntervalSeconds: &intervalSeconds,

View File

@@ -76,8 +76,8 @@ func (ng *AlertNG) saveAlertDefinition(cmd *saveAlertDefinitionCommand) error {
alertDefinition := &AlertDefinition{
OrgID: cmd.OrgID,
Title: cmd.Title,
Condition: cmd.Condition.RefID,
Data: cmd.Condition.QueriesAndExpressions,
Condition: cmd.Condition,
Data: cmd.Data,
IntervalSeconds: intervalSeconds,
Version: initialVersion,
UID: uid,
@@ -133,11 +133,11 @@ func (ng *AlertNG) updateAlertDefinition(cmd *updateAlertDefinitionCommand) erro
if title == "" {
title = existingAlertDefinition.Title
}
condition := cmd.Condition.RefID
condition := cmd.Condition
if condition == "" {
condition = existingAlertDefinition.Condition
}
data := cmd.Condition.QueriesAndExpressions
data := cmd.Data
if data == nil {
data = existingAlertDefinition.Data
}

View File

@@ -74,22 +74,20 @@ func TestCreatingAlertDefinition(t *testing.T) {
t.Cleanup(registry.ClearOverrides)
q := saveAlertDefinitionCommand{
OrgID: 1,
Title: tc.inputTitle,
Condition: eval.Condition{
RefID: "B",
QueriesAndExpressions: []eval.AlertQuery{
{
Model: json.RawMessage(`{
OrgID: 1,
Title: tc.inputTitle,
Condition: "B",
Data: []eval.AlertQuery{
{
Model: json.RawMessage(`{
"datasource": "__expr__",
"type":"math",
"expression":"2 + 3 > 1"
}`),
RefID: "B",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(time.Duration(5) * time.Hour),
To: eval.Duration(time.Duration(3) * time.Hour),
},
RefID: "B",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(time.Duration(5) * time.Hour),
To: eval.Duration(time.Duration(3) * time.Hour),
},
},
},
@@ -117,22 +115,20 @@ func TestCreatingConflictionAlertDefinition(t *testing.T) {
t.Cleanup(registry.ClearOverrides)
q := saveAlertDefinitionCommand{
OrgID: 1,
Title: "title",
Condition: eval.Condition{
RefID: "B",
QueriesAndExpressions: []eval.AlertQuery{
{
Model: json.RawMessage(`{
OrgID: 1,
Title: "title",
Condition: "B",
Data: []eval.AlertQuery{
{
Model: json.RawMessage(`{
"datasource": "__expr__",
"type":"math",
"expression":"2 + 3 > 1"
}`),
RefID: "B",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(time.Duration(5) * time.Hour),
To: eval.Duration(time.Duration(3) * time.Hour),
},
RefID: "B",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(time.Duration(5) * time.Hour),
To: eval.Duration(time.Duration(3) * time.Hour),
},
},
},
@@ -156,23 +152,21 @@ func TestUpdatingAlertDefinition(t *testing.T) {
t.Cleanup(registry.ClearOverrides)
q := updateAlertDefinitionCommand{
UID: "unknown",
OrgID: 1,
Title: "something completely different",
Condition: eval.Condition{
RefID: "A",
QueriesAndExpressions: []eval.AlertQuery{
{
Model: json.RawMessage(`{
UID: "unknown",
OrgID: 1,
Title: "something completely different",
Condition: "A",
Data: []eval.AlertQuery{
{
Model: json.RawMessage(`{
"datasource": "__expr__",
"type":"math",
"expression":"2 + 2 > 1"
}`),
RefID: "A",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(time.Duration(5) * time.Hour),
To: eval.Duration(time.Duration(3) * time.Hour),
},
RefID: "A",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(time.Duration(5) * time.Hour),
To: eval.Duration(time.Duration(3) * time.Hour),
},
},
},
@@ -250,21 +244,19 @@ func TestUpdatingAlertDefinition(t *testing.T) {
}
q := updateAlertDefinitionCommand{
UID: (*alertDefinition).UID,
Condition: eval.Condition{
RefID: "B",
QueriesAndExpressions: []eval.AlertQuery{
{
Model: json.RawMessage(`{
UID: (*alertDefinition).UID,
Condition: "B",
Data: []eval.AlertQuery{
{
Model: json.RawMessage(`{
"datasource": "__expr__",
"type":"math",
"expression":"2 + 3 > 1"
}`),
RefID: "B",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(5 * time.Hour),
To: eval.Duration(3 * time.Hour),
},
RefID: "B",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(5 * time.Hour),
To: eval.Duration(3 * time.Hour),
},
},
},
@@ -335,22 +327,20 @@ func TestUpdatingConflictingAlertDefinition(t *testing.T) {
alertDef2 := createTestAlertDefinition(t, ng, initialInterval)
q := updateAlertDefinitionCommand{
UID: (*alertDef2).UID,
Title: alertDef1.Title,
Condition: eval.Condition{
RefID: "B",
QueriesAndExpressions: []eval.AlertQuery{
{
Model: json.RawMessage(`{
UID: (*alertDef2).UID,
Title: alertDef1.Title,
Condition: "B",
Data: []eval.AlertQuery{
{
Model: json.RawMessage(`{
"datasource": "__expr__",
"type":"math",
"expression":"2 + 3 > 1"
}`),
RefID: "B",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(5 * time.Hour),
To: eval.Duration(3 * time.Hour),
},
RefID: "B",
RelativeTimeRange: eval.RelativeTimeRange{
From: eval.Duration(5 * time.Hour),
To: eval.Duration(3 * time.Hour),
},
},
},

View File

@@ -73,28 +73,31 @@ type deleteAlertDefinitionByUIDCommand struct {
// saveAlertDefinitionCommand is the query for saving a new alert definition.
type saveAlertDefinitionCommand struct {
Title string `json:"title"`
OrgID int64 `json:"-"`
Condition eval.Condition `json:"condition"`
IntervalSeconds *int64 `json:"interval_seconds"`
Title string `json:"title"`
OrgID int64 `json:"-"`
Condition string `json:"condition"`
Data []eval.AlertQuery `json:"data"`
IntervalSeconds *int64 `json:"intervalSeconds"`
Result *AlertDefinition
}
// updateAlertDefinitionCommand is the query for updating an existing alert definition.
type updateAlertDefinitionCommand struct {
Title string `json:"title"`
OrgID int64 `json:"-"`
Condition eval.Condition `json:"condition"`
IntervalSeconds *int64 `json:"interval_seconds"`
UID string `json:"-"`
Title string `json:"title"`
OrgID int64 `json:"-"`
Condition string `json:"condition"`
Data []eval.AlertQuery `json:"data"`
IntervalSeconds *int64 `json:"intervalSeconds"`
UID string `json:"-"`
Result *AlertDefinition
}
type evalAlertConditionCommand struct {
Condition eval.Condition `json:"condition"`
Now time.Time `json:"now"`
Condition string `json:"condition"`
Data []eval.AlertQuery `json:"data"`
Now time.Time `json:"now"`
}
type listAlertDefinitionsQuery struct {