mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(alerting): progress on alerting UI and model, refactoring of dashboard parser and tests into extractor component, moved tests from sqlstore to alerting package
This commit is contained in:
76
pkg/services/alerting/alert_rule.go
Normal file
76
pkg/services/alerting/alert_rule.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package alerting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type AlertRule struct {
|
||||
Id int64
|
||||
OrgId int64
|
||||
DashboardId int64
|
||||
PanelId int64
|
||||
Frequency int64
|
||||
Name string
|
||||
Description string
|
||||
State string
|
||||
Warning Level
|
||||
Critical Level
|
||||
Query AlertQuery
|
||||
Transform string
|
||||
TransformParams simplejson.Json
|
||||
Transformer Transformer
|
||||
}
|
||||
|
||||
func NewAlertRuleFromDBModel(ruleDef *m.AlertRuleModel) (*AlertRule, error) {
|
||||
model := &AlertRule{}
|
||||
model.Id = ruleDef.Id
|
||||
model.OrgId = ruleDef.OrgId
|
||||
model.Name = ruleDef.Name
|
||||
model.Description = ruleDef.Description
|
||||
model.State = ruleDef.State
|
||||
|
||||
critical := ruleDef.Expression.Get("critical")
|
||||
model.Critical = Level{
|
||||
Operator: critical.Get("op").MustString(),
|
||||
Level: critical.Get("level").MustFloat64(),
|
||||
}
|
||||
|
||||
warning := ruleDef.Expression.Get("warning")
|
||||
model.Warning = Level{
|
||||
Operator: warning.Get("op").MustString(),
|
||||
Level: warning.Get("level").MustFloat64(),
|
||||
}
|
||||
|
||||
model.Frequency = ruleDef.Expression.Get("frequency").MustInt64()
|
||||
model.Transform = ruleDef.Expression.Get("transform").Get("type").MustString()
|
||||
model.TransformParams = *ruleDef.Expression.Get("transform")
|
||||
|
||||
if model.Transform == "aggregation" {
|
||||
model.Transformer = &AggregationTransformer{
|
||||
Method: ruleDef.Expression.Get("transform").Get("method").MustString(),
|
||||
}
|
||||
}
|
||||
|
||||
query := ruleDef.Expression.Get("query")
|
||||
model.Query = AlertQuery{
|
||||
Query: query.Get("query").MustString(),
|
||||
DatasourceId: query.Get("datasourceId").MustInt64(),
|
||||
From: query.Get("from").MustString(),
|
||||
To: query.Get("to").MustString(),
|
||||
Aggregator: query.Get("agg").MustString(),
|
||||
}
|
||||
|
||||
if model.Query.Query == "" {
|
||||
return nil, fmt.Errorf("missing query.query")
|
||||
}
|
||||
|
||||
if model.Query.DatasourceId == 0 {
|
||||
return nil, fmt.Errorf("missing query.datasourceId")
|
||||
}
|
||||
|
||||
return model, nil
|
||||
}
|
||||
89
pkg/services/alerting/commands.go
Normal file
89
pkg/services/alerting/commands.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package alerting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type UpdateDashboardAlertsCommand struct {
|
||||
UserId int64
|
||||
OrgId int64
|
||||
Dashboard *m.Dashboard
|
||||
}
|
||||
|
||||
func init() {
|
||||
bus.AddHandler("alerting", updateDashboardAlerts)
|
||||
}
|
||||
|
||||
func updateDashboardAlerts(cmd *UpdateDashboardAlertsCommand) error {
|
||||
saveRulesCmd := m.SaveAlertsCommand{
|
||||
OrgId: cmd.OrgId,
|
||||
UserId: cmd.UserId,
|
||||
}
|
||||
|
||||
extractor := NewAlertRuleExtractor(cmd.Dashboard, cmd.OrgId)
|
||||
|
||||
rules, err := extractor.GetRuleModels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
saveRulesCmd.Alerts = rules
|
||||
if bus.Dispatch(&saveRulesCmd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ConvetAlertModelToAlertRule(ruleDef *m.AlertRuleModel) (*AlertRule, error) {
|
||||
model := &AlertRule{}
|
||||
model.Id = ruleDef.Id
|
||||
model.OrgId = ruleDef.OrgId
|
||||
model.Name = ruleDef.Name
|
||||
model.Description = ruleDef.Description
|
||||
model.State = ruleDef.State
|
||||
|
||||
critical := ruleDef.Expression.Get("critical")
|
||||
model.Critical = Level{
|
||||
Operator: critical.Get("op").MustString(),
|
||||
Level: critical.Get("level").MustFloat64(),
|
||||
}
|
||||
|
||||
warning := ruleDef.Expression.Get("warning")
|
||||
model.Warning = Level{
|
||||
Operator: warning.Get("op").MustString(),
|
||||
Level: warning.Get("level").MustFloat64(),
|
||||
}
|
||||
|
||||
model.Frequency = ruleDef.Expression.Get("frequency").MustInt64()
|
||||
model.Transform = ruleDef.Expression.Get("transform").Get("type").MustString()
|
||||
model.TransformParams = *ruleDef.Expression.Get("transform")
|
||||
|
||||
if model.Transform == "aggregation" {
|
||||
model.Transformer = &AggregationTransformer{
|
||||
Method: ruleDef.Expression.Get("transform").Get("method").MustString(),
|
||||
}
|
||||
}
|
||||
|
||||
query := ruleDef.Expression.Get("query")
|
||||
model.Query = AlertQuery{
|
||||
Query: query.Get("query").MustString(),
|
||||
DatasourceId: query.Get("datasourceId").MustInt64(),
|
||||
From: query.Get("from").MustString(),
|
||||
To: query.Get("to").MustString(),
|
||||
Aggregator: query.Get("agg").MustString(),
|
||||
}
|
||||
|
||||
if model.Query.Query == "" {
|
||||
return nil, fmt.Errorf("missing query.query")
|
||||
}
|
||||
|
||||
if model.Query.DatasourceId == 0 {
|
||||
return nil, fmt.Errorf("missing query.datasourceId")
|
||||
}
|
||||
|
||||
return model, nil
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package alerting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRuleModel {
|
||||
alerts := make([]*m.AlertRuleModel, 0)
|
||||
|
||||
for _, rowObj := range cmd.Dashboard.Get("rows").MustArray() {
|
||||
row := simplejson.NewFromAny(rowObj)
|
||||
|
||||
for _, panelObj := range row.Get("panels").MustArray() {
|
||||
panel := simplejson.NewFromAny(panelObj)
|
||||
|
||||
alerting := panel.Get("alerting")
|
||||
alert := &m.AlertRuleModel{
|
||||
DashboardId: cmd.Result.Id,
|
||||
OrgId: cmd.Result.OrgId,
|
||||
PanelId: panel.Get("id").MustInt64(),
|
||||
Id: alerting.Get("id").MustInt64(),
|
||||
Name: alerting.Get("name").MustString(),
|
||||
Description: alerting.Get("description").MustString(),
|
||||
}
|
||||
|
||||
log.Info("Alertrule: %v", alert.Name)
|
||||
|
||||
valueQuery := alerting.Get("query")
|
||||
valueQueryRef := valueQuery.Get("refId").MustString()
|
||||
for _, targetsObj := range panel.Get("targets").MustArray() {
|
||||
target := simplejson.NewFromAny(targetsObj)
|
||||
|
||||
if target.Get("refId").MustString() == valueQueryRef {
|
||||
datsourceName := ""
|
||||
if target.Get("datasource").MustString() != "" {
|
||||
datsourceName = target.Get("datasource").MustString()
|
||||
} else if panel.Get("datasource").MustString() != "" {
|
||||
datsourceName = panel.Get("datasource").MustString()
|
||||
}
|
||||
|
||||
if datsourceName == "" {
|
||||
query := &m.GetDataSourcesQuery{OrgId: cmd.OrgId}
|
||||
if err := bus.Dispatch(query); err == nil {
|
||||
for _, ds := range query.Result {
|
||||
if ds.IsDefault {
|
||||
alerting.SetPath([]string{"query", "datasourceId"}, ds.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
query := &m.GetDataSourceByNameQuery{
|
||||
Name: panel.Get("datasource").MustString(),
|
||||
OrgId: cmd.OrgId,
|
||||
}
|
||||
bus.Dispatch(query)
|
||||
alerting.SetPath([]string{"query", "datasourceId"}, query.Result.Id)
|
||||
}
|
||||
|
||||
targetQuery := target.Get("target").MustString()
|
||||
if targetQuery != "" {
|
||||
alerting.SetPath([]string{"query", "query"}, targetQuery)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alert.Expression = alerting
|
||||
|
||||
_, err := ConvetAlertModelToAlertRule(alert)
|
||||
|
||||
if err == nil && alert.ValidToSave() {
|
||||
alerts = append(alerts, alert)
|
||||
} else {
|
||||
log.Error2("Failed to parse model from expression", "error", err)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return alerts
|
||||
}
|
||||
|
||||
func ConvetAlertModelToAlertRule(ruleDef *m.AlertRuleModel) (*AlertRule, error) {
|
||||
model := &AlertRule{}
|
||||
model.Id = ruleDef.Id
|
||||
model.OrgId = ruleDef.OrgId
|
||||
model.Name = ruleDef.Name
|
||||
model.Description = ruleDef.Description
|
||||
model.State = ruleDef.State
|
||||
|
||||
critical := ruleDef.Expression.Get("critical")
|
||||
model.Critical = Level{
|
||||
Operator: critical.Get("op").MustString(),
|
||||
Level: critical.Get("level").MustFloat64(),
|
||||
}
|
||||
|
||||
warning := ruleDef.Expression.Get("warning")
|
||||
model.Warning = Level{
|
||||
Operator: warning.Get("op").MustString(),
|
||||
Level: warning.Get("level").MustFloat64(),
|
||||
}
|
||||
|
||||
model.Frequency = ruleDef.Expression.Get("frequency").MustInt64()
|
||||
model.Transform = ruleDef.Expression.Get("transform").Get("type").MustString()
|
||||
model.TransformParams = *ruleDef.Expression.Get("transform")
|
||||
|
||||
if model.Transform == "aggregation" {
|
||||
model.Transformer = &AggregationTransformer{
|
||||
Method: ruleDef.Expression.Get("transform").Get("method").MustString(),
|
||||
}
|
||||
}
|
||||
|
||||
query := ruleDef.Expression.Get("query")
|
||||
model.Query = AlertQuery{
|
||||
Query: query.Get("query").MustString(),
|
||||
DatasourceId: query.Get("datasourceId").MustInt64(),
|
||||
From: query.Get("from").MustString(),
|
||||
To: query.Get("to").MustString(),
|
||||
Aggregator: query.Get("agg").MustString(),
|
||||
}
|
||||
|
||||
if model.Query.Query == "" {
|
||||
return nil, fmt.Errorf("missing query.query")
|
||||
}
|
||||
|
||||
if model.Query.DatasourceId == 0 {
|
||||
return nil, fmt.Errorf("missing query.datasourceId")
|
||||
}
|
||||
|
||||
return model, nil
|
||||
}
|
||||
120
pkg/services/alerting/extractor.go
Normal file
120
pkg/services/alerting/extractor.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package alerting
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type AlertRuleExtractor struct {
|
||||
Dash *m.Dashboard
|
||||
OrgId int64
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func NewAlertRuleExtractor(dash *m.Dashboard, orgId int64) *AlertRuleExtractor {
|
||||
return &AlertRuleExtractor{
|
||||
Dash: dash,
|
||||
OrgId: orgId,
|
||||
log: log.New("alerting.extractor"),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *AlertRuleExtractor) lookupDatasourceId(dsName string) (int64, error) {
|
||||
if dsName == "" {
|
||||
query := &m.GetDataSourcesQuery{OrgId: e.OrgId}
|
||||
if err := bus.Dispatch(query); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
for _, ds := range query.Result {
|
||||
if ds.IsDefault {
|
||||
return ds.Id, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
query := &m.GetDataSourceByNameQuery{Name: dsName, OrgId: e.OrgId}
|
||||
if err := bus.Dispatch(query); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
return query.Result.Id, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, errors.New("Could not find datasource id for " + dsName)
|
||||
}
|
||||
|
||||
func (e *AlertRuleExtractor) GetRuleModels() (m.AlertRules, error) {
|
||||
|
||||
rules := make(m.AlertRules, 0)
|
||||
|
||||
for _, rowObj := range e.Dash.Data.Get("rows").MustArray() {
|
||||
row := simplejson.NewFromAny(rowObj)
|
||||
|
||||
for _, panelObj := range row.Get("panels").MustArray() {
|
||||
panel := simplejson.NewFromAny(panelObj)
|
||||
jsonRule := panel.Get("alerting")
|
||||
|
||||
// check if marked for deletion
|
||||
deleted := jsonRule.Get("deleted").MustBool()
|
||||
if deleted {
|
||||
e.log.Info("Deleted alert rule found")
|
||||
continue
|
||||
}
|
||||
|
||||
ruleModel := &m.AlertRuleModel{
|
||||
DashboardId: e.Dash.Id,
|
||||
OrgId: e.OrgId,
|
||||
PanelId: panel.Get("id").MustInt64(),
|
||||
Id: jsonRule.Get("id").MustInt64(),
|
||||
Name: jsonRule.Get("name").MustString(),
|
||||
Scheduler: jsonRule.Get("scheduler").MustInt64(),
|
||||
Enabled: jsonRule.Get("enabled").MustBool(),
|
||||
Description: jsonRule.Get("description").MustString(),
|
||||
}
|
||||
|
||||
valueQuery := jsonRule.Get("query")
|
||||
valueQueryRef := valueQuery.Get("refId").MustString()
|
||||
for _, targetsObj := range panel.Get("targets").MustArray() {
|
||||
target := simplejson.NewFromAny(targetsObj)
|
||||
|
||||
if target.Get("refId").MustString() == valueQueryRef {
|
||||
dsName := ""
|
||||
if target.Get("datasource").MustString() != "" {
|
||||
dsName = target.Get("datasource").MustString()
|
||||
} else if panel.Get("datasource").MustString() != "" {
|
||||
dsName = panel.Get("datasource").MustString()
|
||||
}
|
||||
|
||||
if datasourceId, err := e.lookupDatasourceId(dsName); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
valueQuery.SetPath([]string{"datasourceId"}, datasourceId)
|
||||
}
|
||||
|
||||
targetQuery := target.Get("target").MustString()
|
||||
if targetQuery != "" {
|
||||
jsonRule.SetPath([]string{"query", "query"}, targetQuery)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ruleModel.Expression = jsonRule
|
||||
|
||||
// validate
|
||||
_, err := NewAlertRuleFromDBModel(ruleModel)
|
||||
if err == nil && ruleModel.ValidToSave() {
|
||||
rules = append(rules, ruleModel)
|
||||
} else {
|
||||
e.log.Error("Failed to extract alert rules from dashboard", "error", err)
|
||||
return nil, errors.New("Failed to extract alert rules from dashboard")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
222
pkg/services/alerting/extractor_test.go
Normal file
222
pkg/services/alerting/extractor_test.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package alerting
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestAlertRuleExtraction(t *testing.T) {
|
||||
|
||||
Convey("Parsing alert rules from dashboard json", t, func() {
|
||||
Convey("Parsing and validating alerts from dashboards", func() {
|
||||
json := `{
|
||||
"id": 57,
|
||||
"title": "Graphite 4",
|
||||
"originalTitle": "Graphite 4",
|
||||
"tags": [
|
||||
"graphite"
|
||||
],
|
||||
"rows": [
|
||||
{
|
||||
|
||||
"panels": [
|
||||
{
|
||||
"title": "Active desktop users",
|
||||
"editable": true,
|
||||
"type": "graph",
|
||||
"id": 3,
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"target": "aliasByNode(statsd.fakesite.counters.session_start.desktop.count, 4)"
|
||||
}
|
||||
],
|
||||
"datasource": null,
|
||||
"alerting": {
|
||||
"name": "name1",
|
||||
"description": "desc1",
|
||||
"scheduler": 1,
|
||||
"enabled": true,
|
||||
"critical": {
|
||||
"level": 20,
|
||||
"op": ">"
|
||||
},
|
||||
"frequency": "60s",
|
||||
"query": {
|
||||
"from": "5m",
|
||||
"refId": "A",
|
||||
"to": "now"
|
||||
},
|
||||
"transform": {
|
||||
"method": "avg",
|
||||
"type": "aggregation"
|
||||
},
|
||||
"warning": {
|
||||
"level": 10,
|
||||
"op": ">"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Active mobile users",
|
||||
"id": 4,
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"
|
||||
}
|
||||
],
|
||||
"datasource": "graphite2",
|
||||
"alerting": {
|
||||
"name": "name2",
|
||||
"description": "desc2",
|
||||
"scheduler": 0,
|
||||
"enabled": true,
|
||||
"critical": {
|
||||
"level": 20,
|
||||
"op": ">"
|
||||
},
|
||||
"frequency": "60s",
|
||||
"query": {
|
||||
"from": "5m",
|
||||
"refId": "A",
|
||||
"to": "now"
|
||||
},
|
||||
"transform": {
|
||||
"method": "avg",
|
||||
"name": "aggregation"
|
||||
},
|
||||
"warning": {
|
||||
"level": 10,
|
||||
"op": ">"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Row"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"datasource": "InfluxDB",
|
||||
"id": 2,
|
||||
"targets": [
|
||||
{
|
||||
"dsType": "influxdb",
|
||||
"groupBy": [
|
||||
{
|
||||
"params": [
|
||||
"$interval"
|
||||
],
|
||||
"type": "time"
|
||||
},
|
||||
{
|
||||
"params": [
|
||||
"null"
|
||||
],
|
||||
"type": "fill"
|
||||
}
|
||||
],
|
||||
"measurement": "cpu",
|
||||
"policy": "default",
|
||||
"query": "SELECT mean(\"value\") FROM \"cpu\" WHERE $timeFilter GROUP BY time($interval) fill(null)",
|
||||
"refId": "A",
|
||||
"resultFormat": "table",
|
||||
"select": [
|
||||
[
|
||||
{
|
||||
"params": [
|
||||
"value"
|
||||
],
|
||||
"type": "field"
|
||||
},
|
||||
{
|
||||
"params": [],
|
||||
"type": "mean"
|
||||
}
|
||||
]
|
||||
],
|
||||
"tags": [],
|
||||
"target": ""
|
||||
}
|
||||
],
|
||||
"title": "Broken influxdb panel",
|
||||
"transform": "table",
|
||||
"type": "table",
|
||||
"alerting": {
|
||||
"deleted": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
}
|
||||
]
|
||||
|
||||
}`
|
||||
dashJson, err := simplejson.NewJson([]byte(json))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
dash := m.NewDashboardFromJson(dashJson)
|
||||
extractor := NewAlertRuleExtractor(dash, 1)
|
||||
|
||||
// mock data
|
||||
defaultDs := &m.DataSource{Id: 12, OrgId: 2, Name: "I am default", IsDefault: true}
|
||||
graphite2Ds := &m.DataSource{Id: 15, OrgId: 2, Name: "graphite2"}
|
||||
|
||||
bus.AddHandler("test", func(query *m.GetDataSourcesQuery) error {
|
||||
query.Result = []*m.DataSource{defaultDs, graphite2Ds}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(query *m.GetDataSourceByNameQuery) error {
|
||||
if query.Name == defaultDs.Name {
|
||||
query.Result = defaultDs
|
||||
}
|
||||
if query.Name == graphite2Ds.Name {
|
||||
query.Result = graphite2Ds
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
alerts, err := extractor.GetRuleModels()
|
||||
|
||||
Convey("Get rules without error", func() {
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("all properties have been set", func() {
|
||||
So(len(alerts), ShouldEqual, 2)
|
||||
|
||||
for _, v := range alerts {
|
||||
So(v.DashboardId, ShouldEqual, 57)
|
||||
So(v.Name, ShouldNotBeEmpty)
|
||||
So(v.Description, ShouldNotBeEmpty)
|
||||
}
|
||||
|
||||
Convey("should extract scheduler property", func() {
|
||||
So(alerts[0].Scheduler, ShouldEqual, 1)
|
||||
So(alerts[1].Scheduler, ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("should extract panel idc", func() {
|
||||
So(alerts[0].PanelId, ShouldEqual, 3)
|
||||
So(alerts[1].PanelId, ShouldEqual, 4)
|
||||
})
|
||||
|
||||
Convey("should extract name and desc", func() {
|
||||
So(alerts[0].Name, ShouldEqual, "name1")
|
||||
So(alerts[0].Description, ShouldEqual, "desc1")
|
||||
So(alerts[1].Name, ShouldEqual, "name2")
|
||||
So(alerts[1].Description, ShouldEqual, "desc2")
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
package alerting
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
)
|
||||
|
||||
type AlertJob struct {
|
||||
Offset int64
|
||||
Delay bool
|
||||
@@ -21,23 +17,6 @@ type AlertResult struct {
|
||||
AlertJob *AlertJob
|
||||
}
|
||||
|
||||
type AlertRule struct {
|
||||
Id int64
|
||||
OrgId int64
|
||||
DashboardId int64
|
||||
PanelId int64
|
||||
Frequency int64
|
||||
Name string
|
||||
Description string
|
||||
State string
|
||||
Warning Level
|
||||
Critical Level
|
||||
Query AlertQuery
|
||||
Transform string
|
||||
TransformParams simplejson.Json
|
||||
Transformer Transformer
|
||||
}
|
||||
|
||||
type Level struct {
|
||||
Operator string
|
||||
Level float64
|
||||
|
||||
Reference in New Issue
Block a user