Skip to content

Commit 8461f50

Browse files
committed
feat(parser): adds support for S3 event notifications through EventBridge
1 parent f3030d2 commit 8461f50

File tree

4 files changed

+172
-2
lines changed

4 files changed

+172
-2
lines changed

aws_lambda_powertools/utilities/data_classes/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from .kinesis_firehose_event import KinesisFirehoseEvent
1717
from .kinesis_stream_event import KinesisStreamEvent
1818
from .lambda_function_url_event import LambdaFunctionUrlEvent
19-
from .s3_event import S3Event
19+
from .s3_event import S3Event, S3EventBridgeEvent
2020
from .ses_event import SESEvent
2121
from .sns_event import SNSEvent
2222
from .sqs_event import SQSEvent
@@ -37,6 +37,7 @@
3737
"KinesisStreamEvent",
3838
"LambdaFunctionUrlEvent",
3939
"S3Event",
40+
"S3EventBridgeEvent",
4041
"SESEvent",
4142
"SNSEvent",
4243
"SQSEvent",

aws_lambda_powertools/utilities/data_classes/s3_event.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
from urllib.parse import unquote_plus
33

44
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
5+
from aws_lambda_powertools.utilities.data_classes.event_bridge_event import (
6+
EventBridgeEvent,
7+
)
58

69

710
class S3Identity(DictWrapper):
@@ -16,6 +19,138 @@ def source_ip_address(self) -> str:
1619
return self["requestParameters"]["sourceIPAddress"]
1720

1821

22+
class S3EventNotificationEventBridgeBucket(DictWrapper):
23+
@property
24+
def name(self) -> str:
25+
return self["name"]
26+
27+
28+
class S3EventBridgeNotificationObject(DictWrapper):
29+
@property
30+
def key(self) -> str:
31+
"""Object key"""
32+
return unquote_plus(self["key"])
33+
34+
@property
35+
def size(self) -> str:
36+
"""Object size"""
37+
return self["size"]
38+
39+
@property
40+
def etag(self) -> str:
41+
"""Object etag"""
42+
return self["etag"]
43+
44+
@property
45+
def version_id(self) -> str:
46+
"""Object version ID"""
47+
return self["version-id"]
48+
49+
@property
50+
def sequencer(self) -> str:
51+
"""Object key"""
52+
return self["sequencer"]
53+
54+
55+
class S3EventBridgeNotificationDetail(DictWrapper):
56+
@property
57+
def version(self) -> str:
58+
"""Get the detail version"""
59+
return self["version"]
60+
61+
@property
62+
def bucket(self) -> S3EventNotificationEventBridgeBucket:
63+
"""Get the bucket name for the S3 notification"""
64+
return S3EventNotificationEventBridgeBucket(self["bucket"])
65+
66+
@property
67+
def object(self) -> S3EventBridgeNotificationObject: # noqa: A003
68+
"""Get the request-id for the S3 notification"""
69+
return S3EventBridgeNotificationObject(self["object"])
70+
71+
@property
72+
def request_id(self) -> str:
73+
"""Get the request-id for the S3 notification"""
74+
return self["request-id"]
75+
76+
@property
77+
def requester(self) -> str:
78+
"""Get the AWS account ID or AWS service principal of requester for the S3 notification"""
79+
return self["requester"]
80+
81+
@property
82+
def source_ip_address(self) -> str:
83+
"""Get the source IP address of S3 request. Only present for events triggered by an S3 request."""
84+
return self["source-ip-address"]
85+
86+
@property
87+
def reason(self) -> Optional[str]:
88+
"""Get the reason for the S3 notification.
89+
90+
For 'Object Created events', the S3 API used to create the object: `PutObject`, `POST Object`, `CopyObject`, or
91+
`CompleteMultipartUpload`. For 'Object Deleted' events, this is set to `DeleteObject` when an object is deleted
92+
by an S3 API call, or 'Lifecycle Expiration' when an object is deleted by an S3 Lifecycle expiration rule.
93+
"""
94+
return self.get("reason")
95+
96+
@property
97+
def deletion_type(self) -> Optional[str]:
98+
"""Get the deletion type for the S3 object in this notification.
99+
100+
For 'Object Deleted' events, when an unversioned object is deleted, or a versioned object is permanently deleted
101+
this is set to 'Permanently Deleted'. When a delete marker is created for a versioned object, this is set to
102+
'Delete Marker Created'.
103+
"""
104+
return self.get("deletion-type")
105+
106+
@property
107+
def restore_expiry_time(self) -> Optional[str]:
108+
"""Get the restore expiry time for the S3 object in this notification.
109+
110+
For 'Object Restore Completed' events, the time when the temporary copy of the object will be deleted from S3.
111+
"""
112+
return self["detail"].get("restore-expiry-time")
113+
114+
@property
115+
def source_storage_class(self) -> Optional[str]:
116+
"""Get the source storage class of the S3 object in this notification.
117+
118+
For 'Object Restore Initiated' and 'Object Restore Completed' events, the storage class of the object being
119+
restored.
120+
"""
121+
return self["detail"].get("source-storage-class")
122+
123+
@property
124+
def destination_storage_class(self) -> Optional[str]:
125+
"""Get the destination storage class of the S3 object in this notification.
126+
127+
For 'Object Storage Class Changed' events, the new storage class of the object.
128+
"""
129+
return self["detail"].get("destination-storage-class")
130+
131+
@property
132+
def destination_access_tier(self) -> Optional[str]:
133+
"""Get the destination access tier of the S3 object in this notification.
134+
135+
For 'Object Access Tier Changed' events, the new access tier of the object.
136+
"""
137+
return self["detail"].get("destination-access-tier")
138+
139+
140+
class S3EventBridgeEvent(EventBridgeEvent):
141+
"""Amazon S3EventBridge Event
142+
143+
Documentation:
144+
--------------
145+
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/ev-events.html
146+
"""
147+
148+
@property
149+
def detail(self): # -> S3EventBridgeNotificationDetail: mypy errors with this return type
150+
"""S3 notification details"""
151+
return S3EventBridgeNotificationDetail(self["detail"])
152+
153+
19154
class S3Bucket(DictWrapper):
20155
@property
21156
def name(self) -> str:

