cfn-response 模块 - AWS CloudFormation
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

cfn-response 模块

如果使用 ZipFile 属性指定函数的源代码并且该函数与 AWS CloudFormation 自定义资源进行交互,您可以加载 cfn-response 模块以将响应发送到这些资源。该模块包含一个 send 方法,它通过 Amazon S3 预签名 URL (ResponseURL) 将响应对象发送到自定义资源。

在执行 send 方法后,Lambda 函数将终止,因此,将忽略在该方法之后写入的任何内容。

注意

只有当您使用 cfn-response 属性编写您的源代码时,ZipFile 模块可用。它对于存储在 Amazon S3 存储桶中的源代码不可用。对于 存储桶中的代码,您必须编写自己的函数来发送响应。

加载 cfn-response 模块

对于 Node.js 函数,使用 require() 函数来加载 cfn-response 模块。例如,以下代码示例创建一个名为 cfn-responseresponse 对象:

var response = require('cfn-response');

对于 Python,使用 import 语句来加载 cfnresponse 模块,如下例所示:

注意

使用这个确切的导入语句。如果您使用导入语句的其他变体,AWS CloudFormation 不会包含响应模块。

import cfnresponse

send 方法参数

您可以将以下参数用于 send 方法。

event

自定义资源请求中的字段。

context

一个 Lambda 函数特定的对象,可用于指定何时函数和任何回调完成执行,或从 Lambda 执行环境中访问信息。有关更多信息,请参阅 AWS Lambda Developer Guide 中的编程模型 (Node.js)

responseStatus

函数是否成功完成。使用 cfnresponse 模块常量指定状态:SUCCESS 表示执行成功;FAILED 表示执行失败。

responseData

自定义资源响应对象Data 字段。数据为名称-值对列表。

physicalResourceId

可选。调用此函数的自定义资源的唯一标识符。默认情况下,该模块使用与 Lambda 函数关联的 Amazon CloudWatch Logs 日志流的名称。

noEcho

可选。指示在使用 Fn::GetAtt 函数检索自定义资源的输出时是否遮蔽它。如果设置为 true,则所有返回的值都将用星号 (*****) 遮蔽,但存储在下面指定位置的信息除外。默认情况下,此值为 false

重要

使用 NoEcho 属性不会遮蔽在以下各区段中存储的任何信息:

  • Metadata 模板区段。CloudFormation 不会转换、修改或编辑您在 Metadata 区段中包含的任何信息。有关更多信息,请参阅 Metadata

  • Outputs 模板区段。有关更多信息,请参阅 Outputs

  • 资源定义的 Metadata 属性。有关更多信息,请参阅 Metadata 属性

强烈建议您不要使用这些机制来包含敏感信息,例如密码。

有关使用 NoEcho 来遮蔽敏感信息的更多信息,请参阅请勿将凭证嵌入您的模板最佳实践。

示例

Node.js

在下面的 Node.js 示例中,内联 Lambda 函数获取输入值并将其乘以 5。内联函数对于较小的函数尤为有用,因为它们让您能够在模板中直接指定源代码,而不必先创建包再将包上传到 Amazon S3 存储桶中。函数使用 cfn-response send 方法将结果发回给调用此函数的自定义资源。

JSON

"ZipFile": { "Fn::Join": ["", [ "var response = require('cfn-response');", "exports.handler = function(event, context) {", " var input = parseInt(event.ResourceProperties.Input);", " var responseData = {Value: input * 5};", " response.send(event, context, response.SUCCESS, responseData);", "};" ]]}

YAML

ZipFile: > var response = require('cfn-response'); exports.handler = function(event, context) { var input = parseInt(event.ResourceProperties.Input); var responseData = {Value: input * 5}; response.send(event, context, response.SUCCESS, responseData); };

Python

在下面的 Python 示例中,内联 Lambda 函数采用一个整数值并将它乘以 5。

JSON

"ZipFile" : { "Fn::Join" : ["\n", [ "import json", "import cfnresponse", "def handler(event, context):", " responseValue = int(event['ResourceProperties']['Input']) * 5", " responseData = {}", " responseData['Data'] = responseValue", " cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, \"CustomResourcePhysicalID\")" ]]}

YAML

ZipFile: | import json import cfnresponse def handler(event, context): responseValue = int(event['ResourceProperties']['Input']) * 5 responseData = {} responseData['Data'] = responseValue cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")

模块源代码

以下是 Node.js 函数的响应模块源代码。请查看这些内容,以理解此模块的功能并帮助您实现自己的响应函数。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: MIT-0 exports.SUCCESS = "SUCCESS"; exports.FAILED = "FAILED"; exports.send = function(event, context, responseStatus, responseData, physicalResourceId, noEcho) { var responseBody = JSON.stringify({ Status: responseStatus, Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName, PhysicalResourceId: physicalResourceId || context.logStreamName, StackId: event.StackId, RequestId: event.RequestId, LogicalResourceId: event.LogicalResourceId, NoEcho: noEcho || false, Data: responseData }); console.log("Response body:\n", responseBody); var https = require("https"); var url = require("url"); var parsedUrl = url.parse(event.ResponseURL); var options = { hostname: parsedUrl.hostname, port: 443, path: parsedUrl.path, method: "PUT", headers: { "content-type": "", "content-length": responseBody.length } }; var request = https.request(options, function(response) { console.log("Status code: " + response.statusCode); console.log("Status message: " + response.statusMessage); context.done(); }); request.on("error", function(error) { console.log("send(..) failed executing https.request(..): " + error); context.done(); }); request.write(responseBody); request.end(); }

以下是 Python 3 函数的响应模块源代码。

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 import requests import json SUCCESS = "SUCCESS" FAILED = "FAILED" def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False): responseUrl = event['ResponseURL'] print(responseUrl) responseBody = {} responseBody['Status'] = responseStatus responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' + context.log_stream_name responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name responseBody['StackId'] = event['StackId'] responseBody['RequestId'] = event['RequestId'] responseBody['LogicalResourceId'] = event['LogicalResourceId'] responseBody['NoEcho'] = noEcho responseBody['Data'] = responseData json_responseBody = json.dumps(responseBody) print("Response body:\n" + json_responseBody) headers = { 'content-type' : '', 'content-length' : str(len(json_responseBody)) } try: response = requests.put(responseUrl, data=json_responseBody, headers=headers) print("Status code: " + response.reason) except Exception as e: print("send(..) failed executing requests.put(..): " + str(e))

以下是 Python 2 函数的响应模块源代码。

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 import requests import json SUCCESS = "SUCCESS" FAILED = "FAILED" def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False): responseUrl = event['ResponseURL'] print responseUrl responseBody = {} responseBody['Status'] = responseStatus responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' + context.log_stream_name responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name responseBody['StackId'] = event['StackId'] responseBody['RequestId'] = event['RequestId'] responseBody['LogicalResourceId'] = event['LogicalResourceId'] responseBody['NoEcho'] = noEcho responseBody['Data'] = responseData json_responseBody = json.dumps(responseBody) print "Response body:\n" + json_responseBody headers = { 'content-type' : '', 'content-length' : str(len(json_responseBody)) } try: response = requests.put(responseUrl, data=json_responseBody, headers=headers) print "Status code: " + response.reason except Exception as e: print "send(..) failed executing requests.put(..): " + str(e)