From a04c0428b1e44a67377ca56532c47bb141f671e3 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 14 Jul 2017 11:49:53 -0700 Subject: [PATCH 01/25] Alphabetize alert endpoint configs --- ui/src/kapacitor/components/AlertTabs.js | 82 ++++++++++++------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/ui/src/kapacitor/components/AlertTabs.js b/ui/src/kapacitor/components/AlertTabs.js index 7b8b15dd0d..7bd60fed89 100644 --- a/ui/src/kapacitor/components/AlertTabs.js +++ b/ui/src/kapacitor/components/AlertTabs.js @@ -135,39 +135,11 @@ class AlertTabs extends Component { ), }, { - type: 'SMTP', + type: 'HipChat', component: ( - this.handleSaveConfig('smtp', p)} - config={this.getSection(configSections, 'smtp')} - /> - ), - }, - { - type: 'Slack', - component: ( - this.handleSaveConfig('slack', p)} - onTest={test} - config={this.getSection(configSections, 'slack')} - /> - ), - }, - { - type: 'VictorOps', - component: ( - this.handleSaveConfig('victorops', p)} - config={this.getSection(configSections, 'victorops')} - /> - ), - }, - { - type: 'Telegram', - component: ( - this.handleSaveConfig('telegram', p)} - config={this.getSection(configSections, 'telegram')} + this.handleSaveConfig('hipchat', p)} + config={this.getSection(configSections, 'hipchat')} /> ), }, @@ -189,15 +161,6 @@ class AlertTabs extends Component { /> ), }, - { - type: 'HipChat', - component: ( - this.handleSaveConfig('hipchat', p)} - config={this.getSection(configSections, 'hipchat')} - /> - ), - }, { type: 'Sensu', component: ( @@ -207,6 +170,25 @@ class AlertTabs extends Component { /> ), }, + { + type: 'Slack', + component: ( + this.handleSaveConfig('slack', p)} + onTest={test} + config={this.getSection(configSections, 'slack')} + /> + ), + }, + { + type: 'SMTP', + component: ( + this.handleSaveConfig('smtp', p)} + config={this.getSection(configSections, 'smtp')} + /> + ), + }, { type: 'Talk', component: ( @@ -216,6 +198,24 @@ class AlertTabs extends Component { /> ), }, + { + type: 'Telegram', + component: ( + this.handleSaveConfig('telegram', p)} + config={this.getSection(configSections, 'telegram')} + /> + ), + }, + { + type: 'VictorOps', + component: ( + this.handleSaveConfig('victorops', p)} + config={this.getSection(configSections, 'victorops')} + /> + ), + }, ] return ( From fb8d5cfc8ebfe1583b724242131d4954b97e7c9b Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 14 Jul 2017 15:36:32 -0700 Subject: [PATCH 02/25] Add Pushover to swagger --- server/swagger.json | 1 + 1 file changed, 1 insertion(+) diff --git a/server/swagger.json b/server/swagger.json index 769a6be2c9..de846ba8f5 100644 --- a/server/swagger.json +++ b/server/swagger.json @@ -2913,6 +2913,7 @@ "hipchat", "opsgenie", "pagerduty", + "pushover", "victorops", "smtp", "email", From 7f8d5f7c003e74a0bd8e4dcba24c8bb5245152ed Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 14 Jul 2017 15:39:06 -0700 Subject: [PATCH 03/25] Only render configs given by Kapacitor proxy --- ui/src/kapacitor/components/AlertTabs.js | 100 +++++++++++++---------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/ui/src/kapacitor/components/AlertTabs.js b/ui/src/kapacitor/components/AlertTabs.js index 7bd60fed89..02be255b43 100644 --- a/ui/src/kapacitor/components/AlertTabs.js +++ b/ui/src/kapacitor/components/AlertTabs.js @@ -124,99 +124,89 @@ class AlertTabs extends Component { this.handleTest('slack', properties) } - const tabs = [ - { + const supportedConfigs = { + alerta: { type: 'Alerta', - component: ( + renderComponent: () => this.handleSaveConfig('alerta', p)} config={this.getSection(configSections, 'alerta')} - /> - ), + />, }, - { + hipchat: { type: 'HipChat', - component: ( + renderComponent: () => this.handleSaveConfig('hipchat', p)} config={this.getSection(configSections, 'hipchat')} - /> - ), + />, }, - { + opsgenie: { type: 'OpsGenie', - component: ( + renderComponent: () => this.handleSaveConfig('opsgenie', p)} config={this.getSection(configSections, 'opsgenie')} - /> - ), + />, }, - { + pagerduty: { type: 'PagerDuty', - component: ( + renderComponent: () => this.handleSaveConfig('pagerduty', p)} config={this.getSection(configSections, 'pagerduty')} - /> - ), + />, }, - { + sensu: { type: 'Sensu', - component: ( + renderComponent: () => this.handleSaveConfig('sensu', p)} config={this.getSection(configSections, 'sensu')} - /> - ), + />, }, - { + slack: { type: 'Slack', - component: ( + renderComponent: () => this.handleSaveConfig('slack', p)} onTest={test} config={this.getSection(configSections, 'slack')} - /> - ), + />, }, - { + smtp: { type: 'SMTP', - component: ( + renderComponent: () => this.handleSaveConfig('smtp', p)} config={this.getSection(configSections, 'smtp')} - /> - ), + />, }, - { + talk: { type: 'Talk', - component: ( + renderComponent: () => this.handleSaveConfig('talk', p)} config={this.getSection(configSections, 'talk')} - /> - ), + />, }, - { + telegram: { type: 'Telegram', - component: ( + renderComponent: () => this.handleSaveConfig('telegram', p)} config={this.getSection(configSections, 'telegram')} - /> - ), + />, }, - { + victorops: { type: 'VictorOps', - component: ( + renderComponent: () => this.handleSaveConfig('victorops', p)} config={this.getSection(configSections, 'victorops')} - /> - ), + />, }, - ] + } return (
@@ -228,11 +218,31 @@ class AlertTabs extends Component { - {tabs.map((t, i) => {tabs[i].type})} + {_.reduce( + configSections, + (acc, _cur, k) => + supportedConfigs[k] + ? acc.concat( + + {supportedConfigs[k].type} + + ) + : acc, + [] + )} - {tabs.map((t, i) => - {t.component} + {_.reduce( + configSections, + (acc, _cur, k) => + supportedConfigs[k] + ? acc.concat( + + {supportedConfigs[k].renderComponent()} + + ) + : acc, + [] )} From 80573d8348cd25563c40f0289a6552b81f67b75f Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 14 Jul 2017 16:10:52 -0700 Subject: [PATCH 04/25] Add Pushover config --- ui/src/kapacitor/components/AlertTabs.js | 9 ++ .../components/config/PushoverConfig.js | 98 +++++++++++++++++++ ui/src/kapacitor/components/config/index.js | 2 + ui/src/kapacitor/copy.js | 15 ++- 4 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 ui/src/kapacitor/components/config/PushoverConfig.js diff --git a/ui/src/kapacitor/components/AlertTabs.js b/ui/src/kapacitor/components/AlertTabs.js index 02be255b43..afe2d7f537 100644 --- a/ui/src/kapacitor/components/AlertTabs.js +++ b/ui/src/kapacitor/components/AlertTabs.js @@ -13,6 +13,7 @@ import { HipChatConfig, OpsGenieConfig, PagerDutyConfig, + PushoverConfig, SensuConfig, SlackConfig, SMTPConfig, @@ -157,6 +158,14 @@ class AlertTabs extends Component { config={this.getSection(configSections, 'pagerduty')} />, }, + pushover: { + type: 'Pushover', + renderComponent: () => + this.handleSaveConfig('pushover', p)} + config={this.getSection(configSections, 'pushover')} + />, + }, sensu: { type: 'Sensu', renderComponent: () => diff --git a/ui/src/kapacitor/components/config/PushoverConfig.js b/ui/src/kapacitor/components/config/PushoverConfig.js new file mode 100644 index 0000000000..3830012610 --- /dev/null +++ b/ui/src/kapacitor/components/config/PushoverConfig.js @@ -0,0 +1,98 @@ +import React, {Component, PropTypes} from 'react' + +import QuestionMarkTooltip from 'shared/components/QuestionMarkTooltip' +import RedactedInput from './RedactedInput' + +import {PUSHOVER_DOCS_LINK} from 'src/kapacitor/copy' + +class PushoverConfig extends Component { + constructor(props) { + super(props) + + this.handleSaveAlert = ::this.handleSaveAlert + } + + handleSaveAlert(e) { + e.preventDefault() + + const properties = { + token: this.token.value, + url: this.url.value, + 'user-key': this.userKey.value, + } + + this.props.onSave(properties) + } + + render() { + const {options} = this.props.config + const {token, url} = options + const userKey = options['user-key'] + + return ( +
+
+ + (this.userKey = r)} + /> +
+ +
+ + (this.token = r)} + /> +
+ +
+ + (this.url = r)} + defaultValue={url || ''} + /> +
+ +
+ +
+
+ ) + } +} + +const {bool, func, shape, string} = PropTypes + +PushoverConfig.propTypes = { + config: shape({ + options: shape({ + token: bool.isRequired, + 'user-key': bool.isRequired, + url: string.isRequired, + }).isRequired, + }).isRequired, + onSave: func.isRequired, +} + +export default PushoverConfig diff --git a/ui/src/kapacitor/components/config/index.js b/ui/src/kapacitor/components/config/index.js index 8cf004a079..7b186a42a2 100644 --- a/ui/src/kapacitor/components/config/index.js +++ b/ui/src/kapacitor/components/config/index.js @@ -2,6 +2,7 @@ import AlertaConfig from './AlertaConfig' import HipChatConfig from './HipChatConfig' import OpsGenieConfig from './OpsGenieConfig' import PagerDutyConfig from './PagerDutyConfig' +import PushoverConfig from './PushoverConfig' import SensuConfig from './SensuConfig' import SlackConfig from './SlackConfig' import SMTPConfig from './SMTPConfig' @@ -14,6 +15,7 @@ export { HipChatConfig, OpsGenieConfig, PagerDutyConfig, + PushoverConfig, SensuConfig, SlackConfig, SMTPConfig, diff --git a/ui/src/kapacitor/copy.js b/ui/src/kapacitor/copy.js index c624d2e824..0adaecebf8 100644 --- a/ui/src/kapacitor/copy.js +++ b/ui/src/kapacitor/copy.js @@ -1,3 +1,14 @@ +// HipChat +const hipchatTokenLink = + 'https://docs.influxdata.com/kapacitor/latest/guides/event-handler-setup/#hipchat-api-access-token' +export const HIPCHAT_TOKEN_TIP = `

Need help creating a token?
Check out these steps.

` + +// Pushover +const pushoverDocsLink = + 'https://docs.influxdata.com/kapacitor/latest/nodes/alert_node/#pushover' +export const PUSHOVER_DOCS_LINK = `

Need help setting up Pushover?
Check out the docs here.

` + +// Telegram const telegramChatIDLink = 'https://docs.influxdata.com/kapacitor/latest/guides/event-handler-setup/#telegram-chat-id' export const TELEGRAM_CHAT_ID_TIP = `

Need help finding your chat id?
Check out these steps.

` @@ -5,7 +16,3 @@ export const TELEGRAM_CHAT_ID_TIP = `

Need help finding your chat id?
Chec const telegramTokenLink = 'https://docs.influxdata.com/kapacitor/latest/guides/event-handler-setup/#telegram-api-access-token' export const TELEGRAM_TOKEN_TIP = `

Need help finding your token?
Check out these steps.

` - -const hipchatTokenLink = - 'https://docs.influxdata.com/kapacitor/latest/guides/event-handler-setup/#hipchat-api-access-token' -export const HIPCHAT_TOKEN_TIP = `

Need help creating a token?
Check out these steps.

` From 7d93b930409175996c1bfdf943367fa25fe434ac Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 14 Jul 2017 17:34:02 -0700 Subject: [PATCH 05/25] Update changelog --- CHANGELOG.md | 1 + ui/src/kapacitor/constants/index.js | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7613754c15..e427a1b5ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Features 1. [#1717](https://github.com/influxdata/chronograf/pull/1717): View server generated TICKscripts 1. [#1681](https://github.com/influxdata/chronograf/pull/1681): Add the ability to select Custom Time Ranges in the Hostpages, Data Explorer, and Dashboards. +1. [#1724](https://github.com/influxdata/chronograf/pull/1724): Add alert configuration for Kapacitor support of Pushover ### UI Improvements diff --git a/ui/src/kapacitor/constants/index.js b/ui/src/kapacitor/constants/index.js index 3cf36b53e7..a219af7e3a 100644 --- a/ui/src/kapacitor/constants/index.js +++ b/ui/src/kapacitor/constants/index.js @@ -40,6 +40,7 @@ export const ALERTS = [ 'hipchat', 'opsgenie', 'pagerduty', + 'pushover', 'sensu', 'slack', 'smtp', From 8bea47e0722813b1c391762baa3f8ce7900c1414 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Mon, 17 Jul 2017 17:01:30 -0700 Subject: [PATCH 06/25] Change order of alert endpoint options to make defaults be first --- ui/src/kapacitor/components/RuleMessage.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/src/kapacitor/components/RuleMessage.js b/ui/src/kapacitor/components/RuleMessage.js index 7e333cb43e..e207e1f592 100644 --- a/ui/src/kapacitor/components/RuleMessage.js +++ b/ui/src/kapacitor/components/RuleMessage.js @@ -43,11 +43,12 @@ export const RuleMessage = React.createClass({ return {text, ruleID: rule.id} }) - const alerts = enabledAlerts - .map(text => { + const alerts = [ + ...defaultAlertEndpoints, + ...enabledAlerts.map(text => { return {text, ruleID: rule.id} - }) - .concat(defaultAlertEndpoints) + }), + ] const selectedAlert = rule.alerts[0] || alerts[0].text From ed883cffa6353508bfe89c92293a497f8ca73ad4 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Mon, 17 Jul 2017 17:29:26 -0700 Subject: [PATCH 07/25] Add Pushover as valid Kapacitor handler endpoint type --- kapacitor/alerts.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kapacitor/alerts.go b/kapacitor/alerts.go index 759b161fe1..638b6fb8b8 100644 --- a/kapacitor/alerts.go +++ b/kapacitor/alerts.go @@ -21,7 +21,7 @@ func kapaHandler(handler string) (string, error) { return "email", nil case "http": return "post", nil - case "alerta", "sensu", "slack", "email", "talk", "telegram", "post", "tcp", "exec", "log": + case "alerta", "sensu", "slack", "email", "talk", "telegram", "post", "tcp", "exec", "log", "pushover": return handler, nil default: return "", fmt.Errorf("Unsupported alert handler %s", handler) From 40ad225752d42850a973024b9e24b44357ee0577 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Mon, 17 Jul 2017 17:30:12 -0700 Subject: [PATCH 08/25] Extract Pushover properties for Kapa alert via AST --- kapacitor/ast.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/kapacitor/ast.go b/kapacitor/ast.go index 673eb670d8..e99a166755 100644 --- a/kapacitor/ast.go +++ b/kapacitor/ast.go @@ -492,6 +492,7 @@ func extractAlertNodes(p *pipeline.Pipeline, rule *chronograf.AlertRule) { extractSlack(t, rule) extractTalk(t, rule) extractTelegram(t, rule) + extractPushover(t, rule) extractTCP(t, rule) extractLog(t, rule) extractExec(t, rule) @@ -851,3 +852,58 @@ func extractExec(node *pipeline.AlertNode, rule *chronograf.AlertRule) { rule.AlertNodes = append(rule.AlertNodes, alert) } + +func extractPushover(node *pipeline.AlertNode, rule *chronograf.AlertRule) { + if node.PushoverHandlers == nil { + return + } + rule.Alerts = append(rule.Alerts, "pushover") + a := node.PushoverHandlers[0] + alert := chronograf.KapacitorNode{ + Name: "pushover", + } + + if a.UserKey != "" { + alert.Properties = append(alert.Properties, chronograf.KapacitorProperty{ + Name: "user-key", + Args: []string{a.UserKey}, + }) + } + + 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: "url-title", + 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) +} From 2170b455a1031aeb6e648e3f35caf4a83250b65d Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Tue, 18 Jul 2017 12:02:07 -0700 Subject: [PATCH 09/25] Refactor RuleMessage templates into separate components, update to ES6 --- ui/src/kapacitor/components/CodeData.js | 34 +++++++++++ ui/src/kapacitor/components/RuleMessage.js | 56 +++---------------- .../components/RuleMessageTemplates.js | 50 +++++++++++++++++ 3 files changed, 91 insertions(+), 49 deletions(-) create mode 100644 ui/src/kapacitor/components/CodeData.js create mode 100644 ui/src/kapacitor/components/RuleMessageTemplates.js diff --git a/ui/src/kapacitor/components/CodeData.js b/ui/src/kapacitor/components/CodeData.js new file mode 100644 index 0000000000..fe19351308 --- /dev/null +++ b/ui/src/kapacitor/components/CodeData.js @@ -0,0 +1,34 @@ +import React, {Component, PropTypes} from 'react' + +// needs to be React Component for click handler to work +class CodeData extends Component { + constructor(props) { + super(props) + } + + render() { + const {onClickTemplate, template} = this.props + + return ( + + {template.label} + + ) + } +} + +const {func, shape, string} = PropTypes + +CodeData.propTypes = { + onClickTemplate: func, + template: shape({ + label: string, + text: string, + }), +} + +export default CodeData diff --git a/ui/src/kapacitor/components/RuleMessage.js b/ui/src/kapacitor/components/RuleMessage.js index e207e1f592..5876d83c8c 100644 --- a/ui/src/kapacitor/components/RuleMessage.js +++ b/ui/src/kapacitor/components/RuleMessage.js @@ -1,10 +1,10 @@ import React, {PropTypes} from 'react' import classnames from 'classnames' -import ReactTooltip from 'react-tooltip' import RuleMessageAlertConfig from 'src/kapacitor/components/RuleMessageAlertConfig' +import RuleMessageTemplates from 'src/kapacitor/components/RuleMessageTemplates' -import {RULE_MESSAGE_TEMPLATES as templates, DEFAULT_ALERTS} from '../constants' +import {RULE_MESSAGE_TEMPLATES, DEFAULT_ALERTS} from '../constants' const {arrayOf, func, shape, string} = PropTypes @@ -98,57 +98,15 @@ export const RuleMessage = React.createClass({ value={rule.message} spellCheck={false} /> -
-

Templates:

- {Object.keys(templates).map(t => { - return ( - - actions.updateMessage( - rule.id, - `${this.message.value} ${templates[t].label}` - )} - /> - ) - })} - -
+
) }, }) -const CodeData = React.createClass({ - propTypes: { - onClickTemplate: func, - template: shape({ - label: string, - text: string, - }), - }, - - render() { - const {onClickTemplate, template} = this.props - const {label, text} = template - - return ( - - {label} - - ) - }, -}) - export default RuleMessage diff --git a/ui/src/kapacitor/components/RuleMessageTemplates.js b/ui/src/kapacitor/components/RuleMessageTemplates.js new file mode 100644 index 0000000000..915e1fe203 --- /dev/null +++ b/ui/src/kapacitor/components/RuleMessageTemplates.js @@ -0,0 +1,50 @@ +import React, {Component, PropTypes} from 'react' +import ReactTooltip from 'react-tooltip' + +import CodeData from 'src/kapacitor/components/CodeData' + +// needs to be React Component for CodeData click handler to work +class RuleMessageTemplates extends Component { + constructor(props) { + super(props) + } + + render() { + const {templates, actions, rule} = this.props + + return ( +
+

