|
|
|
@ -8,6 +8,8 @@ try:
|
|
|
|
|
except ImportError:
|
|
|
|
|
from yaml import Loader, Dumper
|
|
|
|
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
import orjson
|
|
|
|
|
from asgiref.sync import async_to_sync
|
|
|
|
|
from siphashc import siphash
|
|
|
|
@ -271,9 +273,27 @@ class NotificationRuleData(object):
|
|
|
|
|
op, value = self.aggs[agg_name]
|
|
|
|
|
new_aggs[agg_name] = f"{agg['value']}{op}{value}"
|
|
|
|
|
|
|
|
|
|
return new_aggs
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
async def ingest_matches(self, index, matches, meta):
|
|
|
|
|
"""
|
|
|
|
|
Store all matches for an index.
|
|
|
|
|
:param index: the index to store the matches for
|
|
|
|
|
:param matches: the matches to store
|
|
|
|
|
"""
|
|
|
|
|
if not isinstance(matches, list):
|
|
|
|
|
matches = [matches]
|
|
|
|
|
matches_copy = matches.copy()
|
|
|
|
|
print("MATHCES COPY: ", matches_copy)
|
|
|
|
|
match_ts = datetime.utcnow().isoformat()
|
|
|
|
|
for match_index, _ in enumerate(matches_copy):
|
|
|
|
|
matches_copy[match_index]["index"] = index
|
|
|
|
|
matches_copy[match_index]["rule_uuid"] = self.object.id
|
|
|
|
|
matches_copy[match_index]["meta"] = meta
|
|
|
|
|
matches_copy[match_index]["match_ts"] = match_ts
|
|
|
|
|
await self.db.async_store_matches(matches_copy)
|
|
|
|
|
|
|
|
|
|
def rule_matched(self, index, message, meta):
|
|
|
|
|
async def rule_matched(self, index, message, meta):
|
|
|
|
|
"""
|
|
|
|
|
A rule has matched.
|
|
|
|
|
If the previous run did not match, send a notification after formatting
|
|
|
|
@ -289,8 +309,9 @@ class NotificationRuleData(object):
|
|
|
|
|
meta["matched"] = self.format_aggs(meta["aggs"])
|
|
|
|
|
rule_notify(self.object, index, message, meta)
|
|
|
|
|
self.store_match(index, message)
|
|
|
|
|
await self.ingest_matches(index, message, meta)
|
|
|
|
|
|
|
|
|
|
def rule_no_match(self, index=None):
|
|
|
|
|
async def rule_no_match(self, index=None):
|
|
|
|
|
"""
|
|
|
|
|
A rule has not matched.
|
|
|
|
|
If the previous run did match, send a notification if configured to notify
|
|
|
|
@ -315,11 +336,11 @@ class NotificationRuleData(object):
|
|
|
|
|
response = await self.db.schedule_query_results(self)
|
|
|
|
|
if not response:
|
|
|
|
|
# No results in the result_map
|
|
|
|
|
self.rule_no_match()
|
|
|
|
|
await self.rule_no_match()
|
|
|
|
|
for index, (meta, results) in response.items():
|
|
|
|
|
if not results:
|
|
|
|
|
# Falsy results, no matches
|
|
|
|
|
self.rule_not_matched(index)
|
|
|
|
|
await self.rule_no_match(index)
|
|
|
|
|
|
|
|
|
|
# Add the match values of all aggregations to a list
|
|
|
|
|
aggs_for_index = []
|
|
|
|
@ -332,10 +353,10 @@ class NotificationRuleData(object):
|
|
|
|
|
if len(aggs_for_index) == len(self.aggs.keys()):
|
|
|
|
|
if all(aggs_for_index):
|
|
|
|
|
# All aggs have matched
|
|
|
|
|
self.rule_matched(index, results[: self.object.amount], meta)
|
|
|
|
|
await self.rule_matched(index, results[: self.object.amount], meta)
|
|
|
|
|
continue
|
|
|
|
|
# Default branch, since the happy path has a continue keyword
|
|
|
|
|
self.rule_no_match(index)
|
|
|
|
|
await self.rule_no_match(index)
|
|
|
|
|
|
|
|
|
|
def test_schedule(self):
|
|
|
|
|
"""
|
|
|
|
|