Pytanie Włącz funkcję Lambda do wiadra S3 przy użyciu chmury


Tworzymy wiaderko S3 przy użyciu szablonu CloudFormation. Chciałbym skojarzyć (Dodaj wydarzenie do wiadra S3) funkcję Lambda za każdym razem, gdy plik jest dodawany do wiadra S3.

Jak to jest możliwe dzięki szablonom CloudFormation. Jakie są właściwości, które muszą być używane w CloudFormation.


14
2018-03-31 16:28


pochodzenie


Chcesz, aby lambda została uruchomiona po utworzeniu pojemnika lub gdy obiekt (PutObject) został utworzony w wiadrze? - helloV


Odpowiedzi:


Oto kompletny, samodzielny szablon CloudFormation, który demonstruje sposób wyzwalania funkcji Lambda za każdym razem, gdy plik zostanie dodany do zasobnika S3:

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

16
2018-01-07 06:27



Dziękuję bardzo za przykład pracy. Zaoszczędził dużo czasu! Ale czy mógłbyś mi powiedzieć, dlaczego tak jest S3Object w tym szablonie? Nie widzę, że nigdzie się nie odzywa? - Cherry
@Wiśnia S3Object i S3ObjectFunction automatycznie tworzy obiekt w wiadrze S3, aby uruchomić funkcję Lambda, tylko do testowania. Normalnie byłby on uruchamiany przez obiekty wysyłane ręcznie, więc nie jest potrzebny we własnej implementacji. - wjordan


Potrzebna jest właściwość PowiadomienieKonferencji w szablonie CloudFormation. Niestety, wydaje się, że wiadro już istnieje. Aby obejść ten problem, możesz utworzyć początkowy stos, a następnie zaktualizować go za pomocą konfiguracji NotificationConfiguration. Na przykład:

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

Możesz użyć narzędzia aws CLI, aby utworzyć stos w ten sposób:

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

5
2018-03-31 17:25



Czy potrzebujemy napisać kod dla lambda tutaj w sekcji zasobów CFT? jak odnosisz się do mylambda ?? - shiv455
Pytanie brzmi, jak wyzwolić lambdę, gdy wiadro zostanie utworzone, a nie kiedy nowy plik zostanie dodany do wiadra. - helloV
Wartość lambda nie musi być zdefiniowana w tym samym szablonie. Konfiguracja łyżki wymaga tylko ARN lambda. Jeśli twoja lambda jest ustawiona gdzie indziej, po prostu podaj ARN jako parametr szablonu. - ataylor
@ataylor, czy możesz wspomnieć w ur code, jak przekazać ARN jako parametr szablonu? - shiv455
Zaktualizowałem swoją odpowiedź, aby wprowadzić parametr lambda ARN jako parametr. - ataylor


dodałem poniŜej bucket perm wraz z powiadomieniem konfiguracyjnym w cloudformation, który jest uŜywany do tworzenia S3 bucket..it worked !!

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

1
2018-04-08 00:30





Tak, jest to możliwe dzięki Cloudformation, a to, co musisz skonfigurować, to:

1) AWS::S3::Bucket zasób i

2) NotificationConfiguration konfiguracja (użyj LambdaConfigurations w tym przypadku) dla zasobu s3 powyżej.

Powiązana dokumentacja, której potrzebujesz:

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
2018-02-07 23:16





Jest wyraźnie powiedziane w dokumentach AWS, że AWS :: S3 :: Bucket służy do tworzenia zasobu, jeśli mamy już istniejące wiadro, nie możemy go zmodyfikować, aby dodać usługę NotificationConfiguration. Więc wiadro S3 nie może istnieć, aby powyższy szablon działał. Niech CloudFormation tworzy wszystkie zasoby, w tym zasobnik S3.


0
2017-07-02 17:10