Merge pull request #1762 from influxdata/feature/kapa_alert_props-1755

Restore and add all supported Kapacitor alert services; fix Kapa alert state bug
pull/1770/head
Jared Scheib 2017-07-24 12:04:24 -07:00 committed by GitHub
commit d1b08ae7f2
6 changed files with 104 additions and 63 deletions

View File

@ -13,6 +13,7 @@
1. [#1752](https://github.com/influxdata/chronograf/pull/1752): Clarify BoltPath server flag help text by making example the default path
1. [#1738](https://github.com/influxdata/chronograf/pull/1738): Add shared secret JWT authorization to InfluxDB
1. [#1724](https://github.com/influxdata/chronograf/pull/1724): Add Pushover alert support
1. [#1762](https://github.com/influxdata/chronograf/pull/1762): Restore all supported Kapacitor services when creating rules, and add most optional message parameters
### UI Improvements
1. [#1707](https://github.com/influxdata/chronograf/pull/1707): Polish alerts table in status page to wrap text less

View File

@ -752,6 +752,7 @@ func extractSlack(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractTalk(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.TalkHandlers) == 0 {
return
@ -763,6 +764,7 @@ func extractTalk(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractTelegram(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if len(node.TelegramHandlers) == 0 {
return

View File

@ -1,4 +1,5 @@
import React, {Component, PropTypes} from 'react'
import _ from 'lodash'
import classnames from 'classnames'
import RuleMessageOptions from 'src/kapacitor/components/RuleMessageOptions'
@ -55,9 +56,7 @@ class RuleMessage extends Component {
<ul className="nav nav-tablist nav-tablist-sm nav-tablist-malachite">
{alerts
// only display alert endpoints that have rule alert options configured
.filter(alert =>
Object.keys(RULE_ALERT_OPTIONS).includes(alert.text)
)
.filter(alert => _.get(RULE_ALERT_OPTIONS, alert.text, false))
.map(alert =>
<li
key={alert.text}

View File

@ -35,19 +35,6 @@ export const OPERATORS = [
export const PERIODS = ['1m', '5m', '10m', '30m', '1h', '2h', '24h']
export const CHANGES = ['change', '% change']
export const SHIFTS = ['1m', '5m', '10m', '30m', '1h', '2h', '24h']
export const ALERTS = [
'alerta',
'hipchat',
'opsgenie',
'pagerduty',
'pushover',
'sensu',
'slack',
'smtp',
'talk',
'telegram',
'victorops',
]
export const DEFAULT_RULE_ID = 'DEFAULT_RULE_ID'
@ -89,6 +76,10 @@ export const RULE_ALERT_OPTIONS = {
label: 'URL:',
placeholder: 'Ex: http://example.com/api/alert',
},
// properties: [
// {name: 'endpoint', label: 'Endpoint:', placeholder: 'Endpoint'},
// {name: 'header', label: 'Headers:', placeholder: 'Headers (Delimited)'}, // TODO: determine how to delimit
// ],
},
tcp: {
args: {
@ -98,7 +89,7 @@ export const RULE_ALERT_OPTIONS = {
},
exec: {
args: {
label: 'Add Command (Arguments separated by Spaces):',
label: 'Command (Arguments separated by Spaces):',
placeholder: 'Ex: woogie boogie',
},
},
@ -108,6 +99,66 @@ export const RULE_ALERT_OPTIONS = {
placeholder: 'Ex: /tmp/alerts.log',
},
},
alerta: {
args: {
label: 'Paste Alerta TICKscript:', // TODO: remove this
placeholder: 'alerta()',
},
// properties: [
// {name: 'token', label: 'Token:', placeholder: 'Token'},
// {name: 'resource', label: 'Resource:', placeholder: 'Resource'},
// {name: 'event', label: 'Event:', placeholder: 'Event'},
// {name: 'environment', label: 'Environment:', placeholder: 'Environment'},
// {name: 'group', label: 'Group:', placeholder: 'Group'},
// {name: 'value', label: 'Value:', placeholder: 'Value'},
// {name: 'origin', label: 'Origin:', placeholder: 'Origin'},
// {name: 'services', label: 'Services:', placeholder: 'Services'}, // TODO: what format?
// ],
},
hipchat: {
properties: [
{name: 'room', label: 'Room:', placeholder: 'happy_place'},
{name: 'token', label: 'Token:', placeholder: 'a_gilded_token'},
],
},
opsgenie: {
// properties: [
// {name: 'recipients', label: 'Recipients:', placeholder: 'happy_place'}, // TODO: what format?
// {name: 'teams', label: 'Teams:', placeholder: 'blue,yellow,maroon'}, // TODO: what format?
// ],
},
pagerduty: {
properties: [
{
name: 'serviceKey',
label: 'Service Key:',
placeholder: 'one_rad_key',
},
],
},
pushover: {
properties: [
{
name: 'device',
label: 'Device:',
placeholder: 'dv1,dv2 (Comma Separated)', // TODO: do these need to be parsed before sent?
},
{name: 'title', label: 'Title:', placeholder: 'Important Message'},
{name: 'URL', label: 'URL:', placeholder: 'https://influxdata.com'},
{name: 'URLTitle', label: 'URL Title:', placeholder: 'InfluxData'},
{name: 'sound', label: 'Sound:', placeholder: 'alien'},
],
},
sensu: {
// TODO: apparently no args or properties, according to kapacitor/ast.go ?
},
slack: {
properties: [
{name: 'channel', label: 'Channel:', placeholder: '#cubeoctohedron'},
{name: 'iconEmoji', label: 'Emoji:', placeholder: ':cubeapple:'},
{name: 'username', label: 'Username:', placeholder: 'pineapple'},
],
},
smtp: {
args: {
label: 'Email Addresses (Separated by Spaces):',
@ -116,29 +167,26 @@ export const RULE_ALERT_OPTIONS = {
},
details: {placeholder: 'Email body text goes here'},
},
slack: {
args: {
label: 'Send alerts to Slack channel:',
placeholder: '#alerts',
},
},
alerta: {
args: {
label: 'Paste Alerta TICKscript:',
placeholder: 'alerta()',
},
},
pushover: {
talk: {},
telegram: {
properties: [
{
name: 'device',
label: 'Device:',
placeholder: 'dv1,dv2 (Comma Separated)',
},
{name: 'title', label: 'Title:', placeholder: 'Important Message'},
{name: 'URL', label: 'URL:', placeholder: 'https://influxdata.com'},
{name: 'URLTitle', label: 'URL Title:', placeholder: 'InfluxData'},
{name: 'sound', label: 'Sound:', placeholder: 'alien'},
{name: 'chatId', label: 'Chat ID:', placeholder: 'xxxxxxxxx'},
{name: 'parseMode', label: 'Emoji:', placeholder: 'Markdown'},
// {
// name: 'disableWebPagePreview',
// label: 'Disable Web Page Preview:',
// placeholder: 'true', // TODO: format to bool
// },
// {
// name: 'disableNotification',
// label: 'Disable Notification:',
// placeholder: 'false', // TODO: format to bool
// },
],
},
victorops: {
properties: [
{name: 'routingKey', label: 'Channel:', placeholder: 'team_rocket'},
],
},
}
@ -149,7 +197,6 @@ export const ALERT_NODES_ACCESSORS = {
exec: rule => _.get(rule, 'alertNodes[0].args', []).join(' '),
log: rule => _.get(rule, 'alertNodes[0].args[0]', ''),
smtp: rule => _.get(rule, 'alertNodes[0].args', []).join(' '),
slack: rule => _.get(rule, 'alertNodes[0].properties[0].args', ''),
alerta: rule =>
_.get(rule, 'alertNodes[0].properties', [])
.reduce(

View File

@ -7,7 +7,7 @@ import * as queryActionCreators from 'src/data_explorer/actions/view'
import {bindActionCreators} from 'redux'
import {getActiveKapacitor, getKapacitorConfig} from 'shared/apis/index'
import {ALERTS, DEFAULT_RULE_ID} from 'src/kapacitor/constants'
import {RULE_ALERT_OPTIONS, DEFAULT_RULE_ID} from 'src/kapacitor/constants'
import KapacitorRule from 'src/kapacitor/components/KapacitorRule'
class KapacitorRulePage extends Component {
@ -40,15 +40,14 @@ class KapacitorRulePage extends Component {
try {
const {data: {sections}} = await getKapacitorConfig(kapacitor)
const enabledAlerts = Object.keys(sections).filter(section => {
return (
const enabledAlerts = Object.keys(sections).filter(
section =>
_.get(
sections,
[section, 'elements', '0', 'options', 'enabled'],
false
) && ALERTS.includes(section)
)
})
) && _.get(RULE_ALERT_OPTIONS, section, false)
)
this.setState({kapacitor, enabledAlerts})
} catch (error) {

View File

@ -114,19 +114,6 @@ export default function rules(state = {}, action) {
},
]
break
case 'slack':
alertNodesByType = [
{
name: alertNodeName,
properties: [
{
name: 'channel',
args: [alertNodesText],
},
],
},
]
break
case 'alerta':
alertNodesByType = [
{
@ -136,6 +123,12 @@ export default function rules(state = {}, action) {
},
]
break
case 'hipchat':
case 'opsgenie':
case 'pagerduty':
case 'slack':
case 'telegram':
case 'victorops':
case 'pushover':
default:
alertNodesByType = [
@ -146,7 +139,6 @@ export default function rules(state = {}, action) {
},
]
}
return Object.assign({}, state, {
[ruleID]: Object.assign({}, state[ruleID], {
alertNodes: alertNodesByType,
@ -156,7 +148,6 @@ export default function rules(state = {}, action) {
case 'UPDATE_RULE_ALERT_PROPERTY': {
const {ruleID, alertNodeName, alertProperty} = action.payload
const newAlertNodes = state[ruleID].alertNodes.map(alertNode => {
if (alertNode.name !== alertNodeName) {
return alertNode
@ -181,8 +172,10 @@ export default function rules(state = {}, action) {
return {
...state,
[ruleID]: {...state[ruleID]},
alertNodes: newAlertNodes,
[ruleID]: {
...state[ruleID],
alertNodes: newAlertNodes,
},
}
}