CloudFormation - Custom Resources¶
AWS CloudFormation invokes your Lambda function asynchronously with an event that includes a callback URL.
Request¶
Documentation on the lifecycle on a custom resource
- Create request docs - Custom resource provider requests with
RequestType
set toCreate
are sent when the template developer creates a stack that contains a custom resource. - Delete request docs - Custom resource provider requests with
RequestType
set toDelete
are sent when the template developer deletes a stack that contains a custom resource. - Update request docs - Custom resource provider requests with
RequestType
set toUpdate
are sent when there's any change to the properties of the custom resource within the template. Therefore, custom resource code doesn't have to detect changes because it knows that its properties have changed when Update is being called.
Request fields¶
RequestType
(String)- The request type is set by the AWS CloudFormation stack operation (create-stack, update-stack, or delete-stack) that was initiated by
the template developer for the stack that contains the custom resource.
Must be one of:
Create
,Update
, orDelete
. ResponseURL
(String)- The response URL identifies a presigned S3 bucket that receives responses from the custom resource provider to AWS CloudFormation.
StackId
(String)- The Amazon Resource Name (ARN) that identifies the stack that contains the custom resource.
Combining the
StackId
with theRequestId
forms a value that you can use to uniquely identify a request on a particular custom resource. RequestId
(String)- A unique ID for the request. Combining the
StackId
with theRequestId
forms a value that you can use to uniquely identify a request on a particular custom resource. ResourceType
(String)- The template developer-chosen resource type of the custom resource in the AWS CloudFormation template. Custom resource type names can
be up to 60 characters long and can include alphanumeric and the following characters:
_@-.
LogicalResourceId
(String)- The template developer-chosen name (logical ID) of the custom resource in the AWS CloudFormation template. This is provided to facilitate communication between the custom resource provider and the template developer.
PhysicalResourceId
(String)- A required custom resource provider-defined physical ID that is unique for that provider. Required: Always sent with Update and Delete requests; never sent with Create.
ResourceProperties
(Optional, Object)- This field contains the contents of the Properties object sent by the template developer. Its contents are defined by the custom resource provider.
OldResourceProperties
(Object)- Used only for
Update
requests. Contains the resource properties that were declared previous to the update request.
Request examples¶
Create event
{
"RequestType": "Create",
"ServiceToken": "arn:aws:lambda:us-east-2:123456789012:function:lambda-error-processor-primer-14ROR2T3JKU66",
"ResponseURL": "https://cloudformation-custom-resource-response-useast2.s3-us-east-2.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-2%3A123456789012%3Astack/lambda-error-processor/1134083a-2608-1e91-9897-022501a2c456%7Cprimerinvoke%7C5d478078-13e9-baf0-464a-7ef285ecc786?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Expires=1555451971&Signature=28UijZePE5I4dvukKQqM%2F9Rf1o4%3D",
"StackId": "arn:aws:cloudformation:us-east-2:123456789012:stack/lambda-error-processor/1134083a-2608-1e91-9897-022501a2c456",
"RequestId": "5d478078-13e9-baf0-464a-7ef285ecc786",
"LogicalResourceId": "primerinvoke",
"ResourceType": "AWS::CloudFormation::CustomResource",
"ResourceProperties": {
"ServiceToken": "arn:aws:lambda:us-east-2:123456789012:function:lambda-error-processor-primer-14ROR2T3JKU66",
"FunctionName": "lambda-error-processor-randomerror-ZWUC391MQAJK"
}
}
Update event
{
"RequestType": "Update",
"ResponseURL": "http://pre-signed-S3-url-for-response",
"StackId": "arn:aws:cloudformation:eu-central-1:123456789012:stack/MyStack/guid",
"RequestId": "unique id for this create request",
"ResourceType": "Custom::TestResource",
"LogicalResourceId": "MyTestResource",
"PhysicalResourceId": "MyTestResourceId",
"ServiceToken": "abcd",
"ResourceProperties": {
"StackName": "MyStack",
"List": [
"1",
"2",
"3"
]
},
"OldResourceProperties": {
"StackName": "MyStack",
"List": [
"1"
]
}
}
Delete event
{
"RequestType": "Delete",
"RequestId": "unique id for this delete request",
"ResponseURL": "pre-signed-url-for-delete-response",
"ResourceType": "Custom::MyCustomResourceType",
"LogicalResourceId": "name of resource in template",
"StackId": "arn:aws:cloudformation:us-east-2:namespace:stack/stack-name/guid",
"PhysicalResourceId": "custom resource provider-defined physical id",
"ResourceProperties": {
"key1": "string",
"key2": [
"list"
],
"key3": {
"key4": "map"
}
}
}
Generating sample events¶
Response¶
Responses are submitted via the pre-signed URL in the ResponseURL
field of the request via the cfn-response module.
Status
(String)- The status value sent by the custom resource provider in response to an AWS CloudFormation-generated request.
Must be either
SUCCESS
orFAILED
. Reason
(String)- Describes the reason for a failure response.
Required: Required if Status is
FAILED
. It's optional otherwise. PhysicalResourceId
(String)- This value should be an identifier unique to the custom resource vendor, and can be up to 1 KB in size. The value must be a non-empty string and must be identical for all responses for the same resource.
StackId
(String)- The Amazon Resource Name (ARN) that identifies the stack that contains the custom resource. This response value should be copied verbatim from the request.
RequestId
(String)- A unique ID for the request. This response value should be copied verbatim from the request.
LogicalResourceId
(String)- The template developer-chosen name (logical ID) of the custom resource in the AWS CloudFormation template. This response value should be copied verbatim from the request.
NoEcho
(Optional, Boolean)- Optional. Indicates whether to mask the output of the custom resource when retrieved by using the
Fn::GetAtt
function. If set to true, all returned values are masked with asterisks (*****
), except for those stored in the Metadata section of the template. AWS CloudFormation does not transform, modify, or redact any information you include in the Metadata section. The default value isfalse
. Data
(Optional, Object)- Optional. The custom resource provider-defined name-value pairs to send with the response.
You can access the values provided here by name in the template with
Fn::GetAtt
.
The following is an example of a custom resource response
{
"Status" : "SUCCESS",
"PhysicalResourceId" : "Tester1",
"StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/stack-name/guid",
"RequestId" : "unique id for this create request",
"LogicalResourceId" : "MySeleniumTester",
"Data" : {
"resultsPage" : "http://www.myexampledomain/test-results/guid",
"lastUpdate" : "2012-11-14T03:30Z",
}
}
Resources¶
Custom Resource handlers
- Custom Resource Helper - Python - pip
crhelper
- Custom Resources Handler - Java - Maven
software.amazon.lambda:powertools-cloudformation
- cfn-response module
Custom resource typing and data classes
- Java - CloudFormationCustomResourceEvent
- Go - -
github.com/aws/aws-lambda-go/cfn
Code Examples¶
app.py
from __future__ import print_function
from crhelper import CfnResource
import logging
logger = logging.getLogger(__name__)
# Initialise the helper, all inputs are optional, this example shows the defaults
helper = CfnResource(json_logging=False, log_level='DEBUG', boto_level='CRITICAL', sleep_on_delete=120, ssl_verify=None)
try:
## Init code goes here
pass
except Exception as e:
helper.init_failure(e)
@helper.create
def create(event, context):
logger.info("Got Create")
# Optionally return an ID that will be used for the resource PhysicalResourceId,
# if None is returned an ID will be generated. If a poll_create function is defined
# return value is placed into the poll event as event['CrHelperData']['PhysicalResourceId']
#
# To add response data update the helper.Data dict
# If poll is enabled data is placed into poll event as event['CrHelperData']
helper.Data.update({"test": "testdata"})
# To return an error to cloudformation you raise an exception:
if not helper.Data.get("test"):
raise ValueError("this error will show in the cloudformation events log and console.")
return "MyResourceId"
@helper.update
def update(event, context):
logger.info("Got Update")
# If the update resulted in a new resource being created, return an id for the new resource.
# CloudFormation will send a delete event with the old id when stack update completes
@helper.delete
def delete(event, context):
logger.info("Got Delete")
# Delete never returns anything. Should not fail if the underlying resources are already deleted.
# Desired state.
@helper.poll_create
def poll_create(event, context):
logger.info("Got create poll")
# Return a resource id or True to indicate that creation is complete. if True is returned an id
# will be generated
return True
def handler(event, context):
helper(event, context)