-
Notifications
You must be signed in to change notification settings - Fork 291
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
18 changed files
with
724 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
engine/apps/alerts/migrations/0065_alter_alertgrouplogrecord_action_source.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Generated by Django 4.2.16 on 2024-11-20 16:53 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('alerts', '0064_migrate_resolutionnoteslackmessage_slack_channel_id'), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterField( | ||
model_name='alertgrouplogrecord', | ||
name='action_source', | ||
field=models.SmallIntegerField(default=None, null=True, verbose_name=[(0, 'Slack'), (1, 'Web'), (2, 'Phone'), (3, 'Telegram'), (4, 'API'), (5, 'Backsync'), (6, 'Mattermost')]), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import logging | ||
import typing | ||
|
||
from rest_framework import exceptions | ||
from rest_framework.authentication import BaseAuthentication | ||
|
||
from apps.mattermost.models import MattermostUser | ||
from apps.mattermost.utils import MattermostEventAuthenticator, MattermostEventTokenInvalid | ||
from apps.user_management.models import User | ||
|
||
logger = logging.getLogger(__name__) | ||
logger.setLevel(logging.DEBUG) | ||
|
||
|
||
class MattermostEventAuthentication(BaseAuthentication): | ||
def authenticate(self, request) -> typing.Tuple[User, None]: | ||
if "context" not in request.data or "token" not in request.data["context"]: | ||
raise exceptions.AuthenticationFailed("Auth token is missing") | ||
|
||
auth = request.data["context"]["token"] | ||
try: | ||
MattermostEventAuthenticator.verify(auth) | ||
mattermost_user = MattermostUser.objects.get(mattermost_user_id=request.data["user_id"]) | ||
except MattermostEventTokenInvalid: | ||
raise exceptions.AuthenticationFailed("Invalid auth token") | ||
except MattermostUser.DoesNotExist: | ||
raise exceptions.AuthenticationFailed("Mattermost user not integrated") | ||
|
||
return mattermost_user.user, None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .alert_group_actions_handler import AlertGroupActionHandler # noqa: F401 |
94 changes: 94 additions & 0 deletions
94
engine/apps/mattermost/events/alert_group_actions_handler.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import logging | ||
import typing | ||
|
||
from apps.alerts.constants import ActionSource | ||
from apps.alerts.models import AlertGroup | ||
from apps.mattermost.events.event_handler import MattermostEventHandler | ||
from apps.mattermost.events.types import EventAction | ||
from apps.mattermost.models import MattermostMessage | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class AlertGroupActionHandler(MattermostEventHandler): | ||
""" | ||
Handles the alert group actions from the mattermost message buttons | ||
""" | ||
|
||
def is_match(self): | ||
action = self._get_action() | ||
return action and action in [ | ||
EventAction.ACKNOWLEDGE, | ||
EventAction.UNACKNOWLEDGE, | ||
EventAction.RESOLVE, | ||
EventAction.UNRESOLVE, | ||
] | ||
|
||
def process(self): | ||
alert_group = self._get_alert_group() | ||
action = self._get_action() | ||
|
||
if not alert_group or not action: | ||
return | ||
|
||
action_fn, fn_kwargs = self._get_action_function(alert_group, action) | ||
action_fn(user=self.user, action_source=ActionSource.MATTERMOST, **fn_kwargs) | ||
|
||
def _get_action(self) -> typing.Optional[EventAction]: | ||
if "context" not in self.event or "action" not in self.event["context"]: | ||
return | ||
|
||
try: | ||
action = self.event["context"]["action"] | ||
return EventAction(action) | ||
except ValueError: | ||
logger.info(f"Mattermost event action not found {action}") | ||
return | ||
|
||
def _get_alert_group(self) -> typing.Optional[AlertGroup]: | ||
return self._get_alert_group_from_event() or self._get_alert_group_from_message() | ||
|
||
def _get_alert_group_from_event(self) -> typing.Optional[AlertGroup]: | ||
if "context" not in self.event or "alert" not in self.event["context"]: | ||
return | ||
|
||
try: | ||
alert_group = AlertGroup.objects.get(pk=self.event["context"]["alert"]) | ||
except AlertGroup.DoesNotExist: | ||
return | ||
|
||
return alert_group | ||
|
||
def _get_alert_group_from_message(self) -> typing.Optional[AlertGroup]: | ||
try: | ||
mattermost_message = MattermostMessage.objects.get( | ||
channel_id=self.event["channel_id"], post_id=self.event["post_id"] | ||
) | ||
return mattermost_message.alert_group | ||
except MattermostMessage.DoesNotExist: | ||
logger.info( | ||
f"Mattermost message not found for channel_id: {self.event['channel_id']} and post_id {self.event['post_id']}" | ||
) | ||
return | ||
|
||
def _get_action_function(self, alert_group: AlertGroup, action: EventAction) -> typing.Tuple[typing.Callable, dict]: | ||
action_to_fn = { | ||
EventAction.ACKNOWLEDGE: { | ||
"fn_name": "acknowledge_by_user_or_backsync", | ||
"kwargs": {}, | ||
}, | ||
EventAction.UNACKNOWLEDGE: { | ||
"fn_name": "un_acknowledge_by_user_or_backsync", | ||
"kwargs": {}, | ||
}, | ||
EventAction.RESOLVE: { | ||
"fn_name": "resolve_by_user_or_backsync", | ||
"kwargs": {}, | ||
}, | ||
EventAction.UNRESOLVE: {"fn_name": "un_resolve_by_user_or_backsync", "kwargs": {}}, | ||
} | ||
|
||
fn_info = action_to_fn[action] | ||
fn = getattr(alert_group, fn_info["fn_name"]) | ||
|
||
return fn, fn_info["kwargs"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from abc import ABC, abstractmethod | ||
|
||
from apps.mattermost.events.types import MattermostEvent | ||
from apps.user_management.models import User | ||
|
||
|
||
class MattermostEventHandler(ABC): | ||
def __init__(self, event: MattermostEvent, user: User): | ||
self.event: MattermostEvent = event | ||
self.user: User = user | ||
|
||
@abstractmethod | ||
def is_match(self) -> bool: | ||
pass | ||
|
||
@abstractmethod | ||
def process(self) -> None: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import logging | ||
import typing | ||
|
||
from rest_framework.request import Request | ||
|
||
from apps.mattermost.events.event_handler import MattermostEventHandler | ||
from apps.mattermost.events.types import MattermostEvent | ||
from apps.user_management.models import User | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class EventManager: | ||
""" | ||
Manager for mattermost events | ||
""" | ||
|
||
@classmethod | ||
def process_request(cls, request: Request): | ||
user = request.user | ||
event = request.data | ||
handler = cls.select_event_handler(user=user, event=event) | ||
if handler is None: | ||
logger.info("No event handler found") | ||
return | ||
|
||
logger.info(f"Processing mattermost event with handler: {handler.__class__.__name__}") | ||
handler.process() | ||
|
||
@staticmethod | ||
def select_event_handler(user: User, event: MattermostEvent) -> typing.Optional[MattermostEventHandler]: | ||
handler_classes = MattermostEventHandler.__subclasses__() | ||
for handler_class in handler_classes: | ||
handler = handler_class(user=user, event=event) | ||
if handler.is_match(): | ||
return handler | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import enum | ||
import typing | ||
|
||
|
||
class MattermostAlertGroupContext(typing.TypedDict): | ||
action: str | ||
token: str | ||
alert: int | ||
|
||
|
||
class MattermostEvent(typing.TypedDict): | ||
user_id: str | ||
user_name: str | ||
channel_id: str | ||
channel_name: str | ||
team_id: str | ||
team_domain: str | ||
post_id: str | ||
trigger_id: str | ||
type: str | ||
data_source: str | ||
context: MattermostAlertGroupContext | ||
|
||
|
||
class EventAction(enum.StrEnum): | ||
ACKNOWLEDGE = "acknowledge" | ||
UNACKNOWLEDGE = "unacknowledge" | ||
RESOLVE = "resolve" | ||
UNRESOLVE = "unresolve" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.