Add full kapacitor ast to chronograf.AlertRule with tests
parent
cbc5ee5e13
commit
a449a74c72
426
kapacitor/ast.go
426
kapacitor/ast.go
|
@ -3,6 +3,7 @@ package kapacitor
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -23,6 +24,43 @@ func varString(kapaVar string, vars map[string]tick.Var) (string, bool) {
|
||||||
return strVar, ok
|
return strVar, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func varValue(kapaVar string, vars map[string]tick.Var) (string, bool) {
|
||||||
|
var ok bool
|
||||||
|
v, ok := vars[kapaVar]
|
||||||
|
if !ok {
|
||||||
|
return "", ok
|
||||||
|
}
|
||||||
|
switch val := v.Value.(type) {
|
||||||
|
case string:
|
||||||
|
return val, true
|
||||||
|
case float64:
|
||||||
|
return strconv.FormatFloat(val, 'f', -1, 32), true
|
||||||
|
case int64:
|
||||||
|
return strconv.FormatInt(val, 10), true
|
||||||
|
case bool:
|
||||||
|
return strconv.FormatBool(val), true
|
||||||
|
case time.Time:
|
||||||
|
return val.String(), true
|
||||||
|
case *regexp.Regexp:
|
||||||
|
return val.String(), true
|
||||||
|
default:
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func varDuration(kapaVar string, vars map[string]tick.Var) (string, bool) {
|
||||||
|
var ok bool
|
||||||
|
v, ok := vars[kapaVar]
|
||||||
|
if !ok {
|
||||||
|
return "", ok
|
||||||
|
}
|
||||||
|
durVar, ok := v.Value.(time.Duration)
|
||||||
|
if !ok {
|
||||||
|
return "", ok
|
||||||
|
}
|
||||||
|
return durVar.String(), true
|
||||||
|
}
|
||||||
|
|
||||||
func varStringList(kapaVar string, vars map[string]tick.Var) ([]string, bool) {
|
func varStringList(kapaVar string, vars map[string]tick.Var) ([]string, bool) {
|
||||||
v, ok := vars[kapaVar]
|
v, ok := vars[kapaVar]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -93,6 +131,9 @@ func varWhereFilter(vars map[string]tick.Var) (WhereFilter, bool) {
|
||||||
return WhereFilter{}, false
|
return WhereFilter{}, false
|
||||||
}
|
}
|
||||||
for op := range opSet {
|
for op := range opSet {
|
||||||
|
if op != "==" && op != "!=" {
|
||||||
|
return WhereFilter{}, false
|
||||||
|
}
|
||||||
filter.Operator = op
|
filter.Operator = op
|
||||||
}
|
}
|
||||||
return filter, true
|
return filter, true
|
||||||
|
@ -100,56 +141,67 @@ func varWhereFilter(vars map[string]tick.Var) (WhereFilter, bool) {
|
||||||
|
|
||||||
// CommonVars includes all the variables of a chronograf TICKScript
|
// CommonVars includes all the variables of a chronograf TICKScript
|
||||||
type CommonVars struct {
|
type CommonVars struct {
|
||||||
Vars map[string]string
|
DB string
|
||||||
GroupBy []string
|
RP string
|
||||||
Filter WhereFilter
|
Measurement string
|
||||||
Period string
|
Name string
|
||||||
Every string
|
Message string
|
||||||
Detail string
|
TriggerType string
|
||||||
|
GroupBy []string
|
||||||
|
Filter WhereFilter
|
||||||
|
Period string
|
||||||
|
Every string
|
||||||
|
Detail string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ThresholdVars represents the critical value where an alert occurs
|
||||||
type ThresholdVars struct {
|
type ThresholdVars struct {
|
||||||
Crit string
|
Crit string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RangeVars represents the critical range where an alert occurs
|
||||||
type RangeVars struct {
|
type RangeVars struct {
|
||||||
Lower string
|
Lower string
|
||||||
Upper string
|
Upper string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RelativeVars represents the critical range and time in the past an alert occurs
|
||||||
type RelativeVars struct {
|
type RelativeVars struct {
|
||||||
Shift string
|
Shift string
|
||||||
Crit string
|
Crit string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeadmanVars represents a deadman alert
|
||||||
type DeadmanVars struct{}
|
type DeadmanVars struct{}
|
||||||
|
|
||||||
func extractCommonVars(script chronograf.TICKScript) (CommonVars, error) {
|
func extractCommonVars(vars map[string]tick.Var) (CommonVars, error) {
|
||||||
scope := stateful.NewScope()
|
|
||||||
template, err := pipeline.CreateTemplatePipeline(string(script), pipeline.StreamEdge, scope, &deadman{})
|
|
||||||
if err != nil {
|
|
||||||
return CommonVars{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
vars := template.Vars()
|
|
||||||
res := CommonVars{}
|
res := CommonVars{}
|
||||||
// All these variables must exist to be a chronograf TICKScript
|
// All these variables must exist to be a chronograf TICKScript
|
||||||
commonStrs := []string{
|
// If any of these don't exist, then this isn't a tickscript we can process
|
||||||
"db",
|
var ok bool
|
||||||
"rp",
|
res.DB, ok = varString("db", vars)
|
||||||
"measurement",
|
if !ok {
|
||||||
"name",
|
return CommonVars{}, ErrNotChronoTickscript
|
||||||
"message",
|
|
||||||
"triggerType",
|
|
||||||
}
|
}
|
||||||
|
res.RP, ok = varString("rp", vars)
|
||||||
for _, v := range commonStrs {
|
if !ok {
|
||||||
str, ok := varString(v, vars)
|
return CommonVars{}, ErrNotChronoTickscript
|
||||||
// Didn't exist so, this isn't a tickscript we can process
|
}
|
||||||
if !ok {
|
res.Measurement, ok = varString("measurement", vars)
|
||||||
return CommonVars{}, ErrNotChronoTickscript
|
if !ok {
|
||||||
}
|
return CommonVars{}, ErrNotChronoTickscript
|
||||||
res.Vars[v] = str
|
}
|
||||||
|
res.Name, ok = varString("name", vars)
|
||||||
|
if !ok {
|
||||||
|
return CommonVars{}, ErrNotChronoTickscript
|
||||||
|
}
|
||||||
|
res.Message, ok = varString("message", vars)
|
||||||
|
if !ok {
|
||||||
|
return CommonVars{}, ErrNotChronoTickscript
|
||||||
|
}
|
||||||
|
res.TriggerType, ok = varString("triggerType", vars)
|
||||||
|
if !ok {
|
||||||
|
return CommonVars{}, ErrNotChronoTickscript
|
||||||
}
|
}
|
||||||
|
|
||||||
// All chronograf TICKScripts have groupBy. Possible to be empty list though.
|
// All chronograf TICKScripts have groupBy. Possible to be empty list though.
|
||||||
|
@ -172,12 +224,12 @@ func extractCommonVars(script chronograf.TICKScript) (CommonVars, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relative and Threshold alerts may have an every variables
|
// Relative and Threshold alerts may have an every variables
|
||||||
if every, ok := varString("every", vars); ok {
|
if every, ok := varDuration("every", vars); ok {
|
||||||
res.Every = every
|
res.Every = every
|
||||||
}
|
}
|
||||||
|
|
||||||
// All alert types may have a period variables
|
// All alert types may have a period variables
|
||||||
if period, ok := varString("period", vars); ok {
|
if period, ok := varDuration("period", vars); ok {
|
||||||
res.Period = period
|
res.Period = period
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
|
@ -194,27 +246,28 @@ func extractAlertVars(vars map[string]tick.Var) (interface{}, error) {
|
||||||
case Deadman:
|
case Deadman:
|
||||||
return &DeadmanVars{}, nil
|
return &DeadmanVars{}, nil
|
||||||
case Threshold:
|
case Threshold:
|
||||||
if crit, ok := varString("crit", vars); ok {
|
if crit, ok := varValue("crit", vars); ok {
|
||||||
return &ThresholdVars{
|
return &ThresholdVars{
|
||||||
Crit: crit,
|
Crit: crit,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
r := &RangeVars{}
|
r := &RangeVars{}
|
||||||
// Threshold Range alerts must have both an upper and lower bound
|
// Threshold Range alerts must have both an upper and lower bound
|
||||||
if r.Lower, ok = varString("lower", vars); !ok {
|
if r.Lower, ok = varValue("lower", vars); !ok {
|
||||||
return nil, ErrNotChronoTickscript
|
return nil, ErrNotChronoTickscript
|
||||||
}
|
}
|
||||||
if r.Upper, ok = varString("upper", vars); !ok {
|
if r.Upper, ok = varValue("upper", vars); !ok {
|
||||||
return nil, ErrNotChronoTickscript
|
return nil, ErrNotChronoTickscript
|
||||||
}
|
}
|
||||||
return r, nil
|
return r, nil
|
||||||
case Relative:
|
case Relative:
|
||||||
// Relative alerts must have a time shift and critical value
|
// Relative alerts must have a time shift and critical value
|
||||||
r := &RelativeVars{}
|
r := &RelativeVars{}
|
||||||
if r.Shift, ok = varString("shift", vars); !ok {
|
if r.Shift, ok = varDuration("shift", vars); !ok {
|
||||||
return nil, ErrNotChronoTickscript
|
return nil, ErrNotChronoTickscript
|
||||||
}
|
}
|
||||||
if r.Crit, ok = varString("crit", vars); !ok {
|
// TODO: crit could be string, float, int
|
||||||
|
if r.Crit, ok = varValue("crit", vars); !ok {
|
||||||
return nil, ErrNotChronoTickscript
|
return nil, ErrNotChronoTickscript
|
||||||
}
|
}
|
||||||
return r, nil
|
return r, nil
|
||||||
|
@ -254,6 +307,7 @@ func extractFieldFunc(script chronograf.TICKScript) FieldFunc {
|
||||||
return FieldFunc{}
|
return FieldFunc{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CritCondition represents the operators that determine when the alert should go critical
|
||||||
type CritCondition struct {
|
type CritCondition struct {
|
||||||
Operators []string
|
Operators []string
|
||||||
}
|
}
|
||||||
|
@ -317,12 +371,106 @@ func Reverse(script chronograf.TICKScript) (chronograf.AlertRule, error) {
|
||||||
rule := chronograf.AlertRule{
|
rule := chronograf.AlertRule{
|
||||||
Alerts: []string{},
|
Alerts: []string{},
|
||||||
}
|
}
|
||||||
|
t, err := alertType(script)
|
||||||
|
if err != nil {
|
||||||
|
return rule, err
|
||||||
|
}
|
||||||
|
|
||||||
scope := stateful.NewScope()
|
scope := stateful.NewScope()
|
||||||
template, err := pipeline.CreateTemplatePipeline(string(script), pipeline.StreamEdge, scope, &deadman{})
|
template, err := pipeline.CreateTemplatePipeline(string(script), pipeline.StreamEdge, scope, &deadman{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return chronograf.AlertRule{}, err
|
return chronograf.AlertRule{}, err
|
||||||
}
|
}
|
||||||
vars := template.Vars()
|
vars := template.Vars()
|
||||||
|
|
||||||
|
commonVars, err := extractCommonVars(vars)
|
||||||
|
if err != nil {
|
||||||
|
return rule, err
|
||||||
|
}
|
||||||
|
alertVars, err := extractAlertVars(vars)
|
||||||
|
if err != nil {
|
||||||
|
return rule, err
|
||||||
|
}
|
||||||
|
fieldFunc := extractFieldFunc(script)
|
||||||
|
critCond := extractCrit(script)
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case Threshold, ChangeAmount, ChangePercent:
|
||||||
|
if len(critCond.Operators) != 1 {
|
||||||
|
return rule, ErrNotChronoTickscript
|
||||||
|
}
|
||||||
|
case ThresholdRange:
|
||||||
|
if len(critCond.Operators) != 3 {
|
||||||
|
return rule, ErrNotChronoTickscript
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rule.Name = commonVars.Name
|
||||||
|
rule.Trigger = commonVars.TriggerType
|
||||||
|
rule.Details = commonVars.Detail
|
||||||
|
rule.Query.Database = commonVars.DB
|
||||||
|
rule.Query.RetentionPolicy = commonVars.RP
|
||||||
|
rule.Query.Measurement = commonVars.Measurement
|
||||||
|
rule.Query.GroupBy.Tags = commonVars.GroupBy
|
||||||
|
|
||||||
|
if commonVars.Filter.Operator == "==" {
|
||||||
|
rule.Query.AreTagsAccepted = true
|
||||||
|
}
|
||||||
|
rule.Query.Tags = commonVars.Filter.TagValues
|
||||||
|
|
||||||
|
if t == Deadman {
|
||||||
|
rule.TriggerValues.Period = commonVars.Period
|
||||||
|
} else {
|
||||||
|
rule.Query.GroupBy.Time = commonVars.Period
|
||||||
|
rule.Every = commonVars.Every
|
||||||
|
rule.Query.Fields = []chronograf.Field{
|
||||||
|
{
|
||||||
|
Field: fieldFunc.Field,
|
||||||
|
Funcs: []string{fieldFunc.Func},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case ChangeAmount, ChangePercent:
|
||||||
|
rule.TriggerValues.Change = t
|
||||||
|
rule.TriggerValues.Operator, err = chronoOperator(critCond.Operators[0])
|
||||||
|
if err != nil {
|
||||||
|
return rule, ErrNotChronoTickscript
|
||||||
|
}
|
||||||
|
v, ok := alertVars.(*RelativeVars)
|
||||||
|
if !ok {
|
||||||
|
return rule, ErrNotChronoTickscript
|
||||||
|
}
|
||||||
|
rule.TriggerValues.Value = v.Crit
|
||||||
|
rule.TriggerValues.Shift = v.Shift
|
||||||
|
case Threshold:
|
||||||
|
rule.TriggerValues.Operator, err = chronoOperator(critCond.Operators[0])
|
||||||
|
if err != nil {
|
||||||
|
return rule, ErrNotChronoTickscript
|
||||||
|
}
|
||||||
|
v, ok := alertVars.(*ThresholdVars)
|
||||||
|
if !ok {
|
||||||
|
return rule, ErrNotChronoTickscript
|
||||||
|
}
|
||||||
|
rule.TriggerValues.Value = v.Crit
|
||||||
|
case ThresholdRange:
|
||||||
|
rule.TriggerValues.Operator, err = chronoRangeOperators(critCond.Operators)
|
||||||
|
v, ok := alertVars.(*RangeVars)
|
||||||
|
if !ok {
|
||||||
|
return rule, ErrNotChronoTickscript
|
||||||
|
}
|
||||||
|
rule.TriggerValues.Value = v.Lower
|
||||||
|
rule.TriggerValues.RangeValue = v.Upper
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := pipeline.CreatePipeline(string(script), pipeline.StreamEdge, stateful.NewScope(), &deadman{}, vars)
|
||||||
|
if err != nil {
|
||||||
|
return chronograf.AlertRule{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
extractAlertNodes(p, &rule)
|
||||||
|
|
||||||
if err := valueStr("db", &rule.Query.Database, vars); err != nil {
|
if err := valueStr("db", &rule.Query.Database, vars); err != nil {
|
||||||
return chronograf.AlertRule{}, err
|
return chronograf.AlertRule{}, err
|
||||||
}
|
}
|
||||||
|
@ -382,56 +530,6 @@ func Reverse(script chronograf.TICKScript) (chronograf.AlertRule, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := pipeline.CreatePipeline(string(script), pipeline.StreamEdge, stateful.NewScope(), &deadman{}, vars)
|
|
||||||
if err != nil {
|
|
||||||
return chronograf.AlertRule{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Walk(func(n pipeline.Node) error {
|
|
||||||
switch t := n.(type) {
|
|
||||||
case *pipeline.AlertNode:
|
|
||||||
if t.HipChatHandlers != nil {
|
|
||||||
|
|
||||||
}
|
|
||||||
if t.OpsGenieHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "hipchat")
|
|
||||||
}
|
|
||||||
if t.PagerDutyHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "pagerduty")
|
|
||||||
}
|
|
||||||
if t.VictorOpsHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "victorops")
|
|
||||||
}
|
|
||||||
if t.EmailHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "smtp")
|
|
||||||
}
|
|
||||||
if t.PostHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "http")
|
|
||||||
}
|
|
||||||
if t.AlertaHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "alerta")
|
|
||||||
}
|
|
||||||
if t.SensuHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "sensu")
|
|
||||||
}
|
|
||||||
if t.SlackHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "slack")
|
|
||||||
}
|
|
||||||
if t.TalkHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "talk")
|
|
||||||
}
|
|
||||||
if t.TelegramHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "telegram")
|
|
||||||
}
|
|
||||||
if t.TcpHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "tcp")
|
|
||||||
}
|
|
||||||
if t.ExecHandlers != nil {
|
|
||||||
rule.Alerts = append(rule.Alerts, "exec")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return rule, err
|
return rule, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,6 +546,28 @@ func valueStr(key string, value *string, vars map[string]tick.Var) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractAlertNodes(p *pipeline.Pipeline, rule *chronograf.AlertRule) {
|
||||||
|
p.Walk(func(n pipeline.Node) error {
|
||||||
|
switch t := n.(type) {
|
||||||
|
case *pipeline.AlertNode:
|
||||||
|
extractHipchat(t, rule)
|
||||||
|
extractOpsgenie(t, rule)
|
||||||
|
extractPagerduty(t, rule)
|
||||||
|
extractVictorops(t, rule)
|
||||||
|
extractEmail(t, rule)
|
||||||
|
extractPost(t, rule)
|
||||||
|
extractAlerta(t, rule)
|
||||||
|
extractSensu(t, rule)
|
||||||
|
extractSlack(t, rule)
|
||||||
|
extractTalk(t, rule)
|
||||||
|
extractTelegram(t, rule)
|
||||||
|
extractTCP(t, rule)
|
||||||
|
extractExec(t, rule)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func extractHipchat(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
func extractHipchat(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
if node.HipChatHandlers == nil {
|
if node.HipChatHandlers == nil {
|
||||||
return
|
return
|
||||||
|
@ -455,8 +575,7 @@ func extractHipchat(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
rule.Alerts = append(rule.Alerts, "hipchat")
|
rule.Alerts = append(rule.Alerts, "hipchat")
|
||||||
h := node.HipChatHandlers[0]
|
h := node.HipChatHandlers[0]
|
||||||
alert := chronograf.KapacitorNode{
|
alert := chronograf.KapacitorNode{
|
||||||
Name: "hipchat",
|
Name: "hipchat",
|
||||||
Properties: []chronograf.KapacitorProperty{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.Room != "" {
|
if h.Room != "" {
|
||||||
|
@ -482,18 +601,17 @@ func extractOpsgenie(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
rule.Alerts = append(rule.Alerts, "opsgenie")
|
rule.Alerts = append(rule.Alerts, "opsgenie")
|
||||||
o := node.OpsGenieHandlers[0]
|
o := node.OpsGenieHandlers[0]
|
||||||
alert := chronograf.KapacitorNode{
|
alert := chronograf.KapacitorNode{
|
||||||
Name: "opsgenie",
|
Name: "opsgenie",
|
||||||
Properties: []chronograf.KapacitorProperty{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.RecipientsList != nil {
|
if len(o.RecipientsList) != 0 {
|
||||||
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
||||||
Name: "recipients",
|
Name: "recipients",
|
||||||
Args: o.RecipientsList,
|
Args: o.RecipientsList,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.TeamsList != nil {
|
if len(o.TeamsList) != 0 {
|
||||||
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
||||||
Name: "teams",
|
Name: "teams",
|
||||||
Args: o.TeamsList,
|
Args: o.TeamsList,
|
||||||
|
@ -509,8 +627,7 @@ func extractPagerduty(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
rule.Alerts = append(rule.Alerts, "pagerduty")
|
rule.Alerts = append(rule.Alerts, "pagerduty")
|
||||||
p := node.PagerDutyHandlers[0]
|
p := node.PagerDutyHandlers[0]
|
||||||
alert := chronograf.KapacitorNode{
|
alert := chronograf.KapacitorNode{
|
||||||
Name: "paperduty",
|
Name: "paperduty",
|
||||||
Properties: []chronograf.KapacitorProperty{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.ServiceKey != "" {
|
if p.ServiceKey != "" {
|
||||||
|
@ -529,8 +646,7 @@ func extractVictorops(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
rule.Alerts = append(rule.Alerts, "victorops")
|
rule.Alerts = append(rule.Alerts, "victorops")
|
||||||
v := node.VictorOpsHandlers[0]
|
v := node.VictorOpsHandlers[0]
|
||||||
alert := chronograf.KapacitorNode{
|
alert := chronograf.KapacitorNode{
|
||||||
Name: "victorops",
|
Name: "victorops",
|
||||||
Properties: []chronograf.KapacitorProperty{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.RoutingKey != "" {
|
if v.RoutingKey != "" {
|
||||||
|
@ -549,11 +665,10 @@ func extractEmail(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
rule.Alerts = append(rule.Alerts, "smtp")
|
rule.Alerts = append(rule.Alerts, "smtp")
|
||||||
e := node.EmailHandlers[0]
|
e := node.EmailHandlers[0]
|
||||||
alert := chronograf.KapacitorNode{
|
alert := chronograf.KapacitorNode{
|
||||||
Name: "smtp",
|
Name: "smtp",
|
||||||
Properties: []chronograf.KapacitorProperty{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.ToList != nil {
|
if len(e.ToList) != 0 {
|
||||||
alert.Args = e.ToList
|
alert.Args = e.ToList
|
||||||
}
|
}
|
||||||
rule.AlertNodes = append(rule.AlertNodes, alert)
|
rule.AlertNodes = append(rule.AlertNodes, alert)
|
||||||
|
@ -567,7 +682,10 @@ func extractPost(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
p := node.PostHandlers[0]
|
p := node.PostHandlers[0]
|
||||||
alert := chronograf.KapacitorNode{
|
alert := chronograf.KapacitorNode{
|
||||||
Name: "http",
|
Name: "http",
|
||||||
Args: []string{p.URL},
|
}
|
||||||
|
|
||||||
|
if p.URL != "" {
|
||||||
|
alert.Args = []string{p.URL}
|
||||||
}
|
}
|
||||||
|
|
||||||
rule.AlertNodes = append(rule.AlertNodes, alert)
|
rule.AlertNodes = append(rule.AlertNodes, alert)
|
||||||
|
@ -580,8 +698,7 @@ func extractAlerta(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
rule.Alerts = append(rule.Alerts, "alerta")
|
rule.Alerts = append(rule.Alerts, "alerta")
|
||||||
a := node.AlertaHandlers[0]
|
a := node.AlertaHandlers[0]
|
||||||
alert := chronograf.KapacitorNode{
|
alert := chronograf.KapacitorNode{
|
||||||
Name: "alerta",
|
Name: "alerta",
|
||||||
Properties: []chronograf.KapacitorProperty{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.Token != "" {
|
if a.Token != "" {
|
||||||
|
@ -662,15 +779,110 @@ func extractSlack(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
rule.Alerts = append(rule.Alerts, "slack")
|
rule.Alerts = append(rule.Alerts, "slack")
|
||||||
s := node.SlackHandlers[0]
|
s := node.SlackHandlers[0]
|
||||||
alert := chronograf.KapacitorNode{
|
alert := chronograf.KapacitorNode{
|
||||||
Name: "slack",
|
Name: "slack",
|
||||||
Properties: []chronograf.KapacitorProperty{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.Token != "" {
|
if s.Channel != "" {
|
||||||
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
||||||
Name: "token",
|
Name: "channel",
|
||||||
Args: []string{a.Token},
|
Args: []string{s.Channel},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.IconEmoji != "" {
|
||||||
|
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
||||||
|
Name: "iconEmoji",
|
||||||
|
Args: []string{s.IconEmoji},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Username != "" {
|
||||||
|
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
||||||
|
Name: "username",
|
||||||
|
Args: []string{s.Username},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
rule.AlertNodes = append(rule.AlertNodes, alert)
|
rule.AlertNodes = append(rule.AlertNodes, alert)
|
||||||
}
|
}
|
||||||
|
func extractTalk(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
|
if node.TalkHandlers == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rule.Alerts = append(rule.Alerts, "talk")
|
||||||
|
alert := chronograf.KapacitorNode{
|
||||||
|
Name: "talk",
|
||||||
|
}
|
||||||
|
|
||||||
|
rule.AlertNodes = append(rule.AlertNodes, alert)
|
||||||
|
}
|
||||||
|
func extractTelegram(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
|
if node.TelegramHandlers == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rule.Alerts = append(rule.Alerts, "telegram")
|
||||||
|
t := node.TelegramHandlers[0]
|
||||||
|
alert := chronograf.KapacitorNode{
|
||||||
|
Name: "telegram",
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.ChatId != "" {
|
||||||
|
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
||||||
|
Name: "chatId",
|
||||||
|
Args: []string{t.ChatId},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.ParseMode != "" {
|
||||||
|
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
||||||
|
Name: "parseMode",
|
||||||
|
Args: []string{t.ParseMode},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.IsDisableWebPagePreview {
|
||||||
|
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
||||||
|
Name: "disableWebPagePreview",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.IsDisableNotification {
|
||||||
|
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
|
||||||
|
Name: "disableNotification",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
rule.AlertNodes = append(rule.AlertNodes, alert)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractTCP(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
|
if node.TcpHandlers == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rule.Alerts = append(rule.Alerts, "tcp")
|
||||||
|
t := node.TcpHandlers[0]
|
||||||
|
alert := chronograf.KapacitorNode{
|
||||||
|
Name: "tcp",
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Address != "" {
|
||||||
|
alert.Args = []string{t.Address}
|
||||||
|
}
|
||||||
|
|
||||||
|
rule.AlertNodes = append(rule.AlertNodes, alert)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractExec(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
|
||||||
|
if node.ExecHandlers == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rule.Alerts = append(rule.Alerts, "exec")
|
||||||
|
exec := node.ExecHandlers[0]
|
||||||
|
alert := chronograf.KapacitorNode{
|
||||||
|
Name: "exec",
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(exec.Command) != 0 {
|
||||||
|
alert.Args = exec.Command
|
||||||
|
}
|
||||||
|
|
||||||
|
rule.AlertNodes = append(rule.AlertNodes, alert)
|
||||||
|
}
|
||||||
|
|
|
@ -58,13 +58,25 @@ func TestReverse(t *testing.T) {
|
||||||
.durationField(durationField)
|
.durationField(durationField)
|
||||||
.slack()
|
.slack()
|
||||||
.victorOps()
|
.victorOps()
|
||||||
.email()
|
.email('howdy@howdy.com')
|
||||||
`),
|
`),
|
||||||
|
|
||||||
want: chronograf.AlertRule{
|
want: chronograf.AlertRule{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Trigger: "threshold",
|
Trigger: "threshold",
|
||||||
Alerts: []string{"victorops", "slack", "email"},
|
Alerts: []string{"victorops", "smtp", "slack"},
|
||||||
|
AlertNodes: []chronograf.KapacitorNode{
|
||||||
|
{
|
||||||
|
Name: "victorops",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "smtp",
|
||||||
|
Args: []string{"howdy@howdy.com"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "slack",
|
||||||
|
},
|
||||||
|
},
|
||||||
TriggerValues: chronograf.TriggerValues{
|
TriggerValues: chronograf.TriggerValues{
|
||||||
Operator: "greater than",
|
Operator: "greater than",
|
||||||
Value: "90",
|
Value: "90",
|
||||||
|
@ -180,6 +192,52 @@ trigger
|
||||||
|
|
||||||
trigger
|
trigger
|
||||||
|httpOut('output')`,
|
|httpOut('output')`,
|
||||||
|
want: chronograf.AlertRule{
|
||||||
|
Query: chronograf.QueryConfig{
|
||||||
|
Database: "telegraf",
|
||||||
|
Measurement: "cpu",
|
||||||
|
RetentionPolicy: "autogen",
|
||||||
|
Fields: []chronograf.Field{
|
||||||
|
chronograf.Field{
|
||||||
|
Field: "usage_user",
|
||||||
|
Funcs: []string{"mean"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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",
|
||||||
|
Alerts: []string{
|
||||||
|
"victorops",
|
||||||
|
"smtp",
|
||||||
|
"slack",
|
||||||
|
},
|
||||||
|
AlertNodes: []chronograf.KapacitorNode{
|
||||||
|
chronograf.KapacitorNode{
|
||||||
|
Name: "victorops",
|
||||||
|
},
|
||||||
|
chronograf.KapacitorNode{
|
||||||
|
Name: "smtp",
|
||||||
|
},
|
||||||
|
chronograf.KapacitorNode{
|
||||||
|
Name: "slack",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "message",
|
||||||
|
Trigger: "threshold",
|
||||||
|
TriggerValues: chronograf.TriggerValues{
|
||||||
|
Operator: "greater than",
|
||||||
|
Value: "90",
|
||||||
|
},
|
||||||
|
Name: "name",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
Loading…
Reference in New Issue