From a1fc501b27720dc3219a2e22e87fa2a0b14ede3a Mon Sep 17 00:00:00 2001 From: nsano-rururu Date: Sun, 6 Jun 2021 00:26:01 +0900 Subject: [PATCH 1/5] Add Kibana Discover url in mattermost alerts --- docs/source/ruletypes.rst | 6 + elastalert/alerters/mattermost.py | 12 ++ elastalert/schema.yaml | 3 + tests/alerters/mattermost_test.py | 192 ++++++++++++++++++++++++++++++ 4 files changed, 213 insertions(+) diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index e127d110..6ac59fb6 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -2223,6 +2223,12 @@ Example mattermost_msg_fields:: ``mattermost_author_icon``: An optional URL used to display a 16x16 pixel icon beside the author_name. Defaults to "". +``mattermost_attach_kibana_discover_url``: Enables the attachment of the ``kibana_discover_url`` to the mattermost notification. The config ``generate_kibana_discover_url`` must also be ``True`` in order to generate the url. Defaults to ``False``. + +``mattermost_kibana_discover_color``: The color of the Kibana Discover url attachment. Defaults to ``#ec4b98``. + +``mattermost_kibana_discover_title``: The title of the Kibana Discover url attachment. Defaults to ``Discover in Kibana``. + Microsoft Teams ~~~~~~~~~~~~~~~ diff --git a/elastalert/alerters/mattermost.py b/elastalert/alerters/mattermost.py index 1ed7c56b..8270e31e 100644 --- a/elastalert/alerters/mattermost.py +++ b/elastalert/alerters/mattermost.py @@ -40,6 +40,9 @@ def __init__(self, rule): self.mattermost_author_name = self.rule.get('mattermost_author_name', '') self.mattermost_author_link = self.rule.get('mattermost_author_link', '') self.mattermost_author_icon = self.rule.get('mattermost_author_icon', '') + self.mattermost_attach_kibana_discover_url = self.rule.get('mattermost_attach_kibana_discover_url', False) + self.mattermost_kibana_discover_color = self.rule.get('mattermost_kibana_discover_color', '#ec4b98') + self.mattermost_kibana_discover_title = self.rule.get('mattermost_kibana_discover_title', 'Discover in Kibana') def get_aggregation_summary_text__maximum_width(self): width = super(MattermostAlerter, self).get_aggregation_summary_text__maximum_width() @@ -128,6 +131,15 @@ def alert(self, matches): if self.mattermost_author_icon != '': payload['attachments'][0]['author_icon'] = self.mattermost_author_icon + if self.mattermost_attach_kibana_discover_url: + kibana_discover_url = lookup_es_key(matches[0], 'kibana_discover_url') + if kibana_discover_url: + payload['attachments'].append({ + 'color': self.mattermost_kibana_discover_color, + 'title': self.mattermost_kibana_discover_title, + 'title_link': kibana_discover_url + }) + for url in self.mattermost_webhook_url: try: if self.mattermost_ignore_ssl_errors: diff --git a/elastalert/schema.yaml b/elastalert/schema.yaml index bffcc140..8528a516 100644 --- a/elastalert/schema.yaml +++ b/elastalert/schema.yaml @@ -406,6 +406,9 @@ properties: mattermost_author_name: {type: string} mattermost_author_link: {type: string} mattermost_author_icon: {type: string} + mattermost_attach_kibana_discover_url {type: boolean} + mattermost_kibana_discover_color {type: string} + mattermost_kibana_discover_title {type: string} ### Microsoft Teams ms_teams_webhook_url: *arrayOfString diff --git a/tests/alerters/mattermost_test.py b/tests/alerters/mattermost_test.py index b2df662d..aa22e1d3 100644 --- a/tests/alerters/mattermost_test.py +++ b/tests/alerters/mattermost_test.py @@ -904,3 +904,195 @@ def test_mattermost_key_error(mattermost_webhook_url, expected_data): assert expected_data == actual_data except KeyError: assert expected_data + + +def test_mattermost_attach_kibana_discover_url_when_generated(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'alert_text_type': 'alert_text_only', + 'mattermost_attach_kibana_discover_url': True, + 'mattermost_webhook_url': 'http://please.dontgohere.mattermost', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = MattermostAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'kibana_discover_url': 'http://localhost:5601/app/discover#/' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'attachments': [ + { + 'fallback': 'Test Rule: ', + 'color': 'danger', + 'title': 'Test Rule', + 'pretext': '', + 'fields': [], + 'text': 'Test Rule\n\n' + }, + { + 'color': '#ec4b98', + 'title': 'Discover in Kibana', + 'title_link': 'http://localhost:5601/app/discover#/' + } + ], 'username': 'elastalert' + } + mock_post_request.assert_called_once_with( + rule['mattermost_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + verify=True, + proxies=None + ) + + actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) + print(actual_data) + assert expected_data == actual_data + + +def test_mattermost_attach_kibana_discover_url_when_not_generated(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'alert_text_type': 'alert_text_only', + 'mattermost_attach_kibana_discover_url': True, + 'mattermost_webhook_url': 'http://please.dontgohere.mattermost', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = MattermostAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'attachments': [ + { + 'fallback': 'Test Rule: ', + 'color': 'danger', + 'title': 'Test Rule', + 'pretext': '', + 'fields': [], + 'text': 'Test Rule\n\n' + } + ], 'username': 'elastalert' + } + mock_post_request.assert_called_once_with( + rule['mattermost_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + verify=True, + proxies=None + ) + + actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) + print(actual_data) + assert expected_data == actual_data + + +def test_mattermost_kibana_discover_title(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'alert_text_type': 'alert_text_only', + 'mattermost_attach_kibana_discover_url': True, + 'mattermost_kibana_discover_title': 'Click to discover in Kibana', + 'mattermost_webhook_url': 'http://please.dontgohere.mattermost', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = MattermostAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'kibana_discover_url': 'http://localhost:5601/app/discover#/' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'attachments': [ + { + 'fallback': 'Test Rule: ', + 'color': 'danger', + 'title': 'Test Rule', + 'pretext': '', + 'fields': [], + 'text': 'Test Rule\n\n' + }, + { + 'color': '#ec4b98', + 'title': 'Click to discover in Kibana', + 'title_link': 'http://localhost:5601/app/discover#/' + } + ], 'username': 'elastalert' + } + mock_post_request.assert_called_once_with( + rule['mattermost_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + verify=True, + proxies=None + ) + + actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) + print(actual_data) + assert expected_data == actual_data + + +def test_mattermost_kibana_discover_color(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'alert_text_type': 'alert_text_only', + 'mattermost_attach_kibana_discover_url': True, + 'mattermost_kibana_discover_color': 'blue', + 'mattermost_webhook_url': 'http://please.dontgohere.mattermost', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = MattermostAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'kibana_discover_url': 'http://localhost:5601/app/discover#/' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'attachments': [ + { + 'fallback': 'Test Rule: ', + 'color': 'danger', + 'title': 'Test Rule', + 'pretext': '', + 'fields': [], + 'text': 'Test Rule\n\n' + }, + { + 'color': 'blue', + 'title': 'Discover in Kibana', + 'title_link': 'http://localhost:5601/app/discover#/' + } + ], 'username': 'elastalert' + } + mock_post_request.assert_called_once_with( + rule['mattermost_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + verify=True, + proxies=None + ) + + actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) + print(actual_data) + assert expected_data == actual_data From 69eaf9b9eb2e85868e5d692b4e9a8e6d5dfd7baf Mon Sep 17 00:00:00 2001 From: nsano-rururu Date: Sun, 6 Jun 2021 17:49:50 +0900 Subject: [PATCH 2/5] Remove mattermost_msg_fields from schema.yaml --- elastalert/schema.yaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/elastalert/schema.yaml b/elastalert/schema.yaml index 8528a516..960706d5 100644 --- a/elastalert/schema.yaml +++ b/elastalert/schema.yaml @@ -36,15 +36,6 @@ definitions: filter: &filter {} - mattermostField: &mattermostField - type: object - additionalProperties: false - properties: - title: {type: string} - value: {type: string} - args: *arrayOfString - short: {type: boolean} - required: [type, index, alert] type: object @@ -397,7 +388,6 @@ properties: mattermost_icon_url_override: {type: string} mattermost_msg_pretext: {type: string} mattermost_msg_color: {enum: [good, warning, danger]} - mattermost_msg_fields: *mattermostField mattermost_title_link: {type: string} mattermost_footer: {type: string} mattermost_footer_icon: {type: string} From f29d96350396634a7b9aa21109c25221cda88142 Mon Sep 17 00:00:00 2001 From: nsano-rururu Date: Sun, 6 Jun 2021 17:57:17 +0900 Subject: [PATCH 3/5] fix testcode --- tests/alerters/mattermost_test.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/alerters/mattermost_test.py b/tests/alerters/mattermost_test.py index 1fa81b9a..18b39369 100644 --- a/tests/alerters/mattermost_test.py +++ b/tests/alerters/mattermost_test.py @@ -951,7 +951,6 @@ def test_mattermost_attach_kibana_discover_url_when_generated(): ) actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - print(actual_data) assert expected_data == actual_data @@ -994,7 +993,6 @@ def test_mattermost_attach_kibana_discover_url_when_not_generated(): ) actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - print(actual_data) assert expected_data == actual_data @@ -1044,7 +1042,6 @@ def test_mattermost_kibana_discover_title(): ) actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - print(actual_data) assert expected_data == actual_data @@ -1094,7 +1091,4 @@ def test_mattermost_kibana_discover_color(): ) actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - print(actual_data) assert expected_data == actual_data - except Exception as ea: - assert expected_data in str(ea) From c8a6af5bed0ba865e12a50f5adf82e75250fb100 Mon Sep 17 00:00:00 2001 From: nsano-rururu Date: Sun, 6 Jun 2021 19:11:37 +0900 Subject: [PATCH 4/5] Fix schema.yaml --- elastalert/schema.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/elastalert/schema.yaml b/elastalert/schema.yaml index 960706d5..bae822b0 100644 --- a/elastalert/schema.yaml +++ b/elastalert/schema.yaml @@ -34,6 +34,19 @@ definitions: milliseconds: {type: number} schedule: {type: string} + mattermostField: &mattermostField + type: object + additionalProperties: false + properties: + title: {type: string} + value: {type: string} + args: *arrayOfString + short: {type: boolean} + + arrayOfMattermostFields: &arrayOfMattermostField + type: array + items: *mattermostField + filter: &filter {} required: [type, index, alert] @@ -388,6 +401,7 @@ properties: mattermost_icon_url_override: {type: string} mattermost_msg_pretext: {type: string} mattermost_msg_color: {enum: [good, warning, danger]} + mattermost_msg_fields: *arrayOfMattermostField mattermost_title_link: {type: string} mattermost_footer: {type: string} mattermost_footer_icon: {type: string} From 7fb672a6c88f842568cdc5f893a913efcf956fc2 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Sun, 6 Jun 2021 06:21:01 -0400 Subject: [PATCH 5/5] Add PR 239 --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee6decd5..c37cdef6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,8 @@ - Add support for Elasticsearch API key authentication - [#208](https://github.com/jertel/elastalert2/pull/208) - @vbisserie - Add support for Elasticsearch 7.13 for building Kibana Discover URLs - [#212](https://github.com/jertel/elastalert2/pull/212) - @nsano-rururu - Follow symbolic links when traversing rules folder for rule files - [#214](https://github.com/jertel/elastalert2/pull/214) - @vbisserie -- Support optional suppression of SSL log warnings when http-posting alerts - [#222](https://github.com/jertel/elastalert2/pull/222/files) - @nsano-rururu +- Support optional suppression of SSL log warnings when http-posting alerts - [#222](https://github.com/jertel/elastalert2/pull/222) - @nsano-rururu +- Add support for inclusion of Kibana Discover URLs in MatterMost messages - [#239](https://github.com/jertel/elastalert2/pull/239) - @nsano-rururu ## Other changes - Speed up unit tests by adding default parallelism - [#164](https://github.com/jertel/elastalert2/pull/164) - @ferozsalam @@ -46,7 +47,8 @@ - Migrate away from external test mock dependency - [#233](https://github.com/jertel/elastalert2/pull/233) - @nsano-rururu - Improve ElastAlert 2 documentation relating to running scenarios - [#234](https://github.com/jertel/elastalert2/pull/234) - @ferozsalam - Improve test coverage and correct dict lookup syntax for alerter init functions - [#235](https://github.com/jertel/elastalert2/pull/235) - @nsano-rururu - +- Fix schema bug with MatterMost alerts - [#239](https://github.com/jertel/elastalert2/pull/239) - @nsano-rururu +- # 2.1.0 ## Breaking changes