aws_lambda_powertools/utilities/parser/models/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
KinesisFirehoseRecordMetadata,
4444
)
4545
from .lambda_function_url import LambdaFunctionUrlModel
46-
from .s3 import S3Model, S3RecordModel
46+
from .s3 import S3EventNotificationEventBridgeDetailModel, S3Model, S3RecordModel
4747
from .s3_object_event import (
4848
S3ObjectConfiguration,
4949
S3ObjectContext,
@@ -105,6 +105,7 @@
105105
"S3ObjectUserRequest",
106106
"S3ObjectConfiguration",
107107
"S3ObjectContext",
108+
"S3EventNotificationEventBridgeDetailModel",
108109
"SesModel",
109110
"SesRecordModel",
110111
"SesMessage",

aws_lambda_powertools/utilities/parser/models/s3.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from aws_lambda_powertools.utilities.parser.types import Literal
1010

11+
from .event_bridge import EventBridgeModel
12+
1113

1214
class S3EventRecordGlacierRestoreEventData(BaseModel):
1315
lifecycleRestorationExpiryTime: datetime
@@ -56,6 +58,37 @@ class S3Message(BaseModel):
5658
object: S3Object # noqa: A003,VNE003
5759

5860

61+
class S3EventNotificationObjectModel(BaseModel):
62+
key: str
63+
size: Optional[NonNegativeFloat]
64+
etag: str
65+
version_id: str = Field(None, alias="version-id")
66+
sequencer: str
67+
68+
69+
class S3EventNotificationEventBridgeBucketModel(BaseModel):
70+
name: str
71+
72+
73+
class S3EventNotificationEventBridgeDetailModel(BaseModel):
74+
version: str
75+
bucket: S3EventNotificationEventBridgeBucketModel
76+
object: S3EventNotificationObjectModel # noqa: A003,VNE003
77+
request_id: str = Field(None, alias="request-id")
78+
requester: str
79+
source_ip_address: str = Field(None, alias="source-ip-address")
80+
reason: Optional[str]
81+
deletion_type: Optional[str]
82+
restore_expiry_time: Optional[str]
83+
source_storage_class: Optional[str]
84+
destination_storage_class: Optional[str]
85+
destination_access_tier: Optional[str]
86+
87+
88+
class S3EventNotificationEventBridgeModel(EventBridgeModel):
89+
detail = S3EventNotificationEventBridgeDetailModel
90+
91+
5992
class S3RecordModel(BaseModel):
6093
eventVersion: str
6194
eventSource: Literal["aws:s3"]

0 commit comments

Comments
 (0)