Skip to content

Commit 501c2f3

Browse files
kdnaktbmoffatt
andauthored
Add S3ObjectLambdaEvent (#536)
* Add S3ObjectLambdaEvent * Update S3 Object Lambda sample code * Avoid the generic name of Configuration * Follow stylecheck * Add S3ObjectLambda prefix * fix Url to URL --------- Co-authored-by: Bryan Moffatt <[email protected]>
1 parent 50dbfb1 commit 501c2f3

8 files changed

+343
-0
lines changed

events/README_S3_Object_Lambda.md

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Sample Function
2+
3+
The following is a sample class and Lambda function that receives Amazon S3 Object Lambda event record data as an input and returns an object metadata output.
4+
5+
```go
6+
7+
// main.go
8+
package main
9+
10+
import (
11+
"context"
12+
"crypto/md5"
13+
"encoding/hex"
14+
"encoding/json"
15+
"io/ioutil"
16+
"net/http"
17+
"github.com/aws/aws-lambda-go/lambda"
18+
"github.com/aws/aws-lambda-go/events"
19+
"github.com/aws/aws-sdk-go-v2/config"
20+
"github.com/aws/aws-sdk-go-v2/service/s3"
21+
)
22+
23+
func handler(ctx context.Context, event events.S3ObjectLambdaEvent) error {
24+
url := event.GetObjectContext.InputS3Url
25+
resp, err := http.Get(url)
26+
if err != nil {
27+
return err
28+
}
29+
defer resp.Body.Close()
30+
bodyBytes, err := ioutil.ReadAll(resp.Body)
31+
if err != nil {
32+
return err
33+
}
34+
transformedObject := TransformedObject{
35+
Metadata: Metadata{
36+
Length: len(bodyBytes),
37+
Md5: toMd5(bodyBytes),
38+
},
39+
}
40+
jsonData, err := json.Marshal(transformedObject)
41+
if err != nil {
42+
return err
43+
}
44+
cfg, err := config.LoadDefaultConfig(context.TODO())
45+
if err != nil {
46+
return err
47+
}
48+
svc := s3.NewFromConfig(cfg)
49+
input := &s3.WriteGetObjectResponseInput{
50+
RequestRoute: &event.GetObjectContext.OutputRoute,
51+
RequestToken: &event.GetObjectContext.OutputToken,
52+
Body: strings.NewReader(string(jsonData)),
53+
}
54+
res, err := svc.WriteGetObjectResponse(ctx, input)
55+
if err != nil {
56+
return err
57+
}
58+
fmt.Printf("%v", res)
59+
return nil
60+
}
61+
62+
func toMd5(data []byte) string {
63+
hasher := md5.New()
64+
hasher.Write(data)
65+
hash := hasher.Sum(nil)
66+
67+
return hex.EncodeToString(hash)
68+
}
69+
70+
type TransformedObject struct {
71+
Metadata Metadata `json:"metadata"`
72+
}
73+
74+
type Metadata struct {
75+
Length int `json:"length"`
76+
Md5 string `json:"md5"`
77+
}
78+
79+
func main() {
80+
lambda.Start(handler)
81+
}
82+
83+
```

events/s3_object_lambda.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package events
2+
3+
type S3ObjectLambdaEvent struct {
4+
XAmzRequestID string `json:"xAmzRequestId"`
5+
GetObjectContext *S3ObjectLambdaGetObjectContext `json:"getObjectContext,omitempty"`
6+
ListObjectsContext *S3ObjectLambdaListObjectsContext `json:"listObjectsContext,omitempty"`
7+
ListObjectsV2Context *S3ObjectLambdaListObjectsV2Context `json:"listObjectsV2Context,omitempty"`
8+
HeadObjectContext *S3ObjectLambdaHeadObjectContext `json:"headObjectContext,omitempty"`
9+
Configuration S3ObjectLambdaConfiguration `json:"configuration"`
10+
UserRequest S3ObjectLambdaUserRequest `json:"userRequest"`
11+
UserIdentity S3ObjectLambdaUserIdentity `json:"userIdentity"`
12+
ProtocolVersion string `json:"protocolVersion"`
13+
}
14+
15+
type S3ObjectLambdaGetObjectContext struct {
16+
InputS3URL string `json:"inputS3Url"`
17+
OutputRoute string `json:"outputRoute"`
18+
OutputToken string `json:"outputToken"`
19+
}
20+
21+
type S3ObjectLambdaListObjectsContext struct {
22+
InputS3URL string `json:"inputS3Url"`
23+
}
24+
25+
type S3ObjectLambdaListObjectsV2Context struct {
26+
InputS3URL string `json:"inputS3Url"`
27+
}
28+
29+
type S3ObjectLambdaHeadObjectContext struct {
30+
InputS3URL string `json:"inputS3Url"`
31+
}
32+
33+
type S3ObjectLambdaConfiguration struct {
34+
AccessPointARN string `json:"accessPointArn"`
35+
SupportingAccessPointARN string `json:"supportingAccessPointArn"`
36+
Payload string `json:"payload"`
37+
}
38+
39+
type S3ObjectLambdaUserRequest struct {
40+
URL string `json:"url"`
41+
Headers map[string]string `json:"headers"`
42+
}
43+
44+
type S3ObjectLambdaUserIdentity struct {
45+
Type string `json:"type"`
46+
PrincipalID string `json:"principalId"`
47+
ARN string `json:"arn"`
48+
AccountID string `json:"accountId"`
49+
AccessKeyID string `json:"accessKeyId"`
50+
SessionContext *S3ObjectLambdaSessionContext `json:"sessionContext,omitempty"`
51+
}
52+
53+
type S3ObjectLambdaSessionContext struct {
54+
Attributes map[string]string `json:"attributes"`
55+
SessionIssuer *S3ObjectLambdaSessionIssuer `json:"sessionIssuer,omitempty"`
56+
}
57+
58+
type S3ObjectLambdaSessionIssuer struct {
59+
Type string `json:"type"`
60+
PrincipalID string `json:"principalId"`
61+
ARN string `json:"arn"`
62+
AccountID string `json:"accountId"`
63+
UserName string `json:"userName"`
64+
}

events/s3_object_lambda_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package events
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/aws/aws-lambda-go/events/test"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestS3ObjectLambdaEventMarshaling(t *testing.T) {
12+
tests := []struct {
13+
file string
14+
}{
15+
{"./testdata/s3-object-lambda-event-get-object-iam.json"},
16+
{"./testdata/s3-object-lambda-event-get-object-assumed-role.json"},
17+
{"./testdata/s3-object-lambda-event-head-object-iam.json"},
18+
{"./testdata/s3-object-lambda-event-list-objects-iam.json"},
19+
{"./testdata/s3-object-lambda-event-list-objects-v2-iam.json"},
20+
}
21+
22+
for _, tc := range tests {
23+
tc := tc
24+
t.Run(tc.file, func(t *testing.T) {
25+
inputJSON := test.ReadJSONFromFile(t, tc.file)
26+
27+
var inputEvent S3ObjectLambdaEvent
28+
if err := json.Unmarshal(inputJSON, &inputEvent); err != nil {
29+
t.Errorf("could not unmarshal event. details: %v", err)
30+
}
31+
32+
outputJSON, err := json.Marshal(inputEvent)
33+
if err != nil {
34+
t.Errorf("could not marshal event. details: %v", err)
35+
}
36+
37+
assert.JSONEq(t, string(inputJSON), string(outputJSON))
38+
})
39+
}
40+
}
41+
42+
func TestS3ObjectLambdaMarshalingMalformedJson(t *testing.T) {
43+
test.TestMalformedJson(t, S3ObjectLambdaEvent{})
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"xAmzRequestId": "requestId",
3+
"getObjectContext": {
4+
"inputS3Url": "https://my-s3-ap-111122223333.s3-accesspoint.us-east-1.amazonaws.com/example?X-Amz-Security-Token=<snip>",
5+
"outputRoute": "io-use1-001",
6+
"outputToken": "OutputToken"
7+
},
8+
"configuration": {
9+
"accessPointArn": "arn:aws:s3-object-lambda:us-east-1:111122223333:accesspoint/example-object-lambda-ap",
10+
"supportingAccessPointArn": "arn:aws:s3:us-east-1:111122223333:accesspoint/example-ap",
11+
"payload": "{}"
12+
},
13+
"userRequest": {
14+
"url": "https://object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com/example",
15+
"headers": {
16+
"Host": "object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com",
17+
"Accept-Encoding": "identity",
18+
"X-Amz-Content-SHA256": "e3b0c44298fc1example"
19+
}
20+
},
21+
"userIdentity": {
22+
"type": "AssumedRole",
23+
"principalId": "principalId",
24+
"arn": "arn:aws:sts::111122223333:assumed-role/Admin/example",
25+
"accountId": "111122223333",
26+
"accessKeyId": "accessKeyId",
27+
"sessionContext": {
28+
"attributes": {
29+
"mfaAuthenticated": "false",
30+
"creationDate": "Wed Mar 10 23:41:52 UTC 2021"
31+
},
32+
"sessionIssuer": {
33+
"type": "Role",
34+
"principalId": "principalId",
35+
"arn": "arn:aws:iam::111122223333:role/Admin",
36+
"accountId": "111122223333",
37+
"userName": "Admin"
38+
}
39+
}
40+
},
41+
"protocolVersion": "1.00"
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"xAmzRequestId": "requestId",
3+
"getObjectContext": {
4+
"inputS3Url": "https://my-s3-ap-111122223333.s3-accesspoint.us-east-1.amazonaws.com/example?X-Amz-Security-Token=<snip>",
5+
"outputRoute": "io-use1-001",
6+
"outputToken": "OutputToken"
7+
},
8+
"configuration": {
9+
"accessPointArn": "arn:aws:s3-object-lambda:us-east-1:111122223333:accesspoint/example-object-lambda-ap",
10+
"supportingAccessPointArn": "arn:aws:s3:us-east-1:111122223333:accesspoint/example-ap",
11+
"payload": "{}"
12+
},
13+
"userRequest": {
14+
"url": "https://object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com/example",
15+
"headers": {
16+
"Host": "object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com",
17+
"Accept-Encoding": "identity",
18+
"X-Amz-Content-SHA256": "e3b0c44298fc1example"
19+
}
20+
},
21+
"userIdentity": {
22+
"type": "IAMUser",
23+
"principalId": "principalId",
24+
"arn": "arn:aws:iam::111122223333:user/username",
25+
"accountId": "111122223333",
26+
"accessKeyId": "accessKeyId"
27+
},
28+
"protocolVersion": "1.00"
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"xAmzRequestId": "requestId",
3+
"headObjectContext": {
4+
"inputS3Url": "https://my-s3-ap-111122223333.s3-accesspoint.us-east-1.amazonaws.com/example?X-Amz-Security-Token=<snip>"
5+
},
6+
"configuration": {
7+
"accessPointArn": "arn:aws:s3-object-lambda:us-east-1:111122223333:accesspoint/example-object-lambda-ap",
8+
"supportingAccessPointArn": "arn:aws:s3:us-east-1:111122223333:accesspoint/example-ap",
9+
"payload": "{}"
10+
},
11+
"userRequest": {
12+
"url": "https://object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com/example",
13+
"headers": {
14+
"Host": "object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com",
15+
"Accept-Encoding": "identity",
16+
"X-Amz-Content-SHA256": "e3b0c44298fc1example"
17+
}
18+
},
19+
"userIdentity": {
20+
"type": "IAMUser",
21+
"principalId": "principalId",
22+
"arn": "arn:aws:iam::111122223333:user/username",
23+
"accountId": "111122223333",
24+
"accessKeyId": "accessKeyId"
25+
},
26+
"protocolVersion": "1.01"
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"xAmzRequestId": "requestId",
3+
"listObjectsContext": {
4+
"inputS3Url": "https://my-s3-ap-111122223333.s3-accesspoint.us-east-1.amazonaws.com/example?X-Amz-Security-Token=<snip>"
5+
},
6+
"configuration": {
7+
"accessPointArn": "arn:aws:s3-object-lambda:us-east-1:111122223333:accesspoint/example-object-lambda-ap",
8+
"supportingAccessPointArn": "arn:aws:s3:us-east-1:111122223333:accesspoint/example-ap",
9+
"payload": "{}"
10+
},
11+
"userRequest": {
12+
"url": "https://object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com/example",
13+
"headers": {
14+
"Host": "object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com",
15+
"Accept-Encoding": "identity",
16+
"X-Amz-Content-SHA256": "e3b0c44298fc1example"
17+
}
18+
},
19+
"userIdentity": {
20+
"type": "IAMUser",
21+
"principalId": "principalId",
22+
"arn": "arn:aws:iam::111122223333:user/username",
23+
"accountId": "111122223333",
24+
"accessKeyId": "accessKeyId"
25+
},
26+
"protocolVersion": "1.01"
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"xAmzRequestId": "requestId",
3+
"listObjectsV2Context": {
4+
"inputS3Url": "https://my-s3-ap-111122223333.s3-accesspoint.us-east-1.amazonaws.com/example?X-Amz-Security-Token=<snip>"
5+
},
6+
"configuration": {
7+
"accessPointArn": "arn:aws:s3-object-lambda:us-east-1:111122223333:accesspoint/example-object-lambda-ap",
8+
"supportingAccessPointArn": "arn:aws:s3:us-east-1:111122223333:accesspoint/example-ap",
9+
"payload": "{}"
10+
},
11+
"userRequest": {
12+
"url": "https://object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com/example",
13+
"headers": {
14+
"Host": "object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com",
15+
"Accept-Encoding": "identity",
16+
"X-Amz-Content-SHA256": "e3b0c44298fc1example"
17+
}
18+
},
19+
"userIdentity": {
20+
"type": "IAMUser",
21+
"principalId": "principalId",
22+
"arn": "arn:aws:iam::111122223333:user/username",
23+
"accountId": "111122223333",
24+
"accessKeyId": "accessKeyId"
25+
},
26+
"protocolVersion": "1.01"
27+
}

0 commit comments

Comments
 (0)