#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. вы правы! Спасибо, что подняли эту проблему, теперь ребята могут ее найти.