Skip to content

Commit bd3edcd

Browse files
authored
Merge pull request #2409 from aws-samples/ide/s3-lambda-resizing-python
New pattern - S3 Lambda resizing image (python)
2 parents 23cbea3 + 9e83806 commit bd3edcd

File tree

9 files changed

+336
-0
lines changed

9 files changed

+336
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Resizing images uploaded to Amazon S3 with AWS Lambda
2+
3+
The SAM template deploys an AWS Lambda function, an Amazon S3 bucket, and the IAM resources required to run the application. A Lambda function consumes <code>ObjectCreated</code> events from an Amazon S3 bucket. The Lambda code checks if the uploaded file is an image and then creates a thumbnail version of the image in the same bucket.
4+
5+
Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.
6+
7+
## Requirements
8+
9+
* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
10+
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
11+
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
12+
* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) (AWS SAM) installed
13+
14+
## Deployment Instructions
15+
16+
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
17+
```
18+
git clone https://github.com/aws-samples/serverless-patterns
19+
```
20+
1. Change directory to the pattern directory:
21+
```
22+
cd s3-lambda-resizing-python
23+
```
24+
1. From the command line, use AWS SAM to build and deploy the AWS resources for the pattern as specified in the template.yml file:
25+
```
26+
sam build
27+
sam deploy --guided
28+
```
29+
1. During the prompts:
30+
* Enter a stack name
31+
* Enter the desired AWS Region
32+
* Enter names for your source and destination S3 buckets. Make sure these are unique as S3 bucket names share a global namespace.
33+
* Allow SAM CLI to create IAM roles with the required permissions.
34+
35+
Once you have run `sam deploy --guided` mode once and saved arguments to a configuration file (samconfig.toml), you can use `sam deploy` in future to use these defaults.
36+
37+
1. Note the outputs from the SAM deployment process. These contain the resource names and/or ARNs which are used for testing.
38+
39+
## How it works
40+
41+
* Use the AWS CLI upload an image to S3
42+
* If the object is a .jpeg or a .png, the code creates a thumbnail and saves it to the target bucket.
43+
* The code assumes that the destination bucket exists.
44+
45+
==============================================
46+
47+
## Testing
48+
49+
Run the following S3 CLI command to upload an image to the S3 bucket. Note, you must edit the {SourceBucketName} placeholder with the name of the S3 Bucket. This is provided in the stack outputs.
50+
51+
```bash
52+
aws s3 cp './events/white_dog.jpeg' s3://{SourceBucketName}
53+
```
54+
55+
Run the following command to check that a new version of the image has been created in the destination bucket.
56+
57+
```bash
58+
aws s3 ls s3://{DestinationBucketName}
59+
```
60+
61+
## Cleanup
62+
63+
1. Delete the stack
64+
```bash
65+
sam delete --stack-name STACK_NAME
66+
```
67+
1. Confirm the stack has been deleted
68+
```bash
69+
aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'STACK_NAME')].StackStatus"
70+
```
71+
----
72+
Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
73+
74+
SPDX-License-Identifier: MIT-0
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"Records": [
3+
{
4+
"eventVersion": "2.1",
5+
"eventSource": "aws:s3",
6+
"awsRegion": "us-east-1",
7+
"eventTime": "2024-07-03T19:37:27.192Z",
8+
"eventName": "ObjectCreated:Put",
9+
"userIdentity": {
10+
"principalId": "AWS:AIDAINPONIXQXHT3IKHL2"
11+
},
12+
"requestParameters": {
13+
"sourceIPAddress": "205.255.255.255"
14+
},
15+
"responseElements": {
16+
"x-amz-request-id": "D82B88E5F771F645",
17+
"x-amz-id-2": "vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo="
18+
},
19+
"s3": {
20+
"s3SchemaVersion": "1.0",
21+
"configurationId": "828aa6fc-f7b5-4305-8584-487c791949c1",
22+
"bucket": {
23+
"name": "<your-bucket-name-here",
24+
"ownerIdentity": {
25+
"principalId": "A3I5XTEXAMAI3E"
26+
},
27+
"arn": "arn:aws:s3:::lambda-artifacts-deafc19498e3f2df"
28+
},
29+
"object": {
30+
"key": "<your-source-object-key-here>",
31+
"size": 1305107,
32+
"eTag": "b21b84d653bb07b05b1e6b33684dc11b",
33+
"sequencer": "0C0F6F405D6ED209E1"
34+
}
35+
}
36+
}
37+
]
38+
}
4.54 MB
Loading
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"title": "AWS Amazon S3 to AWS Lambda Image Resizing",
3+
"description": "Create a Lambda function that resizes images uploaded to S3.",
4+
"language": "Python",
5+
"level": "200",
6+
"framework": "SAM",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"A Lambda function consumes events from an Amazon S3 bucket. The Lambda code checks the uploaded file is an image and creates a thumbnail version of the image in the destination bucket.",
11+
"This pattern deploys a Lambda function and two S3 buckets."
12+
]
13+
},
14+
"gitHub": {
15+
"template": {
16+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/s3-lambda-resizing-python",
17+
"templateURL": "serverless-patterns/s3-lambda-resizing-python",
18+
"projectFolder": "s3-lambda-resizing-python",
19+
"templateFile": "template.yaml"
20+
}
21+
},
22+
"resources": {
23+
"bullets": [
24+
{
25+
"text": "Process S3 events with Lambda",
26+
"link": "https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html"
27+
}
28+
]
29+
},
30+
"deploy": {
31+
"text": [
32+
"sam deploy --guided"
33+
]
34+
},
35+
"testing": {
36+
"text": [
37+
"See the GitHub repo for detailed testing instructions."
38+
]
39+
},
40+
"cleanup": {
41+
"text": [
42+
"Delete the application: <code>sam delete</code>."
43+
]
44+
},
45+
"authors": [
46+
{
47+
"name": "Seshu Brahma",
48+
"image": "https://i.postimg.cc/ZR0MyrTN/seshub-photo.jpg",
49+
"bio": "SDE for AWS Lambda",
50+
"linkedin": "seshu-brahma"
51+
}
52+
]
53+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{
2+
"title": "Resizing images uploaded to Amazon S3 with AWS Lambda",
3+
"description": "Create an AWS Lambda function that resizes images uploaded to Amazon S3.",
4+
"language": "Python",
5+
"level": "200",
6+
"framework": "SAM",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"A Lambda function consumes events from an Amazon S3 bucket. The Lambda code checks the uploaded file is an image, creates a thumbnail version of the image, then uploads the thumbnail to the destination bucket.",
11+
"This pattern deploys a Lambda function and two S3 buckets."
12+
]
13+
},
14+
"gitHub": {
15+
"template": {
16+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/s3-lambda-resizing-python",
17+
"templateURL": "serverless-patterns/s3-lambda-resizing-python",
18+
"projectFolder": "s3-lambda-resizing-python",
19+
"templateFile": "template.yaml"
20+
}
21+
},
22+
"resources": {
23+
"bullets": [
24+
{
25+
"text": "Process S3 events with Lambda",
26+
"link": "https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html"
27+
}
28+
]
29+
},
30+
"deploy": {
31+
"text": [
32+
"sam deploy --guided"
33+
]
34+
},
35+
"testing": {
36+
"text": [
37+
"See the GitHub repo for detailed testing instructions."
38+
]
39+
},
40+
"cleanup": {
41+
"text": [
42+
"Delete the application: <code>sam delete</code>."
43+
]
44+
},
45+
"authors": [
46+
{
47+
"name": "Seshu Brahma",
48+
"image": "https://i.postimg.cc/ZR0MyrTN/seshub-photo.jpg",
49+
"bio": "SDE for AWS Lambda",
50+
"linkedin": "seshu-brahma"
51+
}
52+
],
53+
"patternArch": {
54+
"icon1": {
55+
"x": 20,
56+
"y": 50,
57+
"service": "s3",
58+
"label": "Amazon S3"
59+
},
60+
"icon2": {
61+
"x": 50,
62+
"y": 50,
63+
"service": "lambda",
64+
"label": "AWS Lambda"
65+
},
66+
"icon3": {
67+
"x": 80,
68+
"y": 50,
69+
"service": "s3",
70+
"label": "Amazon S3"
71+
},
72+
"line1": {
73+
"from": "icon1",
74+
"to": "icon2",
75+
"label": "Object Created"
76+
},
77+
"line2": {
78+
"from": "icon2",
79+
"to": "icon3"
80+
}
81+
}
82+
}

