1570 lines
32 KiB
Go
1570 lines
32 KiB
Go
package kapacitor
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/influxdata/influxdb/chronograf"
|
|
)
|
|
|
|
func TestReverse(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
script chronograf.TICKScript
|
|
want chronograf.AlertRule
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "simple stream tickscript",
|
|
script: chronograf.TICKScript(`
|
|
var name = 'name'
|
|
var triggerType = 'threshold'
|
|
var every = 30s
|
|
var period = 10m
|
|
var groupBy = ['host', 'cluster_id']
|
|
var db = 'telegraf'
|
|
var rp = 'autogen'
|
|
var measurement = 'cpu'
|
|
var message = 'message'
|
|
var details = 'details'
|
|
var crit = 90
|
|
var idVar = name + ':{{.Group}}'
|
|
var idTag = 'alertID'
|
|
var levelTag = 'level'
|
|
var messageField = 'message'
|
|
var durationField = 'duration'
|
|
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
|window()
|
|
.period(period)
|
|
.every(every)
|
|
.align()
|
|
|mean('usage_user')
|
|
.as('value')
|
|
var trigger = data
|
|
|alert()
|
|
.crit(lambda: "value" > crit)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.slack()
|
|
.victorOps()
|
|
.email('howdy@howdy.com', 'doody@doody.com')
|
|
.log('/tmp/alerts.log')
|
|
.post('http://backin.tm')
|
|
.endpoint('myendpoint')
|
|
.header('key', 'value')
|
|
`),
|
|
|
|
want: chronograf.AlertRule{
|
|
Name: "name",
|
|
Trigger: "threshold",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Slack: []*chronograf.Slack{
|
|
{},
|
|
},
|
|
VictorOps: []*chronograf.VictorOps{
|
|
{},
|
|
},
|
|
Email: []*chronograf.Email{
|
|
{
|
|
To: []string{"howdy@howdy.com", "doody@doody.com"},
|
|
},
|
|
},
|
|
Log: []*chronograf.Log{
|
|
{
|
|
FilePath: "/tmp/alerts.log",
|
|
},
|
|
},
|
|
Posts: []*chronograf.Post{
|
|
{
|
|
URL: "http://backin.tm",
|
|
Headers: map[string]string{"key": "value"},
|
|
},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Operator: "greater than",
|
|
Value: "90",
|
|
},
|
|
Every: "30s",
|
|
Message: "message",
|
|
Details: "details",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "telegraf",
|
|
RetentionPolicy: "autogen",
|
|
Measurement: "cpu",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "mean",
|
|
Args: []chronograf.Field{
|
|
{
|
|
Value: "usage_user",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Type: "func",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "10m0s",
|
|
Tags: []string{"host", "cluster_id"},
|
|
},
|
|
Tags: map[string][]string{
|
|
"cpu": []string{
|
|
"cpu_total",
|
|
},
|
|
"host": []string{
|
|
"acc-0eabc309-eu-west-1-data-3",
|
|
"prod",
|
|
},
|
|
},
|
|
AreTagsAccepted: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test Threshold",
|
|
script: `var db = 'telegraf'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'cpu'
|
|
|
|
var groupBy = ['host', 'cluster_id']
|
|
|
|
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
|
|
|
|
var period = 10m
|
|
|
|
var every = 30s
|
|
|
|
var name = 'name'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'message'
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'threshold'
|
|
|
|
var crit = 90
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|window()
|
|
.period(period)
|
|
.every(every)
|
|
.align()
|
|
|mean('usage_user')
|
|
.as('value')
|
|
|
|
var trigger = data
|
|
|alert()
|
|
.crit(lambda: "value" > crit)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.slack()
|
|
.victorOps()
|
|
.email()
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')`,
|
|
want: chronograf.AlertRule{
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "telegraf",
|
|
Measurement: "cpu",
|
|
RetentionPolicy: "autogen",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "mean",
|
|
Args: []chronograf.Field{
|
|
{
|
|
Value: "usage_user",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Type: "func",
|
|
},
|
|
},
|
|
Tags: map[string][]string{
|
|
"cpu": []string{"cpu_total"},
|
|
"host": []string{"acc-0eabc309-eu-west-1-data-3", "prod"},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "10m0s",
|
|
Tags: []string{"host", "cluster_id"},
|
|
},
|
|
AreTagsAccepted: true,
|
|
},
|
|
Every: "30s",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
|
|
Slack: []*chronograf.Slack{
|
|
{},
|
|
},
|
|
VictorOps: []*chronograf.VictorOps{
|
|
{},
|
|
},
|
|
Email: []*chronograf.Email{
|
|
{
|
|
To: []string{},
|
|
},
|
|
},
|
|
},
|
|
Message: "message",
|
|
Trigger: "threshold",
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Operator: "greater than",
|
|
Value: "90",
|
|
},
|
|
Name: "name",
|
|
},
|
|
},
|
|
{
|
|
name: "Test haproxy string comparison",
|
|
script: `var db = 'influxdb'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'haproxy'
|
|
|
|
var groupBy = ['pxname']
|
|
|
|
var whereFilter = lambda: TRUE
|
|
|
|
var period = 10s
|
|
|
|
var every = 10s
|
|
|
|
var name = 'haproxy'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} '
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'threshold'
|
|
|
|
var details = 'Email template'
|
|
|
|
var crit = 'DOWN'
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|window()
|
|
.period(period)
|
|
.every(every)
|
|
.align()
|
|
|last('status')
|
|
.as('value')
|
|
|
|
var trigger = data
|
|
|alert()
|
|
.crit(lambda: "value" == crit)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.details(details)
|
|
.email()
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "haproxy",
|
|
Trigger: "threshold",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Email: []*chronograf.Email{
|
|
{To: []string{}},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Operator: "equal to",
|
|
Value: "DOWN",
|
|
},
|
|
Every: "10s",
|
|
Message: `Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} `,
|
|
Details: "Email template",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "influxdb",
|
|
RetentionPolicy: "autogen",
|
|
Measurement: "haproxy",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "last",
|
|
Args: []chronograf.Field{
|
|
{
|
|
Value: "status",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Type: "func",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "10s",
|
|
Tags: []string{"pxname"},
|
|
},
|
|
AreTagsAccepted: false,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test haproxy",
|
|
script: `var db = 'influxdb'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'haproxy'
|
|
|
|
var groupBy = ['pxname']
|
|
|
|
var whereFilter = lambda: TRUE
|
|
|
|
var period = 10s
|
|
|
|
var every = 10s
|
|
|
|
var name = 'haproxy'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} '
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'threshold'
|
|
|
|
var details = 'Email template'
|
|
|
|
var crit = 'DOWN'
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|window()
|
|
.period(period)
|
|
.every(every)
|
|
.align()
|
|
|last('status')
|
|
.as('value')
|
|
|
|
var trigger = data
|
|
|alert()
|
|
.crit(lambda: "value" > crit)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.details(details)
|
|
.email()
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "haproxy",
|
|
Trigger: "threshold",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Email: []*chronograf.Email{
|
|
{To: []string{}},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Operator: "greater than",
|
|
Value: "DOWN",
|
|
},
|
|
Every: "10s",
|
|
Message: `Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} `,
|
|
Details: "Email template",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "influxdb",
|
|
RetentionPolicy: "autogen",
|
|
Measurement: "haproxy",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "last",
|
|
Args: []chronograf.Field{
|
|
{
|
|
Value: "status",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Type: "func",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "10s",
|
|
Tags: []string{"pxname"},
|
|
},
|
|
AreTagsAccepted: false,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test valid template alert with detail",
|
|
script: `var db = 'telegraf'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'cpu'
|
|
|
|
var groupBy = ['host', 'cluster_id']
|
|
|
|
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
|
|
|
|
var period = 10m
|
|
|
|
var every = 30s
|
|
|
|
var name = 'name'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'message'
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'threshold'
|
|
|
|
var details = 'details'
|
|
|
|
var crit = 90
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|window()
|
|
.period(period)
|
|
.every(every)
|
|
.align()
|
|
|mean('usage_user')
|
|
.as('value')
|
|
|
|
var trigger = data
|
|
|alert()
|
|
.crit(lambda: "value" > crit)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.details(details)
|
|
.slack()
|
|
.victorOps()
|
|
.email()
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "name",
|
|
Trigger: "threshold",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Slack: []*chronograf.Slack{
|
|
{},
|
|
},
|
|
VictorOps: []*chronograf.VictorOps{
|
|
{},
|
|
},
|
|
Email: []*chronograf.Email{
|
|
{To: []string{}},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Operator: "greater than",
|
|
Value: "90",
|
|
},
|
|
Every: "30s",
|
|
Message: "message",
|
|
Details: "details",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "telegraf",
|
|
Measurement: "cpu",
|
|
RetentionPolicy: "autogen",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "mean",
|
|
Args: []chronograf.Field{
|
|
{
|
|
Value: "usage_user",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Type: "func",
|
|
},
|
|
},
|
|
Tags: map[string][]string{
|
|
"host": []string{
|
|
"acc-0eabc309-eu-west-1-data-3",
|
|
"prod",
|
|
},
|
|
"cpu": []string{
|
|
"cpu_total",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "10m0s",
|
|
Tags: []string{"host", "cluster_id"},
|
|
},
|
|
AreTagsAccepted: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test valid threshold inside range",
|
|
script: `var db = 'telegraf'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'cpu'
|
|
|
|
var groupBy = ['host', 'cluster_id']
|
|
|
|
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
|
|
|
|
var period = 10m
|
|
|
|
var every = 30s
|
|
|
|
var name = 'name'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'message'
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'threshold'
|
|
|
|
var lower = 90
|
|
|
|
var upper = 100
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|window()
|
|
.period(period)
|
|
.every(every)
|
|
.align()
|
|
|mean('usage_user')
|
|
.as('value')
|
|
|
|
var trigger = data
|
|
|alert()
|
|
.crit(lambda: "value" >= lower AND "value" <= upper)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.slack()
|
|
.victorOps()
|
|
.email()
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "name",
|
|
Trigger: "threshold",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Slack: []*chronograf.Slack{
|
|
{},
|
|
},
|
|
VictorOps: []*chronograf.VictorOps{
|
|
{},
|
|
},
|
|
Email: []*chronograf.Email{
|
|
{To: []string{}},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Operator: "inside range",
|
|
Value: "90",
|
|
RangeValue: "100",
|
|
},
|
|
Every: "30s",
|
|
Message: "message",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "telegraf",
|
|
Measurement: "cpu",
|
|
RetentionPolicy: "autogen",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "mean",
|
|
Args: []chronograf.Field{
|
|
{
|
|
Value: "usage_user",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Type: "func",
|
|
},
|
|
},
|
|
Tags: map[string][]string{
|
|
"host": []string{
|
|
"acc-0eabc309-eu-west-1-data-3",
|
|
"prod",
|
|
},
|
|
"cpu": []string{
|
|
"cpu_total",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "10m0s",
|
|
Tags: []string{"host", "cluster_id"},
|
|
},
|
|
AreTagsAccepted: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test valid threshold outside range",
|
|
script: `var db = 'telegraf'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'cpu'
|
|
|
|
var groupBy = ['host', 'cluster_id']
|
|
|
|
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
|
|
|
|
var period = 10m
|
|
|
|
var every = 30s
|
|
|
|
var name = 'name'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'message'
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'threshold'
|
|
|
|
var lower = 90
|
|
|
|
var upper = 100
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|window()
|
|
.period(period)
|
|
.every(every)
|
|
.align()
|
|
|mean('usage_user')
|
|
.as('value')
|
|
|
|
var trigger = data
|
|
|alert()
|
|
.crit(lambda: "value" < lower OR "value" > upper)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.slack()
|
|
.victorOps()
|
|
.email()
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "name",
|
|
Trigger: "threshold",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Slack: []*chronograf.Slack{
|
|
{},
|
|
},
|
|
VictorOps: []*chronograf.VictorOps{
|
|
{},
|
|
},
|
|
Email: []*chronograf.Email{
|
|
{To: []string{}},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Operator: "outside range",
|
|
Value: "90",
|
|
RangeValue: "100",
|
|
},
|
|
Every: "30s",
|
|
Message: "message",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "telegraf",
|
|
Measurement: "cpu",
|
|
RetentionPolicy: "autogen",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "mean",
|
|
Args: []chronograf.Field{
|
|
{
|
|
Value: "usage_user",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Type: "func",
|
|
},
|
|
},
|
|
Tags: map[string][]string{
|
|
"host": []string{
|
|
"acc-0eabc309-eu-west-1-data-3",
|
|
"prod",
|
|
},
|
|
"cpu": []string{
|
|
"cpu_total",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "10m0s",
|
|
Tags: []string{"host", "cluster_id"},
|
|
},
|
|
AreTagsAccepted: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test threshold no aggregate",
|
|
script: `var db = 'telegraf'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'cpu'
|
|
|
|
var groupBy = ['host', 'cluster_id']
|
|
|
|
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
|
|
|
|
var name = 'name'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'message'
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'threshold'
|
|
|
|
var crit = 90
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|eval(lambda: "usage_user")
|
|
.as('value')
|
|
|
|
var trigger = data
|
|
|alert()
|
|
.crit(lambda: "value" > crit)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.slack()
|
|
.victorOps()
|
|
.email()
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "name",
|
|
Trigger: "threshold",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Slack: []*chronograf.Slack{
|
|
{},
|
|
},
|
|
VictorOps: []*chronograf.VictorOps{
|
|
{},
|
|
},
|
|
Email: []*chronograf.Email{
|
|
{To: []string{}},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Operator: "greater than",
|
|
Value: "90",
|
|
},
|
|
Message: "message",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "telegraf",
|
|
Measurement: "cpu",
|
|
RetentionPolicy: "autogen",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "usage_user",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Tags: map[string][]string{
|
|
"host": []string{
|
|
"acc-0eabc309-eu-west-1-data-3",
|
|
"prod",
|
|
},
|
|
"cpu": []string{
|
|
"cpu_total",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Tags: []string{"host", "cluster_id"},
|
|
},
|
|
AreTagsAccepted: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test relative alert",
|
|
script: `var db = 'telegraf'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'cpu'
|
|
|
|
var groupBy = ['host', 'cluster_id']
|
|
|
|
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
|
|
|
|
var period = 10m
|
|
|
|
var every = 30s
|
|
|
|
var name = 'name'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'message'
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'relative'
|
|
|
|
var shift = 1m
|
|
|
|
var crit = 90
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|window()
|
|
.period(period)
|
|
.every(every)
|
|
.align()
|
|
|mean('usage_user')
|
|
.as('value')
|
|
|
|
var past = data
|
|
|shift(shift)
|
|
|
|
var current = data
|
|
|
|
var trigger = past
|
|
|join(current)
|
|
.as('past', 'current')
|
|
|eval(lambda: abs(float("current.value" - "past.value")) / float("past.value") * 100.0)
|
|
.keep()
|
|
.as('value')
|
|
|alert()
|
|
.crit(lambda: "value" > crit)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.slack()
|
|
.victorOps()
|
|
.email()
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "name",
|
|
Trigger: "relative",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Slack: []*chronograf.Slack{
|
|
{},
|
|
},
|
|
VictorOps: []*chronograf.VictorOps{
|
|
{},
|
|
},
|
|
Email: []*chronograf.Email{
|
|
{To: []string{}},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Change: "% change",
|
|
Shift: "1m0s",
|
|
Operator: "greater than",
|
|
Value: "90",
|
|
},
|
|
Every: "30s",
|
|
Message: "message",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "telegraf",
|
|
Measurement: "cpu",
|
|
RetentionPolicy: "autogen",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "mean",
|
|
Args: []chronograf.Field{
|
|
{
|
|
Value: "usage_user",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Type: "func",
|
|
},
|
|
},
|
|
Tags: map[string][]string{
|
|
"host": []string{
|
|
"acc-0eabc309-eu-west-1-data-3",
|
|
"prod",
|
|
},
|
|
"cpu": []string{
|
|
"cpu_total",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "10m0s",
|
|
Tags: []string{"host", "cluster_id"},
|
|
},
|
|
AreTagsAccepted: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test relative change",
|
|
script: `var db = 'telegraf'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'cpu'
|
|
|
|
var groupBy = ['host', 'cluster_id']
|
|
|
|
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
|
|
|
|
var period = 10m
|
|
|
|
var every = 30s
|
|
|
|
var name = 'name'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'message'
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'relative'
|
|
|
|
var shift = 1m
|
|
|
|
var crit = 90
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|window()
|
|
.period(period)
|
|
.every(every)
|
|
.align()
|
|
|mean('usage_user')
|
|
.as('value')
|
|
|
|
var past = data
|
|
|shift(shift)
|
|
|
|
var current = data
|
|
|
|
var trigger = past
|
|
|join(current)
|
|
.as('past', 'current')
|
|
|eval(lambda: float("current.value" - "past.value"))
|
|
.keep()
|
|
.as('value')
|
|
|alert()
|
|
.crit(lambda: "value" > crit)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.slack()
|
|
.victorOps()
|
|
.email()
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "name",
|
|
Trigger: "relative",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Slack: []*chronograf.Slack{
|
|
{},
|
|
},
|
|
VictorOps: []*chronograf.VictorOps{
|
|
{},
|
|
},
|
|
Email: []*chronograf.Email{
|
|
{To: []string{}},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Change: "change",
|
|
Shift: "1m0s",
|
|
Operator: "greater than",
|
|
Value: "90",
|
|
},
|
|
Every: "30s",
|
|
Message: "message",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "telegraf",
|
|
Measurement: "cpu",
|
|
RetentionPolicy: "autogen",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "mean",
|
|
Args: []chronograf.Field{
|
|
{
|
|
Value: "usage_user",
|
|
Type: "field",
|
|
},
|
|
},
|
|
Type: "func",
|
|
},
|
|
},
|
|
Tags: map[string][]string{
|
|
"host": []string{
|
|
"acc-0eabc309-eu-west-1-data-3",
|
|
"prod",
|
|
},
|
|
"cpu": []string{
|
|
"cpu_total",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "10m0s",
|
|
Tags: []string{"host", "cluster_id"},
|
|
},
|
|
AreTagsAccepted: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test deadman",
|
|
script: `var db = 'telegraf'
|
|
|
|
var rp = 'autogen'
|
|
|
|
var measurement = 'cpu'
|
|
|
|
var groupBy = ['host', 'cluster_id']
|
|
|
|
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
|
|
|
|
var period = 10m
|
|
|
|
var name = 'name'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = 'message'
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'deadman'
|
|
|
|
var threshold = 0.0
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|
|
var trigger = data
|
|
|deadman(threshold, period)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
.slack()
|
|
.victorOps()
|
|
.email()
|
|
|
|
trigger
|
|
|eval(lambda: "emitted")
|
|
.as('value')
|
|
.keep('value', messageField, durationField)
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "name",
|
|
Trigger: "deadman",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
Slack: []*chronograf.Slack{
|
|
{},
|
|
},
|
|
VictorOps: []*chronograf.VictorOps{
|
|
{},
|
|
},
|
|
Email: []*chronograf.Email{
|
|
{To: []string{}},
|
|
},
|
|
},
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Period: "10m0s",
|
|
},
|
|
Message: "message",
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "telegraf",
|
|
Measurement: "cpu",
|
|
RetentionPolicy: "autogen",
|
|
Tags: map[string][]string{
|
|
"host": []string{
|
|
"acc-0eabc309-eu-west-1-data-3",
|
|
"prod",
|
|
},
|
|
"cpu": []string{
|
|
"cpu_total",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Time: "",
|
|
Tags: []string{"host", "cluster_id"},
|
|
},
|
|
AreTagsAccepted: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Test threshold lambda",
|
|
script: `var db = '_internal'
|
|
|
|
var rp = 'monitor'
|
|
|
|
var measurement = 'cq'
|
|
|
|
var groupBy = []
|
|
|
|
var whereFilter = lambda: TRUE
|
|
|
|
var name = 'rule 1'
|
|
|
|
var idVar = name + ':{{.Group}}'
|
|
|
|
var message = ''
|
|
|
|
var idTag = 'alertID'
|
|
|
|
var levelTag = 'level'
|
|
|
|
var messageField = 'message'
|
|
|
|
var durationField = 'duration'
|
|
|
|
var outputDB = 'chronograf'
|
|
|
|
var outputRP = 'autogen'
|
|
|
|
var outputMeasurement = 'alerts'
|
|
|
|
var triggerType = 'threshold'
|
|
|
|
var crit = 90000
|
|
|
|
var data = stream
|
|
|from()
|
|
.database(db)
|
|
.retentionPolicy(rp)
|
|
.measurement(measurement)
|
|
.groupBy(groupBy)
|
|
.where(whereFilter)
|
|
|eval(lambda: "queryOk")
|
|
.as('value')
|
|
|
|
var trigger = data
|
|
|alert()
|
|
.crit(lambda: "value" > crit)
|
|
.stateChangesOnly()
|
|
.message(message)
|
|
.id(idVar)
|
|
.idTag(idTag)
|
|
.levelTag(levelTag)
|
|
.messageField(messageField)
|
|
.durationField(durationField)
|
|
|
|
trigger
|
|
|influxDBOut()
|
|
.create()
|
|
.database(outputDB)
|
|
.retentionPolicy(outputRP)
|
|
.measurement(outputMeasurement)
|
|
.tag('alertName', name)
|
|
.tag('triggerType', triggerType)
|
|
|
|
trigger
|
|
|httpOut('output')
|
|
`,
|
|
want: chronograf.AlertRule{
|
|
Name: "rule 1",
|
|
Trigger: "threshold",
|
|
TriggerValues: chronograf.TriggerValues{
|
|
Operator: "greater than",
|
|
Value: "90000",
|
|
},
|
|
Every: "",
|
|
Message: "",
|
|
Details: "",
|
|
AlertNodes: chronograf.AlertNodes{
|
|
IsStateChangesOnly: true,
|
|
},
|
|
Query: &chronograf.QueryConfig{
|
|
Database: "_internal",
|
|
RetentionPolicy: "monitor",
|
|
Measurement: "cq",
|
|
Fields: []chronograf.Field{
|
|
{
|
|
Value: "queryOk",
|
|
Type: "field",
|
|
},
|
|
},
|
|
GroupBy: chronograf.GroupBy{
|
|
Tags: []string{},
|
|
},
|
|
AreTagsAccepted: false,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := Reverse(tt.script)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("reverse error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("reverse = %s", cmp.Diff(got, tt.want))
|
|
if tt.want.Query != nil {
|
|
if got.Query == nil {
|
|
t.Errorf("reverse = got nil QueryConfig")
|
|
} else if !cmp.Equal(*got.Query, *tt.want.Query) {
|
|
t.Errorf("reverse = QueryConfig not equal %s", cmp.Diff(*got.Query, *tt.want.Query))
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|