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
1 change: 1 addition & 0 deletions functions/.flake8
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[flake8]
max-complexity = 10
max-line-length = 120
extend-ignore = E203,E701
exclude =
.pytest_cache
__pycache__/
Expand Down
41 changes: 41 additions & 0 deletions functions/messages/backup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"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"
}
}
}
}
]
}


84 changes: 84 additions & 0 deletions functions/notify_slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,86 @@ def format_aws_health(message: Dict[str, Any], region: str) -> Dict[str, Any]:
}


def aws_backup_field_parser(message: str) -> Dict[str, Any]:
"""
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
"""
field_names = [
"Recovery point ARN",
"Resource ARN",
"BackupJob ID",
"Backup Job Id",
"Backed up Resource ARN",
"Status Message",
]

first = None
field_match = ""

for field in field_names:
index = message.find(field)
if index != -1 and (first is None or index < first):
first = index
field_match = field

if first is not None:
next = None
for field in field_names:
index = message.find(field, first + len(field_match) + 1)
if index != -1 and (next is None or index < next):
next = index

if next is None:
next = len(message)

rem_message = message[next:]
fields = aws_backup_field_parser(rem_message)

text = message[first + len(field_match) + 1:next]
while text.startswith(" ") or text.startswith(":"):
text = text[1:]

fields[field_match] = text
return fields
else:
return {}


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]] = []
antonbabenko marked this conversation as resolved.
Show resolved Hide resolved
attachments = {}

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

if "failed" in title:
title = title + " ⚠️"

if "completed" in title:
title = title + " ✅"

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

list_items = aws_backup_field_parser(message)

for k, v in list_items.items():
fields.append({"value": k, "short": False})
fields.append({"value": "```\n" + v + "\n```", "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 +424,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
37 changes: 37 additions & 0 deletions functions/snapshots/snap_notify_slack_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from snapshottest import Snapshot


snapshots = Snapshot()

snapshots[
Expand Down Expand Up @@ -231,6 +232,42 @@
}
]

snapshots["test_sns_get_slack_message_payload_snapshots message_backup.json"] = [
{
"attachments": [
{
"fields": [
{"title": "An AWS Backup job was completed successfully ✅"},
{"short": False, "value": "BackupJob ID"},
{
"short": False,
"value": """```
1b2345b2-f22c-4dab-5eb6-bbc7890ed123
```""",
},
{"short": False, "value": "Resource ARN"},
{
"short": False,
"value": """```
arn:aws:ec2:us-west-1:123456789012:volume/vol-012f345df6789012e.
```""",
},
{"short": False, "value": "Recovery point ARN"},
{
"short": False,
"value": """```
arn:aws:ec2:us-west-1:123456789012:volume/vol-012f345df6789012d.
```""",
},
]
}
],
"channel": "slack_testing_sandbox",
"icon_emoji": ":aws:",
"username": "notify_slack_test",
}
]

snapshots[
"test_sns_get_slack_message_payload_snapshots message_cloudwatch_alarm.json"
] = [
Expand Down
Loading