Update deserialization of tickscript to AlertHandler

Signed-off-by: Deniz Kusefoglu <denizk@gmail.com>
pull/10616/head
Chris Goller 2017-11-30 16:24:02 -06:00
parent d28a33adc8
commit be741a8fe3
5 changed files with 140 additions and 510 deletions

View File

@ -151,8 +151,6 @@ func Test_addAlertNodes(t *testing.T) {
name: "foo",
handlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Message: "mymessage",
Details: "mydetails",
Email: []*chronograf.Email{
{
To: []string{

View File

@ -1,6 +1,7 @@
package kapacitor
import (
"encoding/json"
"regexp"
"strconv"
"strings"
@ -367,8 +368,7 @@ func alertType(script chronograf.TICKScript) (string, error) {
// Reverse converts tickscript to an AlertRule
func Reverse(script chronograf.TICKScript) (chronograf.AlertRule, error) {
rule := chronograf.AlertRule{
Alerts: []string{},
Query: &chronograf.QueryConfig{},
Query: &chronograf.QueryConfig{},
}
t, err := alertType(script)
if err != nil {
@ -483,432 +483,20 @@ func Reverse(script chronograf.TICKScript) (chronograf.AlertRule, error) {
return chronograf.AlertRule{}, err
}
extractAlertNodes(p, &rule)
err = extractAlertNodes(p, &rule)
return rule, err
}
func extractAlertNodes(p *pipeline.Pipeline, rule *chronograf.AlertRule) {
p.Walk(func(n pipeline.Node) error {
switch t := n.(type) {
func extractAlertNodes(p *pipeline.Pipeline, rule *chronograf.AlertRule) error {
return p.Walk(func(n pipeline.Node) error {
switch node := 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)
extractPushover(t, rule)
extractTCP(t, rule)
extractLog(t, rule)
extractExec(t, rule)
octets, err := json.MarshalIndent(node, "", " ")
if err != nil {
return err
}
return json.Unmarshal(octets, &rule.AlertHandlers)
}
return nil
})
}
func extractHipchat(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.HipChatHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "hipchat")
h := node.HipChatHandlers[0]
alert := chronograf.KapacitorNode{
Name: "hipchat",
}
if h.Room != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "room",
Args: []string{h.Room},
})
}
if h.Token != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "token",
Args: []string{h.Token},
})
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractOpsgenie(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.OpsGenieHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "opsgenie")
o := node.OpsGenieHandlers[0]
alert := chronograf.KapacitorNode{
Name: "opsgenie",
}
if len(o.RecipientsList) != 0 {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "recipients",
Args: o.RecipientsList,
})
}
if len(o.TeamsList) != 0 {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "teams",
Args: o.TeamsList,
})
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractPagerduty(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.PagerDutyHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "pagerduty")
p := node.PagerDutyHandlers[0]
alert := chronograf.KapacitorNode{
Name: "pagerduty",
}
if p.ServiceKey != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "serviceKey",
Args: []string{p.ServiceKey},
})
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractVictorops(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.VictorOpsHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "victorops")
v := node.VictorOpsHandlers[0]
alert := chronograf.KapacitorNode{
Name: "victorops",
}
if v.RoutingKey != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "routingKey",
Args: []string{v.RoutingKey},
})
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractEmail(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.EmailHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "smtp")
e := node.EmailHandlers[0]
alert := chronograf.KapacitorNode{
Name: "smtp",
}
if len(e.ToList) != 0 {
alert.Args = e.ToList
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractPost(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.HTTPPostHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "http")
p := node.HTTPPostHandlers[0]
alert := chronograf.KapacitorNode{
Name: "http",
}
if p.URL != "" {
alert.Args = []string{p.URL}
}
if p.Endpoint != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "endpoint",
Args: []string{p.Endpoint},
})
}
if len(p.Headers) > 0 {
for k, v := range p.Headers {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "header",
Args: []string{k, v},
})
}
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractAlerta(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.AlertaHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "alerta")
a := node.AlertaHandlers[0]
alert := chronograf.KapacitorNode{
Name: "alerta",
}
if a.Token != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "token",
Args: []string{a.Token},
})
}
if a.Resource != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "resource",
Args: []string{a.Resource},
})
}
if a.Event != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "event",
Args: []string{a.Event},
})
}
if a.Environment != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "environment",
Args: []string{a.Environment},
})
}
if a.Group != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "group",
Args: []string{a.Group},
})
}
if a.Value != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "value",
Args: []string{a.Value},
})
}
if a.Origin != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "origin",
Args: []string{a.Origin},
})
}
if a.Service != nil {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "services",
Args: a.Service,
})
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractSensu(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.SensuHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "sensu")
alert := chronograf.KapacitorNode{
Name: "sensu",
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractSlack(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.SlackHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "slack")
s := node.SlackHandlers[0]
alert := chronograf.KapacitorNode{
Name: "slack",
}
if s.Channel != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "channel",
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)
}
func extractTalk(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.TalkHandlers) == 0 {
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 len(node.TelegramHandlers) == 0 {
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 len(node.TcpHandlers) == 0 {
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 extractLog(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.LogHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "log")
log := node.LogHandlers[0]
alert := chronograf.KapacitorNode{
Name: "log",
}
if log.FilePath != "" {
alert.Args = []string{log.FilePath}
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractExec(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.ExecHandlers) == 0 {
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)
}
func extractPushover(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.PushoverHandlers) == 0 {
return
}
rule.Alerts = append(rule.Alerts, "pushover")
a := node.PushoverHandlers[0]
alert := chronograf.KapacitorNode{
Name: "pushover",
}
if a.Device != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "device",
Args: []string{a.Device},
})
}
if a.Title != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "title",
Args: []string{a.Title},
})
}
if a.URL != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "URL",
Args: []string{a.URL},
})
}
if a.URLTitle != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "URLTitle",
Args: []string{a.URLTitle},
})
}
if a.Sound != "" {
alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{
Name: "sound",
Args: []string{a.Sound},
})
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}

