Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improved AWS backup notification readability #222

Merged
merged 10 commits into from
Apr 24, 2024
109 changes: 109 additions & 0 deletions functions/messages/backup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
{
"Records": [
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "arn:aws:sns:...-a3802aa1ed45",
"Sns": {
"Type": "Notification",
"MessageId": "12345678-abcd-123a-def0-abcd1a234567",
"TopicArn": "arn:aws:sns:us-west-1:123456789012:backup-2sqs-sns-topic",
"Subject": "Notification from AWS Backup",
"Message": "An AWS Backup job was completed successfully. Recovery point ARN: arn:aws:ec2:us-west-1:123456789012:volume/vol-012f345df6789012d. Resource ARN : arn:aws:ec2:us-west-1:123456789012:volume/vol-012f345df6789012e. BackupJob ID : 1b2345b2-f22c-4dab-5eb6-bbc7890ed123",
"Timestamp": "2019-08-02T18:46:02.788Z",
"MessageAttributes": {
"EventType": {
"Type": "String",
"Value": "BACKUP_JOB"
},
"State": {
"Type": "String",
"Value": "COMPLETED"
},
"AccountId": {
"Type": "String",
"Value": "123456789012"
},
"Id": {
"Type": "String",
"Value": "1b2345b2-f22c-4dab-5eb6-bbc7890ed123"
},
"StartTime": {
"Type": "String",
"Value": "2019-09-02T13:48:52.226Z"
}
}
}
},
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "arn:aws:sns:...-a3802aa1ed45",
"Sns": {
"Type": "Notification",
"MessageId": "12345678-abcd-123a-def0-abcd1a234567",
"TopicArn": "arn:aws:sns:us-west-1:123456789012:backup-2sqs-sns-topic",
"Subject": "Notification from AWS Backup",
"Message": "An AWS Backup job failed. Resource ARN : arn:aws:ec2:us-west-1:123456789012:volume/vol-012f345df6789012e. BackupJob ID : 1b2345b2-f22c-4dab-5eb6-bbc7890ed123",
"Timestamp": "2019-08-02T18:46:02.788Z",
"MessageAttributes": {
"EventType": {
"Type": "String",
"Value": "BACKUP_JOB"
},
"State": {
"Type": "String",
"Value": "FAILED"
},
"AccountId": {
"Type": "String",
"Value": "123456789012"
},
"Id": {
"Type": "String",
"Value": "1b2345b2-f22c-4dab-5eb6-bbc7890ed123"
},
"StartTime": {
"Type": "String",
"Value": "2019-09-02T13:48:52.226Z"
}
}
}
},
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "arn:aws:sns:...-a3802aa1ed45",
"Sns": {
"Type": "Notification",
"MessageId": "12345678-abcd-123a-def0-abcd1a234567",
"TopicArn": "arn:aws:sns:us-west-1:123456789012:backup-2sqs-sns-topic",
"Subject": "Notification from AWS Backup",
"Message": "An AWS Backup job failed to complete in time. Resource ARN : arn:aws:ec2:us-west-1:123456789012:volume/vol-012f345df6789012e. BackupJob ID : 1b2345b2-f22c-4dab-5eb6-bbc7890ed123",
"Timestamp": "2019-08-02T18:46:02.788Z",
"MessageAttributes": {
"EventType": {
"Type": "String",
"Value": "BACKUP_JOB"
},
"State": {
"Type": "String",
"Value": "EXPIRED"
},
"AccountId": {
"Type": "String",
"Value": "123456789012"
},
"Id": {
"Type": "String",
"Value": "1b2345b2-f22c-4dab-5eb6-bbc7890ed123"
},
"StartTime": {
"Type": "String",
"Value": "2019-09-02T13:48:52.226Z"
}
}
}
}
]
}
65 changes: 65 additions & 0 deletions functions/notify_slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import json
import logging
import os
import re
import urllib.parse
import urllib.request
from enum import Enum
Expand Down Expand Up @@ -266,6 +267,66 @@ def format_aws_health(message: Dict[str, Any], region: str) -> Dict[str, Any]:
}


def aws_backup_field_parser(message: str) -> Dict[str, str]:
"""
Parser for AWS Backup event message. It extracts the fields from the message and returns a dictionary.

:params message: message containing AWS Backup event
:returns: dictionary containing the fields extracted from the message
"""
# Order is somewhat important, working in reverse order of the message payload
# to reduce right most matched values
field_names = {
"BackupJob ID": r"(BackupJob ID : ).*",
"Resource ARN": r"(Resource ARN : ).*[.]",
"Recovery point ARN": r"(Recovery point ARN: ).*[.]",
}
fields = {}

for fname, freg in field_names.items():
match = re.search(freg, message)
if match:
value = match.group(0).split(" ")[-1]
fields[fname] = value.removesuffix(".")

# Remove the matched field from the message
message = message.replace(match.group(0), "")

return fields


def format_aws_backup(message: str) -> Dict[str, Any]:
"""
Format AWS Backup event into Slack message format

:params message: SNS message body containing AWS Backup event
:returns: formatted Slack message payload
"""

fields: list[Dict[str, Any]] = []
attachments = {}

title = message.split(".")[0]

if "failed" in title:
title = f"⚠️ {title}"

if "completed" in title:
title = f"✅ {title}"

fields.append({"title": title})

backup_fields = aws_backup_field_parser(message)

for k, v in backup_fields.items():
fields.append({"value": k, "short": False})
fields.append({"value": f"`{v}`", "short": False})

attachments["fields"] = fields # type: ignore

return attachments


def format_default(
message: Union[str, Dict], subject: Optional[str] = None
) -> Dict[str, Any]:
Expand Down Expand Up @@ -344,6 +405,10 @@ def get_slack_message_payload(
notification = format_aws_health(message=message, region=message["region"])
attachment = notification

elif subject == "Notification from AWS Backup":
notification = format_aws_backup(message=str(message))
attachment = notification

elif "attachments" in message or "text" in message:
payload = {**payload, **message}

Expand Down
Loading