diff --git a/kapacitor/ast.go b/kapacitor/ast.go index e2d695f2d8..9a115a1084 100644 --- a/kapacitor/ast.go +++ b/kapacitor/ast.go @@ -1,7 +1,6 @@ package kapacitor import ( - "fmt" "regexp" "strconv" "strings" @@ -355,7 +354,7 @@ func alertType(script chronograf.TICKScript) (string, error) { } else if strings.Contains(t, `var triggerType = 'relative'`) { if strings.Contains(t, `eval(lambda: float("current.value" - "past.value"))`) { return ChangeAmount, nil - } else if strings.Contains(t, `|eval(lambda: abs(float("current.value" - "past.value"))/float("past.value") * 100.0)`) { + } else if strings.Contains(t, `|eval(lambda: abs(float("current.value" - "past.value")) / float("past.value") * 100.0)`) { return ChangePercent, nil } return "", ErrNotChronoTickscript @@ -477,19 +476,6 @@ func Reverse(script chronograf.TICKScript) (chronograf.AlertRule, error) { return rule, err } -func valueStr(key string, value *string, vars map[string]tick.Var) error { - v, ok := vars[key] - if !ok { - return fmt.Errorf("No %s", key) - } - val, ok := v.Value.(string) - if !ok { - return fmt.Errorf("No %s", key) - } - value = &val - return nil -} - func extractAlertNodes(p *pipeline.Pipeline, rule *chronograf.AlertRule) { p.Walk(func(n pipeline.Node) error { switch t := n.(type) { diff --git a/kapacitor/ast_test.go b/kapacitor/ast_test.go index 5e75c83f52..3fd4985e93 100644 --- a/kapacitor/ast_test.go +++ b/kapacitor/ast_test.go @@ -17,49 +17,49 @@ func TestReverse(t *testing.T) { { 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 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') - `), + 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') + `), want: chronograf.AlertRule{ Name: "name", @@ -117,81 +117,81 @@ func TestReverse(t *testing.T) { name: "Test Threshold", script: `var db = 'telegraf' -var rp = 'autogen' + var rp = 'autogen' -var measurement = 'cpu' + var measurement = 'cpu' -var groupBy = ['host', 'cluster_id'] + var groupBy = ['host', 'cluster_id'] -var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') + var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') -var period = 10m + var period = 10m -var every = 30s + var every = 30s -var name = 'name' + var name = 'name' -var idVar = name + ':{{.Group}}' + var idVar = name + ':{{.Group}}' -var message = 'message' + var message = 'message' -var idTag = 'alertID' + var idTag = 'alertID' -var levelTag = 'level' + var levelTag = 'level' -var messageField = 'message' + var messageField = 'message' -var durationField = 'duration' + var durationField = 'duration' -var outputDB = 'chronograf' + var outputDB = 'chronograf' -var outputRP = 'autogen' + var outputRP = 'autogen' -var outputMeasurement = 'alerts' + var outputMeasurement = 'alerts' -var triggerType = 'threshold' + var triggerType = 'threshold' -var crit = 90 + 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 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() + 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 + |influxDBOut() + .create() + .database(outputDB) + .retentionPolicy(outputRP) + .measurement(outputMeasurement) + .tag('alertName', name) + .tag('triggerType', triggerType) -trigger - |httpOut('output')`, + trigger + |httpOut('output')`, want: chronograf.AlertRule{ Query: chronograf.QueryConfig{ Database: "telegraf", @@ -240,86 +240,86 @@ trigger }, }, { - name: "Test valid template alert", + name: "Test haproxy string comparison", script: `var db = 'influxdb' -var rp = 'autogen' + var rp = 'autogen' -var measurement = 'haproxy' + var measurement = 'haproxy' -var groupBy = ['pxname'] + var groupBy = ['pxname'] -var whereFilter = lambda: TRUE + var whereFilter = lambda: TRUE -var period = 10s + var period = 10s -var every = 10s + var every = 10s -var name = 'haproxy' + var name = 'haproxy' -var idVar = name + ':{{.Group}}' + var idVar = name + ':{{.Group}}' -var message = 'Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} ' + var message = 'Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} ' -var idTag = 'alertID' + var idTag = 'alertID' -var levelTag = 'level' + var levelTag = 'level' -var messageField = 'message' + var messageField = 'message' -var durationField = 'duration' + var durationField = 'duration' -var outputDB = 'chronograf' + var outputDB = 'chronograf' -var outputRP = 'autogen' + var outputRP = 'autogen' -var outputMeasurement = 'alerts' + var outputMeasurement = 'alerts' -var triggerType = 'threshold' + var triggerType = 'threshold' -var details = 'Email template' + var details = 'Email template' -var crit = 'DOWN' + 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 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() + 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 + |influxDBOut() + .create() + .database(outputDB) + .retentionPolicy(outputRP) + .measurement(outputMeasurement) + .tag('alertName', name) + .tag('triggerType', triggerType) -trigger - |httpOut('output') -`, + trigger + |httpOut('output') + `, want: chronograf.AlertRule{ Name: "haproxy", Trigger: "threshold", @@ -351,86 +351,86 @@ trigger }, }, { - name: "Test valid template alert", + name: "Test haproxy", script: `var db = 'influxdb' -var rp = 'autogen' + var rp = 'autogen' -var measurement = 'haproxy' + var measurement = 'haproxy' -var groupBy = ['pxname'] + var groupBy = ['pxname'] -var whereFilter = lambda: TRUE + var whereFilter = lambda: TRUE -var period = 10s + var period = 10s -var every = 10s + var every = 10s -var name = 'haproxy' + var name = 'haproxy' -var idVar = name + ':{{.Group}}' + var idVar = name + ':{{.Group}}' -var message = 'Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} ' + var message = 'Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} ' -var idTag = 'alertID' + var idTag = 'alertID' -var levelTag = 'level' + var levelTag = 'level' -var messageField = 'message' + var messageField = 'message' -var durationField = 'duration' + var durationField = 'duration' -var outputDB = 'chronograf' + var outputDB = 'chronograf' -var outputRP = 'autogen' + var outputRP = 'autogen' -var outputMeasurement = 'alerts' + var outputMeasurement = 'alerts' -var triggerType = 'threshold' + var triggerType = 'threshold' -var details = 'Email template' + var details = 'Email template' -var crit = 'DOWN' + 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 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() + 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 + |influxDBOut() + .create() + .database(outputDB) + .retentionPolicy(outputRP) + .measurement(outputMeasurement) + .tag('alertName', name) + .tag('triggerType', triggerType) -trigger - |httpOut('output') -`, + trigger + |httpOut('output') + `, want: chronograf.AlertRule{ Name: "haproxy", Trigger: "threshold", @@ -469,85 +469,85 @@ trigger name: "Test valid template alert with detail", script: `var db = 'telegraf' -var rp = 'autogen' + var rp = 'autogen' -var measurement = 'cpu' + var measurement = 'cpu' -var groupBy = ['host', 'cluster_id'] + var groupBy = ['host', 'cluster_id'] -var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') + var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') -var period = 10m + var period = 10m -var every = 30s + var every = 30s -var name = 'name' + var name = 'name' -var idVar = name + ':{{.Group}}' + var idVar = name + ':{{.Group}}' -var message = 'message' + var message = 'message' -var idTag = 'alertID' + var idTag = 'alertID' -var levelTag = 'level' + var levelTag = 'level' -var messageField = 'message' + var messageField = 'message' -var durationField = 'duration' + var durationField = 'duration' -var outputDB = 'chronograf' + var outputDB = 'chronograf' -var outputRP = 'autogen' + var outputRP = 'autogen' -var outputMeasurement = 'alerts' + var outputMeasurement = 'alerts' -var triggerType = 'threshold' + var triggerType = 'threshold' -var details = 'details' + var details = 'details' -var crit = 90 + 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 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() + 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 + |influxDBOut() + .create() + .database(outputDB) + .retentionPolicy(outputRP) + .measurement(outputMeasurement) + .tag('alertName', name) + .tag('triggerType', triggerType) -trigger - |httpOut('output') -`, + trigger + |httpOut('output') + `, want: chronograf.AlertRule{ Name: "name", Trigger: "threshold", @@ -596,84 +596,84 @@ trigger name: "Test valid threshold inside range", script: `var db = 'telegraf' -var rp = 'autogen' + var rp = 'autogen' -var measurement = 'cpu' + var measurement = 'cpu' -var groupBy = ['host', 'cluster_id'] + var groupBy = ['host', 'cluster_id'] -var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') + var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') -var period = 10m + var period = 10m -var every = 30s + var every = 30s -var name = 'name' + var name = 'name' -var idVar = name + ':{{.Group}}' + var idVar = name + ':{{.Group}}' -var message = 'message' + var message = 'message' -var idTag = 'alertID' + var idTag = 'alertID' -var levelTag = 'level' + var levelTag = 'level' -var messageField = 'message' + var messageField = 'message' -var durationField = 'duration' + var durationField = 'duration' -var outputDB = 'chronograf' + var outputDB = 'chronograf' -var outputRP = 'autogen' + var outputRP = 'autogen' -var outputMeasurement = 'alerts' + var outputMeasurement = 'alerts' -var triggerType = 'threshold' + var triggerType = 'threshold' -var lower = 90 + var lower = 90 -var upper = 100 + 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 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() + 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 + |influxDBOut() + .create() + .database(outputDB) + .retentionPolicy(outputRP) + .measurement(outputMeasurement) + .tag('alertName', name) + .tag('triggerType', triggerType) -trigger - |httpOut('output') -`, + trigger + |httpOut('output') + `, want: chronograf.AlertRule{ Name: "name", Trigger: "threshold", @@ -722,84 +722,84 @@ trigger name: "Test valid threshold outside range", script: `var db = 'telegraf' -var rp = 'autogen' + var rp = 'autogen' -var measurement = 'cpu' + var measurement = 'cpu' -var groupBy = ['host', 'cluster_id'] + var groupBy = ['host', 'cluster_id'] -var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') + var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') -var period = 10m + var period = 10m -var every = 30s + var every = 30s -var name = 'name' + var name = 'name' -var idVar = name + ':{{.Group}}' + var idVar = name + ':{{.Group}}' -var message = 'message' + var message = 'message' -var idTag = 'alertID' + var idTag = 'alertID' -var levelTag = 'level' + var levelTag = 'level' -var messageField = 'message' + var messageField = 'message' -var durationField = 'duration' + var durationField = 'duration' -var outputDB = 'chronograf' + var outputDB = 'chronograf' -var outputRP = 'autogen' + var outputRP = 'autogen' -var outputMeasurement = 'alerts' + var outputMeasurement = 'alerts' -var triggerType = 'threshold' + var triggerType = 'threshold' -var lower = 90 + var lower = 90 -var upper = 100 + 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 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() + 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 + |influxDBOut() + .create() + .database(outputDB) + .retentionPolicy(outputRP) + .measurement(outputMeasurement) + .tag('alertName', name) + .tag('triggerType', triggerType) -trigger - |httpOut('output') -`, + trigger + |httpOut('output') + `, want: chronograf.AlertRule{ Name: "name", Trigger: "threshold", @@ -848,74 +848,74 @@ trigger name: "Test threshold no aggregate", script: `var db = 'telegraf' -var rp = 'autogen' + var rp = 'autogen' -var measurement = 'cpu' + var measurement = 'cpu' -var groupBy = ['host', 'cluster_id'] + var groupBy = ['host', 'cluster_id'] -var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') + var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod') -var name = 'name' + var name = 'name' -var idVar = name + ':{{.Group}}' + var idVar = name + ':{{.Group}}' -var message = 'message' + var message = 'message' -var idTag = 'alertID' + var idTag = 'alertID' -var levelTag = 'level' + var levelTag = 'level' -var messageField = 'message' + var messageField = 'message' -var durationField = 'duration' + var durationField = 'duration' -var outputDB = 'chronograf' + var outputDB = 'chronograf' -var outputRP = 'autogen' + var outputRP = 'autogen' -var outputMeasurement = 'alerts' + var outputMeasurement = 'alerts' -var triggerType = 'threshold' + var triggerType = 'threshold' -var crit = 90 + var crit = 90 -var data = stream - |from() - .database(db) - .retentionPolicy(rp) - .measurement(measurement) - .groupBy(groupBy) - .where(whereFilter) - |eval(lambda: "usage_user") - .as('value') + 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() + 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 + |influxDBOut() + .create() + .database(outputDB) + .retentionPolicy(outputRP) + .measurement(outputMeasurement) + .tag('alertName', name) + .tag('triggerType', triggerType) -trigger - |httpOut('output') -`, + trigger + |httpOut('output') + `, want: chronograf.AlertRule{ Name: "name", Trigger: "threshold", @@ -957,6 +957,389 @@ trigger }, }, }, + { + 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", + Alerts: []string{"victorops", "smtp", "slack"}, + AlertNodes: []chronograf.KapacitorNode{ + {Name: "victorops"}, + {Name: "smtp"}, + {Name: "slack"}, + }, + 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{ + { + Field: "usage_user", + Funcs: []string{"mean"}, + }, + }, + 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, + RawText: "", + }, + }, + }, + { + 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", + Alerts: []string{"victorops", "smtp", "slack"}, + AlertNodes: []chronograf.KapacitorNode{ + {Name: "victorops"}, + {Name: "smtp"}, + {Name: "slack"}, + }, + 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{ + { + Field: "usage_user", + Funcs: []string{"mean"}, + }, + }, + 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, + RawText: "", + }, + }, + }, + { + 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", + Alerts: []string{"victorops", "smtp", "slack"}, + AlertNodes: []chronograf.KapacitorNode{ + {Name: "victorops"}, + {Name: "smtp"}, + {Name: "slack"}, + }, + 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, + RawText: "", + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {