Update Kapacitor alerts to set queryConfig to null if not parsable.

pull/10616/head
Chris Goller 2017-05-05 14:30:20 -05:00
parent 315ca27b67
commit 3821b1ccff
10 changed files with 83 additions and 80 deletions

View File

@ -234,7 +234,7 @@ type SourcesStore interface {
type AlertRule struct {
ID string `json:"id,omitempty"` // ID is the unique ID of the alert
TICKScript TICKScript `json:"tickscript"` // TICKScript is the raw tickscript associated with this Alert
Query QueryConfig `json:"query"` // Query is the filter of data for the alert.
Query *QueryConfig `json:"query"` // Query is the filter of data for the alert.
Every string `json:"every"` // Every how often to check for the alerting criteria
Alerts []string `json:"alerts"` // Alerts name all the services to notify (e.g. pagerduty)
AlertNodes []KapacitorNode `json:"alertNodes,omitempty"` // AlertNodes define additional arguments to alerts

View File

@ -368,6 +368,7 @@ func alertType(script chronograf.TICKScript) (string, error) {
func Reverse(script chronograf.TICKScript) (chronograf.AlertRule, error) {
rule := chronograf.AlertRule{
Alerts: []string{},
Query: &chronograf.QueryConfig{},
}
t, err := alertType(script)
if err != nil {

View File

@ -84,7 +84,7 @@ func TestReverse(t *testing.T) {
Every: "30s",
Message: "message",
Details: "details",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
RetentionPolicy: "autogen",
Measurement: "cpu",
@ -193,7 +193,7 @@ func TestReverse(t *testing.T) {
trigger
|httpOut('output')`,
want: chronograf.AlertRule{
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -332,7 +332,7 @@ func TestReverse(t *testing.T) {
Every: "10s",
Message: `Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} `,
Details: "Email template",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "influxdb",
RetentionPolicy: "autogen",
Measurement: "haproxy",
@ -447,7 +447,7 @@ func TestReverse(t *testing.T) {
Every: "10s",
Message: `Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} `,
Details: "Email template",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "influxdb",
RetentionPolicy: "autogen",
Measurement: "haproxy",
@ -564,7 +564,7 @@ func TestReverse(t *testing.T) {
Every: "30s",
Message: "message",
Details: "details",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -588,7 +588,6 @@ func TestReverse(t *testing.T) {
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
},
},
@ -690,7 +689,7 @@ func TestReverse(t *testing.T) {
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -714,7 +713,6 @@ func TestReverse(t *testing.T) {
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
},
},
@ -816,7 +814,7 @@ func TestReverse(t *testing.T) {
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -840,7 +838,6 @@ func TestReverse(t *testing.T) {
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
},
},
@ -930,7 +927,7 @@ func TestReverse(t *testing.T) {
Value: "90",
},
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -953,7 +950,6 @@ func TestReverse(t *testing.T) {
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
},
},
@ -1066,7 +1062,7 @@ trigger
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -1090,7 +1086,6 @@ trigger
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
},
},
@ -1203,7 +1198,7 @@ trigger
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -1227,7 +1222,6 @@ trigger
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
},
},
@ -1318,7 +1312,7 @@ trigger
Period: "10m0s",
},
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -1336,7 +1330,6 @@ trigger
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
},
},

View File

@ -185,6 +185,7 @@ func (c *Client) All(ctx context.Context) (map[string]chronograf.AlertRule, erro
}
} else {
rule.ID = task.ID
rule.Query = nil
rule.TICKScript = script
alerts[task.ID] = rule
}
@ -210,6 +211,7 @@ func (c *Client) Get(ctx context.Context, id string) (chronograf.AlertRule, erro
return chronograf.AlertRule{
ID: task.ID,
Name: task.ID,
Query: nil,
TICKScript: script,
}, nil
}
@ -278,8 +280,8 @@ func (c *Client) kapaClient(ctx context.Context) (*client.Client, error) {
})
}
func toTask(q chronograf.QueryConfig) client.TaskType {
if q.RawText == nil || *q.RawText == "" {
func toTask(q *chronograf.QueryConfig) client.TaskType {
if q == nil || q.RawText == nil || *q.RawText == "" {
return client.StreamTask
}
return client.BatchTask

View File

@ -45,7 +45,7 @@ func TestData(t *testing.T) {
}
alert := chronograf.AlertRule{
Trigger: "deadman",
Query: q,
Query: &q,
}
if tick, err := Data(alert); err != nil {
t.Errorf("Error creating tick %v", err)

View File

@ -28,7 +28,7 @@ func TestInfluxOut(t *testing.T) {
got, err := InfluxOut(chronograf.AlertRule{
Name: "name",
Trigger: "deadman",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Fields: []chronograf.Field{
{
Field: "usage_user",

View File

@ -20,7 +20,7 @@ func TestGenerate(t *testing.T) {
Value: "90",
},
Every: "30s",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -65,7 +65,7 @@ func TestThreshold(t *testing.T) {
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -209,7 +209,7 @@ func TestThresholdStringCrit(t *testing.T) {
Every: "10s",
Message: `Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} `,
Details: "Email template",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "influxdb",
RetentionPolicy: "autogen",
Measurement: "haproxy",
@ -347,7 +347,7 @@ func TestThresholdStringCritGreater(t *testing.T) {
Every: "10s",
Message: `Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} `,
Details: "Email template",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "influxdb",
RetentionPolicy: "autogen",
Measurement: "haproxy",
@ -483,7 +483,7 @@ func TestThresholdDetail(t *testing.T) {
Every: "30s",
Message: "message",
Details: "details",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -630,7 +630,7 @@ func TestThresholdInsideRange(t *testing.T) {
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -776,7 +776,7 @@ func TestThresholdOutsideRange(t *testing.T) {
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -921,7 +921,7 @@ func TestThresholdNoAggregate(t *testing.T) {
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -1058,7 +1058,7 @@ func TestRelative(t *testing.T) {
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -1215,7 +1215,7 @@ func TestRelativeChange(t *testing.T) {
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
@ -1369,7 +1369,7 @@ func TestDeadman(t *testing.T) {
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",

View File

@ -140,40 +140,45 @@ func window(rule chronograf.AlertRule) string {
return ""
}
func groupBy(q chronograf.QueryConfig) string {
func groupBy(q *chronograf.QueryConfig) string {
groups := []string{}
for _, tag := range q.GroupBy.Tags {
groups = append(groups, fmt.Sprintf("'%s'", tag))
if q != nil {
for _, tag := range q.GroupBy.Tags {
groups = append(groups, fmt.Sprintf("'%s'", tag))
}
}
return "[" + strings.Join(groups, ",") + "]"
}
func field(q chronograf.QueryConfig) (string, error) {
for _, field := range q.Fields {
return field.Field, nil
func field(q *chronograf.QueryConfig) (string, error) {
if q != nil {
for _, field := range q.Fields {
return field.Field, nil
}
}
return "", fmt.Errorf("No fields set in query")
}
func whereFilter(q chronograf.QueryConfig) string {
operator := "=="
if !q.AreTagsAccepted {
operator = "!="
}
outer := []string{}
for tag, values := range q.Tags {
inner := []string{}
for _, value := range values {
inner = append(inner, fmt.Sprintf(`"%s" %s '%s'`, tag, operator, value))
func whereFilter(q *chronograf.QueryConfig) string {
if q != nil {
operator := "=="
if !q.AreTagsAccepted {
operator = "!="
}
outer = append(outer, "("+strings.Join(inner, " OR ")+")")
}
if len(outer) > 0 {
sort.Strings(outer)
return "lambda: " + strings.Join(outer, " AND ")
}
outer := []string{}
for tag, values := range q.Tags {
inner := []string{}
for _, value := range values {
inner = append(inner, fmt.Sprintf(`"%s" %s '%s'`, tag, operator, value))
}
outer = append(outer, "("+strings.Join(inner, " OR ")+")")
}
if len(outer) > 0 {
sort.Strings(outer)
return "lambda: " + strings.Join(outer, " AND ")
}
}
return "lambda: TRUE"
}

View File

@ -16,7 +16,7 @@ func TestVarsCritStringEqual(t *testing.T) {
Value: "DOWN",
},
Every: "30s",
Query: chronograf.QueryConfig{
Query: &chronograf.QueryConfig{
Database: "telegraf",
Measurement: "haproxy",
RetentionPolicy: "autogen",

View File

@ -357,19 +357,15 @@ func newAlertResponse(rule chronograf.AlertRule, tickScript chronograf.TICKScrip
Status: status,
}
if res.Query.ID == "" {
res.Query.ID = res.ID
if res.Alerts == nil {
res.Alerts = make([]string, 0)
}
if res.AlertRule.Alerts == nil {
res.AlertRule.Alerts = make([]string, 0)
if res.AlertNodes == nil {
res.AlertNodes = make([]chronograf.KapacitorNode, 0)
}
if res.AlertRule.AlertNodes == nil {
res.AlertRule.AlertNodes = make([]chronograf.KapacitorNode, 0)
}
for _, n := range res.AlertRule.AlertNodes {
for _, n := range res.AlertNodes {
if n.Args == nil {
n.Args = make([]string, 0)
}
@ -383,22 +379,28 @@ func newAlertResponse(rule chronograf.AlertRule, tickScript chronograf.TICKScrip
}
}
if res.AlertRule.Query.Fields == nil {
res.AlertRule.Query.Fields = make([]chronograf.Field, 0)
}
for _, f := range res.AlertRule.Query.Fields {
if f.Funcs == nil {
f.Funcs = make([]string, 0)
if res.Query != nil {
if res.Query.ID == "" {
res.Query.ID = res.ID
}
}
if res.AlertRule.Query.GroupBy.Tags == nil {
res.AlertRule.Query.GroupBy.Tags = make([]string, 0)
}
if res.Query.Fields == nil {
res.Query.Fields = make([]chronograf.Field, 0)
}
if res.AlertRule.Query.Tags == nil {
res.AlertRule.Query.Tags = make(map[string][]string)
for _, f := range res.Query.Fields {
if f.Funcs == nil {
f.Funcs = make([]string, 0)
}
}
if res.Query.GroupBy.Tags == nil {
res.Query.GroupBy.Tags = make([]string, 0)
}
if res.Query.Tags == nil {
res.Query.Tags = make(map[string][]string)
}
}
return res
}