Skip to content

Commit 392ba87

Browse files
committed
Merge branch 'mr/forestier/add-default-lifecycle-rule' into 'master'
Add a default LifeCycle rule when creating a bucket See merge request it/e3-aws!46
2 parents 247203f + ef1f3ed commit 392ba87

File tree

3 files changed

+100
-0
lines changed

3 files changed

+100
-0
lines changed

src/e3/aws/troposphere/s3/bucket.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@
2020
from e3.aws.troposphere import Stack
2121
from typing import Any
2222

23+
# A default lifecycle rule to abort and delete incomplete multipart upload
24+
# This rule is recommended by AWS Trusted advisor to avoid excess costs
25+
DEFAULT_LIFECYCLE_RULE = s3.LifecycleRule(
26+
Id="AbortIncompleteMultipartUpload",
27+
AbortIncompleteMultipartUpload=s3.AbortIncompleteMultipartUpload(
28+
DaysAfterInitiation=7
29+
),
30+
Prefix="",
31+
Status="Enabled",
32+
)
33+
2334

2435
class EncryptionAlgorithm(Enum):
2536
"""Provide an Enum to describe encryption algorithms."""
@@ -40,6 +51,7 @@ def __init__(
4051
EncryptionAlgorithm | None
4152
) = EncryptionAlgorithm.AES256,
4253
authorized_encryptions: list[EncryptionAlgorithm] | None = None,
54+
add_multipart_lifecycle_rule: bool = False,
4355
**bucket_kwargs: Any,
4456
):
4557
"""Initialize a bucket.
@@ -51,11 +63,21 @@ def __init__(
5163
:param default_bucket_encryption: type of the default bucket encryption.
5264
:param authorized_encryptions: types of the server side encryptions
5365
to authorize.
66+
:param add_multipart_lifecycle_rule: add default rule is to abort multipart
67+
uploads that remain incomplete after 7 days.
5468
:param bucket_kwargs: keyword arguments to pass to the bucket constructor
5569
"""
5670
self.name = name
5771
self.enable_versioning = enable_versioning
5872
self.lifecycle_rules = lifecycle_rules
73+
74+
if add_multipart_lifecycle_rule:
75+
self.lifecycle_rules = (
76+
self.lifecycle_rules + [DEFAULT_LIFECYCLE_RULE]
77+
if self.lifecycle_rules
78+
else [DEFAULT_LIFECYCLE_RULE]
79+
)
80+
5981
self.default_bucket_encryption = default_bucket_encryption
6082
if authorized_encryptions is None:
6183
self.authorized_encryptions = [EncryptionAlgorithm.AES256]
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"TestBucket": {
3+
"DeletionPolicy": "Retain",
4+
"Properties": {
5+
"BucketName": "test-bucket",
6+
"BucketEncryption": {
7+
"ServerSideEncryptionConfiguration": [
8+
{
9+
"ServerSideEncryptionByDefault": {
10+
"SSEAlgorithm": "AES256"
11+
}
12+
}
13+
]
14+
},
15+
"PublicAccessBlockConfiguration": {
16+
"BlockPublicAcls": true,
17+
"BlockPublicPolicy": true,
18+
"IgnorePublicAcls": true,
19+
"RestrictPublicBuckets": true
20+
},
21+
"LifecycleConfiguration": {
22+
"Rules": [
23+
{
24+
"Id": "AbortIncompleteMultipartUpload",
25+
"AbortIncompleteMultipartUpload": {
26+
"DaysAfterInitiation": 7
27+
},
28+
"Status": "Enabled",
29+
"Prefix": ""
30+
}
31+
]
32+
},
33+
"VersioningConfiguration": {
34+
"Status": "Enabled"
35+
}
36+
},
37+
"Type": "AWS::S3::Bucket"
38+
},
39+
"TestBucketPolicy": {
40+
"Properties": {
41+
"Bucket": {
42+
"Ref": "TestBucket"
43+
},
44+
"PolicyDocument": {
45+
"Version": "2012-10-17",
46+
"Statement": [
47+
{
48+
"Effect": "Deny",
49+
"Principal": {
50+
"AWS": "*"
51+
},
52+
"Action": "s3:*",
53+
"Resource": "arn:aws:s3:::test-bucket/*",
54+
"Condition": {
55+
"Bool": {
56+
"aws:SecureTransport": "false"
57+
}
58+
}
59+
}
60+
]
61+
}
62+
},
63+
"Type": "AWS::S3::BucketPolicy"
64+
}
65+
}

tests/tests_e3_aws/troposphere/s3/s3_test.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,16 @@ def test_bucket_with_roles_and_trust_policies_error(stack: Stack) -> None:
210210
str(exc.value) == "You cannot set 'trust_policy' and "
211211
"'trusted_accounts' at the same time , please use one or the other."
212212
)
213+
214+
215+
def test_bucket_with_default_lifecycle_rule(stack: Stack) -> None:
216+
"""Test bucket creation with default lifecycle rule."""
217+
bucket = Bucket(name="test-bucket", add_multipart_lifecycle_rule=True)
218+
stack.add(bucket)
219+
220+
with open(
221+
os.path.join(TEST_DIR, "bucket-with-multipart-lifecycle-rule.json")
222+
) as fd:
223+
expected_template = json.load(fd)
224+
225+
assert stack.export()["Resources"] == expected_template

0 commit comments

Comments
 (0)