Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,7 @@
"TableName": {
"Ref": "TableCD117FA1"
},
"Region": "us-east-2",
"SkipReplicaDeletion": false
"Region": "us-east-2"
},
"DependsOn": [
"TableSourceTableAttachedManagedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderIsCompleteHandlerServiceRoleBE2B1C1A5DC546D2",
Expand All @@ -191,8 +190,7 @@
"TableName": {
"Ref": "TableCD117FA1"
},
"Region": "eu-west-3",
"SkipReplicaDeletion": false
"Region": "eu-west-3"
},
"DependsOn": [
"TableSourceTableAttachedManagedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderIsCompleteHandlerServiceRoleBE2B1C1A5DC546D2",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
const app = new cdk.App({
postCliContext: {
'@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy': false,
'@aws-cdk/aws-dynamodb:retainTableReplica': false,
},
});
const stack = new cdk.Stack(app, 'aws-cdk-dynamodb-global-replicas-provisioned');
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,7 @@
"TableName": {
"Ref": "TableCD117FA1"
},
"Region": "eu-west-2",
"SkipReplicaDeletion": false
"Region": "eu-west-2"
},
"DependsOn": [
"TableSourceTableAttachedManagedPolicycdkdynamodbglobal20191121awscdkawsdynamodbReplicaProviderIsCompleteHandlerServiceRole3971612857304880",
Expand All @@ -217,8 +216,7 @@
"TableName": {
"Ref": "TableCD117FA1"
},
"Region": "eu-central-1",
"SkipReplicaDeletion": false
"Region": "eu-central-1"
},
"DependsOn": [
"TableReplicaeuwest290D3CD3A",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class TestStack extends Stack {
const app = new App({
postCliContext: {
'@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy': false,
'@aws-cdk/aws-dynamodb:retainTableReplica': false,
},
});
const stack = new TestStack(app, 'cdk-dynamodb-global-20191121', { env: { region: 'eu-west-1' } });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ class TestStack extends Stack {
}
}

const app = new App();
const app = new App({
postCliContext: {
'@aws-cdk/aws-dynamodb:retainTableReplica': true,
},
});
Comment on lines +27 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the cli context for default value is not needed.

const stack = new TestStack(app, 'cdk-dynamodb-skip-replica-deletion');

new IntegTest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { CustomResourceConfig } from 'aws-cdk-lib/custom-resources';

const app = new cdk.App();
const app = new cdk.App({
postCliContext: {
'@aws-cdk/aws-dynamodb:retainTableReplica': true,
},
});
const stack = new cdk.Stack(app, 'MyStack');

new dynamodb.Table(stack, 'Table', {
Expand Down
13 changes: 10 additions & 3 deletions packages/aws-cdk-lib/aws-dynamodb/lib/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import {
Aws, CfnCondition, CfnCustomResource, CfnResource, Duration,
Fn, Lazy, Names, RemovalPolicy, Stack, Token, CustomResource,
CfnDeletionPolicy,
FeatureFlags,
} from '../../core';
import { UnscopedValidationError, ValidationError } from '../../core/lib/errors';
import { addConstructMetadata, MethodMetadata } from '../../core/lib/metadata-resource';
import { DYNAMODB_TABLE_RETAIN_TABLE_REPLICA } from '../../cx-api';

const HASH_KEY_TYPE = 'HASH';
const RANGE_KEY_TYPE = 'RANGE';
Expand Down Expand Up @@ -1691,14 +1693,19 @@ export class Table extends TableBase {

// Replica table's removal policy will default to DynamoDB Table's removal policy
// unless replica removal policy is specified.
const skipReplicaDeletion = Lazy.any({
const retainReplica = FeatureFlags.of(this).isEnabled(DYNAMODB_TABLE_RETAIN_TABLE_REPLICA);

// If feature flag is disabled, never retain replica to maintain backward compatibility
const skipReplicaDeletion = retainReplica ? Lazy.any({
produce: () => {
// If feature flag is enabled, prioritize replica removal policy
if (replicaRemovalPolicy) {
return replicaRemovalPolicy == RemovalPolicy.RETAIN;
}
// Otherwise fall back to source table's removal policy
return (this.node.defaultChild as CfnResource).cfnOptions.deletionPolicy === CfnDeletionPolicy.RETAIN;
},
});
}) : false;

for (const region of new Set(regions)) { // Remove duplicates
// Use multiple custom resources because multiple create/delete
Expand All @@ -1709,7 +1716,7 @@ export class Table extends TableBase {
properties: {
TableName: this.tableName,
Region: region,
SkipReplicaDeletion: skipReplicaDeletion,
...skipReplicaDeletion && { SkipReplicaDeletion: skipReplicaDeletion },
SkipReplicationCompletedWait: waitForReplicationToFinish == null
? undefined
// CFN changes Custom Resource properties to strings anyways,
Expand Down
100 changes: 90 additions & 10 deletions packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,12 @@ testDeprecated('when specifying every property', () => {
});

test('when replica removal policy is not specified', () => {
const stack = new Stack();
const app = new App({
context: {
[cxapi.DYNAMODB_TABLE_RETAIN_TABLE_REPLICA]: true,
},
});
const stack = new Stack(app);
new Table(stack, CONSTRUCT_NAME, {
tableName: TABLE_NAME,
partitionKey: TABLE_PARTITION_KEY,
Expand All @@ -460,7 +465,12 @@ test('when replica removal policy is not specified', () => {
});

test('when replica removal policy is not specified', () => {
const stack = new Stack();
const app = new App({
context: {
[cxapi.DYNAMODB_TABLE_RETAIN_TABLE_REPLICA]: true,
},
});
const stack = new Stack(app);
const table = new Table(stack, CONSTRUCT_NAME, {
tableName: TABLE_NAME,
partitionKey: TABLE_PARTITION_KEY,
Expand All @@ -474,8 +484,13 @@ test('when replica removal policy is not specified', () => {
});

test('when replica and table removal policy is not specified', () => {
const stack = new Stack();
const table = new Table(stack, CONSTRUCT_NAME, {
const app = new App({
context: {
[cxapi.DYNAMODB_TABLE_RETAIN_TABLE_REPLICA]: true,
},
});
const stack = new Stack(app);
new Table(stack, CONSTRUCT_NAME, {
tableName: TABLE_NAME,
partitionKey: TABLE_PARTITION_KEY,
replicationRegions: ['eu-west-2', 'eu-west-3'],
Expand All @@ -486,9 +501,69 @@ test('when replica and table removal policy is not specified', () => {
});
});

test('when replica and table removal policy is not specified', () => {
const stack = new Stack();
const table = new Table(stack, CONSTRUCT_NAME, {
test('when replica and table removal policy is not specified with feature flag true', () => {
const app = new App({
context: {
[cxapi.DYNAMODB_TABLE_RETAIN_TABLE_REPLICA]: true,
},
});
const stack = new Stack(app);
new Table(stack, CONSTRUCT_NAME, {
tableName: TABLE_NAME,
partitionKey: TABLE_PARTITION_KEY,
replicationRegions: ['eu-west-2', 'eu-west-3'],
});

Template.fromStack(stack).hasResourceProperties('Custom::DynamoDBReplica', {
'SkipReplicaDeletion': true,
});
});

test('when table removal policy is specified with feature flag true', () => {
const app = new App({
context: {
[cxapi.DYNAMODB_TABLE_RETAIN_TABLE_REPLICA]: true,
},
});
const stack = new Stack(app);
new Table(stack, CONSTRUCT_NAME, {
tableName: TABLE_NAME,
partitionKey: TABLE_PARTITION_KEY,
removalPolicy: RemovalPolicy.DESTROY,
replicationRegions: ['eu-west-2', 'eu-west-3'],
});

Template.fromStack(stack).hasResourceProperties('Custom::DynamoDBReplica', {
'SkipReplicaDeletion': false,
});
});

test('when replica and table removal policy is not specified with feature flag false', () => {
const app = new App({
context: {
[cxapi.DYNAMODB_TABLE_RETAIN_TABLE_REPLICA]: false,
},
});
const stack = new Stack(app);
new Table(stack, CONSTRUCT_NAME, {
tableName: TABLE_NAME,
partitionKey: TABLE_PARTITION_KEY,
replicationRegions: ['eu-west-2', 'eu-west-3'],
});

Template.fromStack(stack).hasResourceProperties('Custom::DynamoDBReplica', {
'SkipReplicaDeletion': Match.absent(),
});
});

test('when replica is retain and table is destroy', () => {
const app = new App({
context: {
[cxapi.DYNAMODB_TABLE_RETAIN_TABLE_REPLICA]: true,
},
});
const stack = new Stack(app);
new Table(stack, CONSTRUCT_NAME, {
tableName: TABLE_NAME,
partitionKey: TABLE_PARTITION_KEY,
removalPolicy: RemovalPolicy.DESTROY,
Expand All @@ -501,9 +576,14 @@ test('when replica and table removal policy is not specified', () => {
});
});

test('when replica and table removal policy is not specified', () => {
const stack = new Stack();
const table = new Table(stack, CONSTRUCT_NAME, {
test('when replica is destory and table is retain', () => {
const app = new App({
context: {
[cxapi.DYNAMODB_TABLE_RETAIN_TABLE_REPLICA]: true,
},
});
const stack = new Stack(app);
new Table(stack, CONSTRUCT_NAME, {
tableName: TABLE_NAME,
partitionKey: TABLE_PARTITION_KEY,
removalPolicy: RemovalPolicy.RETAIN,
Expand Down
18 changes: 17 additions & 1 deletion packages/aws-cdk-lib/cx-api/FEATURE_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ Flags come in three types:
| [@aws-cdk/aws-s3:setUniqueReplicationRoleName](#aws-cdkaws-s3setuniquereplicationrolename) | When enabled, CDK will automatically generate a unique role name that is used for s3 object replication. | 2.182.0 | (fix) |
| [@aws-cdk/pipelines:reduceStageRoleTrustScope](#aws-cdkpipelinesreducestageroletrustscope) | Remove the root account principal from Stage addActions trust policy | 2.184.0 | (default) |
| [@aws-cdk/aws-events:requireEventBusPolicySid](#aws-cdkaws-eventsrequireeventbuspolicysid) | When enabled, grantPutEventsTo() will use resource policies with Statement IDs for service principals. | 2.186.0 | (fix) |
| [@aws-cdk/aws-dynamodb:retainTableReplica](#aws-cdkaws-dynamodbretaintablereplica) | When enabled, table replica will be default to the removal policy of source table unless specified otherwise. | V2NEXT | (fix) |

<!-- END table -->

Expand Down Expand Up @@ -172,7 +173,8 @@ The following json shows the current recommended set of flags, as `cdk init` wou
"@aws-cdk/core:enableAdditionalMetadataCollection": true,
"@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": true,
"@aws-cdk/aws-s3:setUniqueReplicationRoleName": true,
"@aws-cdk/aws-events:requireEventBusPolicySid": true
"@aws-cdk/aws-events:requireEventBusPolicySid": true,
"@aws-cdk/aws-dynamodb:retainTableReplica": true
}
}
```
Expand Down Expand Up @@ -1767,4 +1769,18 @@ This fixes the issue where permissions were silently not being added for service
| 2.186.0 | `false` | `true` |


### @aws-cdk/aws-dynamodb:retainTableReplica

*When enabled, table replica will be default to the removal policy of source table unless specified otherwise.* (fix)

Currently, table replica will always be deleted when stack deletes regardless of source table's deletion policy.
When enabled, table replica will be default to the removal policy of source table unless specified otherwise.


| Since | Default | Recommended |
| ----- | ----- | ----- |
| (not in v1) | | |
| V2NEXT | `false` | `true` |


<!-- END details -->
15 changes: 15 additions & 0 deletions packages/aws-cdk-lib/cx-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -679,3 +679,18 @@ _cdk.json_
}
}
```

* `@aws-cdk/aws-dynamodb:retainTableReplica`

Currently, table replica will always be deleted when stack deletes regardless of source table's deletion policy.
When enabled, table replica will be default to the removal policy of source table unless specified otherwise.

_cdk.json_

```json
{
"context": {
"@aws-cdk/aws-dynamodb:retainTableReplica": true
}
}
```
Loading