Skip to content

Commit 27d1c46

Browse files
falenseantonbabenkobryantbiggs
authored
feat: Improved AWS backup notification readability (#222)
Co-authored-by: Anton Babenko <anton@antonbabenko.com> Co-authored-by: Bryant Biggs <bryantbiggs@gmail.com>
1 parent 6c17291 commit 27d1c46

File tree

3 files changed

+633
-261
lines changed

3 files changed

+633
-261
lines changed

functions/messages/backup.json

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
{
2+
"Records": [
3+
{
4+
"EventSource": "aws:sns",
5+
"EventVersion": "1.0",
6+
"EventSubscriptionArn": "arn:aws:sns:...-a3802aa1ed45",
7+
"Sns": {
8+
"Type": "Notification",
9+
"MessageId": "12345678-abcd-123a-def0-abcd1a234567",
10+
"TopicArn": "arn:aws:sns:us-west-1:123456789012:backup-2sqs-sns-topic",
11+
"Subject": "Notification from AWS Backup",
12+
"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",
13+
"Timestamp": "2019-08-02T18:46:02.788Z",
14+
"MessageAttributes": {
15+
"EventType": {
16+
"Type": "String",
17+
"Value": "BACKUP_JOB"
18+
},
19+
"State": {
20+
"Type": "String",
21+
"Value": "COMPLETED"
22+
},
23+
"AccountId": {
24+
"Type": "String",
25+
"Value": "123456789012"
26+
},
27+
"Id": {
28+
"Type": "String",
29+
"Value": "1b2345b2-f22c-4dab-5eb6-bbc7890ed123"
30+
},
31+
"StartTime": {
32+
"Type": "String",
33+
"Value": "2019-09-02T13:48:52.226Z"
34+
}
35+
}
36+
}
37+
},
38+
{
39+
"EventSource": "aws:sns",
40+
"EventVersion": "1.0",
41+
"EventSubscriptionArn": "arn:aws:sns:...-a3802aa1ed45",
42+
"Sns": {
43+
"Type": "Notification",
44+
"MessageId": "12345678-abcd-123a-def0-abcd1a234567",
45+
"TopicArn": "arn:aws:sns:us-west-1:123456789012:backup-2sqs-sns-topic",
46+
"Subject": "Notification from AWS Backup",
47+
"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",
48+
"Timestamp": "2019-08-02T18:46:02.788Z",
49+
"MessageAttributes": {
50+
"EventType": {
51+
"Type": "String",
52+
"Value": "BACKUP_JOB"
53+
},
54+
"State": {
55+
"Type": "String",
56+
"Value": "FAILED"
57+
},
58+
"AccountId": {
59+
"Type": "String",
60+
"Value": "123456789012"
61+
},
62+
"Id": {
63+
"Type": "String",
64+
"Value": "1b2345b2-f22c-4dab-5eb6-bbc7890ed123"
65+
},
66+
"StartTime": {
67+
"Type": "String",
68+
"Value": "2019-09-02T13:48:52.226Z"
69+
}
70+
}
71+
}
72+
},
73+
{
74+
"EventSource": "aws:sns",
75+
"EventVersion": "1.0",
76+
"EventSubscriptionArn": "arn:aws:sns:...-a3802aa1ed45",
77+
"Sns": {
78+
"Type": "Notification",
79+
"MessageId": "12345678-abcd-123a-def0-abcd1a234567",
80+
"TopicArn": "arn:aws:sns:us-west-1:123456789012:backup-2sqs-sns-topic",
81+
"Subject": "Notification from AWS Backup",
82+
"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",
83+
"Timestamp": "2019-08-02T18:46:02.788Z",
84+
"MessageAttributes": {
85+
"EventType": {
86+
"Type": "String",
87+
"Value": "BACKUP_JOB"
88+
},
89+
"State": {
90+
"Type": "String",
91+
"Value": "EXPIRED"
92+
},
93+
"AccountId": {
94+
"Type": "String",
95+
"Value": "123456789012"
96+
},
97+
"Id": {
98+
"Type": "String",
99+
"Value": "1b2345b2-f22c-4dab-5eb6-bbc7890ed123"
100+
},
101+
"StartTime": {
102+
"Type": "String",
103+
"Value": "2019-09-02T13:48:52.226Z"
104+
}
105+
}
106+
}
107+
}
108+
]
109+
}

functions/notify_slack.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import json
1212
import logging
1313
import os
14+
import re
1415
import urllib.parse
1516
import urllib.request
1617
from enum import Enum
@@ -266,6 +267,66 @@ def format_aws_health(message: Dict[str, Any], region: str) -> Dict[str, Any]:
266267
}
267268

268269

270+
def aws_backup_field_parser(message: str) -> Dict[str, str]:
271+
"""
272+
Parser for AWS Backup event message. It extracts the fields from the message and returns a dictionary.
273+
274+
:params message: message containing AWS Backup event
275+
:returns: dictionary containing the fields extracted from the message
276+
"""
277+
# Order is somewhat important, working in reverse order of the message payload
278+
# to reduce right most matched values
279+
field_names = {
280+
"BackupJob ID": r"(BackupJob ID : ).*",
281+
"Resource ARN": r"(Resource ARN : ).*[.]",
282+
"Recovery point ARN": r"(Recovery point ARN: ).*[.]",
283+
}
284+
fields = {}
285+
286+
for fname, freg in field_names.items():
287+
match = re.search(freg, message)
288+
if match:
289+
value = match.group(0).split(" ")[-1]
290+
fields[fname] = value.removesuffix(".")
291+
292+
# Remove the matched field from the message
293+
message = message.replace(match.group(0), "")
294+
295+
return fields
296+
297+
298+
def format_aws_backup(message: str) -> Dict[str, Any]:
299+
"""
300+
Format AWS Backup event into Slack message format
301+
302+
:params message: SNS message body containing AWS Backup event
303+
:returns: formatted Slack message payload
304+
"""
305+
306+
fields: list[Dict[str, Any]] = []
307+
attachments = {}
308+
309+
title = message.split(".")[0]
310+
311+
if "failed" in title:
312+
title = f"⚠️ {title}"
313+
314+
if "completed" in title:
315+
title = f"✅ {title}"
316+
317+
fields.append({"title": title})
318+
319+
backup_fields = aws_backup_field_parser(message)
320+
321+
for k, v in backup_fields.items():
322+
fields.append({"value": k, "short": False})
323+
fields.append({"value": f"`{v}`", "short": False})
324+
325+
attachments["fields"] = fields # type: ignore
326+
327+
return attachments
328+
329+
269330
def format_default(
270331
message: Union[str, Dict], subject: Optional[str] = None
271332
) -> Dict[str, Any]:
@@ -344,6 +405,10 @@ def get_slack_message_payload(
344405
notification = format_aws_health(message=message, region=message["region"])
345406
attachment = notification
346407

408+
elif subject == "Notification from AWS Backup":
409+
notification = format_aws_backup(message=str(message))
410+
attachment = notification
411+
347412
elif "attachments" in message or "text" in message:
348413
payload = {**payload, **message}
349414

0 commit comments

Comments
 (0)