自定义资源 (lambda) 调用后 AWS CloudFormation 事件挂在 CREATE_IN_PROGRESS 状态

nik*_*kra 5 python aws-cloudformation aws-lambda

我有一个 lambda,它有一个 python 脚本来在参数存储中创建 application.properties 文件。我有一个 cloudformation 模板,它调用此 lambda 来创建 application.properties。我的云信息模板如下所示:

{
   "Description": "Create SSM Parameter",
   "Resources": {
      "primerinvoke": {
         "Type": "AWS::CloudFormation::CustomResource",
         "Properties": {
            "Handler": "lambda_function.lambda_handler",
            "ServiceToken": "arn:aws:lambda:us-east-1:1234:function:test_lambda",
            "FunctionName": "test_lambda"
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

我创建SSM参数的python脚本(其路径是:/myapp/dev/test/application.properties)是:

import boto3
import os

region = os.environ['AWS_REGION']
client = boto3.client('ssm')
def ssm_create():
    response = client.put_parameter(Name='/myapp/'
                                    + os.environ['environment']
                                    + '/test/application.properties',
                                    Description='string',
                                    Value='APPLICATION_NAME=myapp',
                                    Type='SecureString', Overwrite=True)
    return response
def lambda_handler(event, context):
    PutParameterResult = ssm_create()
Run Code Online (Sandbox Code Playgroud)

我按照AWS lambda: No module named 'cfnresponse'import cfnresponse中的建议使用,但是导入不起作用,而且我不知道如何在 lambda 外部安装 cfnresponse 库。

代码成功运行,这意味着 cloudformation 模板能够调用 lambda 及其脚本并创建 SSM 参数,但它ssm_create()在我的脚本中的函数完成后挂起。我不知道如何将“SUCCESS”状态从我的脚本返回到 cloudformation 堆栈以防止其挂起CREATE_IN_PROGRESS状态。

任何帮助将不胜感激!谢谢。

EDIT1:我将代码更新为:

responseStatus = 'SUCCESS'
responseBody={}
def sendResponse(event, context, responseStatus):
            responseBody = {'Status': responseStatus,
                            'Reason': 'See the details in CloudWatch Log Stream: ' + context.log_stream_name,
                            'PhysicalResourceId': context.log_stream_name,
                            'StackId': event['StackId'],
                            'RequestId': event['RequestId'],
                            'LogicalResourceId': event['LogicalResourceId'],
                            }
            print 'RESPONSE BODY:n' + json.dumps(responseBody)
def lambda_handler(event, context):
                logger.info(event)
                test_ssm_create()
                try:
                    req = requests.put(event['ResponseURL'], data=json.dumps(sendResponse(event, context, responseStatus)))
                    if req.status_code != 200:
                        print req.text
                        raise Exception('Recieved non 200 response while sending response to CFN.')
                except requests.exceptions.RequestException as e:
                    print e
                    raise
                return
                print("COMPLETE")
Run Code Online (Sandbox Code Playgroud)

给出req.status_code了 200,但 cloudformation 堆栈再次陷入 CREATE_IN_PROGRESS 状态。仍然不确定如何进行这项工作。

Ash*_*pin 6

正如 CloudFormation 文档中所述,CloudFormation 希望您的 Lambda 函数在完成其操作后回调它;CloudFormation 将暂停执行,直到收到此回调。CloudFormation 发送到您的 Lambda 函数的事件包含回调 URL (ResponseURL),如下例所示:

{
   "RequestType" : "Create",
   "ResponseURL" : "http://pre-signed-S3-url-for-response",
   "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/stack-name/guid",
   "RequestId" : "unique id for this create request",
   "ResourceType" : "Custom::TestResource",
   "LogicalResourceId" : "MyTestResource",
   "ResourceProperties" : {
      "Name" : "Value",
      "List" : [ "1", "2", "3" ]
   }
}
Run Code Online (Sandbox Code Playgroud)

如果您无法导入 cfnresponse 模块(这似乎是 python2 代码),您应该能够使用 python3 模拟相同的内容。尝试在 lambda_handler 函数中添加类似以下代码的内容。请注意,响应中包含此 AWS 文档页面中详细介绍的必需键(即可直接添加的 PhysicalResourceId、StackId、RequestId、LogicalResourceId,请参阅文档)。

import requests
import json
import uuid

status = {'Status': 'SUCCESS',
          'PhysicalResourceId': 'MyResource_' + str(uuid.uuid1()),
          'StackId': event['StackId'],
          'RequestId': event['RequestId'],
          'LogicalResourceId': event['LogicalResourceId']
         }
r = requests.put(event['ResponseURL'], data=json.dumps(status))
Run Code Online (Sandbox Code Playgroud)

因此,要编辑问题中的代码:

responseStatus = 'SUCCESS'

def getResponse(event, context, responseStatus):
            responseBody = {'Status': responseStatus,
                            'PhysicalResourceId': context.log_stream_name,
                            'StackId': event['StackId'],
                            'RequestId': event['RequestId'],
                            'LogicalResourceId': event['LogicalResourceId'],
                            }
            responseBody = json.dumps(responseBody)
            print 'RESPONSE BODY:n' + responseBody

            return responseBody

def lambda_handler(event, context):
                logger.info(event)
                test_ssm_create()
                try:
                    req = requests.put(event['ResponseURL'], data=getResponse(event, context, responseStatus))
                    if req.status_code != 200:
                        print req.text
                        raise Exception('Received non 200 response while sending response to CFN.')
                except requests.exceptions.RequestException as e:
                    print e
                    raise
                return
                print("COMPLETE")
Run Code Online (Sandbox Code Playgroud)