从CloudFormation模板创建时触发Lambda函数是否可行?

38

我尝试使用CloudFormation创建了一组Lambda函数。 我希望在创建后自动触发这些Lambda函数。 我看到许多博客中都提到要创建一个S3或SNS触发器,但似乎没有选项可以在Lambda创建后立即触发它。 有什么其他的选项吗?

7个回答

48

是的,这是可能的。以下是几个选项:

  1. 手动创建SNS主题。将一个AWS::SNS::Subscription添加到您的堆栈中,以lambda函数作为Endpoint和SNS主题作为TopicArn。在堆栈创建/更新时,配置堆栈事件通知发送到此SNS主题。

    • (有关如何在使用AWS控制台创建堆栈时执行此操作的文档,请参见设置AWS CloudFormation堆栈选项,或者如果使用AWS CLI或其他AWS SDK创建/更新堆栈,则使用等效选项,如--notification-arns。)
  2. 添加引用Lambda函数的自定义资源以在创建时调用。

    • 如果需要在创建某些特定的资源之后才调用Lambda函数,请在自定义资源上添加DependsOn属性,引用您想要确保在调用函数之前先创建的资源。
    • 为了使自定义资源成功创建(并且不会导致堆栈失败/回滚),您需要适应您的Lambda函数以支持CloudFormation请求/响应格式(请参见自定义资源参考)。
    • 此选项将在堆栈状态仍为CREATE_IN_PROGRESS时调用Lambda函数,因为自定义资源是堆栈本身的一部分。
    • 当删除堆栈(及其关联的自定义资源)时,Lambda函数也将再次被调用。您需要正确处理此事项,否则您的堆栈可能会陷入DELETE_FAILED状态。
  3. 将Lambda函数引用添加到堆栈输出中,然后编写一个简单的脚本,执行堆栈创建,然后手动调用Lambda函数。


请查看以下链接以通过SAM创建SNS主题:http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html。 - user3002273
1
https://dev59.com/xaTia4cB1Zd3GeqP8yHw#45574936 - user3002273
有趣的参考资料(使用无服务器框架):https://github.com/serverless/serverless/issues/4483,供(2)参考。 - vincent
1
@Abhilashk 正确,因为在这种情况下,自定义资源是堆栈的一部分。我已经更新了答案中的选项2,以使其更清晰。 - wjordan
选项1会触发每个堆栈资源状态更新的SNS消息,但不会针对堆栈本身。这将为每个堆栈资源调用Lambda函数。 - antiplayer
显示剩余2条评论

20

由 yl 提供。

以下代码非常有效!

它在部署的一部分中调用了一个 Lambda:

LambdaFunction2:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: caller
      Code:
        ZipFile: |
      
          import boto3, json
          
          import cfnresponse

          def handler(event, context):
              print('EVENT:[{}]'.format(event))
              lambda_client = boto3.client('lambda')
              test_event = '{"name":"test1"}'
              lambda_client.invoke(
                  FunctionName='target1',
                  InvocationType='Event',
                  Payload=test_event,
              )
              responseValue = 120
              responseData = {}
              responseData['Data'] = responseValue
              cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
              
      Handler: index.handler
      Role:
        arn:aws:iam::11111111111:role/mylambda-role
      Runtime: python3.7
      Timeout: 60

Primerinvoke:
  Type: AWS::CloudFormation::CustomResource
  DependsOn: LambdaFunction2
  Version: "1.0"
  Properties:
    ServiceToken: !GetAtt LambdaFunction2.Arn


如果您已在代码属性中定义了函数,为什么还需要处理程序属性? - Fernando Santiago
明白了,运行得很顺利。 - Fernando Santiago

4

对于寻找类似解决方案的人。

CloudWatch 可以捕获 CloudFormation 的 API 调用,包括 "CreateStack"、"UpdateStack" 和 "DeleteStack",但是堆栈状态,如 "Create_complete" 或 "Complete_Rollback" 是无法捕获的,这意味着这种状态变化不能触发 Lambda。

解决方法是使用 SNS,堆栈能够向 SNS 发送通知(在创建堆栈时的高级设置中)并且 SNS 可以选择触发 Lambda,但是你无法为特定状态进行选择。因此,Lambda 函数负责查找事件的 "Message" 内容中的状态。大家,开始编码吧。


1
我知道这可能有点老了,但解决方案也可以在您的模板中使用CommandRunner作为资源类型。
您可以运行几乎任何shell命令。将DependsOn属性添加到CommandRunner类型,并运行shell脚本:
aws lambda invoke --function-name my-function --invocation-type RequestRespone --payload '{ "name": "Bob" }'。
参考链接:https://aws.amazon.com/blogs/mt/running-bash-commands-in-aws-cloudformation-templates/。

1

在Kyr的答案基础上进行改进,因为它缺少两个重要的内容:

  • 如何向调用的Lambda传递参数
  • 如何处理堆栈上的UPDATE和DELETE(他的解决方案会导致CloudFormation在删除时崩溃)

以下是修订和改进后的代码:

  LambdaInvoker:
      DependsOn: ## important, add stuff here you need to existe BEFORE the lambda is called
      Type: AWS::Lambda::Function
      Properties:
        FunctionName: YourLambdaName
        Description: 'Lambda invoke wrapper for Custom CFN actions'
        Code:
          ZipFile: !Sub |
            import boto3, json
            import cfnresponse

            def handler(event, context):
                print('EVENT:')
                print(event)

                if event['RequestType'] == "Create":
                  lambda_client = boto3.client('lambda')
                  
                  cfn_event = {
                    "param1" : "${Param1}",
                    "param2" : "${Param2}"
                  }

                  lambda_client.invoke(
                      FunctionName='scm-custom-cfn-actions',
                      InvocationType='Event',
                      Payload=json.dumps(cfn_event)
                  )

                responseValue = 120
                responseData = {}
                responseData['Data'] = responseValue
                cfnresponse.send(event, context, cfnresponse.SUCCESS, 
                  responseData, 'scm-cfn-customresource-id')

        Handler: index.handler
        Role: YourLambdaRoleARN
        Runtime: python3.7
        Timeout: 5

0

您可以选择通知到SNS主题,您可以构建一个监听该主题的Lambda,所以工作流程将是:Cloudformation启动 -> SNS主题 -> Lambda。


我可以通过SNS在CloudFormation创建时通知我的Lambda吗?我希望当CloudFormation的状态更改为CREATE_COMPLETE时,我的Lambda能够立即运行。 - ZZzzZZzz

0
以下模板应该调用Lambda函数:
    "InvokeLambda" : {
        "Type": "Custom::InvokeLambda",
        "Version" : "1.0",
        "Properties" : {
        "ServiceToken": {
              "Fn::GetAtt": ["InitFunction","Arn"]
            }
          }
    },

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接