Skip to content

Commit

Permalink
feat(core): new RemovalPolicy.RETAIN_EXCEPT_ON_CREATE to only retain …
Browse files Browse the repository at this point in the history
…resources that have been successfully created (#26602)

Adds support for the RetainExceptOnCreate DeletionPolicy.
When `applyToUpdateReplacePolicy` is set, this uses the 'Retain' UpdateReplacePolicy.

https://aws.amazon.com/about-aws/whats-new/2023/07/aws-cloudformation-deletion-policies-dev-test-cycle/
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html#aws-attribute-deletionpolicy-options

Closes #26570

Replaces #26595

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
mrgrain authored Aug 3, 2023
1 parent 300989a commit c84666c
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 1 deletion.
8 changes: 8 additions & 0 deletions packages/aws-cdk-lib/core/lib/cfn-resource-policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ export enum CfnDeletionPolicy {
*/
RETAIN = 'Retain',

/**
* RetainExceptOnCreate behaves like Retain for stack operations, except for the stack operation that initially created the resource.
* If the stack operation that created the resource is rolled back, CloudFormation deletes the resource. For all other stack operations,
* such as stack deletion, CloudFormation retains the resource and its contents. The result is that new, empty, and unused resources are deleted,
* while in-use resources and their data are retained.
*/
RETAIN_EXCEPT_ON_CREATE = 'RetainExceptOnCreate',

/**
* For resources that support snapshots (AWS::EC2::Volume, AWS::ElastiCache::CacheCluster, AWS::ElastiCache::ReplicationGroup,
* AWS::RDS::DBInstance, AWS::RDS::DBCluster, and AWS::Redshift::Cluster), AWS CloudFormation creates a snapshot for the
Expand Down
11 changes: 10 additions & 1 deletion packages/aws-cdk-lib/core/lib/cfn-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,22 @@ export class CfnResource extends CfnRefElement {
policy = policy || options.default || RemovalPolicy.RETAIN;

let deletionPolicy;
let updateReplacePolicy;

switch (policy) {
case RemovalPolicy.DESTROY:
deletionPolicy = CfnDeletionPolicy.DELETE;
updateReplacePolicy = CfnDeletionPolicy.DELETE;
break;

case RemovalPolicy.RETAIN:
deletionPolicy = CfnDeletionPolicy.RETAIN;
updateReplacePolicy = CfnDeletionPolicy.RETAIN;
break;

case RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE:
deletionPolicy = CfnDeletionPolicy.RETAIN_EXCEPT_ON_CREATE;
updateReplacePolicy = CfnDeletionPolicy.RETAIN;
break;

case RemovalPolicy.SNAPSHOT:
Expand All @@ -153,6 +161,7 @@ export class CfnResource extends CfnRefElement {
}

deletionPolicy = CfnDeletionPolicy.SNAPSHOT;
updateReplacePolicy = CfnDeletionPolicy.SNAPSHOT;
break;

default:
Expand All @@ -161,7 +170,7 @@ export class CfnResource extends CfnRefElement {

this.cfnOptions.deletionPolicy = deletionPolicy;
if (options.applyToUpdateReplacePolicy !== false) {
this.cfnOptions.updateReplacePolicy = deletionPolicy;
this.cfnOptions.updateReplacePolicy = updateReplacePolicy;
}
}

Expand Down
15 changes: 15 additions & 0 deletions packages/aws-cdk-lib/core/lib/removal-policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ export enum RemovalPolicy {
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html#aws-attribute-deletionpolicy-options
*/
SNAPSHOT = 'snapshot',

/**
* Resource will be retained when they are requested to be deleted during a stack delete request
* or need to be replaced due to a stack update request.
* Resource are not retained, if the creation is rolled back.
*
* The result is that new, empty, and unused resources are deleted,
* while in-use resources and their data are retained.
*
* This uses the 'RetainExceptOnCreate' DeletionPolicy,
* and the 'Retain' UpdateReplacePolicy, when `applyToUpdateReplacePolicy` is set.
*
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html#aws-attribute-deletionpolicy-options
*/
RETAIN_ON_UPDATE_OR_DELETE = 'retain-on-update-or-delete',
}

export interface RemovalPolicyOptions {
Expand Down
48 changes: 48 additions & 0 deletions packages/aws-cdk-lib/core/test/removal-policy.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { toCloudFormation } from './util';
import { CfnResource, Stack, RemovalPolicy } from '../lib';

describe('removal policy', () => {
test.each([
[RemovalPolicy.RETAIN, 'Retain'],
[RemovalPolicy.DESTROY, 'Delete'],
[RemovalPolicy.SNAPSHOT, 'Snapshot'],
[RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE, 'RetainExceptOnCreate'],
])('should set correct DeletionPolicy for RemovalPolicy.%s', (removalPolicy: RemovalPolicy, deletionPolicy: string) => {
const stack = new Stack();

const resource = new CfnResource(stack, 'Resource', { type: 'MOCK' });
resource.applyRemovalPolicy(removalPolicy);

expect(toCloudFormation(stack)).toEqual({
Resources: {
Resource: expect.objectContaining({
Type: 'MOCK',
DeletionPolicy: deletionPolicy,
}),
},
});
});

test.each([
[RemovalPolicy.RETAIN, 'Retain'],
[RemovalPolicy.DESTROY, 'Delete'],
[RemovalPolicy.SNAPSHOT, 'Snapshot'],
[RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE, 'Retain'],
])('should set correct UpdateReplacePolicy for RemovalPolicy.%s', (removalPolicy: RemovalPolicy, updateReplacePolicy: string) => {
const stack = new Stack();

const resource = new CfnResource(stack, 'Resource', { type: 'MOCK' });
resource.applyRemovalPolicy(removalPolicy, {
applyToUpdateReplacePolicy: true,
});

expect(toCloudFormation(stack)).toEqual({
Resources: {
Resource: expect.objectContaining({
Type: 'MOCK',
UpdateReplacePolicy: updateReplacePolicy,
}),
},
});
});
});

0 comments on commit c84666c

Please sign in to comment.