You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I expect powertools-cloudformation to use the physicalResourceId sent by CloudFormation during UPDATE events when (A) none are explicitly set, or (B) a RuntimeException was thrown.
Current Behavior
Expand for a primer in CloudFormation Custom Resources
For the context of this issue, we will focus on the three main high level resource lifecycle events: CREATE, UPDATE, DELETE.
For each event, a unique identifier called Physical Resource ID is used to control whether a resource needs to be created, updated, replaced, or deleted. From here on, we'll refer to this as physicalResourceId.
In this context, the typical workflow for a custom resource runs as follows:
CREATE event is invoked when a resource is being provisioned for the first time.
Expected response. CloudFormation expects a physicalResourceId in a successful custom resource response, where its uniqueness is determined by the custom resource itself. From here on, CloudFormation will send the same physicalResourceId for any subsequent operation related to this resource.
UPDATE event is invoked when a resource had a property changed. It sends the physicalResourceId previously known for this resource.
Expected response. For a successful update of the same resource, CloudFormation expects the same physicalResourceId. However, if physicalResourceId is different, CloudFormation recognizes it needs to dispatch a DELETE event to clean up the previous physicalResourceId it had stored - effectively a resource replacement.
DELETE event is invoked when a resource was either removed from the template or its stack is being deleted. It sends the physicalResourceId previously known for this resource.
Expected Response. CloudFormation expects a non-error response to be sure the resource was deleted successfully.
Problem
For successful operations (no-exception), powertools-cloudformation implicitly defines the physicalResourceId value with the CloudWatch Log Stream name.
For unsuccessful operations where you throw a RuntimeException, powertools-cloudformation implements a catch-all exception handler that also sets the physicalResourceId value with the CloudWatch Log Stream name.
This behaviour creates the following unexpected side effects:
Physical resource ID defaulting to CloudWatch Log Stream name on exception
An UPDATE operation that experienced a RuntimeException might lead to a resource replacement, because powertools-cloudformation always set the physicalResourceId value with the CloudWatch Log Stream name, which might be different to the previously recorded physicalResourceId.
@OverrideprotectedResponseupdate(CloudFormationCustomResourceEventcloudFormationCustomResourceEvent, Contextcontext) {
// this will lead to a response containing `physicalResourceId: context.getLogStreamName()`thrownewRuntimeException("something went wrong");
returnResponse.builder().physicalResourceId(cloudFormationCustomResourceEvent.getPhysicalResourceId()).build();
}
Distinct physical resource IDs in CREATE and UPDATE events
You might explicitly set an unique identifier for physicalResourceId during CREATE event, but doesn't use the same value in UPDATE event, or let powertools-cloudformation implicitly discover one.
@OverrideprotectedResponsecreate(CloudFormationCustomResourceEventcloudFormationCustomResourceEvent, Contextcontext) {
finalStringresourceId = UUID.randomUUID().toString();
returnResponse.builder().physicalResourceId(resourceId).build();
}
@OverrideprotectedResponseupdate(CloudFormationCustomResourceEventcloudFormationCustomResourceEvent, Contextcontext) {
returnResponse.success() // physicalResourceID will be the value of CloudWatch Log Group name
}
Distinct physical resource IDs in infrequent UPDATE events
In subsequent UPDATE events, CloudWatch Log Stream name might differ due to Lambda scaling model, leading to a resource replacement.
@OverrideprotectedResponseupdate(CloudFormationCustomResourceEventcloudFormationCustomResourceEvent, Contextcontext) {
// FIRST update: 2023/03/08/[$LATEST]aabbccdd// SECOND update: 2023/03/08/[$LATEST]eeffggaalog.info(context.getLogStreamName()); // FIRST and SECOND update might have different resultsreturnResponse.success();
}
Possible Solution
Backwards compatible change
Since the behaviour is incorrect (a bug), a non-breaking change would be to update the Response class to use the physicalResourceId available in the UPDATE event instead of CloudWatch Log Stream name that is prone to error.
Deprecate 'Response.success()' and 'Response.failure()' and add new functionality which easily allows customers to follow best practices.
If a customer handler throws an exception, we would still provide the physicalResourceId from the CloudFormation event.
Backwards incompatible change
Do all of (1), and modify the interface to the user to throw if no ID is provided. I believe we should make it explicit this is necessary, and never try and guess something to plug in for them - the confusion here arises due to the impedance mismatch between Cloudformation's interface and powertools-cloudformations.
Remove 'Response.success()' and 'Response.failure()' in favour of a new one as described in 1
Documentation update
We should provide (1) a more complete custom resource example to demonstrate a create, update, and delete handler, and (2) an example on how to explicitly set physicalResourceId with the Response builder.
Expected Behavior
I expect
powertools-cloudformation
to use thephysicalResourceId
sent by CloudFormation duringUPDATE
events when (A) none are explicitly set, or (B) aRuntimeException
was thrown.Current Behavior
Expand for a primer in CloudFormation Custom Resources
For the context of this issue, we will focus on the three main high level resource lifecycle events: CREATE, UPDATE, DELETE.
For each event, a unique identifier called Physical Resource ID is used to control whether a resource needs to be created, updated, replaced, or deleted. From here on, we'll refer to this as
physicalResourceId
.In this context, the typical workflow for a custom resource runs as follows:
CREATE event is invoked when a resource is being provisioned for the first time.
physicalResourceId
in a successful custom resource response, where its uniqueness is determined by the custom resource itself. From here on, CloudFormation will send the samephysicalResourceId
for any subsequent operation related to this resource.UPDATE event is invoked when a resource had a property changed. It sends the
physicalResourceId
previously known for this resource.physicalResourceId
. However, ifphysicalResourceId
is different, CloudFormation recognizes it needs to dispatch aDELETE
event to clean up the previousphysicalResourceId
it had stored - effectively a resource replacement.DELETE event is invoked when a resource was either removed from the template or its stack is being deleted. It sends the
physicalResourceId
previously known for this resource.Problem
For successful operations (no-exception),
powertools-cloudformation
implicitly defines thephysicalResourceId
value with the CloudWatch Log Stream name.For unsuccessful operations where you throw a
RuntimeException
,powertools-cloudformation
implements a catch-all exception handler that also sets thephysicalResourceId
value with the CloudWatch Log Stream name.This behaviour creates the following unexpected side effects:
Physical resource ID defaulting to CloudWatch Log Stream name on exception
An
UPDATE
operation that experienced aRuntimeException
might lead to a resource replacement, becausepowertools-cloudformation
always set thephysicalResourceId
value with the CloudWatch Log Stream name, which might be different to the previously recordedphysicalResourceId
.Distinct physical resource IDs in CREATE and UPDATE events
You might explicitly set an unique identifier for
physicalResourceId
duringCREATE
event, but doesn't use the same value inUPDATE
event, or letpowertools-cloudformation
implicitly discover one.Distinct physical resource IDs in infrequent UPDATE events
In subsequent
UPDATE
events, CloudWatch Log Stream name might differ due to Lambda scaling model, leading to a resource replacement.Possible Solution
Backwards compatible change
Since the behaviour is incorrect (a bug), a non-breaking change would be to update the
Response
class to use thephysicalResourceId
available in theUPDATE
event instead of CloudWatch Log Stream name that is prone to error.Deprecate 'Response.success()' and 'Response.failure()' and add new functionality which easily allows customers to follow best practices.
If a customer handler throws an exception, we would still provide the
physicalResourceId
from the CloudFormation event.Backwards incompatible change
Do all of (1), and modify the interface to the user to throw if no ID is provided. I believe we should make it explicit this is necessary, and never try and guess something to plug in for them - the confusion here arises due to the impedance mismatch between Cloudformation's interface and
powertools-cloudformations
.Remove 'Response.success()' and 'Response.failure()' in favour of a new one as described in 1
Documentation update
We should provide (1) a more complete custom resource example to demonstrate a
create
,update
, anddelete
handler, and (2) an example on how to explicitly setphysicalResourceId
with the Response builder.Steps to Reproduce (for bugs)
powertools-cloudformation
for create, update, and delete handlercreate
, explicitly setphysicalResourceId
with anyString
valueupdate
, simply return a successful responseResponse.success()
Environment
CloudFormation Events
The text was updated successfully, but these errors were encountered: