AWS CloudFormation
User Guide (API 版本 2010-05-15)
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 Amazon AWS 入门

AWS Lambda 函数代码

CodeAWS::Lambda::Function 资源的一个属性,可用来指定 AWS Lambda 函数的源代码。您的源代码可能位于 Amazon Simple Storage Service (Amazon S3) 存储桶内的模板或文件中。(仅限 nodejs4.3nodejs6.10python2.7python3.6 运行时环境) 可以在模板中提供源代码作为内联文本。

注意

要更新源代码位于 Amazon S3 存储桶中的 Lambda 函数,您必须更新 S3BucketS3KeyS3ObjectVersion 属性以触发更新。单独更新源代码不会更新函数。

语法

JSON

{ "S3Bucket" : String, "S3Key" : String, "S3ObjectVersion" : String, "ZipFile" : String }

YAML

S3Bucket: String S3Key: String S3ObjectVersion: String ZipFile: String

属性

S3Bucket

在其中存储包含部署程序包的 .zip 文件的 Amazon S3 存储桶的名称。该存储桶必须位于在其中创建 Lambda 函数的同一 AWS 区域。只要 Lambda 函数和存储桶位于相同的区域中,您就可以指定另一个 AWS 账户中的存储桶。

注意

cfn-response 模块对于存储在 Amazon S3 存储桶中的源代码不可用。要发送响应,您必须编写自己的函数。

Required: Conditional 同时指定 S3BucketS3Key 属性,或指定 ZipFile 属性。

Type: String

S3Key

包含您的源代码的 .zip 文件的位置和名称。如果指定此属性,则还必须指定 S3Bucket 属性。

Required: Conditional 您必须同时指定 S3BucketS3Key 属性,或指定 ZipFile 属性。

Type: String

S3ObjectVersion

如果启用了 S3 版本控制,则为包含源代码的 .zip 文件的版本 ID。只有在您指定了 S3BucketS3Key 属性时,才可以指定此属性。

Required: No

Type: String

ZipFile

对于 nodejs4.3nodejs6.10python2.7python3.6 运行时环境,这是您的 Lambda 函数的源代码。您无法为其他运行时环境使用此属性。

您最多可指定 4096 个字符。必须在源代码中的某些特殊字符 (如问号 (")、换行符 (\n)、制表符 (\t) 等) 前添加反斜杠 (\)。有关特殊字符的列表,请参阅 http://json.org/

如果您指定了与 AWS CloudFormation 自定义资源交互的函数,就无需编写自己的函数来发送响应到调用函数的自定义资源。AWS CloudFormation 提供了简化发送响应的响应模块。有关更多信息,请参阅 cfn-response 模块

Required: Conditional 您必须同时指定 S3BucketS3Key 属性,或指定 ZipFile 属性。

Type: String

cfn-response 模块

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

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

注意

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

加载 cfn-response 模块

对于 nodejs4.3nodejs6.10 运行时环境,可使用 require() 函数加载 cfn-response 模块。例如,以下代码示例创建一个名为 responsecfn-response 对象:

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

对于 python2.7python3.6 环境,使用 import 语句加载 cfnresponse 模块,如下例所示:

注意

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

import cfnresponse

send 方法参数

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

event

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

context

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

responseStatus

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

responseData

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

noEcho

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

physicalResourceId

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

示例

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 示例中 (该示例适用于 2.7 和 3.6 版本),内联 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")

模块源代码

以下为 nodejs4.3nodejs6.10 运行时环境的响应模块源代码。请查看这些内容,以理解此模块的功能并帮助您实现自己的响应函数。

/* Copyright 2015 Amazon Web Services, Inc. or its affiliates. All Rights Reserved. This file is licensed to you under the AWS Customer Agreement (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at http://aws.amazon.com/agreement/ . This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and limitations under the License. */ 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(); }

以下是 python3.6 环境的响应模块源代码:

# Copyright 2016 Amazon Web Services, Inc. or its affiliates. All Rights Reserved. # This file is licensed to you under the AWS Customer Agreement (the "License"). # You may not use this file except in compliance with the License. # A copy of the License is located at http://aws.amazon.com/agreement/ . # This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. # See the License for the specific language governing permissions and limitations under the License. from botocore.vendored 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))

以下是 python2.7 环境的响应模块源代码:

# Copyright 2016 Amazon Web Services, Inc. or its affiliates. All Rights Reserved. # This file is licensed to you under the AWS Customer Agreement (the "License"). # You may not use this file except in compliance with the License. # A copy of the License is located at http://aws.amazon.com/agreement/ . # This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. # See the License for the specific language governing permissions and limitations under the License. from botocore.vendored 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)