【问题标题】:Is it possible to trigger a lambda on creation from CloudFormation template是否可以在从 CloudFormation 模板创建时触发 lambda
【发布时间】:2017-05-12 01:17:51
【问题描述】:

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

【问题讨论】:

    标签: aws-lambda amazon-cloudformation


    【解决方案1】:

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

    • 如何将参数传递给您调用的 Lambda
    • 如何处理 Stack 上的 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
    

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        【解决方案3】:

        由 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
        
        

        【讨论】:

        • 在code属性中定义了函数,为什么还要有handler属性?
        • 知道了,效果很好
        【解决方案4】:

        以下模板应调用 lambda:

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

        【讨论】:

          【解决方案5】:

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

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

            • (有关使用 AWS 控制台创建堆栈时如何执行此操作的文档,请参阅 Setting AWS CloudFormation Stack Options,如果使用 AWS CLI 或其他 AWS 开发工具包创建/更新堆栈,请使用 --notification-arns 等等效选项。 )
          2. 添加一个 Custom Resource 引用要在创建时调用的 Lambda 函数。

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

          【讨论】:

          【解决方案6】:

          适合寻找类似解决方法的人。

          CloudWatch 能够捕获 CloudFormation 的 API 调用,即“CreateStack”、“UpdateStack”和“DeleteStack”,“Create_complete”或“Complete_Rollback”等堆栈状态无法捕获,这意味着此类状态更改无法触发拉姆达。

          解决方法是 SNS,堆栈可以向 SNS 发送通知(创建堆栈时预先设置)并且 SNS 可以选择触发 lambda,但是您不能选择特定状态。因此,lambda 函数负责找出事件的“消息”内容中的状态。大家,只是编码。

          【讨论】:

            【解决方案7】:

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

            【讨论】:

            • 我能否通过 SNS 通知我的 lambda 从 cloudformation 创建。我基本上希望我的 lambda 在我的 cloudformation 状态更改为 CREATE_COMPLETE 的那一刻运行。