2016-08-03 138 views
7

我正尝试在CloudFormation模板中为Lambda函数创建S3触发器。 S3存储桶已存在,并且正在创建Lambda函数。使用CloudFormation在S3存储桶中创建Lambda通知

This表示无法使用CFT修改预先存在的基础设施(本例中为S3),但this似乎表示该存储桶必须预先存在。

  1. 似乎无法使用CFT类型“AWS :: Lambda ...”创建触发器,并且源服务需要创建触发器。就我而言,这是s3存储桶的NotificationConfiguration-LambdaConfiguration。这一切是否正确?

  2. 当我试图将一个NotificationConfiguration添加到现有的带有CFT的S3存储桶时,它说我不能。有没有办法做到这一点?

+0

我相当肯定,而桶中有存在,它没有创作模板之前存在。会在同一模板中的通知配置和lambda函数旁边创建存储桶以适合您的用例吗?如果是这样,这种方法比修改现有的基础设施更容易帮助你。无论哪种方式都有解决方案,但其中一个更漂亮 –

+0

当您说'S3存储桶已经存在'时,您是否还暗示该存储桶是在CloudFormation之外创建的? – Aditya

回答

4

不幸的是,官方AWS::CloudFormation模板只允许您控制Amazon S3 NotificationConfiguration作为父AWS::S3::Bucket资源,这意味着你不能这个配置连接到任何现有的桶的NotificationConfiguration property,你必须把它应用到CloudFormation管理的存储桶可以工作。

解决方法是使用putBucketNotificationConfiguration JavaScript API调用直接将PUT Bucket Notification API调用作为Lambda-backed Custom Resource。但是,由于修改S3存储桶上的NotificationConfiguration仅限于存储桶的创建者,因此还需要添加一个AWS::S3::BucketPolicy资源,以授予您的Lambda功能访问s3:PutBucketNotification操作的权限。

以下是一个演示如何触发每当一个文件被添加到现有 S3桶lambda函数,使用2 LAMBDA后援自定义资源(BucketConfiguration设置桶通知配置一个完整的,自包含的CloudFormation模板, S3Object将对象上传到存储区)和第三个Lambda函数(BucketWatcher以在对象上载到存储区时触发等待条件)。

Launch Stack

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 (must already exist) 
    Type: String 
Resources: 
    BucketConfiguration: 
    Type: Custom::S3BucketConfiguration 
    DependsOn: 
    - BucketPermission 
    - NotificationBucketPolicy 
    Properties: 
     ServiceToken: !GetAtt S3BucketConfiguration.Arn 
     Bucket: !Ref BucketName 
     NotificationConfiguration: 
     LambdaFunctionConfigurations: 
     - Events: ['s3:ObjectCreated:*'] 
      LambdaFunctionArn: !GetAtt BucketWatcher.Arn 
    S3BucketConfiguration: 
    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) { 
      var respond = (e) => response.send(event, context, e ? response.FAILED : response.SUCCESS, e ? e : {}); 
      process.on('uncaughtException', e=>failed(e)); 
      var params = event.ResourceProperties; 
      delete params.ServiceToken; 
      if (event.RequestType === 'Delete') { 
       params.NotificationConfiguration = {}; 
       s3.putBucketNotificationConfiguration(params).promise() 
       .then((data)=>respond()) 
       .catch((e)=>respond()); 
      } else { 
       s3.putBucketNotificationConfiguration(params).promise() 
       .then((data)=>respond()) 
       .catch((e)=>respond(e)); 
      } 
      }; 
     Timeout: 30 
     Runtime: nodejs4.3 
    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 
    DependsOn: BucketConfiguration 
    Properties: 
     ServiceToken: !GetAtt S3ObjectFunction.Arn 
     Bucket: !Ref BucketName 
     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) { 
      var respond = (e) => response.send(event, context, e ? response.FAILED : response.SUCCESS, e ? e : {}); 
      var params = event.ResourceProperties; 
      delete params.ServiceToken; 
      if (event.RequestType == 'Create' || event.RequestType == 'Update') { 
       s3.putObject(params).promise() 
       .then((data)=>respond()) 
       .catch((e)=>respond(e)); 
      } else if (event.RequestType == 'Delete') { 
       delete params.Body; 
       s3.deleteObject(params).promise() 
       .then((data)=>respond()) 
       .catch((e)=>respond(e)); 
      } else { 
       respond({Error: 'Invalid request type'}); 
      } 
      }; 
     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}" 
    NotificationBucketPolicy: 
    Type: AWS::S3::BucketPolicy 
    Properties: 
     Bucket: !Ref BucketName 
     PolicyDocument: 
     Statement: 
      - Effect: "Allow" 
      Action: 
      - 's3:PutBucketNotification' 
      Resource: !Sub "arn:aws:s3:::${BucketName}" 
      Principal: 
       AWS: !GetAtt LambdaExecutionRole.Arn 
Outputs: 
    Result: 
    Value: !GetAtt Wait.Data 
相关问题