Стек Amazon Cloudformation зависает после завершения лямбда-функции

#aws-lambda #amazon-cloudformation

#aws-lambda #aws-cloudformation

Вопрос:

У меня есть простой шаблон для создания корзины S3, а затем вызова моей лямбда-функции для копирования в нее объекта из общедоступной корзины:

 AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: Create an S3 Bucket, populate it with a copy of a sample CSV file
Parameters:
  bucketname:
    Type: String
    Description: Name of bucket where the CSV file will be bootstrapped, bucket names MUST be unique across AWS and no Upper Case characters - 8 or more characters
    MinLength: 8
Outputs:
  bucketURL:
    Value:
      Fn::Join:
        - ''
        - - 'https://s3.amazonaws.com/'
          - !Ref bucketname
Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Properties:
      BucketName: !Ref bucketname
  deploytos3:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs12.x
      CodeUri: 's3://mongodb-aws-jam/lambdaDeploy.zip'
      Policies:
        - AWSLambdaBasicExecutionRole
        - AmazonS3FullAccess
  DeploymentCustomResource:
    Type: Custom::deploytos3
    Properties:
      ServiceToken: !GetAtt deploytos3.Arn
      bucketname: !Ref bucketname
  

Это лямбда-функция:

 const AWS = require('aws-sdk');
var response = require('cfn-response');

const s3 = new AWS.S3();
const srcBucket = "mongodb-aws-jam"
const srcKey = "SampleData.csv"

exports.handler = async (event, context) => {
    console.log("start")
    myBucket = event.ResourceProperties['bucketname']
    console.log(`Will bootstrap ${srcKey} object in ${myBucket} bucket`)

    const copyparams = {
        Bucket : myBucket,
        CopySource : `/${srcBucket}/${srcKey}`,
        Key : srcKey
    };

    try {
        await s3.copyObject(copyparams).promise();
    } catch (error) {
        const errorText = `Failed to copy file to ${myBucket}/${srcKey}: error`
        console.log(errorText)
        // callback(null, {statusCode: 500, body: errorText})
        response.send(event, context, response.FAILED, {Error: errorText})
        return
    }
    resultText = `Copied file to ${myBucket}/${srcKey}`
    console.log(resultText)
    // callback(null, {statusCode: 200, body: resultText})
    response.send(event, context, response.SUCCESS, {})
};
  

Стеку удается создать и загрузить новую корзину, но история стека показывает, что DeploymentCustomResource ресурс никогда не выходит за пределы CREATE_IN_PROGRESS статуса, хотя журналы lambda показывают, что функция успешно завершена. Я пробовал различные альтернативы использованию обратного вызова и сократил функцию до того, что она не выполняла никакой работы, но стек всегда зависает.

Есть предложения?

Ответ №1:

Ваша функция застревает, CREATE_IN_PROGRESS поскольку CloudFormation (CFN) ожидает правильного ответа от функции. Ваш код этого не предоставляет.

Функции для пользовательских ресурсов требуют специального дизайна. Необходимо правильно обработать событие CFN и соответствующим образом отреагировать.

Для функций в nodejs вы можете использовать вспомогательную библиотеку cfn-response , как показано в модуле cfn-response . Примеры функций ресурсов cusstom в nodejs приведены здесь.

Комментарии:

1. Я также пробовал cfn-response , например var response = require('cfn-response'); ... response.send(event, context, response.SUCCESS, {}) , но пользовательский ресурс остается в CREATE_IN_PROGRESS состоянии.

2. @AndrewMorgan Добавления var response = require('cfn-response') недостаточно. Вам необходимо полностью переписать свою функцию, чтобы она соответствовала пользовательскому формату ресурсов CFN. Я предлагаю проверить документацию и примеры того, как должны быть спроектированы такие функции.

3. Я следую примеру, вызывая response.send(event, context, response.SUCCESS, {}) . Я вижу Response body: {"Status":"SUCCESS","Reason":"See the details in CloudWatch Log Stream: 2020/10/12/[$LATEST]... в журналах. Чего еще не хватает?

4. @AndrewMorgan Можете ли вы обновить свой вопрос новой версией кода?

5. @AndrewMorgan Я предполагаю, что вы связали cfn-response модуль со своей функцией?

Ответ №2:

Я думаю, проблема заключалась в том, что handler она была асинхронной.

Это рабочая функция:

 const AWS = require('aws-sdk');
const response = require('cfn-response');

const s3 = new AWS.S3();
const srcBucket = "mongodb-aws-jam"
const srcKey = "SampleData.csv"

exports.handler = function(event, context) {
  var bucket = event.ResourceProperties.bucketname;
  console.log(`Bucket: ${bucket}`);
  const copyparams = {
    Bucket : bucket,
    CopySource : `/${srcBucket}/${srcKey}`,
    Key : srcKey
  };
  s3.copyObject(copyparams).promise()
  .then (() => {
      var responseData = {Value: bucket};
      console.log("Success");
      response.send(event, context, response.SUCCESS, responseData);
  }, error => {
      const errorText = `Failed to copy file to ${bucket}/${srcKey}: ${error}`
      console.log(errorText)
      response.send(event, context, response.FAILED, {Error: errorText})
  })
};
  

Комментарии:

1. вы правы! Спасибо, что подняли эту проблему, теперь ребята могут ее найти.