Skip to content

Commit

Permalink
Merge pull request #2488 from JeffAshton/slack-kibana-discover-url-at…
Browse files Browse the repository at this point in the history
…tachment

Adding ability to attach the Kibana Discover url in slack alerts
  • Loading branch information
Qmando authored Sep 27, 2019
2 parents 872826c + a02b146 commit 9c2c898
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 0 deletions.
6 changes: 6 additions & 0 deletions docs/source/ruletypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1781,6 +1781,12 @@ Provide absolute address of the pciture, for example: http://some.address.com/im

``slack_timeout``: You can specify a timeout value, in seconds, for making communicating with Slac. The default is 10. If a timeout occurs, the alert will be retried next time elastalert cycles.

``slack_attach_kibana_discover_url``: Enables the attachment of the ``kibana_discover_url`` to the slack notification. The config ``generate_kibana_discover_url`` must also be ``True`` in order to generate the url. Defaults to ``False``.

``slack_kibana_discover_color``: The color of the Kibana Discover url attachment. Defaults to ``#ec4b98``.

``slack_kibana_discover_title``: The title of the Kibana Discover url attachment. Defaults to ``Discover in Kibana``.

Mattermost
~~~~~~~~~~

Expand Down
12 changes: 12 additions & 0 deletions elastalert/alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,9 @@ def __init__(self, rule):
self.slack_ignore_ssl_errors = self.rule.get('slack_ignore_ssl_errors', False)
self.slack_timeout = self.rule.get('slack_timeout', 10)
self.slack_ca_certs = self.rule.get('slack_ca_certs')
self.slack_attach_kibana_discover_url = self.rule.get('slack_attach_kibana_discover_url', False)
self.slack_kibana_discover_color = self.rule.get('slack_kibana_discover_color', '#ec4b98')
self.slack_kibana_discover_title = self.rule.get('slack_kibana_discover_title', 'Discover in Kibana')

def format_body(self, body):
# https://api.slack.com/docs/formatting
Expand Down Expand Up @@ -1191,6 +1194,15 @@ def alert(self, matches):
if self.slack_title_link != '':
payload['attachments'][0]['title_link'] = self.slack_title_link

if self.slack_attach_kibana_discover_url:
kibana_discover_url = lookup_es_key(matches[0], 'kibana_discover_url')
if kibana_discover_url:
payload['attachments'].append({
'color': self.slack_kibana_discover_color,
'title': self.slack_kibana_discover_title,
'title_link': kibana_discover_url
})

for url in self.slack_webhook_url:
for channel_override in self.slack_channel_override:
try:
Expand Down
3 changes: 3 additions & 0 deletions elastalert/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ properties:
slack_text_string: {type: string}
slack_ignore_ssl_errors: {type: boolean}
slack_ca_certs: {type: string}
slack_attach_kibana_discover_url {type: boolean}
slack_kibana_discover_color {type: string}
slack_kibana_discover_title {type: string}

### Mattermost
mattermost_webhook_url: *arrayOfString
Expand Down
200 changes: 200 additions & 0 deletions tests/alerts_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,206 @@ def test_slack_uses_list_of_custom_slack_channel():
assert expected_data2 == json.loads(mock_post_request.call_args_list[1][1]['data'])


def test_slack_attach_kibana_discover_url_when_generated():
rule = {
'name': 'Test Rule',
'type': 'any',
'slack_attach_kibana_discover_url': True,
'slack_webhook_url': 'http://please.dontgohere.slack',
'alert': []
}
rules_loader = FileRulesLoader({})
rules_loader.load_modules(rule)
alert = SlackAlerter(rule)
match = {
'@timestamp': '2016-01-01T00:00:00',
'kibana_discover_url': 'http://kibana#discover'
}
with mock.patch('requests.post') as mock_post_request:
alert.alert([match])

expected_data = {
'username': 'elastalert',
'parse': 'none',
'text': '',
'attachments': [
{
'color': 'danger',
'title': 'Test Rule',
'text': BasicMatchString(rule, match).__str__(),
'mrkdwn_in': ['text', 'pretext'],
'fields': []
},
{
'color': '#ec4b98',
'title': 'Discover in Kibana',
'title_link': 'http://kibana#discover'
}
],
'icon_emoji': ':ghost:',
'channel': ''
}
mock_post_request.assert_called_once_with(
rule['slack_webhook_url'],
data=mock.ANY,
headers={'content-type': 'application/json'},
proxies=None,
verify=False,
timeout=10
)
actual_data = json.loads(mock_post_request.call_args_list[0][1]['data'])
assert expected_data == actual_data