Templates:

+ {Object.keys(templates).map(t => { + return ( + + actions.updateMessage( + rule.id, + `${rule.message} ${templates[t].label}` + )} + /> + ) + })} + +
+ ) + } +} + +const {shape} = PropTypes + +RuleMessageTemplates.propTypes = { + templates: shape().isRequired, + actions: shape().isRequired, + rule: shape().isRequired, +} + +export default RuleMessageTemplates From 113c4cfae4fd36f8cdad9b7a929eb33db21d25d2 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Tue, 18 Jul 2017 12:15:59 -0700 Subject: [PATCH 10/25] Factor out RuleMessageText into dedicated ES6 component --- ui/src/kapacitor/components/RuleMessage.js | 14 +++------ .../kapacitor/components/RuleMessageText.js | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 ui/src/kapacitor/components/RuleMessageText.js diff --git a/ui/src/kapacitor/components/RuleMessage.js b/ui/src/kapacitor/components/RuleMessage.js index 5876d83c8c..5b41b964c0 100644 --- a/ui/src/kapacitor/components/RuleMessage.js +++ b/ui/src/kapacitor/components/RuleMessage.js @@ -2,6 +2,7 @@ import React, {PropTypes} from 'react' import classnames from 'classnames' import RuleMessageAlertConfig from 'src/kapacitor/components/RuleMessageAlertConfig' +import RuleMessageText from 'src/kapacitor/components/RuleMessageText' import RuleMessageTemplates from 'src/kapacitor/components/RuleMessageTemplates' import {RULE_MESSAGE_TEMPLATES, DEFAULT_ALERTS} from '../constants' @@ -90,18 +91,11 @@ export const RuleMessage = React.createClass({ /> : null} -