如何为在 Python 2.7/3.6/3.7 上运行的 AWS Lambda 函数更新 AWS CloudFormation cfn-response 模块?
我想为在 Python 2.7/3.6/3.7 上运行的 AWS Lambda 函数更新 AWS CloudFormation cfn-response 模块。
解决方法
**注意:**以下步骤仅适用于在 Python 2.7/3.6/3.7 上运行的 Lambda 函数。以下命令适用于 Linux 和 macOS 环境。Windows PowerShell 上的语法可能有所不同。
注意:如果您在运行 AWS 命令行界面 (AWS CLI) 命令时收到错误,请确保您运行的是最新版本的 AWS CLI。
1. 要查找包含自定义资源的堆栈,请运行以下命令:
aws cloudformation list-stacks --region us-east-1 | grep -oE 'arn:[^"]+' | while read arn; do aws cloudformation list-stack-resources --stack-name $arn --region us-east-1 | grep -E '(Custom::)|(::CustomResource)' | awk '{print $2}' | while read resource; do if [[ -n $resource ]]; then echo $arn; echo $resource; fi; done; done
您应会看到与以下示例输出类似的输出:
arn:aws:cloudformation:us-east-1:123456789012:stack/TestStack/3497b950-55f1-11eb-aad4-124a026c8667 "ResourceType": "AWS::CloudFormation::CustomResource",
2. 要查找与自定义资源关联的 Lambda 函数,请运行以下命令以从堆栈模板中检查自定义资源的 ServiceToken 属性:
aws cloudformation get-template --stack-name TestStack | jq -r .TemplateBody
**注意:**步骤 2 中的命令通过使用 jq选项(来自 jq 网站)格式化响应来预览堆栈模板。
您应会看到与以下示例输出类似的输出:
Resources: MyCustomResource: Type: AWS::CloudFormation::CustomResource Properties: ServiceToken: !GetAtt MyFunction.Arn Name: "John" MyFunction: Type: AWS::Lambda::Function Properties: Handler: index.handler Role: !GetAtt MyRole.Arn Runtime: python3.7 Code: ZipFile: | import cfnresponse def handler(event, context): responseData = {'Message': 'Hello {}!'.format(event['ResourceProperties']['Name'])} cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID") MyRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" Outputs: Result: Value: !GetAtt MyCustomResource.Message
注意:从步骤 2 输出中获得的模板是 Lambda 支持的自定义资源的最小模板示例。属性 ServiceToken: !GetAtt MyFunction.Arn 位于 MyCustomResource 部分。ServiceToken 属性的 !GetAtt MyFunction.Arn 解析的值是 Amazon Simple Notification Service (Amazon SNS) 主题的 Amazon 资源名称 (ARN) 或 Lambda 函数。
3. 在步骤 2 的模板中,确定 Lambda 函数的定义位置。
如果您的 Lambda 函数与自定义资源位于同一堆栈中,请跳至步骤 4。例如,步骤 2 中的 Fn::GetAtt 函数显示 Lambda 函数与自定义资源在同一模板中定义。
如果 ServiceToken 属性指向硬编码的 ARN,则 Lambda 函数可能位于另一个堆栈中。如果 ServiceToken 属性是通过 Fn::Import 解析的,则使用 AWS CloudFormation 中的 list-exports API 来查找值。例如:
aws cloudformation list-exports --region us-east-1 { "Exports": [ { "ExportingStackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/SomeOtherStack/481dc040-b283-11e9-b1bd-12d607a4fd1c", "Value": "arn:aws:lambda:us-east-1:123456789012:function:SomeOtherStack-MyFunction-5ZE2CQO8RAA9", "Name": "MyExport" } ] }
然后,通过使用 list-tags 找到 AWS CloudFormation 堆栈 ARN,检查位于单独堆栈中的函数标签。例如:
aws lambda list-tags --resource arn:aws:lambda:us-east-1:123456789012:function:TestStack-MyFunction-5ZE2CQO8RAA9 | grep stack-id
您会收到类似如下内容的输出:
"aws:cloudformation:stack-id": "arn:aws:cloudformation:us-east-1:123456789012:stack/TestStack/3497b950-55f1-11eb-aad4-124a026c8667"
**注意:**您还可以在 AWS Lambda 控制台中找到函数标签。
4. 要允许 AWS CloudFormation 在您的 Lambda 函数中加载最新的 cfn-response 模块,请更新 Lambda 函数的内联源代码。例如:
Code: ZipFile: | import cfnresponse def handler(event, context): responseData = {'Message': 'Hello {}!'.format(event['ResourceProperties']['Name'])} cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
**注意:**请参阅步骤 2 以获取具有 Lambda 函数(含内联源代码)的示例模板。
现在,AWS CloudFormation 会将以下 cfn-response 模块代码示例加载到您的 Lambda 函数中。例如:
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
**注意:**有关更多信息,请参阅 cfn-response 模块的“模块源代码”部分中的代码示例。
cfn-response 模块代码示例使用 Lambda 函数部署程序包中的 botocore.requests。
要将 cfn-response 模块更新为使用 urllib3 的最新版本,请更新 AWS CloudFormation 模板中的函数内联代码。通过向内联 Lambda 函数的代码添加注释来实现此操作。例如:
ZipFile: | import cfnresponse def handler(event, context): + # This comment was added to force an update on this function's code responseData = {'Message': 'Hello {}!'.format(event['ResourceProperties']['Name'])} cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID") MyRole:
5. 保存对包含 Lambda 函数的模板所做的任何更改。
6. 更新堆栈。
在堆栈更新完成后,cfn-response 模块将被修改。
**注意:**如果您的函数代码位于 Amazon Simple Storage Service (Amazon S3) 存储桶或 Amazon Elastic Container Registry (Amazon ECR) 映像中,则必须自行更新模块以包含具有 urllib3 的版本。要获取 cfn-response 模块的最新版本的源代码,请参阅 cfn-response 模块。
注意:如果新的 Python 或 JavaScript 运行时引入了重大更改,则必须更新 cfn-response 模块。无需再次更新 ZipFile,只要更新函数的运行时属性,即可自动附加最新版本的 cfn-response 模块。

相关内容
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前
- AWS 官方已更新 5 个月前