I am trying to create custom resource in CloudFormation to tag Event Rule. This is the lambda:
from json import dumps
import sys
import traceback
import urllib.request
import boto3
def send_response(event, context, response):
"""Send a response to CloudFormation to handle the custom resource lifecycle"""
response_body = {
'Status': response,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
}
print('RESPONSE BODY: \n' + dumps(response_body))
data = dumps(response_body).encode('utf-8')
req = urllib.request.Request(
event['ResponseURL'],
data,
headers={'Content-Length': len(data), 'Content-Type': ''})
req.get_method = lambda: 'PUT'
try:
with urllib.request.urlopen(req) as resp:
print(f'response.status: {resp.status}, ' +
f'response.reason: {resp.reason}')
print('response from cfn: ' + resp.read().decode('utf-8'))
except Exception as e:
print(e)
raise Exception('Received non-200 response while sending response to AWS CloudFormation')
return True
def custom_resource_handler(event, context):
print("Event JSON: \n" + dumps(event))
ResourceARN = event['ResourceProperties']['ResourceARN']
tags = event['ResourceProperties']['Tags']
response = 'FAILED'
client = boto3.client('events')
if event['RequestType'] == 'Create':
try:
response = client.tag_resource(
ResourceARN=ResourceARN,
Tags=tags)
response = 'SUCCESS'
except Exception as e:
print(e)
send_response(event, context, response)
return
if event['RequestType'] == 'Update':
# Do nothing and send a success immediately
send_response(event, context, response)
return
if event['RequestType'] == 'Delete':
try:
response = client.untag_resource(
ResourceARN = ResourceARN,
TagKeys = tags['Key']
)
response = 'SUCCESS'
except Exception as e:
print(e)
send_response(event, context, response)
def lambda_handler(event, context):
"""Lambda handler for the custom resource"""
try:
return custom_resource_handler(event, context)
except Exception as e:
print(e)
raise
This is the CFN block:
CustomTagEvent:
Type: Custom::TagEventRule
Version: "1.0"
DependsOn: EventRule
Properties:
ServiceToken: "LAMBDA_ARN"
ResourceARN:
Fn::GetAtt:
- "EventRule"
- "Arn"
Tags:
-
Key: Name
While creating CLoudFormation it gave error "CREATE FAILED".
"Invalid PhysicalResourceId"
But, somehow managed to create tags. Need help to understand why it gave the CloudFormation error if it created the tags?
Custom resources require specific output which contains PhysicalResourceId
:
{
"Status" : "SUCCESS",
"PhysicalResourceId" : "TestResource1",
"StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/stack-name/guid",
"RequestId" : "unique id for this create request",
"LogicalResourceId" : "MyTestResource",
"Data" : {
"OutputName1" : "Value1",
"OutputName2" : "Value2",
}
}
Your lambda function does not generate such a response, thus it errors out.
The best way to create custom resources is by using cfn-response provided by AWS specially for that purpose.