elastalert2 2.28.0__tar.gz → 2.30.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {elastalert2-2.28.0/elastalert2.egg-info → elastalert2-2.30.0}/PKG-INFO +14 -13
- {elastalert2-2.28.0 → elastalert2-2.30.0}/README.md +1 -1
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/datadog.py +2 -4
- elastalert2-2.30.0/elastalert/alerters/sqs.py +83 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerts.py +24 -9
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/elastalert.py +2 -2
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/loaders.py +2 -2
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/schema.yaml +19 -28
- {elastalert2-2.28.0 → elastalert2-2.30.0/elastalert2.egg-info}/PKG-INFO +14 -13
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert2.egg-info/SOURCES.txt +2 -2
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert2.egg-info/requires.txt +12 -11
- {elastalert2-2.28.0 → elastalert2-2.30.0}/setup.py +13 -12
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/datadog_test.py +67 -0
- elastalert2-2.30.0/tests/alerters/sqs_test.py +224 -0
- elastalert2-2.28.0/elastalert/alerters/teams.py +0 -120
- elastalert2-2.28.0/tests/alerters/teams_test.py +0 -650
- {elastalert2-2.28.0 → elastalert2-2.30.0}/LICENSE +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/__init__.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/__init__.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/alerta.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/alertmanager.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/chatwork.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/command.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/debug.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/dingtalk.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/discord.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/email.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/exotel.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/flashduty.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/gelf.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/gitter.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/googlechat.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/httppost.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/httppost2.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/indexer.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/iris.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/jira.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/lark.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/line.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/matrixhookshot.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/mattermost.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/opsgenie.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/pagerduty.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/pagertree.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/powerautomate.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/rocketchat.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/servicenow.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/ses.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/slack.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/smseagle.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/sns.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/stomp.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/telegram.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/tencentsms.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/thehive.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/twilio.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/victorops.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/webex_webhook.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/workwechat.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/yzj.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/alerters/zabbix.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/auth.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/config.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/create_index.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/enhancements.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/eql.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/7/elastalert.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/7/elastalert_error.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/7/elastalert_status.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/7/past_elastalert.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/7/silence.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/8/elastalert.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/8/elastalert_error.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/8/elastalert_status.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/8/past_elastalert.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/es_mappings/8/silence.json +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/kibana_discover.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/kibana_external_url_formatter.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/opensearch_discover.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/opensearch_external_url_formatter.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/prometheus_wrapper.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/ruletypes.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/test_rule.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/util.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert/yaml.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert2.egg-info/dependency_links.txt +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert2.egg-info/entry_points.txt +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/elastalert2.egg-info/top_level.txt +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/setup.cfg +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/__init__.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/alerta_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/alertmanager_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/chatwork_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/command_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/debug_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/dingtalk_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/discord_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/email_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/exotel_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/flashduty_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/gelf_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/gitter_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/googlechat_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/httppost2_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/httppost_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/indexer_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/iris_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/jira_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/lark_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/line_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/matrixhookshot_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/mattermost_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/opsgenie_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/pagerduty_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/pagertree_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/powerautomate_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/rocketchat_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/servicenow_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/ses_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/slack_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/smseagle_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/sns_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/stomp_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/telegram_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/tencentsms_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/thehive_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/twilio_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/victorops_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/webex_webhook_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/workwechat_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/yzj_test.py +0 -0
- {elastalert2-2.28.0 → elastalert2-2.30.0}/tests/alerters/zabbix_test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elastalert2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.30.0
|
|
4
4
|
Summary: Automated rule-based alerting for Elasticsearch
|
|
5
5
|
Home-page: https://github.com/jertel/elastalert2
|
|
6
6
|
License: Apache 2.0
|
|
@@ -15,31 +15,32 @@ Classifier: Operating System :: OS Independent
|
|
|
15
15
|
Requires-Python: >=3.12
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: apscheduler<4.0,>=3.11.
|
|
18
|
+
Requires-Dist: apscheduler<4.0,>=3.11.2
|
|
19
19
|
Requires-Dist: aws-requests-auth>=0.4.3
|
|
20
|
-
Requires-Dist: boto3>=1.
|
|
20
|
+
Requires-Dist: boto3>=1.42.89
|
|
21
21
|
Requires-Dist: cffi>=2.0.0
|
|
22
|
-
Requires-Dist: croniter>=6.
|
|
22
|
+
Requires-Dist: croniter>=6.2.2
|
|
23
23
|
Requires-Dist: elasticsearch==7.10.1
|
|
24
24
|
Requires-Dist: envparse>=0.2.0
|
|
25
25
|
Requires-Dist: exotel==0.1.5
|
|
26
26
|
Requires-Dist: Jinja2>=3.1.6
|
|
27
27
|
Requires-Dist: jira>=3.10.5
|
|
28
|
-
Requires-Dist: jsonpointer>=3.
|
|
29
|
-
Requires-Dist: jsonschema>=4.
|
|
30
|
-
Requires-Dist: prettytable>=3.
|
|
28
|
+
Requires-Dist: jsonpointer>=3.1.1
|
|
29
|
+
Requires-Dist: jsonschema>=4.26.0
|
|
30
|
+
Requires-Dist: prettytable>=3.17.0
|
|
31
31
|
Requires-Dist: prison>=0.2.1
|
|
32
|
-
Requires-Dist:
|
|
32
|
+
Requires-Dist: prometheus-client>=0.25.0
|
|
33
33
|
Requires-Dist: python-dateutil>=2.9.0.post0
|
|
34
|
+
Requires-Dist: pytz>=2026.1.post1
|
|
34
35
|
Requires-Dist: PyYAML>=6.0.3
|
|
35
|
-
Requires-Dist: zabbix-utils>=2.0.
|
|
36
|
-
Requires-Dist: requests>=2.
|
|
36
|
+
Requires-Dist: zabbix-utils>=2.0.4
|
|
37
|
+
Requires-Dist: requests>=2.33.1
|
|
37
38
|
Requires-Dist: sortedcontainers>=2.4.0
|
|
38
39
|
Requires-Dist: statsd-tags==3.2.1.post1
|
|
39
40
|
Requires-Dist: stomp.py>=8.2.0
|
|
40
|
-
Requires-Dist: tencentcloud-sdk-python>=3.
|
|
41
|
+
Requires-Dist: tencentcloud-sdk-python>=3.1.79
|
|
41
42
|
Requires-Dist: texttable>=1.7.0
|
|
42
|
-
Requires-Dist: twilio>=9.
|
|
43
|
+
Requires-Dist: twilio>=9.10.5
|
|
43
44
|
Dynamic: classifier
|
|
44
45
|
Dynamic: description
|
|
45
46
|
Dynamic: description-content-type
|
|
@@ -85,7 +86,7 @@ See our [security policy][13] for reporting urgent vulnerabilities.
|
|
|
85
86
|
|
|
86
87
|
ElastAlert 2 is licensed under the [Apache License, Version 2.0][5].
|
|
87
88
|
|
|
88
|
-
[0]: https://github.com/
|
|
89
|
+
[0]: https://github.com/YelpArchive/elastalert
|
|
89
90
|
[1]: https://github.com/jertel/elastalert2/blob/master/examples/config.yaml.example
|
|
90
91
|
[2]: https://hub.docker.com/r/jertel/elastalert2
|
|
91
92
|
[3]: https://elastalert2.readthedocs.io/
|
|
@@ -32,7 +32,7 @@ See our [security policy][13] for reporting urgent vulnerabilities.
|
|
|
32
32
|
|
|
33
33
|
ElastAlert 2 is licensed under the [Apache License, Version 2.0][5].
|
|
34
34
|
|
|
35
|
-
[0]: https://github.com/
|
|
35
|
+
[0]: https://github.com/YelpArchive/elastalert
|
|
36
36
|
[1]: https://github.com/jertel/elastalert2/blob/master/examples/config.yaml.example
|
|
37
37
|
[2]: https://hub.docker.com/r/jertel/elastalert2
|
|
38
38
|
[3]: https://elastalert2.readthedocs.io/
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
|
-
|
|
3
2
|
import requests
|
|
4
3
|
from requests import RequestException
|
|
5
|
-
|
|
6
4
|
from elastalert.alerts import Alerter, DateTimeEncoder
|
|
7
5
|
from elastalert.util import EAException, elastalert_logger
|
|
8
6
|
|
|
@@ -15,9 +13,9 @@ class DatadogAlerter(Alerter):
|
|
|
15
13
|
super(DatadogAlerter, self).__init__(rule)
|
|
16
14
|
self.dd_api_key = self.rule.get('datadog_api_key', None)
|
|
17
15
|
self.dd_app_key = self.rule.get('datadog_app_key', None)
|
|
16
|
+
self.dd_api_url = self.rule.get('datadog_api_url', 'https://api.datadoghq.com/api/v1/events')
|
|
18
17
|
|
|
19
18
|
def alert(self, matches):
|
|
20
|
-
url = 'https://api.datadoghq.com/api/v1/events'
|
|
21
19
|
headers = {
|
|
22
20
|
'Content-Type': 'application/json',
|
|
23
21
|
'DD-API-KEY': self.dd_api_key,
|
|
@@ -28,7 +26,7 @@ class DatadogAlerter(Alerter):
|
|
|
28
26
|
'text': self.create_alert_body(matches)
|
|
29
27
|
}
|
|
30
28
|
try:
|
|
31
|
-
response = requests.post(
|
|
29
|
+
response = requests.post(self.dd_api_url, data=json.dumps(payload, cls=DateTimeEncoder), headers=headers)
|
|
32
30
|
response.raise_for_status()
|
|
33
31
|
except RequestException as e:
|
|
34
32
|
raise EAException('Error posting event to Datadog: %s' % e)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import boto3
|
|
2
|
+
import json
|
|
3
|
+
from urllib.parse import urlparse
|
|
4
|
+
|
|
5
|
+
from elastalert.alerts import Alerter
|
|
6
|
+
from elastalert.util import elastalert_logger, EAException
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _get_region_from_sqs_url(queue_url, default_region="us-east-1"):
|
|
10
|
+
"""Infer the AWS region from an SQS queue URL like
|
|
11
|
+
https://sqs.us-east-1.amazonaws.com/123456789012/my-queue.
|
|
12
|
+
Falls back to default_region if it cannot be determined.
|
|
13
|
+
"""
|
|
14
|
+
host = urlparse(queue_url).hostname or ""
|
|
15
|
+
parts = host.split(".")
|
|
16
|
+
if len(parts) >= 3 and parts[0] == "sqs":
|
|
17
|
+
return parts[1]
|
|
18
|
+
return default_region
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SqsAlerter(Alerter):
|
|
22
|
+
"""Send alert using AWS SQS service"""
|
|
23
|
+
|
|
24
|
+
required_options = frozenset(["sqs_queue_url"])
|
|
25
|
+
|
|
26
|
+
def __init__(self, *args):
|
|
27
|
+
super(SqsAlerter, self).__init__(*args)
|
|
28
|
+
self.sqs_queue_url = self.rule.get("sqs_queue_url", None)
|
|
29
|
+
self.sqs_aws_access_key_id = self.rule.get("sqs_aws_access_key_id")
|
|
30
|
+
self.sqs_aws_secret_access_key = self.rule.get("sqs_aws_secret_access_key")
|
|
31
|
+
explicit_region = self.rule.get("sqs_aws_region")
|
|
32
|
+
if explicit_region:
|
|
33
|
+
self.sqs_aws_region = explicit_region
|
|
34
|
+
else:
|
|
35
|
+
# If no region is configured explicitly, derive it from the queue URL.
|
|
36
|
+
self.sqs_aws_region = _get_region_from_sqs_url(self.sqs_queue_url or "")
|
|
37
|
+
self.profile = self.rule.get("sqs_aws_profile", None)
|
|
38
|
+
|
|
39
|
+
def alert(self, matches):
|
|
40
|
+
# Create the alert as a JSON object
|
|
41
|
+
alert_data = {
|
|
42
|
+
"rule_name": self.rule["name"],
|
|
43
|
+
"matches": matches,
|
|
44
|
+
}
|
|
45
|
+
alert_text = self.create_alert_body(matches)
|
|
46
|
+
# SQS message body limit is 1 MB; crop text at ~800KB to be safe
|
|
47
|
+
if len(alert_text) > 800000:
|
|
48
|
+
alert_text = alert_text[:800000]
|
|
49
|
+
alert_text += "\n*message was cropped according to SQS limits!*"
|
|
50
|
+
alert_data["text"] = alert_text
|
|
51
|
+
body = json.dumps(alert_data, default=str)
|
|
52
|
+
|
|
53
|
+
# If the body is still too long, remove the text field
|
|
54
|
+
if len(body) > 1048576:
|
|
55
|
+
alert_data["text"] = "Text message omitted due to SQS size limit."
|
|
56
|
+
body = json.dumps(alert_data, default=str)
|
|
57
|
+
try:
|
|
58
|
+
# Always create the session in the configured region. SQS does not
|
|
59
|
+
# infer the region from the queue URL; the client region must match.
|
|
60
|
+
if self.profile is None:
|
|
61
|
+
session = boto3.Session(
|
|
62
|
+
aws_access_key_id=self.sqs_aws_access_key_id,
|
|
63
|
+
aws_secret_access_key=self.sqs_aws_secret_access_key,
|
|
64
|
+
region_name=self.sqs_aws_region,
|
|
65
|
+
)
|
|
66
|
+
else:
|
|
67
|
+
session = boto3.Session(
|
|
68
|
+
profile_name=self.profile,
|
|
69
|
+
region_name=self.sqs_aws_region,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
sqs_client = session.client("sqs")
|
|
73
|
+
|
|
74
|
+
response = sqs_client.send_message(
|
|
75
|
+
QueueUrl=self.sqs_queue_url,
|
|
76
|
+
MessageBody=body,
|
|
77
|
+
)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
raise EAException("Error sending Amazon SQS: %s" % e)
|
|
80
|
+
elastalert_logger.info("Sent Amazon SQS message to %s, MessageId: %s" % (self.sqs_queue_url, response.get("MessageId")))
|
|
81
|
+
|
|
82
|
+
def get_info(self):
|
|
83
|
+
return {"type": "sqs"}
|
|
@@ -256,10 +256,25 @@ class Alerter(object):
|
|
|
256
256
|
if not isinstance(summary_table_fields, list):
|
|
257
257
|
summary_table_fields = [summary_table_fields]
|
|
258
258
|
|
|
259
|
+
# Each entry is either a string field path, or a dict with required 'path' and optional 'header'.
|
|
260
|
+
# Split into parallel lists so paths drive lookups/logging while headers drive rendered column names.
|
|
261
|
+
summary_table_paths = []
|
|
262
|
+
summary_table_headers = []
|
|
263
|
+
for entry in summary_table_fields:
|
|
264
|
+
if isinstance(entry, dict):
|
|
265
|
+
path = entry['path']
|
|
266
|
+
header = entry.get('header', path)
|
|
267
|
+
else:
|
|
268
|
+
path = entry
|
|
269
|
+
header = entry
|
|
270
|
+
summary_table_paths.append(path)
|
|
271
|
+
summary_table_headers.append(header)
|
|
272
|
+
|
|
259
273
|
# Include a count aggregation so that we can see at a glance how many of each aggregation_key were encountered
|
|
260
|
-
|
|
274
|
+
summary_table_paths_with_count = summary_table_paths + ['count']
|
|
275
|
+
summary_table_headers_with_count = summary_table_headers + ['count']
|
|
261
276
|
text += "Aggregation resulted in the following data for summary_table_fields ==> {0}:\n\n".format(
|
|
262
|
-
|
|
277
|
+
summary_table_paths_with_count
|
|
263
278
|
)
|
|
264
279
|
|
|
265
280
|
# Prepare match_aggregation used in both table types
|
|
@@ -267,7 +282,7 @@ class Alerter(object):
|
|
|
267
282
|
|
|
268
283
|
# Maintain an aggregate count for each unique key encountered in the aggregation period
|
|
269
284
|
for match in matches:
|
|
270
|
-
key_tuple = tuple([str(lookup_es_key(match, key)) for key in
|
|
285
|
+
key_tuple = tuple([str(lookup_es_key(match, key)) for key in summary_table_paths])
|
|
271
286
|
if key_tuple not in match_aggregation:
|
|
272
287
|
match_aggregation[key_tuple] = 1
|
|
273
288
|
else:
|
|
@@ -281,9 +296,9 @@ class Alerter(object):
|
|
|
281
296
|
# Type dependent table style
|
|
282
297
|
if summary_table_type == 'ascii':
|
|
283
298
|
text_table = Texttable(max_width=self.get_aggregation_summary_text__maximum_width())
|
|
284
|
-
text_table.header(
|
|
299
|
+
text_table.header(summary_table_headers_with_count)
|
|
285
300
|
# Format all fields as 'text' to avoid long numbers being shown as scientific notation
|
|
286
|
-
text_table.set_cols_dtype(['t' for i in
|
|
301
|
+
text_table.set_cols_dtype(['t' for i in summary_table_headers_with_count])
|
|
287
302
|
|
|
288
303
|
for keys, count in match_aggregation.items():
|
|
289
304
|
text_table.add_row([key for key in keys] + [count])
|
|
@@ -292,9 +307,9 @@ class Alerter(object):
|
|
|
292
307
|
elif summary_table_type == 'markdown':
|
|
293
308
|
# Adapted from https://github.com/codazoda/tomark/blob/master/tomark/tomark.py
|
|
294
309
|
# Create table header
|
|
295
|
-
text += '| ' + ' | '.join(map(str,
|
|
310
|
+
text += '| ' + ' | '.join(map(str, summary_table_headers_with_count)) + ' |\n'
|
|
296
311
|
# Create header separator
|
|
297
|
-
text += '|-----' * len(
|
|
312
|
+
text += '|-----' * len(summary_table_headers_with_count) + '|\n'
|
|
298
313
|
# Create table row
|
|
299
314
|
for keys, count in match_aggregation.items():
|
|
300
315
|
markdown_row = ""
|
|
@@ -302,12 +317,12 @@ class Alerter(object):
|
|
|
302
317
|
markdown_row += '| ' + str(key) + ' '
|
|
303
318
|
text += markdown_row + '| ' + str(count) + ' |\n'
|
|
304
319
|
text += '\n'
|
|
305
|
-
|
|
320
|
+
|
|
306
321
|
elif summary_table_type == 'html':
|
|
307
322
|
# Portions of the following block of HTML formatting code was taken from
|
|
308
323
|
# an abandoned PR (https://github.com/jertel/elastalert2/pull/1227).
|
|
309
324
|
text_table = PrettyTable()
|
|
310
|
-
text_table.field_names =
|
|
325
|
+
text_table.field_names = summary_table_headers_with_count
|
|
311
326
|
text_table.set_style(TableStyle.MSWORD_FRIENDLY)
|
|
312
327
|
text_table.border = True
|
|
313
328
|
text_table.header = True
|
|
@@ -1606,7 +1606,7 @@ class ElastAlerter(object):
|
|
|
1606
1606
|
|
|
1607
1607
|
# Delete it from the index
|
|
1608
1608
|
try:
|
|
1609
|
-
self.writeback_es.
|
|
1609
|
+
self.writeback_es.delete_by_query(index=self.writeback_index, body={'query': {'term': {'_id': _id}}})
|
|
1610
1610
|
except ElasticsearchException: # TODO: Give this a more relevant exception, try:except: is evil.
|
|
1611
1611
|
self.handle_error("Failed to delete alert %s at %s" % (_id, alert_time))
|
|
1612
1612
|
|
|
@@ -1640,7 +1640,7 @@ class ElastAlerter(object):
|
|
|
1640
1640
|
size=self.max_aggregation)
|
|
1641
1641
|
for match in res['hits']['hits']:
|
|
1642
1642
|
matches.append(match['_source'])
|
|
1643
|
-
self.writeback_es.
|
|
1643
|
+
self.writeback_es.delete_by_query(index=self.writeback_index, body={'query': {'term': {'_id': match['_id']}}})
|
|
1644
1644
|
except (KeyError, ElasticsearchException) as e:
|
|
1645
1645
|
self.handle_error("Error fetching aggregated matches: %s" % (e), {'id': _id})
|
|
1646
1646
|
return matches
|
|
@@ -52,7 +52,7 @@ from elastalert.alerters.pagerduty import PagerDutyAlerter
|
|
|
52
52
|
from elastalert.alerters.slack import SlackAlerter
|
|
53
53
|
from elastalert.alerters.smseagle import SMSEagleAlerter
|
|
54
54
|
from elastalert.alerters.sns import SnsAlerter
|
|
55
|
-
from elastalert.alerters.
|
|
55
|
+
from elastalert.alerters.sqs import SqsAlerter
|
|
56
56
|
from elastalert.alerters.powerautomate import MsPowerAutomateAlerter
|
|
57
57
|
from elastalert.alerters.yzj import YzjAlerter
|
|
58
58
|
from elastalert.alerters.zabbix import ZabbixAlerter
|
|
@@ -115,7 +115,7 @@ class RulesLoader(object):
|
|
|
115
115
|
'debug': elastalert.alerters.debug.DebugAlerter,
|
|
116
116
|
'command': elastalert.alerters.command.CommandAlerter,
|
|
117
117
|
'sns': SnsAlerter,
|
|
118
|
-
'
|
|
118
|
+
'sqs': SqsAlerter,
|
|
119
119
|
'ms_power_automate': MsPowerAutomateAlerter,
|
|
120
120
|
'slack': SlackAlerter,
|
|
121
121
|
'mattermost': MattermostAlerter,
|
|
@@ -51,13 +51,6 @@ definitions:
|
|
|
51
51
|
type: array
|
|
52
52
|
items: *slackField
|
|
53
53
|
|
|
54
|
-
msTeamsFact: &msTeamsFact
|
|
55
|
-
type: object
|
|
56
|
-
additionalProperties: false
|
|
57
|
-
properties:
|
|
58
|
-
name: {type: string}
|
|
59
|
-
value: {type: string}
|
|
60
|
-
|
|
61
54
|
msPowerAutomateFact: &msPowerAutomateFact
|
|
62
55
|
type: object
|
|
63
56
|
additionalProperties: false
|
|
@@ -65,10 +58,6 @@ definitions:
|
|
|
65
58
|
name: {type: string}
|
|
66
59
|
value: {type: string}
|
|
67
60
|
|
|
68
|
-
arrayOfMsTeamsFacts: &arrayOfMsTeamsFacts
|
|
69
|
-
type: array
|
|
70
|
-
items: *msTeamsFact
|
|
71
|
-
|
|
72
61
|
arrayOfMsPowerAutomateFacts: &arrayOfMsPowerAutomateFacts
|
|
73
62
|
type: array
|
|
74
63
|
items: *msPowerAutomateFact
|
|
@@ -319,7 +308,17 @@ properties:
|
|
|
319
308
|
notify_all_errors: {type: boolean}
|
|
320
309
|
|
|
321
310
|
### summary table
|
|
322
|
-
summary_table_fields:
|
|
311
|
+
summary_table_fields:
|
|
312
|
+
type: array
|
|
313
|
+
items:
|
|
314
|
+
oneOf:
|
|
315
|
+
- type: string
|
|
316
|
+
- type: object
|
|
317
|
+
additionalProperties: false
|
|
318
|
+
required: [path]
|
|
319
|
+
properties:
|
|
320
|
+
path: {type: string, minLength: 1}
|
|
321
|
+
header: {type: string}
|
|
323
322
|
summary_table_type: {type: string, enum: ['ascii', 'html', 'markdown']}
|
|
324
323
|
summary_table_max_rows: {type: integer, minimum: 0}
|
|
325
324
|
summary_prefix: {type: string}
|
|
@@ -445,6 +444,13 @@ properties:
|
|
|
445
444
|
sns_aws_region: {type: string}
|
|
446
445
|
sns_aws_profile: {type: string}
|
|
447
446
|
|
|
447
|
+
### AWS SQS
|
|
448
|
+
sqs_queue_url: {type: string}
|
|
449
|
+
sqs_aws_access_key_id: {type: string}
|
|
450
|
+
sqs_aws_secret_access_key: {type: string}
|
|
451
|
+
sqs_aws_region: {type: string}
|
|
452
|
+
sqs_aws_profile: {type: string}
|
|
453
|
+
|
|
448
454
|
### Chatwork
|
|
449
455
|
chatwork_apikey: {type: string}
|
|
450
456
|
chatwork_room_id: {type: string}
|
|
@@ -461,6 +467,7 @@ properties:
|
|
|
461
467
|
### Datadog
|
|
462
468
|
datadog_api_key: {type: string}
|
|
463
469
|
datadog_app_key: {type: string}
|
|
470
|
+
datadog_api_url: {type: string}
|
|
464
471
|
|
|
465
472
|
### Dingtalk
|
|
466
473
|
dingtalk_access_token: {type: string}
|
|
@@ -703,22 +710,6 @@ properties:
|
|
|
703
710
|
mattermost_opensearch_discover_color: {type: string}
|
|
704
711
|
mattermost_opensearch_discover_title: {type: string}
|
|
705
712
|
|
|
706
|
-
|
|
707
|
-
### Microsoft Teams
|
|
708
|
-
ms_teams_webhook_url: *arrayOfString
|
|
709
|
-
ms_teams_alert_summary: {type: string}
|
|
710
|
-
ms_teams_theme_color: {type: string}
|
|
711
|
-
ms_teams_proxy: {type: string}
|
|
712
|
-
ms_teams_alert_fixed_width: {type: boolean}
|
|
713
|
-
ms_teams_alert_facts: *arrayOfMsTeamsFacts
|
|
714
|
-
ms_teams_attach_kibana_discover_url: {type: boolean}
|
|
715
|
-
ms_teams_kibana_discover_title: {type: string}
|
|
716
|
-
ms_teams_ca_certs: {type: [boolean, string]}
|
|
717
|
-
ms_teams_ignore_ssl_errors: {type: boolean}
|
|
718
|
-
ms_teams_attach_opensearch_discover_url: {type: boolean}
|
|
719
|
-
ms_teams_opensearch_discover_title: {type: string}
|
|
720
|
-
|
|
721
|
-
|
|
722
713
|
### Microsoft Power Automate
|
|
723
714
|
ms_power_automate_webhook_url: *arrayOfString
|
|
724
715
|
ms_power_automate_webhook_url_from_field: { type: string }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elastalert2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.30.0
|
|
4
4
|
Summary: Automated rule-based alerting for Elasticsearch
|
|
5
5
|
Home-page: https://github.com/jertel/elastalert2
|
|
6
6
|
License: Apache 2.0
|
|
@@ -15,31 +15,32 @@ Classifier: Operating System :: OS Independent
|
|
|
15
15
|
Requires-Python: >=3.12
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: apscheduler<4.0,>=3.11.
|
|
18
|
+
Requires-Dist: apscheduler<4.0,>=3.11.2
|
|
19
19
|
Requires-Dist: aws-requests-auth>=0.4.3
|
|
20
|
-
Requires-Dist: boto3>=1.
|
|
20
|
+
Requires-Dist: boto3>=1.42.89
|
|
21
21
|
Requires-Dist: cffi>=2.0.0
|
|
22
|
-
Requires-Dist: croniter>=6.
|
|
22
|
+
Requires-Dist: croniter>=6.2.2
|
|
23
23
|
Requires-Dist: elasticsearch==7.10.1
|
|
24
24
|
Requires-Dist: envparse>=0.2.0
|
|
25
25
|
Requires-Dist: exotel==0.1.5
|
|
26
26
|
Requires-Dist: Jinja2>=3.1.6
|
|
27
27
|
Requires-Dist: jira>=3.10.5
|
|
28
|
-
Requires-Dist: jsonpointer>=3.
|
|
29
|
-
Requires-Dist: jsonschema>=4.
|
|
30
|
-
Requires-Dist: prettytable>=3.
|
|
28
|
+
Requires-Dist: jsonpointer>=3.1.1
|
|
29
|
+
Requires-Dist: jsonschema>=4.26.0
|
|
30
|
+
Requires-Dist: prettytable>=3.17.0
|
|
31
31
|
Requires-Dist: prison>=0.2.1
|
|
32
|
-
Requires-Dist:
|
|
32
|
+
Requires-Dist: prometheus-client>=0.25.0
|
|
33
33
|
Requires-Dist: python-dateutil>=2.9.0.post0
|
|
34
|
+
Requires-Dist: pytz>=2026.1.post1
|
|
34
35
|
Requires-Dist: PyYAML>=6.0.3
|
|
35
|
-
Requires-Dist: zabbix-utils>=2.0.
|
|
36
|
-
Requires-Dist: requests>=2.
|
|
36
|
+
Requires-Dist: zabbix-utils>=2.0.4
|
|
37
|
+
Requires-Dist: requests>=2.33.1
|
|
37
38
|
Requires-Dist: sortedcontainers>=2.4.0
|
|
38
39
|
Requires-Dist: statsd-tags==3.2.1.post1
|
|
39
40
|
Requires-Dist: stomp.py>=8.2.0
|
|
40
|
-
Requires-Dist: tencentcloud-sdk-python>=3.
|
|
41
|
+
Requires-Dist: tencentcloud-sdk-python>=3.1.79
|
|
41
42
|
Requires-Dist: texttable>=1.7.0
|
|
42
|
-
Requires-Dist: twilio>=9.
|
|
43
|
+
Requires-Dist: twilio>=9.10.5
|
|
43
44
|
Dynamic: classifier
|
|
44
45
|
Dynamic: description
|
|
45
46
|
Dynamic: description-content-type
|
|
@@ -85,7 +86,7 @@ See our [security policy][13] for reporting urgent vulnerabilities.
|
|
|
85
86
|
|
|
86
87
|
ElastAlert 2 is licensed under the [Apache License, Version 2.0][5].
|
|
87
88
|
|
|
88
|
-
[0]: https://github.com/
|
|
89
|
+
[0]: https://github.com/YelpArchive/elastalert
|
|
89
90
|
[1]: https://github.com/jertel/elastalert2/blob/master/examples/config.yaml.example
|
|
90
91
|
[2]: https://hub.docker.com/r/jertel/elastalert2
|
|
91
92
|
[3]: https://elastalert2.readthedocs.io/
|
|
@@ -55,8 +55,8 @@ elastalert/alerters/ses.py
|
|
|
55
55
|
elastalert/alerters/slack.py
|
|
56
56
|
elastalert/alerters/smseagle.py
|
|
57
57
|
elastalert/alerters/sns.py
|
|
58
|
+
elastalert/alerters/sqs.py
|
|
58
59
|
elastalert/alerters/stomp.py
|
|
59
|
-
elastalert/alerters/teams.py
|
|
60
60
|
elastalert/alerters/telegram.py
|
|
61
61
|
elastalert/alerters/tencentsms.py
|
|
62
62
|
elastalert/alerters/thehive.py
|
|
@@ -116,8 +116,8 @@ tests/alerters/ses_test.py
|
|
|
116
116
|
tests/alerters/slack_test.py
|
|
117
117
|
tests/alerters/smseagle_test.py
|
|
118
118
|
tests/alerters/sns_test.py
|
|
119
|
+
tests/alerters/sqs_test.py
|
|
119
120
|
tests/alerters/stomp_test.py
|
|
120
|
-
tests/alerters/teams_test.py
|
|
121
121
|
tests/alerters/telegram_test.py
|
|
122
122
|
tests/alerters/tencentsms_test.py
|
|
123
123
|
tests/alerters/thehive_test.py
|
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
apscheduler<4.0,>=3.11.
|
|
1
|
+
apscheduler<4.0,>=3.11.2
|
|
2
2
|
aws-requests-auth>=0.4.3
|
|
3
|
-
boto3>=1.
|
|
3
|
+
boto3>=1.42.89
|
|
4
4
|
cffi>=2.0.0
|
|
5
|
-
croniter>=6.
|
|
5
|
+
croniter>=6.2.2
|
|
6
6
|
elasticsearch==7.10.1
|
|
7
7
|
envparse>=0.2.0
|
|
8
8
|
exotel==0.1.5
|
|
9
9
|
Jinja2>=3.1.6
|
|
10
10
|
jira>=3.10.5
|
|
11
|
-
jsonpointer>=3.
|
|
12
|
-
jsonschema>=4.
|
|
13
|
-
prettytable>=3.
|
|
11
|
+
jsonpointer>=3.1.1
|
|
12
|
+
jsonschema>=4.26.0
|
|
13
|
+
prettytable>=3.17.0
|
|
14
14
|
prison>=0.2.1
|
|
15
|
-
|
|
15
|
+
prometheus-client>=0.25.0
|
|
16
16
|
python-dateutil>=2.9.0.post0
|
|
17
|
+
pytz>=2026.1.post1
|
|
17
18
|
PyYAML>=6.0.3
|
|
18
|
-
zabbix-utils>=2.0.
|
|
19
|
-
requests>=2.
|
|
19
|
+
zabbix-utils>=2.0.4
|
|
20
|
+
requests>=2.33.1
|
|
20
21
|
sortedcontainers>=2.4.0
|
|
21
22
|
statsd-tags==3.2.1.post1
|
|
22
23
|
stomp.py>=8.2.0
|
|
23
|
-
tencentcloud-sdk-python>=3.
|
|
24
|
+
tencentcloud-sdk-python>=3.1.79
|
|
24
25
|
texttable>=1.7.0
|
|
25
|
-
twilio>=9.
|
|
26
|
+
twilio>=9.10.5
|
|
@@ -8,7 +8,7 @@ from setuptools import setup
|
|
|
8
8
|
base_dir = os.path.dirname(__file__)
|
|
9
9
|
setup(
|
|
10
10
|
name='elastalert2',
|
|
11
|
-
version='2.
|
|
11
|
+
version='2.30.0',
|
|
12
12
|
description='Automated rule-based alerting for Elasticsearch',
|
|
13
13
|
long_description=open('README.md').read(),
|
|
14
14
|
long_description_content_type="text/markdown",
|
|
@@ -35,30 +35,31 @@ setup(
|
|
|
35
35
|
package_data={'elastalert': ['schema.yaml', 'es_mappings/**/*.json']},
|
|
36
36
|
python_requires='>=3.12',
|
|
37
37
|
install_requires=[
|
|
38
|
-
'apscheduler>=3.11.
|
|
38
|
+
'apscheduler>=3.11.2,<4.0',
|
|
39
39
|
'aws-requests-auth>=0.4.3',
|
|
40
|
-
'boto3>=1.
|
|
40
|
+
'boto3>=1.42.89',
|
|
41
41
|
'cffi>=2.0.0',
|
|
42
|
-
'croniter>=6.
|
|
42
|
+
'croniter>=6.2.2',
|
|
43
43
|
'elasticsearch==7.10.1',
|
|
44
44
|
'envparse>=0.2.0',
|
|
45
45
|
'exotel==0.1.5',
|
|
46
46
|
'Jinja2>=3.1.6',
|
|
47
47
|
'jira>=3.10.5',
|
|
48
|
-
'jsonpointer>=3.
|
|
49
|
-
'jsonschema>=4.
|
|
50
|
-
'prettytable>=3.
|
|
48
|
+
'jsonpointer>=3.1.1',
|
|
49
|
+
'jsonschema>=4.26.0',
|
|
50
|
+
'prettytable>=3.17.0',
|
|
51
51
|
'prison>=0.2.1',
|
|
52
|
-
'
|
|
52
|
+
'prometheus-client>=0.25.0',
|
|
53
53
|
'python-dateutil>=2.9.0.post0',
|
|
54
|
+
'pytz>=2026.1.post1',
|
|
54
55
|
'PyYAML>=6.0.3',
|
|
55
|
-
'zabbix-utils>=2.0.
|
|
56
|
-
'requests>=2.
|
|
56
|
+
'zabbix-utils>=2.0.4',
|
|
57
|
+
'requests>=2.33.1',
|
|
57
58
|
'sortedcontainers>=2.4.0',
|
|
58
59
|
'statsd-tags==3.2.1.post1',
|
|
59
60
|
'stomp.py>=8.2.0',
|
|
60
|
-
'tencentcloud-sdk-python>=3.
|
|
61
|
+
'tencentcloud-sdk-python>=3.1.79',
|
|
61
62
|
'texttable>=1.7.0',
|
|
62
|
-
'twilio>=9.
|
|
63
|
+
'twilio>=9.10.5',
|
|
63
64
|
]
|
|
64
65
|
)
|
|
@@ -49,6 +49,73 @@ def test_datadog_alerter(caplog):
|
|
|
49
49
|
assert ('elastalert', logging.INFO, 'Alert sent to Datadog') == caplog.record_tuples[0]
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
def test_datadog_alerter_custom_api_url(caplog):
|
|
53
|
+
"""datadog_api_url overrides the default endpoint when provided."""
|
|
54
|
+
caplog.set_level(logging.INFO)
|
|
55
|
+
rule = {
|
|
56
|
+
'name': 'Test Datadog Event Alerter',
|
|
57
|
+
'type': 'any',
|
|
58
|
+
'datadog_api_key': 'test-api-key',
|
|
59
|
+
'datadog_app_key': 'test-app-key',
|
|
60
|
+
'datadog_api_url': 'https://api.us5.datadoghq.com/api/v1/events',
|
|
61
|
+
'alert': [],
|
|
62
|
+
'alert_subject': 'Test Datadog Event Alert'
|
|
63
|
+
}
|
|
64
|
+
rules_loader = FileRulesLoader({})
|
|
65
|
+
rules_loader.load_modules(rule)
|
|
66
|
+
alert = DatadogAlerter(rule)
|
|
67
|
+
match = {
|
|
68
|
+
'@timestamp': '2021-01-01T00:00:00',
|
|
69
|
+
'name': 'datadog-test-name'
|
|
70
|
+
}
|
|
71
|
+
with mock.patch('requests.post') as mock_post_request:
|
|
72
|
+
alert.alert([match])
|
|
73
|
+
|
|
74
|
+
mock_post_request.assert_called_once_with(
|
|
75
|
+
'https://api.us5.datadoghq.com/api/v1/events',
|
|
76
|
+
data=mock.ANY,
|
|
77
|
+
headers={
|
|
78
|
+
'Content-Type': 'application/json',
|
|
79
|
+
'DD-API-KEY': rule['datadog_api_key'],
|
|
80
|
+
'DD-APPLICATION-KEY': rule['datadog_app_key']
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
assert ('elastalert', logging.INFO, 'Alert sent to Datadog') == caplog.record_tuples[0]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_datadog_alerter_default_api_url(caplog):
|
|
87
|
+
"""datadog_api_url defaults to the US1 endpoint when not provided."""
|
|
88
|
+
caplog.set_level(logging.INFO)
|
|
89
|
+
rule = {
|
|
90
|
+
'name': 'Test Datadog Event Alerter',
|
|
91
|
+
'type': 'any',
|
|
92
|
+
'datadog_api_key': 'test-api-key',
|
|
93
|
+
'datadog_app_key': 'test-app-key',
|
|
94
|
+
'alert': [],
|
|
95
|
+
'alert_subject': 'Test Datadog Event Alert'
|
|
96
|
+
}
|
|
97
|
+
rules_loader = FileRulesLoader({})
|
|
98
|
+
rules_loader.load_modules(rule)
|
|
99
|
+
alert = DatadogAlerter(rule)
|
|
100
|
+
match = {
|
|
101
|
+
'@timestamp': '2021-01-01T00:00:00',
|
|
102
|
+
'name': 'datadog-test-name'
|
|
103
|
+
}
|
|
104
|
+
with mock.patch('requests.post') as mock_post_request:
|
|
105
|
+
alert.alert([match])
|
|
106
|
+
|
|
107
|
+
mock_post_request.assert_called_once_with(
|
|
108
|
+
'https://api.datadoghq.com/api/v1/events',
|
|
109
|
+
data=mock.ANY,
|
|
110
|
+
headers={
|
|
111
|
+
'Content-Type': 'application/json',
|
|
112
|
+
'DD-API-KEY': rule['datadog_api_key'],
|
|
113
|
+
'DD-APPLICATION-KEY': rule['datadog_app_key']
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
assert ('elastalert', logging.INFO, 'Alert sent to Datadog') == caplog.record_tuples[0]
|
|
117
|
+
|
|
118
|
+
|
|
52
119
|
def test_datadog_ea_exception():
|
|
53
120
|
with pytest.raises(EAException) as ea:
|
|
54
121
|
rule = {
|