s3-lambda-resizing-python/src/__init__.py

Whitespace-only changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import os
2+
import uuid
3+
from urllib.parse import unquote_plus
4+
import boto3
5+
from PIL import Image
6+
7+
s3_client = boto3.client('s3')
8+
9+
def resize_image(image_path, resized_path):
10+
with Image.open(image_path) as image:
11+
image.thumbnail(tuple(x / 2 for x in image.size))
12+
image.save(resized_path)
13+
14+
def lambda_handler(event, context):
15+
for record in event['Records']:
16+
bucket = record['s3']['bucket']['name']
17+
key = unquote_plus(record['s3']['object']['key'])
18+
tmpkey = key.replace('/', '')
19+
download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey)
20+
upload_path = '/tmp/resized-{}'.format(tmpkey)
21+
s3_client.download_file(bucket, key, download_path)
22+
resize_image(download_path, upload_path)
23+
s3_client.upload_file(upload_path, os.getenv('DESTINATION_BUCKETNAME'), 'resized-{}'.format(key))
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pillow
2+
boto3
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: Image resizing service (uksb-1tthgi812) (tag:s3-lambda-resizing-python)
4+
5+
Parameters:
6+
SourceBucketName:
7+
Type: String
8+
# Pass your bucket name dynamically or change it here
9+
Default: my-source-bucket-name
10+
DestinationBucketName:
11+
Type: String
12+
# Pass your bucket name dynamically or change it here
13+
Default: my-destination-bucket-name
14+
15+
Resources:
16+
## S3 bucket
17+
SourceBucket:
18+
Type: AWS::S3::Bucket
19+
Properties:
20+
BucketName: !Ref SourceBucketName
21+
DestinationBucket:
22+
Type: AWS::S3::Bucket
23+
Properties:
24+
BucketName: !Ref DestinationBucketName
25+
26+
## Lambda function
27+
ResizerFunction:
28+
Type: AWS::Serverless::Function
29+
Properties:
30+
CodeUri: src/
31+
Handler: app.lambda_handler
32+
Runtime: python3.12
33+
MemorySize: 2048
34+
Layers:
35+
- !Sub 'arn:aws:lambda:${AWS::Region}:175033217214:layer:graphicsmagick:2'
36+
Policies:
37+
- S3ReadPolicy:
38+
BucketName: !Ref SourceBucketName
39+
- S3CrudPolicy:
40+
BucketName: !Ref DestinationBucketName
41+
Environment:
42+
Variables:
43+
DESTINATION_BUCKETNAME: !Ref DestinationBucketName
44+
Events:
45+
FileUpload:
46+
Type: S3
47+
Properties:
48+
Bucket: !Ref SourceBucket
49+
Events: s3:ObjectCreated:*
50+
Filter:
51+
S3Key:
52+
Rules:
53+
- Name: suffix
54+
Value: '.jpeg'
55+
Outputs:
56+
SourceBucketName:
57+
Value: !Ref SourceBucketName
58+
Description: S3 Bucket for object storage
59+
DestinationBucketName:
60+
Value: !Ref DestinationBucketName
61+
Description: S3 destination Bucket for object storage
62+
FunctionArn:
63+
Value: !Ref ResizerFunction
64+
Description: ResizerFunction function Arn

0 commit comments

Comments
 (0)