github.com/mweagle/Sparta@v1.15.0/docs_source/content/reference/eventsources/s3.md (about) 1 --- 2 date: 2016-03-09T19:56:50+01:00 3 title: S3 4 weight: 10 5 --- 6 7 8 In this section we'll walkthrough how to trigger your lambda function in response to S3 events. This overview is based on the [SpartaImager](https://github.com/mweagle/SpartaImager) sample code if you'd rather jump to the end result. 9 10 # Goal 11 12 Assume we have an S3 bucket that stores images. You've been asked to write a service that creates a duplicate image that includes a characteristic stamp overlay and store it in the same S3 bucket. 13 14 ## Getting Started 15 16 We'll start with an empty lambda function and build up the needed functionality. 17 18 ```go 19 import ( 20 awsLambdaEvents "github.com/aws/aws-lambda-go/events" 21 awsLambdaContext "github.com/aws/aws-lambda-go/lambdacontext" 22 ) 23 24 type transformedResponse struct { 25 Bucket string 26 Key string 27 } 28 29 func transformImage(ctx context.Context, event awsLambdaEvents.S3Event) ([]transformedResponse, error) { 30 logger, _ := ctx.Value(sparta.ContextKeyLogger).(*logrus.Logger) 31 lambdaContext, _ := awsLambdaContext.FromContext(ctx) 32 logger.WithFields(logrus.Fields{ 33 "RequestID": lambdaContext.AwsRequestID, 34 "RecordCount": len(event.Records), 35 }).Info("Request received 👍") 36 37 ``` 38 39 40 Since the `transformImage` is expected to be triggered by S3 event changes, we can transparently unmarshal 41 the incoming request into an [S3Event](https://github.com/aws/aws-lambda-go/blob/master/events/s3.go#L9) 42 defined by the AWS Go Lambda SDK. 43 44 S3 events are delivered in batches, via lists of [EventRecords](https://godoc.org/github.com/mweagle/Sparta/aws/s3#EventRecord), so we'll need to process each record. 45 46 ```go 47 for _, eachRecord := range event.Records { 48 // What happened? 49 switch eachRecord.EventName { 50 case "ObjectCreated:Put": 51 { 52 err = stampImage(eachRecord.S3.Bucket.Name, eachRecord.S3.Object.Key, logger) 53 } 54 case "s3:ObjectRemoved:Delete": 55 { 56 // Delete stamped image 57 } 58 default: 59 { 60 logger.Info("Unsupported event: ", eachRecord.EventName) 61 } 62 } 63 64 // 65 if err != nil { 66 logger.Error("Failed to process event: ", err.Error()) 67 http.Error(w, err.Error(), http.StatusInternalServerError) 68 } 69 } 70 ``` 71 72 The [stampImage](https://github.com/mweagle/SpartaImager/blob/master/application.go#L57) function does most of the work, fetching the S3 image to memory, 73 applying the stamp, and putting the transformed content back to S3 with a new name. It uses a simple **xformed_** keyname prefix to identify 74 items which have already been stamped & prevents an "event-storm" from being triggered. This simple approach is acceptable for an example, 75 but in production you should use a more durable approach. 76 77 ## Sparta Integration 78 79 With the core of the `transformImage` complete, the next step is to integrate the **go** function with Sparta. This is performed by the [imagerFunctions](https://github.com/mweagle/SpartaImager/blob/master/application.go#L200) source. 80 81 Our lambda function needs to both *Get* and *Put* items back to an S3 bucket, so we need an IAM Role that grants those privileges under which the function will execute: 82 83 ```go 84 // Provision an IAM::Role as part of this application 85 var iamRole = sparta.IAMRoleDefinition{} 86 87 // Setup the ARN that includes all child keys 88 resourceArn := fmt.Sprintf("%s/*", s3EventBroadcasterBucket) 89 iamRole.Privileges = append(iamRole.Privileges, sparta.IAMRolePrivilege{ 90 Actions: []string{"s3:GetObject", 91 "s3:PutObject", 92 }, 93 Resource: resourceArn, 94 }) 95 ``` 96 97 The `s3EventBroadcasterBucket` param is the ARN of the S3 bucket that will trigger your lambda function (eg: _arn:aws:s3:::MyImagingS3Bucket_). 98 99 With the IAM Role defined, we can create the Sparta lambda function for `transformImage`: 100 101 ```go 102 // The default timeout is 3 seconds - increase that to 30 seconds s.t. the 103 // transform lambda doesn't fail early. 104 transformOptions := &sparta.LambdaFunctionOptions{ 105 Description: "Stamp assets in S3", 106 MemorySize: 128, 107 Timeout: 30, 108 } 109 lambdaFn, _ := sparta.NewAWSLambda(sparta.LambdaName(transformImage), 110 transformImage, 111 iamRole) 112 lambdaFn.Options = transformOptions 113 ``` 114 115 It typically takes more than 3 seconds to apply the transform, so we increase the execution timeout and provision a new 116 lambda function using the `iamRole` we defined earlier. 117 118 ## Event Source Registration 119 120 If we were to deploy this Sparta application, the `transformImage` function would have the ability to *Get* and *Put* back 121 to the `s3EventBroadcasterBucket`, but would not be invoked in response to events triggered by that bucket. To register 122 for state change events, we need to configure the lambda's [Permissions](http://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html): 123 124 ```go 125 ////////////////////////////////////////////////////////////////////////////// 126 // S3 configuration 127 // 128 lambdaFn.Permissions = append(lambdaFn.Permissions, sparta.S3Permission{ 129 BasePermission: sparta.BasePermission{ 130 SourceArn: s3EventBroadcasterBucket, 131 }, 132 Events: []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:*"}, 133 }) 134 lambdaFunctions = append(lambdaFunctions, lambdaFn) 135 ``` 136 137 When `Sparta` generates the CloudFormation template, it scans for `Permission` configurations. 138 For [push based sources](http://docs.aws.amazon.com/lambda/latest/dg/intro-invocation-modes.html) like S3, Sparta uses that 139 service's APIs to register your lambda function as a publishing target for events. This remote registration is handled 140 automatically by CustomResources added to the CloudFormation template. 141 142 # Wrapping Up 143 144 With the `lambdaFn` fully defined, we can provide it to `sparta.Main()` and deploy our service. The workflow below is shared by all S3-triggered lambda functions: 145 146 * Define the lambda function (`transformImage`). 147 * Implement the associated business logic (`stampImage`). 148 * If needed, create the required [IAMRoleDefinition](https://godoc.org/github.com/mweagle/Sparta*IAMRoleDefinition) with appropriate privileges. 149 * Provide the lambda function & IAMRoleDefinition to `sparta.NewAWSLambda()` 150 * Add the necessary [Permissions](https://godoc.org/github.com/mweagle/Sparta#LambdaAWSInfo) to the `LambdaAWSInfo` struct so that the lambda function is triggered. 151 152 The [SpartaImager](https://github.com/mweagle/SpartaImager) repo contains the full code, and includes [API Gateway](/reference/apigateway) support that allows you to publicly fetch the stamped image via an expiring S3 URL. 153 154 ## Other Resources 155 156 * The AWS docs have an excellent [S3 event source](http://docs.aws.amazon.com/lambda/latest/dg/getting-started-amazons3-events.html) walkthrough.