33# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
44# SPDX-License-Identifier: Apache-2.0.
55import argparse
6+ import json
67import boto3
78import botocore
89import sys
@@ -114,7 +115,7 @@ def create_bucket(client, **kwargs):
114115 raise e
115116
116117
117- def create_bucket_with_lifecycle (availability_zone = None , client = s3_client ):
118+ def create_bucket_with_lifecycle (availability_zone = None , client = s3_client , region = REGION ):
118119 if availability_zone is not None :
119120 bucket_config = {
120121 'Location' : {
@@ -128,37 +129,58 @@ def create_bucket_with_lifecycle(availability_zone=None, client=s3_client):
128129 }
129130 bucket_name = BUCKET_NAME_BASE + f"--{ availability_zone } --x-s3"
130131 else :
131- bucket_config = {'LocationConstraint' : REGION }
132+ bucket_config = {'LocationConstraint' : region }
132133 bucket_name = BUCKET_NAME_BASE
133134
134135 create_bucket (client ,
135136 Bucket = bucket_name ,
136137 CreateBucketConfiguration = bucket_config )
137- if availability_zone is None :
138- print (f"s3://{ bucket_name } - Configuring bucket..." )
139- client .put_bucket_lifecycle_configuration (
140- Bucket = bucket_name ,
141- LifecycleConfiguration = {
142- 'Rules' : [
143- {
144- 'ID' : 'clean up non-pre-existing objects' ,
145- 'Expiration' : {
146- 'Days' : 1 ,
147- },
148- 'Filter' : {
149- 'Prefix' : 'upload/' ,
150- },
151- 'Status' : 'Enabled' ,
152- 'NoncurrentVersionExpiration' : {
153- 'NoncurrentDays' : 1 ,
154- },
155- 'AbortIncompleteMultipartUpload' : {
156- 'DaysAfterInitiation' : 1 ,
157- },
138+ print (f"s3://{ bucket_name } - Configuring bucket..." )
139+ if availability_zone is not None :
140+ # https://docs.aws.amazon.com/AmazonS3/latest/userguide/directory-buckets-objects-lifecycle.html#directory-bucket-lifecycle-differences
141+ # S3 express requires a bucket policy to allow session-based access to perform lifecycle actions
142+ account_id = boto3 .client (
143+ 'sts' ).get_caller_identity ().get ('Account' )
144+ bucket_policy = {
145+ "Version" : "2008-10-17" ,
146+ "Statement" : [
147+ {
148+ "Effect" : "Allow" ,
149+ "Principal" : {
150+ "Service" : "lifecycle.s3.amazonaws.com"
158151 },
159- ],
160- },
161- )
152+ "Action" : "s3express:CreateSession" ,
153+ "Condition" : {
154+ "StringEquals" : {
155+ "s3express:SessionMode" : "ReadWrite"
156+ }
157+ },
158+ "Resource" : [
159+ f"arn:aws:s3express:{ region } :{ account_id } :bucket/{ bucket_name } "
160+ ]
161+ }
162+ ]
163+ }
164+ client .put_bucket_policy (
165+ Bucket = bucket_name , Policy = json .dumps (bucket_policy ))
166+
167+ client .put_bucket_lifecycle_configuration (
168+ Bucket = bucket_name ,
169+ LifecycleConfiguration = {
170+ 'Rules' : [
171+ {
172+ 'ID' : 'Abort all incomplete multipart uploads after 1 day' ,
173+ 'Status' : 'Enabled' ,
174+ 'Filter' : {'Prefix' : '' }, # blank string means all
175+ 'AbortIncompleteMultipartUpload' : {'DaysAfterInitiation' : 1 },
176+ },
177+ {
178+ 'ID' : 'Objects under upload directory expire after 1 day' ,
179+ 'Status' : 'Enabled' ,
180+ 'Filter' : {'Prefix' : 'upload/' },
181+ 'Expiration' : {'Days' : 1 },
182+ },
183+ ]})
162184
163185 put_pre_existing_objects (
164186 10 * MB , 'pre-existing-10MB' , bucket = bucket_name , client = client )
@@ -231,7 +253,7 @@ def cleanup(bucket_name, availability_zone=None, client=s3_client):
231253
232254
233255if args .action == 'init' :
234- create_bucket_with_lifecycle ("use1-az4" , s3_client_east1 )
256+ create_bucket_with_lifecycle ("use1-az4" , s3_client_east1 , "us-east-1" )
235257 create_bucket_with_lifecycle ("usw2-az1" )
236258 create_bucket_with_lifecycle ()
237259 create_bucket_with_public_object ()
0 commit comments