View File

@ -59,7 +59,7 @@ func TestReverse(t *testing.T) {
.durationField(durationField)
.slack()
.victorOps()
.email('howdy@howdy.com')
.email('howdy@howdy.com', 'doody@doody.com')
.log('/tmp/alerts.log')
.post('http://backin.tm')
.endpoint('myendpoint')
@ -69,35 +69,29 @@ func TestReverse(t *testing.T) {
want: chronograf.AlertRule{
Name: "name",
Trigger: "threshold",
Alerts: []string{"victorops", "smtp", "http", "slack", "log"},
AlertNodes: []chronograf.KapacitorNode{
{
Name: "victorops",
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Slack: []*chronograf.Slack{
{},
},
{
Name: "smtp",
Args: []string{"howdy@howdy.com"},
VictorOps: []*chronograf.VictorOps{
{},
},
{
Name: "http",
Args: []string{"http://backin.tm"},
Properties: []chronograf.KapacitorProperty{
{
Name: "endpoint",
Args: []string{"myendpoint"},
},
{
Name: "header",
Args: []string{"key", "value"},
},
Email: []*chronograf.Email{
{
To: []string{"howdy@howdy.com", "doody@doody.com"},
},
},
{
Name: "slack",
Log: []*chronograf.Log{
{
FilePath: "/tmp/alerts.log",
},
},
{
Name: "log",
Args: []string{"/tmp/alerts.log"},
Posts: []*chronograf.Post{
{
URL: "http://backin.tm",
Headers: map[string]string{"key": "value"},
},
},
},
TriggerValues: chronograf.TriggerValues{
@ -247,20 +241,19 @@ func TestReverse(t *testing.T) {
AreTagsAccepted: true,
},
Every: "30s",
Alerts: []string{
"victorops",
"smtp",
"slack",
},
AlertNodes: []chronograf.KapacitorNode{
chronograf.KapacitorNode{
Name: "victorops",
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Slack: []*chronograf.Slack{
{},
},
chronograf.KapacitorNode{
Name: "smtp",
VictorOps: []*chronograf.VictorOps{
{},
},
chronograf.KapacitorNode{
Name: "slack",
Email: []*chronograf.Email{
{
To: []string{},
},
},
},
Message: "message",
@ -354,10 +347,14 @@ func TestReverse(t *testing.T) {
|httpOut('output')
`,
want: chronograf.AlertRule{
Name: "haproxy",
Trigger: "threshold",
Alerts: []string{"smtp"},
AlertNodes: []chronograf.KapacitorNode{chronograf.KapacitorNode{Name: "smtp"}},
Name: "haproxy",
Trigger: "threshold",
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Email: []*chronograf.Email{
{To: []string{}},
},
},
TriggerValues: chronograf.TriggerValues{
Operator: "equal to",
Value: "DOWN",
@ -473,10 +470,10 @@ func TestReverse(t *testing.T) {
want: chronograf.AlertRule{
Name: "haproxy",
Trigger: "threshold",
Alerts: []string{"smtp"},
AlertNodes: []chronograf.KapacitorNode{
chronograf.KapacitorNode{
Name: "smtp",
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Email: []*chronograf.Email{
{To: []string{}},
},
},
TriggerValues: chronograf.TriggerValues{
@ -596,11 +593,17 @@ func TestReverse(t *testing.T) {
want: chronograf.AlertRule{
Name: "name",
Trigger: "threshold",
Alerts: []string{"victorops", "smtp", "slack"},
AlertNodes: []chronograf.KapacitorNode{
{Name: "victorops"},
{Name: "smtp"},
{Name: "slack"},
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Slack: []*chronograf.Slack{
{},
},
VictorOps: []*chronograf.VictorOps{
{},
},
Email: []*chronograf.Email{
{To: []string{}},
},
},
TriggerValues: chronograf.TriggerValues{
Operator: "greater than",
@ -727,11 +730,17 @@ func TestReverse(t *testing.T) {
want: chronograf.AlertRule{
Name: "name",
Trigger: "threshold",
Alerts: []string{"victorops", "smtp", "slack"},
AlertNodes: []chronograf.KapacitorNode{
{Name: "victorops"},
{Name: "smtp"},
{Name: "slack"},
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Slack: []*chronograf.Slack{
{},
},
VictorOps: []*chronograf.VictorOps{
{},
},
Email: []*chronograf.Email{
{To: []string{}},
},
},
TriggerValues: chronograf.TriggerValues{
Operator: "inside range",
@ -858,11 +867,17 @@ func TestReverse(t *testing.T) {
want: chronograf.AlertRule{
Name: "name",
Trigger: "threshold",
Alerts: []string{"victorops", "smtp", "slack"},
AlertNodes: []chronograf.KapacitorNode{
{Name: "victorops"},
{Name: "smtp"},
{Name: "slack"},
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Slack: []*chronograf.Slack{
{},
},
VictorOps: []*chronograf.VictorOps{
{},
},
Email: []*chronograf.Email{
{To: []string{}},
},
},
TriggerValues: chronograf.TriggerValues{
Operator: "outside range",
@ -979,11 +994,17 @@ func TestReverse(t *testing.T) {
want: chronograf.AlertRule{
Name: "name",
Trigger: "threshold",
Alerts: []string{"victorops", "smtp", "slack"},
AlertNodes: []chronograf.KapacitorNode{
{Name: "victorops"},
{Name: "smtp"},
{Name: "slack"},
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Slack: []*chronograf.Slack{
{},
},
VictorOps: []*chronograf.VictorOps{
{},
},
Email: []*chronograf.Email{
{To: []string{}},
},
},
TriggerValues: chronograf.TriggerValues{
Operator: "greater than",
@ -1111,11 +1132,17 @@ trigger
want: chronograf.AlertRule{
Name: "name",
Trigger: "relative",
Alerts: []string{"victorops", "smtp", "slack"},
AlertNodes: []chronograf.KapacitorNode{
{Name: "victorops"},
{Name: "smtp"},
{Name: "slack"},
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Slack: []*chronograf.Slack{
{},
},
VictorOps: []*chronograf.VictorOps{
{},
},
Email: []*chronograf.Email{
{To: []string{}},
},
},
TriggerValues: chronograf.TriggerValues{
Change: "% change",
@ -1253,11 +1280,17 @@ trigger
want: chronograf.AlertRule{
Name: "name",
Trigger: "relative",
Alerts: []string{"victorops", "smtp", "slack"},
AlertNodes: []chronograf.KapacitorNode{
{Name: "victorops"},
{Name: "smtp"},
{Name: "slack"},
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Slack: []*chronograf.Slack{
{},
},
VictorOps: []*chronograf.VictorOps{
{},
},
Email: []*chronograf.Email{
{To: []string{}},
},
},
TriggerValues: chronograf.TriggerValues{
Change: "change",
@ -1377,11 +1410,17 @@ trigger
want: chronograf.AlertRule{
Name: "name",
Trigger: "deadman",
Alerts: []string{"victorops", "smtp", "slack"},
AlertNodes: []chronograf.KapacitorNode{
{Name: "victorops"},
{Name: "smtp"},
{Name: "slack"},
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
Slack: []*chronograf.Slack{
{},
},
VictorOps: []*chronograf.VictorOps{
{},
},
Email: []*chronograf.Email{
{To: []string{}},
},
},
TriggerValues: chronograf.TriggerValues{
Period: "10m0s",
@ -1480,7 +1519,6 @@ trigger
want: chronograf.AlertRule{
Name: "rule 1",
Trigger: "threshold",
Alerts: []string{},
TriggerValues: chronograf.TriggerValues{
Operator: "greater than",
Value: "90000",
@ -1488,6 +1526,9 @@ trigger
Every: "",
Message: "",
Details: "",
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
},
Query: &chronograf.QueryConfig{
Database: "_internal",
RetentionPolicy: "monitor",
@ -1514,7 +1555,7 @@ trigger
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Reverse() = \n%#v\n, want \n%#v\n", 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")

View File

@ -312,11 +312,13 @@ trigger
|httpOut('output')
`,
Trigger: "threshold",
Alerts: []string{},
TriggerValues: chronograf.TriggerValues{
Operator: "greater than",
Value: "90000",
},
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
},
Query: &chronograf.QueryConfig{
Database: "_internal",
RetentionPolicy: "monitor",
@ -635,11 +637,13 @@ trigger
|httpOut('output')
`,
Trigger: "threshold",
Alerts: []string{},
TriggerValues: chronograf.TriggerValues{
Operator: "greater than",
Value: "90000",
},
AlertHandlers: chronograf.AlertHandlers{
IsStateChangesOnly: true,
},
Query: &chronograf.QueryConfig{
Database: "_internal",
RetentionPolicy: "monitor",

View File

@ -368,7 +368,6 @@ func TestThresholdStringCritGreater(t *testing.T) {
alert := chronograf.AlertRule{
Name: "haproxy",
Trigger: "threshold",
Alerts: []string{"email"},
AlertHandlers: chronograf.AlertHandlers{
Email: []*chronograf.Email{{}},
},