webentwicklung-frage-antwort-db.com.de

Aktivieren Sie die Lambda-Funktion für einen S3-Bucket mit Wolkenbildung

Wir erstellen einen S3-Bucket mit einer CloudFormation-Vorlage. Ich möchte eine Lambda-Funktion verknüpfen (Hinzufügen eines Ereignisses zu S3-Bucket), wenn eine Datei zum S3-Bucket hinzugefügt wird.

Wie ist es durch CloudFormation-Vorlagen möglich? Welche Eigenschaften müssen in CloudFormation verwendet werden?.

19
shiv455

Hier ist eine vollständige, in sich geschlossene CloudFormation-Vorlage, die zeigt, wie eine Lambda-Funktion ausgelöst wird, wenn eine Datei einem S3-Bucket hinzugefügt wird:

 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
    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
23
wjordan

Sie benötigen eine NotificationConfiguration-Eigenschaft in Ihrer CloudFormation-Vorlage. Leider scheint es, dass der Bucket bereits existiert. Um dies zu umgehen, können Sie einen anfänglichen Stapel erstellen und ihn dann mit NotificationConfiguration aktualisieren. Zum Beispiel:

// 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"}
            }
          ]
        }
      }
    }
  }
}

Sie können das aws-CLI-Tool verwenden, um den Stapel folgendermaßen zu erstellen:

$ 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>
6
ataylor

Ja, es ist durch Cloudformation möglich, und Sie müssen Folgendes konfigurieren:

1) AWS::S3::Bucket Ressource und

2) NotificationConfiguration configuration (verwenden Sie in diesem Fall LambdaConfigurations) für die s3-Ressource oben.

Zugehörige Dokumentation, die Sie benötigen:

https://docs.aws.Amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-notification

https://docs.aws.Amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-notificationconfig.html

1
Winters

ich habe unten Bucket Perm zusammen mit der Benachrichtigungskonfiguration in Cloudformation hinzugefügt, die verwendet wird, um S3 Bucket zu erstellen.

"bucketperm": {
            "Type": "AWS::Lambda::Permission",
            "Properties": {
                "Action": "lambda:invokeFunction",
                "FunctionName": "<arnvalue>",
                "Principal": "s3.amazonaws.com"
            }
}
0
shiv455

In AWS-Dokumenten wird eindeutig angegeben, dass AWS :: S3 :: Bucket zum Erstellen einer Ressource verwendet wird. Wenn bereits ein Bucket vorhanden ist, kann dieser nicht geändert werden, um NotificationConfiguration hinzuzufügen. Der S3-Bucket muss also nicht vorhanden sein, damit die oben angegebene Vorlage funktioniert. Lassen Sie CloudFormation alle Ressourcen einschließlich des S3-Buckets erstellen.

0