CloudFormationテンプレートを使用してS3バケットを作成しています。ファイルがS3バケットに追加されるたびにLambda関数を関連付けます(イベントをS3バケットに追加します)。
CloudFormationテンプレートを通じてどのように可能ですか。 CloudFormationで使用する必要があるプロパティは何ですか。
以下は、ファイルがS3バケットに追加されるたびにLambda関数をトリガーする方法を示す完全な自己完結型のCloudFormationテンプレートです。
Description: Upload an object to an S3 bucket, triggering a Lambda event, returning the object key as a Stack Output.
Parameters:
Key:
Description: S3 Object key
Type: String
Default: test
Body:
Description: S3 Object body content
Type: String
Default: TEST CONTENT
BucketName:
Description: S3 Bucket name
Type: String
Resources:
Bucket:
Type: AWS::S3::Bucket
DependsOn: BucketPermission
Properties:
BucketName: !Ref BucketName
NotificationConfiguration:
LambdaConfigurations:
- Event: 's3:ObjectCreated:*'
Function: !GetAtt BucketWatcher.Arn
BucketPermission:
Type: AWS::Lambda::Permission
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: !Ref BucketWatcher
Principal: s3.amazonaws.com
SourceAccount: !Ref "AWS::AccountId"
SourceArn: !Sub "arn:aws:s3:::${BucketName}"
BucketWatcher:
Type: AWS::Lambda::Function
Properties:
Description: Sends a Wait Condition signal to Handle when invoked
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: !Sub |
exports.handler = function(event, context) {
console.log("Request received:\n", JSON.stringify(event));
var responseBody = JSON.stringify({
"Status" : "SUCCESS",
"UniqueId" : "Key",
"Data" : event.Records[0].s3.object.key,
"Reason" : ""
});
var https = require("https");
var url = require("url");
var parsedUrl = url.parse('${Handle}');
var options = {
hostname: parsedUrl.hostname,
port: 443,
path: parsedUrl.path,
method: "PUT",
headers: {
"content-type": "",
"content-length": responseBody.length
}
};
var request = https.request(options, function(response) {
console.log("Status code: " + response.statusCode);
console.log("Status message: " + response.statusMessage);
context.done();
});
request.on("error", function(error) {
console.log("send(..) failed executing https.request(..): " + error);
context.done();
});
request.write(responseBody);
request.end();
};
Timeout: 30
Runtime: nodejs4.3
Handle:
Type: AWS::CloudFormation::WaitConditionHandle
Wait:
Type: AWS::CloudFormation::WaitCondition
Properties:
Handle: !Ref Handle
Timeout: 300
S3Object:
Type: Custom::S3Object
Properties:
ServiceToken: !GetAtt S3ObjectFunction.Arn
Bucket: !Ref Bucket
Key: !Ref Key
Body: !Ref Body
S3ObjectFunction:
Type: AWS::Lambda::Function
Properties:
Description: S3 Object Custom Resource
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: !Sub |
var response = require('cfn-response');
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
exports.handler = function(event, context) {
console.log("Request received:\n", JSON.stringify(event));
var responseData = {};
if (event.RequestType == 'Create') {
var params = {
Bucket: event.ResourceProperties.Bucket,
Key: event.ResourceProperties.Key,
Body: event.ResourceProperties.Body
};
s3.putObject(params).promise().then(function(data) {
response.send(event, context, response.SUCCESS, responseData);
}).catch(function(err) {
console.log(JSON.stringify(err));
response.send(event, context, response.FAILED, responseData);
});
} else if (event.RequestType == 'Delete') {
var deleteParams = {
Bucket: event.ResourceProperties.Bucket,
Key: event.ResourceProperties.Key
};
s3.deleteObject(deleteParams).promise().then(function(data) {
response.send(event, context, response.SUCCESS, responseData);
}).catch(function(err) {
console.log(JSON.stringify(err));
response.send(event, context, response.FAILED, responseData);
});
} else {
response.send(event, context, response.SUCCESS, responseData);
}
};
Timeout: 30
Runtime: nodejs4.3
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: {Service: [lambda.amazonaws.com]}
Action: ['sts:AssumeRole']
Path: /
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
Policies:
- PolicyName: S3Policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 's3:PutObject'
- 'S3:DeleteObject'
Resource: !Sub "arn:aws:s3:::${BucketName}/${Key}"
Outputs:
Result:
Value: !GetAtt Wait.Data
CloudFormationテンプレートにNotificationConfigurationプロパティが必要です。残念ながら、バケットがすでに存在している必要があります。これを回避するには、初期スタックを作成し、NotificationConfigurationで更新します。例えば:
// template1.json
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"mylambda": {
"Type": "String"
}
},
"Resources": {
"bucketperm": {
"Type": "AWS::Lambda::Permission",
"Properties" : {
"Action": "lambda:InvokeFunction",
"FunctionName": {"Ref": "mylambda"},
"Principal": "s3.amazonaws.com",
"SourceAccount": {"Ref": "AWS::AccountId"},
"SourceArn": { "Fn::Join": [":", [
"arn", "aws", "s3", "" , "", {"Ref" : "mybucket"}]]
}
}
},
"mybucket": {
"Type": "AWS::S3::Bucket"
}
}
}
// template2.json -- adds the ConfigurationNotification
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"mylambda": {
"Type": "String"
}
},
"Resources": {
"bucketperm": {
"Type": "AWS::Lambda::Permission",
"Properties" : {
"Action": "lambda:InvokeFunction",
"FunctionName": {"Ref": "mylambda"},
"Principal": "s3.amazonaws.com",
"SourceAccount": {"Ref": "AWS::AccountId"},
"SourceArn": { "Fn::Join": [":", [
"arn", "aws", "s3", "" , "", {"Ref" : "mybucket"}]]
}
}
},
"mybucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"NotificationConfiguration": {
"LambdaConfigurations": [
{
"Event" : "s3:ObjectCreated:*",
"Function" : {"Ref": "mylambda"}
}
]
}
}
}
}
}
Aws CLIツールを使用して、次のようなスタックを作成できます。
$ aws cloudformation create-stack --stack-name mystack --template-body file://template1.json --parameters ParameterKey=mylambda,ParameterValue=<lambda arn>
# wait until stack is created
$ aws cloudformation update-stack --stack-name mystack --template-body file://template2.json --parameters ParameterKey=mylambda,ParameterValue=<lambda arn>
はい、Cloudformationを通じて可能です。設定する必要があるものは次のとおりです。
1)AWS::S3::Bucket
リソース、および
2)上記のs3リソースのNotificationConfiguration
設定(この場合はLambdaConfigurations
を使用)。
必要な関連ドキュメント:
s3バケットを作成するために使用されるcloudformationの通知設定とともにバケットpermを追加しました。
"bucketperm": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:invokeFunction",
"FunctionName": "<arnvalue>",
"Principal": "s3.amazonaws.com"
}
}
AWSのドキュメントには、リソースの作成にAWS :: S3 :: Bucketが使用されていることが明記されています。既に存在するバケットがある場合、NotificationConfigurationを追加するためにそれを変更することはできません。したがって、上記のテンプレートが機能するには、S3バケットが存在していてはなりません。 CloudFormationがS3バケットを含むすべてのリソースを作成するようにします。