def test_slack_attach_kibana_discover_url_when_not_generated():
rule = {
'name': 'Test Rule',
'type': 'any',
'slack_attach_kibana_discover_url': True,
'slack_webhook_url': 'http://please.dontgohere.slack',
'alert': []
}
rules_loader = FileRulesLoader({})
rules_loader.load_modules(rule)
alert = SlackAlerter(rule)
match = {
'@timestamp': '2016-01-01T00:00:00'
}
with mock.patch('requests.post') as mock_post_request:
alert.alert([match])

expected_data = {
'username': 'elastalert',
'parse': 'none',
'text': '',
'attachments': [
{
'color': 'danger',
'title': 'Test Rule',
'text': BasicMatchString(rule, match).__str__(),
'mrkdwn_in': ['text', 'pretext'],
'fields': []
}
],
'icon_emoji': ':ghost:',
'channel': ''
}
mock_post_request.assert_called_once_with(
rule['slack_webhook_url'],
data=mock.ANY,
headers={'content-type': 'application/json'},
proxies=None,
verify=False,
timeout=10
)
actual_data = json.loads(mock_post_request.call_args_list[0][1]['data'])
assert expected_data == actual_data


def test_slack_kibana_discover_title():
rule = {
'name': 'Test Rule',
'type': 'any',
'slack_attach_kibana_discover_url': True,
'slack_kibana_discover_title': 'Click to discover in Kibana',
'slack_webhook_url': 'http://please.dontgohere.slack',
'alert': []
}
rules_loader = FileRulesLoader({})
rules_loader.load_modules(rule)
alert = SlackAlerter(rule)
match = {
'@timestamp': '2016-01-01T00:00:00',
'kibana_discover_url': 'http://kibana#discover'
}
with mock.patch('requests.post') as mock_post_request:
alert.alert([match])

expected_data = {
'username': 'elastalert',
'parse': 'none',
'text': '',
'attachments': [
{
'color': 'danger',
'title': 'Test Rule',
'text': BasicMatchString(rule, match).__str__(),
'mrkdwn_in': ['text', 'pretext'],
'fields': []
},
{
'color': '#ec4b98',
'title': 'Click to discover in Kibana',
'title_link': 'http://kibana#discover'
}
],
'icon_emoji': ':ghost:',
'channel': ''
}
mock_post_request.assert_called_once_with(
rule['slack_webhook_url'],
data=mock.ANY,
headers={'content-type': 'application/json'},
proxies=None,
verify=False,
timeout=10
)
actual_data = json.loads(mock_post_request.call_args_list[0][1]['data'])
assert expected_data == actual_data


def test_slack_kibana_discover_color():
rule = {
'name': 'Test Rule',
'type': 'any',
'slack_attach_kibana_discover_url': True,
'slack_kibana_discover_color': 'blue',
'slack_webhook_url': 'http://please.dontgohere.slack',
'alert': []
}
rules_loader = FileRulesLoader({})
rules_loader.load_modules(rule)
alert = SlackAlerter(rule)
match = {
'@timestamp': '2016-01-01T00:00:00',
'kibana_discover_url': 'http://kibana#discover'
}
with mock.patch('requests.post') as mock_post_request:
alert.alert([match])

expected_data = {
'username': 'elastalert',
'parse': 'none',
'text': '',
'attachments': [
{
'color': 'danger',
'title': 'Test Rule',
'text': BasicMatchString(rule, match).__str__(),
'mrkdwn_in': ['text', 'pretext'],
'fields': []
},
{
'color': 'blue',
'title': 'Discover in Kibana',
'title_link': 'http://kibana#discover'
}
],
'icon_emoji': ':ghost:',
'channel': ''
}
mock_post_request.assert_called_once_with(
rule['slack_webhook_url'],
data=mock.ANY,
headers={'content-type': 'application/json'},
proxies=None,
verify=False,
timeout=10
)
actual_data = json.loads(mock_post_request.call_args_list[0][1]['data'])
assert expected_data == actual_data


def test_http_alerter_with_payload():
rule = {
'name': 'Test HTTP Post Alerter With Payload',
Expand Down

0 comments on commit 9c2c898

Please sign in to comment.