Fix notification delivery

This commit is contained in:
Mark Veidemanis 2023-02-10 22:52:59 +00:00
parent df273a6009
commit 87c232d3f9
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
3 changed files with 57 additions and 35 deletions

View File

@ -350,8 +350,8 @@ class ElasticsearchBackend(StorageBackend):
range_query = { range_query = {
"range": { "range": {
"ts": { "ts": {
"gte": f"now-{rule_object.window}/d", "gte": f"now-{rule_object.window}",
"lte": "now/d", "lte": "now",
} }
} }
} }

View File

@ -56,9 +56,11 @@ def webhook_sendmsg(**kwargs):
msg = kwargs.get("msg", None) msg = kwargs.get("msg", None)
notification_settings = kwargs.get("notification_settings") notification_settings = kwargs.get("notification_settings")
url = notification_settings.get("url") url = notification_settings.get("url")
headers = {"Content-type": "application/json"}
try: try:
requests.post( requests.post(
f"{url}", f"{url}",
headers=headers,
data=msg, data=msg,
) )
except requests.exceptions.ConnectionError as e: except requests.exceptions.ConnectionError as e:

View File

@ -9,6 +9,7 @@ except ImportError:
from yaml import Loader, Dumper from yaml import Loader, Dumper
import uuid import uuid
from copy import deepcopy
from datetime import datetime from datetime import datetime
import orjson import orjson
@ -44,14 +45,18 @@ def format_ntfy(**kwargs):
rule: The rule object, must be specified rule: The rule object, must be specified
index: The index the rule matched on, can be None index: The index the rule matched on, can be None
message: The message to send, can be None message: The message to send, can be None
meta:
matched: The matched fields, can be None matched: The matched fields, can be None
total_hits: The total number of matches, optional total_hits: The total number of matches, optional
""" """
rule = kwargs.get("rule") rule = kwargs.get("rule")
index = kwargs.get("index") index = kwargs.get("index")
message = kwargs.get("message") message = kwargs.get("message")
matched = kwargs.get("matched")
total_hits = kwargs.get("total_hits", 0) meta = kwargs.get("meta", {})
total_hits = meta.get("total_hits", 0)
matched = meta.get("matched")
if message: if message:
# Dump the message in YAML for readability # Dump the message in YAML for readability
messages_formatted = "" messages_formatted = ""
@ -88,25 +93,22 @@ def format_webhook(**kwargs):
rule: The rule object, must be specified rule: The rule object, must be specified
index: The index the rule matched on, can be None index: The index the rule matched on, can be None
message: The message to send, can be None, but will be sent as None message: The message to send, can be None, but will be sent as None
meta:
matched: The matched fields, can be None, but will be sent as None matched: The matched fields, can be None, but will be sent as None
total_hits: The total number of matches, optional total_hits: The total number of matches, optional
notification_settings: The notification settings, must be specified notification_settings: The notification settings, must be specified
priority: The priority of the message, optional priority: The priority of the message, optional
topic: The topic of the message, optional topic: The topic of the message, optional
""" """
rule = kwargs.get("rule") # rule = kwargs.get("rule")
index = kwargs.get("index") # index = kwargs.get("index")
message = kwargs.get("message") message = kwargs.get("message")
matched = kwargs.get("matched") meta = kwargs.get("meta")
total_hits = kwargs.get("total_hits", 0)
notification_settings = kwargs.get("notification_settings") notification_settings = kwargs.get("notification_settings")
notify_message = { notify_message = {
"rule_id": rule.id,
"rule_name": rule.name,
"matched": matched,
"total_hits": total_hits,
"index": index,
"data": message, "data": message,
"meta": meta,
} }
if "priority" in notification_settings: if "priority" in notification_settings:
notify_message["priority"] = notification_settings["priority"] notify_message["priority"] = notification_settings["priority"]
@ -144,20 +146,23 @@ def rule_notify(rule, index, message, meta=None):
# Don't send anything # Don't send anything
return return
# double sigh
message_copy = deepcopy(message)
for index, _ in enumerate(message_copy):
if "meta" in message_copy[index]:
del message_copy[index]["meta"]
# Create a cast we can reuse for the formatting helpers and sendmsg # Create a cast we can reuse for the formatting helpers and sendmsg
cast = { cast = {
"title": title, "title": title,
"user": rule.user, "user": rule.user,
"rule": rule, "rule": rule,
"index": index, "index": index,
"message": message, "message": message_copy,
"notification_settings": notification_settings, "notification_settings": notification_settings,
} }
if meta: if meta:
if "matched" in meta: cast["meta"] = meta
cast["matched"] = meta["matched"]
if "total_hits" in meta:
cast["total_hits"] = meta["total_hits"]
if rule.service == "ntfy": if rule.service == "ntfy":
cast["msg"] = format_ntfy(**cast) cast["msg"] = format_ntfy(**cast)
@ -341,8 +346,8 @@ class NotificationRuleData(object):
:param index: the index to store the matches for :param index: the index to store the matches for
:param matches: the matches to store :param matches: the matches to store
""" """
new_matches = self.reform_matches(index, matches, meta, mode) # new_matches = self.reform_matches(index, matches, meta, mode)
await self.db.async_store_matches(new_matches) await self.db.async_store_matches(matches)
def ingest_matches_sync(self, index, matches, meta, mode): def ingest_matches_sync(self, index, matches, meta, mode):
""" """
@ -350,8 +355,8 @@ class NotificationRuleData(object):
:param index: the index to store the matches for :param index: the index to store the matches for
:param matches: the matches to store :param matches: the matches to store
""" """
new_matches = self.reform_matches(index, matches, meta, mode) # new_matches = self.reform_matches(index, matches, meta, mode)
self.db.store_matches(new_matches) self.db.store_matches(matches)
async def rule_matched(self, index, message, meta, mode): async def rule_matched(self, index, message, meta, mode):
""" """
@ -386,8 +391,11 @@ class NotificationRuleData(object):
if aggs_formatted: if aggs_formatted:
meta["matched_aggs"] = aggs_formatted meta["matched_aggs"] = aggs_formatted
rule_notify(self.object, index, message, meta) meta["is_match"] = True
self.store_match(index, message) self.store_match(index, message)
message = self.reform_matches(index, message, meta, mode)
rule_notify(self.object, index, message, meta)
await self.ingest_matches(index, message, meta, mode) await self.ingest_matches(index, message, meta, mode)
def rule_matched_sync(self, index, message, meta, mode): def rule_matched_sync(self, index, message, meta, mode):
@ -423,12 +431,15 @@ class NotificationRuleData(object):
if aggs_formatted: if aggs_formatted:
meta["matched_aggs"] = aggs_formatted meta["matched_aggs"] = aggs_formatted
rule_notify(self.object, index, message, meta) meta["is_match"] = True
self.store_match(index, message) self.store_match(index, message)
message = self.reform_matches(index, message, meta, mode)
rule_notify(self.object, index, message, meta)
self.ingest_matches_sync(index, message, meta, mode) self.ingest_matches_sync(index, message, meta, mode)
# No async helper for this one as we only need it for schedules # No async helper for this one as we only need it for schedules
async def rule_no_match(self, index=None, message=None): async def rule_no_match(self, index=None, message=None, mode=None):
""" """
A rule has not matched. A rule has not matched.
If the previous run did match, send a notification if configured to notify If the previous run did match, send a notification if configured to notify
@ -455,11 +466,14 @@ class NotificationRuleData(object):
if self.policy in ["always", "change"]: if self.policy in ["always", "change"]:
# Never notify for empty matches on default policy # Never notify for empty matches on default policy
rule_notify(self.object, index, "no_match", None) meta = {"msg": message, "is_match": False}
matches = [{"msg": None}]
message = self.reform_matches(index, matches, meta, mode)
rule_notify(self.object, index, matches, meta)
await self.ingest_matches( await self.ingest_matches(
index=index, index=index,
matches=[{"msg": None}], matches=matches,
meta={"msg": message}, meta=meta,
mode="schedule", mode="schedule",
) )
@ -472,12 +486,16 @@ class NotificationRuleData(object):
response = await self.db.schedule_query_results(self) response = await self.db.schedule_query_results(self)
if not response: if not response:
# No results in the result_map # No results in the result_map
await self.rule_no_match(message="No response from database") await self.rule_no_match(
message="No response from database", mode="schedule"
)
return return
for index, (meta, results) in response.items(): for index, (meta, results) in response.items():
if not results: if not results:
# Falsy results, no matches # Falsy results, no matches
await self.rule_no_match(index, message="No results for index") await self.rule_no_match(
index, message="No results for index", mode="schedule"
)
continue continue
# Add the match values of all aggregations to a list # Add the match values of all aggregations to a list
@ -496,7 +514,9 @@ class NotificationRuleData(object):
) )
continue continue
# Default branch, since the happy path has a continue keyword # Default branch, since the happy path has a continue keyword
await self.rule_no_match(index, message="Aggregation did not match") await self.rule_no_match(
index, message="Aggregation did not match", mode="schedule"
)
def test_schedule(self): def test_schedule(self):
""" """