首页 > 解决方案 > 为什么自定义资源未能在 AWS Cloudformation 中按预期时间稳定?

问题描述

我想要一个使用 CloudFormation 创建一个新的自定义资源来获得当前日期减去 X 天的结果,当我创建 lambda 函数时,我得到错误:

资源未能在预期时间内稳定下来。

我的代码是:

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  Environment:
    Description: Environment
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - test
      - prod
      - sbx
  DaysToSubstract:
    Description: Days To Substract to calculate dates to ingest with RedshiftLoader
    Type: Number
    Default: 1
Resources:
  lambdaDateRedshiftLoader:
    Type: 'AWS::Lambda::Function'
    DependsOn:
      - lambdaDateRedshiftLoaderRole
    Properties:
      Code:
        ZipFile: !Sub |
          from datetime import date, timedelta
          import cfnresponse
          def lambda_handler(event, context):
              current_delta = date.today() - timedelta(days=event['DaysToSubstract'])
              current_delta_str = current_delta.strftime("%Y-%m-%d")
              responseData['Dates'] = current_delta_str
              cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
      Environment:
        Variables:
          DaysToSubstract: !Sub '${DaysToSubstract}'
      Description: >-
        Calculate yesterday date to obtain start and end date to load the data
        with RedshiftLoader
      Handler: index.lambda_handler
      MemorySize: 128
      Role: !GetAtt lambdaDateRedshiftLoaderRole.Arn
      Runtime: python3.7
      Timeout: 30
  lambdaDateRedshiftLoaderRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: !Sub 'a3m${Environment}-datesRL-lambda-role'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action:
              - 'sts:AssumeRole'
            Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
      Path: /service-role/
      Policies:
        - PolicyName: !Sub 'a3m${Environment}-lambda-datesRL-lambda-logs-policy'
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Effect: Allow
                Resource:
                  - !Sub >-
                    arn:aws:logs:eu-west-1:${AWS::AccountId}:log-group:/aws/lambda/lambda-datesRL-uyc:*
  lambdaRL:
    Type: 'Custom::Value'
    Properties:
      ServiceToken: !GetAtt lambdaDateRedshiftLoader.Arn
Outputs:
  LambdaFunctionOutput:
    Value: !GetAtt lambdaRL.Dates
    Description: Return Value of Lambda Function (Date minus x days)

我在输出中使用cfnresponseSUCCESS使用!GetAtt lambdaRL.Dates

先感谢您

标签: amazon-web-servicesaws-lambdaamazon-cloudformationaws-cloudformation-custom-resource

解决方案


您的 Lambda 函数出现错误,因此它从来没有机会调用cfnresponse.send()。这意味着 CloudFormation 一直在等待响应。

这是 Lambda 函数的更新版本:

from datetime import date, timedelta
import cfnresponse, os

def lambda_handler(event, context):
    current_delta = date.today() - timedelta(days=int(os.environ['DaysToSubtract']))
    current_delta_str = current_delta.strftime("%Y-%m-%d")
    responseData = {}
    responseData['Dates'] = current_delta_str
    cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)

问题是:

  • 环境变量是通过的os.environ(),而不是event()
  • DaysToSubtract值以 astring而非 a 的形式出现int,因此该timedelta()功能失败(小心...拼写Substractvs Subtract
  • responseData字典未初始化,因此出现NameError: name 'responseData' is not defined错误

我强烈建议您先在控制台中开发 Lambda 函数。然后,一旦它们开始工作,就将它们移动到 CloudFormation 模板中。这使调试变得容易得多。

哦,还请注意,自定义资源在堆栈被创建、更新和删除时被调用。这可能会导致一些意想不到的行为,尤其是在Delete操作期间。插入if语句以仅在Create阶段运行代码通常是一个好主意,方法是使用:

if event['RequestType'] == 'Create':

推荐阅读