How do I update the AWS CloudFormation cfn-response module for AWS Lambda functions that run on Python 3.7?
I want to update the AWS CloudFormation cfn-response module for AWS Lambda functions that run on Python 3.7.
Resolution
The following steps are applicable only to Lambda functions that run on Python 3.7. The following commands apply for both Linux and macOS environments. Syntax might vary on PowerShell.
Note: If you receive errors when you run AWS Command Line Interface (AWS CLI) commands, then see Troubleshoot AWS CLI errors. Also, make sure that you're using the most recent AWS CLI version.
To update the cfn-response module, complete the following steps:
-
To find the stacks that contain custom resources, run the list-stacks following command:
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
You should see output similar to the following example output:
arn:aws:cloudformation:us-east-1:123456789012:stack/TestStack/3497b950-55f1-11eb-aad4-124a026c8667 "ResourceType": "AWS::CloudFormation::CustomResource",
-
To find the Lambda function associated with the custom resource, run the get-template command. The command checks the custom resource's ServiceToken property from the stack's template:
aws cloudformation get-template --stack-name TestStack | jq -r .TemplateBody
Note: The command in step 2 previews the stack's template by using the jq option (from the jq website) to format the response.
Example output:
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
Note: The output for step 2 is an example of a minimal template for a Lambda-backed custom resource. The property ServiceToken: !GetAtt MyFunction.Arn is in the MyCustomResource section. The value for !GetAtt MyFunction.Arn is either the Amazon Resource Name (ARN) of the Amazon Simple Notification Service (Amazon SNS) topic or the Lambda function.
-
From the command output template in step 2, identify where your Lambda function is defined. If your Lambda function is in the same stack as the custom resource, skip to step 4. For example, the Fn::GetAtt function in step 2 shows that the Lambda function is defined in the same template as the custom resource.
If the ServiceToken property points to a hardcoded ARN, then the Lambda function could be in another stack. If the ServiceToken property is resolved through Fn::Import, then use the list-exports API in AWS CloudFormation to look up the value. For example:
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" } ] }
Use the function list-tags to check for function tags located in a separate stack in order to identify the AWS CloudFormation stack ARN. For example:
aws lambda list-tags --resource arn:aws:lambda:us-east-1:123456789012:function:TestStack-MyFunction-5ZE2CQO8RAA9 | grep stack-id
You receive output similar to the following:
"aws:cloudformation:stack-id": "arn:aws:cloudformation:us-east-1:123456789012:stack/TestStack/3497b950-55f1-11eb-aad4-124a026c8667"
Note: You can also find function tags in the AWS Lambda console.
-
To allow AWS CloudFormation to load the latest cfn-response module in your Lambda function, update the inline source code of your Lambda function. For example:
Code: ZipFile: | import cfnresponse def handler(event, context): responseData = {'Message': 'Hello {}!'.format(event['ResourceProperties']['Name'])} cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
Note: See step 2 for an example template that has a Lambda function with inline source code.
The following cfn-response module code example is loaded by AWS CloudFormation into your Lambda function. For example:
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
Note: For more information, see the code examples in the "Module source code" section of the cfn-response module.
The cfn-response module code example uses botocore.requests in the Lambda function's deployment package.
To update the cfn-response module to the latest version that uses urllib3, update the function's inline code in the AWS CloudFormation template. Do this by adding a comment to the inline Lambda function's code. For example:
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:
-
Save any changes to the template that contains your Lambda function.
-
Update your stack. The cfn-response module is modified after the stack is finished updating.
Note: If your function's code resides in an Amazon Simple Storage Service (Amazon S3) bucket or Amazon Elastic Container Registry (Amazon ECR) image, then you must update the module to include the version with urllib3. To get the source code for the latest version of the cfn-response module, see cfn-response module.
Note: If a new Python or JavaScript runtime introduces a breaking change, you must update the cfn-response module. Instead of updating the ZipFile again, you can automatically attach the newest version of the cfn-response module whenever a function's Runtime property is updated.
Relevant content
- asked a year agolg...
- asked 9 months agolg...
- asked a year agolg...
- asked 9 months agolg...
- AWS OFFICIALUpdated 2 years ago
- AWS OFFICIALUpdated 6 months ago
- AWS OFFICIALUpdated 3 years ago
- AWS OFFICIALUpdated 9 months ago