是否可以在从 CloudFormation 模板创建时触发 lambda

Is it possible to trigger a lambda on creation from CloudFormation template

我尝试使用 cloudformation 创建一组 lambda。我希望 lambda 在创建后被触发。我在各种博客上看到要创建 s3sns 的触发器,但 none 似乎是创建后触发 lambda 的选项。有什么选择吗?

您可以选择通知 SNS 主题,您可以构建一个侦听该主题的 lambda,因此工作流程为:Cloudformation 启动 -> SNS 主题 -> Lambda。

是的,这是可能的。这里有几个选项:

  1. 手动 create an SNS Topic. Add an AWS::SNS::Subscription to your stack with the lambda function as the Endpoint and the SNS topic as the TopicArn。在堆栈 creation/update 上,配置要发送到此 SNS 主题的堆栈事件通知。

    • (请参阅 Setting AWS CloudFormation Stack Options for documentation on how to do this when using the AWS Console to create your stack, or use the equivalent option like --notification-arns if creating/updating your stack using the AWS CLI 或其他 AWS SDK。)
  2. 添加一个 Custom Resource 引用要在创建时调用的 Lambda 函数。

    • 如果您需要在 创建某些特定资源后调用 Lambda 函数,请在引用您要确保的资源的自定义资源上添加 DependsOn attribute在调用函数之前首先创建。
    • 为了成功创建自定义资源(而不是在您的堆栈中导致 failure/rollback),您需要调整您的 Lambda 函数以支持 CloudFormation request/response 格式(请参阅 Custom Resource Reference).
    • 此选项将在 stack status 仍为 CREATE_IN_PROGRESS 时调用 Lambda 函数,因为自定义资源是堆栈本身的一部分。
    • 删除堆栈(和关联的自定义资源)时,也会再次调用 Lambda 函数。这需要由您的 Lambda 函数正确处理,否则您的堆栈可能会卡在 DELETE_FAILED 状态。
  3. 将 Lambda 函数引用添加到 Stack Output,然后编写一个简单的脚本来执行堆栈创建,然后手动调用 Lambda 函数。

寻找类似解决方法的人。

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

解决方法是SNS,stack可以向SNS发送通知(创建stack时提前设置),SNS可以选择触发lambda,但是不能选择特定状态。因此,lambda 函数负责找出事件的 "Message" 内容中的状态。每个人,只是编码。

以下模板应调用 lambda:

    "InvokeLambda" : {
        "Type": "Custom::InvokeLambda",
        "Version" : "1.0",
        "Properties" : {
        "ServiceToken": {
              "Fn::GetAtt": ["InitFunction","Arn"]
            }
          }
    },

由 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

我知道这有点过时了 - 但解决方案也可以是在模板中使用 CommandRunner 作为资源类型。

https://aws.amazon.com/blogs/mt/running-bash-commands-in-aws-cloudformation-templates/.

您几乎可以 运行 任何 shell 命令。将 DependsOn 属性添加到您的 CommandRunner 类型和 运行 一个 shell 脚本:

aws lambda invoke --function-name my-function --invocation-type RequestRespone --payload '{ "name": "Bob" }'

改进 Kyr 的回答,因为它缺少两个重要的东西:

  • 如何将参数传递给您调用的 Lambda
  • 如何处理堆栈上的更新和删除(他的解决方案会导致 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