From 9e30d9e67b413d7230ba78eb4b8fe8752e5041a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Mon, 24 Jun 2019 13:27:48 +0200 Subject: [PATCH 1/6] feat(dynamodb): Support RemovalPolicy Add support for RemovalPolicy on DynamoDB `Table`s, defaulting to `RemovalPolicy.RETAIN` as the resource is inherently stateful. --- packages/@aws-cdk/aws-dynamodb/lib/table.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index ac14172dd7130..fec1ea4f9cd59 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -1,6 +1,6 @@ import appscaling = require('@aws-cdk/aws-applicationautoscaling'); import iam = require('@aws-cdk/aws-iam'); -import { Aws, Construct, Lazy, Resource, Stack } from '@aws-cdk/core'; +import { Aws, Construct, Lazy, Resource, Stack, RemovalPolicy } from '@aws-cdk/core'; import { CfnTable } from './dynamodb.generated'; import { EnableScalingProps, IScalableTableAttribute } from './scalable-attribute-api'; import { ScalableTableAttribute } from './scalable-table-attribute'; @@ -107,6 +107,13 @@ export interface TableOptions { * @default undefined, streams are disabled */ readonly stream?: StreamViewType; + + /** + * The removal policy to apply to the DynamoDB Table. + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: RemovalPolicy; } export interface TableProps extends TableOptions { @@ -247,6 +254,7 @@ export class Table extends Resource { streamSpecification: props.stream ? { streamViewType: props.stream } : undefined, timeToLiveSpecification: props.timeToLiveAttribute ? { attributeName: props.timeToLiveAttribute, enabled: true } : undefined }); + this.table.applyRemovalPolicy(props.removalPolicy, { default: RemovalPolicy.RETAIN }); if (props.tableName) { this.node.addMetadata('aws:cdk:hasPhysicalName', props.tableName); } From 5b6b6bd73f9c4a6dccec7ac6885dfa5ad078a7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Mon, 24 Jun 2019 14:14:06 +0200 Subject: [PATCH 2/6] Add needed tests --- packages/@aws-cdk/aws-dynamodb/lib/table.ts | 4 +- .../test/integ.autoscaling.lit.expected.json | 15 +- .../test/integ.autoscaling.lit.ts | 5 +- .../test/integ.dynamodb.expected.json | 12 +- .../integ.dynamodb.ondemand.expected.json | 18 +- .../test/integ.dynamodb.ondemand.ts | 10 +- .../aws-dynamodb/test/integ.dynamodb.ts | 14 +- .../aws-dynamodb/test/test.dynamodb.ts | 424 +++++++++--------- 8 files changed, 266 insertions(+), 236 deletions(-) diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index fec1ea4f9cd59..f0c4f5dd11759 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -1,6 +1,6 @@ import appscaling = require('@aws-cdk/aws-applicationautoscaling'); import iam = require('@aws-cdk/aws-iam'); -import { Aws, Construct, Lazy, Resource, Stack, RemovalPolicy } from '@aws-cdk/core'; +import { Aws, Construct, Lazy, RemovalPolicy, Resource, Stack } from '@aws-cdk/core'; import { CfnTable } from './dynamodb.generated'; import { EnableScalingProps, IScalableTableAttribute } from './scalable-attribute-api'; import { ScalableTableAttribute } from './scalable-table-attribute'; @@ -254,7 +254,7 @@ export class Table extends Resource { streamSpecification: props.stream ? { streamViewType: props.stream } : undefined, timeToLiveSpecification: props.timeToLiveAttribute ? { attributeName: props.timeToLiveAttribute, enabled: true } : undefined }); - this.table.applyRemovalPolicy(props.removalPolicy, { default: RemovalPolicy.RETAIN }); + this.table.applyRemovalPolicy(props.removalPolicy); if (props.tableName) { this.node.addMetadata('aws:cdk:hasPhysicalName', props.tableName); } diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.expected.json index ddc2c38d6ebdb..bb20518e3d8d4 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.expected.json @@ -9,17 +9,18 @@ "KeyType": "HASH" } ], - "ProvisionedThroughput": { - "ReadCapacityUnits": 5, - "WriteCapacityUnits": 5 - }, "AttributeDefinitions": [ { "AttributeName": "hashKey", "AttributeType": "S" } - ] - } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "DeletionPolicy": "Delete" }, "TableReadScalingTargetF96E9F76": { "Type": "AWS::ApplicationAutoScaling::ScalableTarget", @@ -94,4 +95,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.ts index 5527c906c6c15..9f430496b7724 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.ts @@ -6,7 +6,8 @@ const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-dynamodb'); const table = new dynamodb.Table(stack, 'Table', { - partitionKey: { name: 'hashKey', type: dynamodb.AttributeType.STRING } + partitionKey: { name: 'hashKey', type: dynamodb.AttributeType.STRING }, + removalPolicy: cdk.RemovalPolicy.DESTROY, }); /// !show @@ -27,4 +28,4 @@ readScaling.scaleOnSchedule('ScaleDownAtNight', { }); /// !hide -app.synth(); \ No newline at end of file +app.synth(); diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.expected.json index f16e8e27d15d0..bd4f7aa45abdd 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.expected.json @@ -19,7 +19,8 @@ "ReadCapacityUnits": 5, "WriteCapacityUnits": 5 } - } + }, + "DeletionPolicy": "Delete" }, "TableWithGlobalAndLocalSecondaryIndexBC540710": { "Type": "AWS::DynamoDB::Table", @@ -267,7 +268,8 @@ "AttributeName": "timeToLive", "Enabled": true } - } + }, + "DeletionPolicy": "Delete" }, "TableWithGlobalSecondaryIndexCC8E841E": { "Type": "AWS::DynamoDB::Table", @@ -310,7 +312,8 @@ "ReadCapacityUnits": 5, "WriteCapacityUnits": 5 } - } + }, + "DeletionPolicy": "Delete" }, "TableWithLocalSecondaryIndex4DA3D08F": { "Type": "AWS::DynamoDB::Table", @@ -361,7 +364,8 @@ "ReadCapacityUnits": 5, "WriteCapacityUnits": 5 } - } + }, + "DeletionPolicy": "Delete" }, "User00B015A1": { "Type": "AWS::IAM::User" diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.expected.json index 5e75e73fe82be..94b2f19fa5659 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.expected.json @@ -9,14 +9,15 @@ "KeyType": "HASH" } ], - "BillingMode": "PAY_PER_REQUEST", "AttributeDefinitions": [ { "AttributeName": "hashKey", "AttributeType": "S" } - ] - } + ], + "BillingMode": "PAY_PER_REQUEST" + }, + "DeletionPolicy": "Delete" }, "TableWithGlobalAndLocalSecondaryIndexBC540710": { "Type": "AWS::DynamoDB::Table", @@ -31,7 +32,6 @@ "KeyType": "RANGE" } ], - "BillingMode": "PAY_PER_REQUEST", "AttributeDefinitions": [ { "AttributeName": "hashKey", @@ -54,6 +54,7 @@ "AttributeType": "N" } ], + "BillingMode": "PAY_PER_REQUEST", "GlobalSecondaryIndexes": [ { "IndexName": "GSI-PartitionKeyOnly", @@ -241,7 +242,8 @@ "AttributeName": "timeToLive", "Enabled": true } - } + }, + "DeletionPolicy": "Delete" }, "TableWithGlobalSecondaryIndexCC8E841E": { "Type": "AWS::DynamoDB::Table", @@ -277,7 +279,8 @@ } } ] - } + }, + "DeletionPolicy": "Delete" }, "TableWithLocalSecondaryIndex4DA3D08F": { "Type": "AWS::DynamoDB::Table", @@ -325,7 +328,8 @@ } } ] - } + }, + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts index 2ceea0aed5c38..fe3a4376a23aa 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts @@ -1,4 +1,4 @@ -import { App, Stack, Tag } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, Tag } from '@aws-cdk/core'; import { Attribute, AttributeType, BillingMode, ProjectionType, StreamViewType, Table } from '../lib'; // CDK parameters @@ -43,7 +43,8 @@ const stack = new Stack(app, STACK_NAME); // Provisioned tables new Table(stack, TABLE, { billingMode: BillingMode.PAY_PER_REQUEST, - partitionKey: TABLE_PARTITION_KEY + partitionKey: TABLE_PARTITION_KEY, + removalPolicy: RemovalPolicy.DESTROY, }); const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_AND_LOCAL_SECONDARY_INDEX, { @@ -53,7 +54,8 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL billingMode: BillingMode.PAY_PER_REQUEST, timeToLiveAttribute: 'timeToLive', partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY + sortKey: TABLE_SORT_KEY, + removalPolicy: RemovalPolicy.DESTROY, }); tableWithGlobalAndLocalSecondaryIndex.node.applyAspect(new Tag('Environment', 'Production')); @@ -109,6 +111,7 @@ tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({ const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, { billingMode: BillingMode.PAY_PER_REQUEST, partitionKey: TABLE_PARTITION_KEY, + removalPolicy: RemovalPolicy.DESTROY, }); tableWithGlobalSecondaryIndex.addGlobalSecondaryIndex({ indexName: GSI_TEST_CASE_1, @@ -119,6 +122,7 @@ const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY billingMode: BillingMode.PAY_PER_REQUEST, partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY, + removalPolicy: RemovalPolicy.DESTROY, }); tableWithLocalSecondaryIndex.addLocalSecondaryIndex({ diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts index 581557af10fdb..265a0dc63236e 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts @@ -1,5 +1,5 @@ import iam = require('@aws-cdk/aws-iam'); -import { App, Stack, Tag } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, Tag } from '@aws-cdk/core'; import { Attribute, AttributeType, ProjectionType, StreamViewType, Table } from '../lib'; // CDK parameters @@ -42,7 +42,8 @@ const app = new App(); const stack = new Stack(app, STACK_NAME); const table = new Table(stack, TABLE, { - partitionKey: TABLE_PARTITION_KEY + partitionKey: TABLE_PARTITION_KEY, + removalPolicy: RemovalPolicy.DESTROY, }); const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_AND_LOCAL_SECONDARY_INDEX, { @@ -51,7 +52,8 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL stream: StreamViewType.KEYS_ONLY, timeToLiveAttribute: 'timeToLive', partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY + sortKey: TABLE_SORT_KEY, + removalPolicy: RemovalPolicy.DESTROY, }); tableWithGlobalAndLocalSecondaryIndex.node.applyAspect(new Tag('Environment', 'Production')); @@ -106,7 +108,8 @@ tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({ }); const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, { - partitionKey: TABLE_PARTITION_KEY + partitionKey: TABLE_PARTITION_KEY, + removalPolicy: RemovalPolicy.DESTROY, }); tableWithGlobalSecondaryIndex.addGlobalSecondaryIndex({ indexName: GSI_TEST_CASE_1, @@ -115,7 +118,8 @@ tableWithGlobalSecondaryIndex.addGlobalSecondaryIndex({ const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, { partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY + sortKey: TABLE_SORT_KEY, + removalPolicy: RemovalPolicy.DESTROY, }); tableWithLocalSecondaryIndex.addLocalSecondaryIndex({ diff --git a/packages/@aws-cdk/aws-dynamodb/test/test.dynamodb.ts b/packages/@aws-cdk/aws-dynamodb/test/test.dynamodb.ts index ece8ad53da7c5..d410ce0940b83 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/test.dynamodb.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/test.dynamodb.ts @@ -1,7 +1,7 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; import appscaling = require('@aws-cdk/aws-applicationautoscaling'); import iam = require('@aws-cdk/aws-iam'); -import { ConstructNode, Stack, Tag } from '@aws-cdk/core'; +import { CfnDeletionPolicy, ConstructNode, RemovalPolicy, Stack, Tag } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Attribute, @@ -75,236 +75,248 @@ export = { KeySchema: [{ AttributeName: 'hashKey', KeyType: 'HASH' }], ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } })); + + expect(stack).to(haveResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.RETAIN }, ResourcePart.CompleteDefinition)); + test.done(); }, - 'hash + range key'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); + 'removalPolicy is DESTROY'(test: Test) { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, removalPolicy: RemovalPolicy.DESTROY }); - expect(stack).to(haveResource('AWS::DynamoDB::Table', { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - })); - test.done(); - }, + expect(stack).to(haveResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.DELETE }, ResourcePart.CompleteDefinition)); - 'hash + range key can also be specified in props'(test: Test) { - const stack = new Stack(); + test.done(); + }, - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); + 'hash + range key'(test: Test) { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + expect(stack).to(haveResource('AWS::DynamoDB::Table', { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, })); + test.done(); + }, - test.done(); - }, + 'hash + range key can also be specified in props'(test: Test) { + const stack = new Stack(); - 'point-in-time recovery is not enabled'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - )); - test.done(); - }, + expect(stack).to(haveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + })); - 'server-side encryption is not enabled'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY, - }); + test.done(); + }, - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - )); - test.done(); - }, + 'point-in-time recovery is not enabled'(test: Test) { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); - 'stream is not enabled'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY, - }); + expect(stack).to(haveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + )); + test.done(); + }, - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - )); - test.done(); - }, + 'server-side encryption is not enabled'(test: Test) { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + }); - 'ttl is not enabled'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY, - }); + expect(stack).to(haveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + )); + test.done(); + }, - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - )); - test.done(); - }, + 'stream is not enabled'(test: Test) { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + }); - 'can specify new and old images'(test: Test) { - const stack = new Stack(); + expect(stack).to(haveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + )); + test.done(); + }, - new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - readCapacity: 42, - writeCapacity: 1337, - stream: StreamViewType.NEW_AND_OLD_IMAGES, - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); + 'ttl is not enabled'(test: Test) { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + }); - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - StreamSpecification: { StreamViewType: 'NEW_AND_OLD_IMAGES' }, - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, - TableName: 'MyTable' - } - )); - test.done(); - }, + expect(stack).to(haveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + )); + test.done(); + }, - 'can specify new images only'(test: Test) { - const stack = new Stack(); + 'can specify new and old images'(test: Test) { + const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - readCapacity: 42, - writeCapacity: 1337, - stream: StreamViewType.NEW_IMAGE, - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); + new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + readCapacity: 42, + writeCapacity: 1337, + stream: StreamViewType.NEW_AND_OLD_IMAGES, + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - StreamSpecification: { StreamViewType: 'NEW_IMAGE' }, - TableName: 'MyTable', - } - )); - test.done(); - }, + expect(stack).to(haveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + StreamSpecification: { StreamViewType: 'NEW_AND_OLD_IMAGES' }, + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, + TableName: 'MyTable' + } + )); + test.done(); + }, - 'can specify old images only'(test: Test) { - const stack = new Stack(); + 'can specify new images only'(test: Test) { + const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - readCapacity: 42, - writeCapacity: 1337, - stream: StreamViewType.OLD_IMAGE, - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); + new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + readCapacity: 42, + writeCapacity: 1337, + stream: StreamViewType.NEW_IMAGE, + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - StreamSpecification: { StreamViewType: 'OLD_IMAGE' }, - TableName: 'MyTable', - } - )); - test.done(); - } -}, + expect(stack).to(haveResource('AWS::DynamoDB::Table', + { + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + StreamSpecification: { StreamViewType: 'NEW_IMAGE' }, + TableName: 'MyTable', + } + )); + test.done(); + }, + + 'can specify old images only'(test: Test) { + const stack = new Stack(); + + new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + readCapacity: 42, + writeCapacity: 1337, + stream: StreamViewType.OLD_IMAGE, + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + expect(stack).to(haveResource('AWS::DynamoDB::Table', + { + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + StreamSpecification: { StreamViewType: 'OLD_IMAGE' }, + TableName: 'MyTable', + } + )); + test.done(); + } + }, 'when specifying every property'(test: Test) { const stack = new Stack(); From 5b67e5e9bc03ca6e26f4febf5a251c7c616dd567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Wed, 26 Jun 2019 09:41:35 +0200 Subject: [PATCH 3/6] Correctly allow control of update policies in Global Tables --- .../aws-dynamodb-global/lib/aws-dynamodb-global.ts | 3 ++- .../aws-dynamodb-global/lib/global-table-coordinator.ts | 1 + .../test/integ.dynamodb.global.expected.json | 9 ++++++--- .../aws-dynamodb-global/test/integ.dynamodb.global.ts | 5 +++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts b/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts index 4371a7625838a..a1cf49f9f2eef 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts @@ -47,7 +47,8 @@ export class GlobalTable extends cdk.Construct { // And no way to set a default value in an interface const stackProps: dynamodb.TableProps = { ...props, - stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES + removalPolicy: props.removalPolicy, + stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES, }; // here we loop through the configured regions. diff --git a/packages/@aws-cdk/aws-dynamodb-global/lib/global-table-coordinator.ts b/packages/@aws-cdk/aws-dynamodb-global/lib/global-table-coordinator.ts index b14fa6fff9718..d8d2fab517924 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lib/global-table-coordinator.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/lib/global-table-coordinator.ts @@ -30,6 +30,7 @@ export class GlobalTableCoordinator extends cdk.Stack { resourceType: "Custom::DynamoGlobalTableCoordinator", tableName: props.tableName, }, + removalPolicy: props.removalPolicy, }); } } diff --git a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json index 73f41fd9ea2c0..a9ba8bef0f046 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json @@ -24,7 +24,8 @@ "StreamViewType": "NEW_AND_OLD_IMAGES" }, "TableName": "integrationtest" - } + }, + "DeletionPolicy": "Retain" } } }, @@ -53,7 +54,8 @@ "StreamViewType": "NEW_AND_OLD_IMAGES" }, "TableName": "integrationtest" - } + }, + "DeletionPolicy": "Retain" } } }, @@ -82,7 +84,8 @@ "StreamViewType": "NEW_AND_OLD_IMAGES" }, "TableName": "integrationtest" - } + }, + "DeletionPolicy": "Retain" } } }, diff --git a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.ts b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.ts index 3cf7f886844c5..f967d30882690 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.ts @@ -1,12 +1,13 @@ /// !cdk-integ * import { AttributeType } from '@aws-cdk/aws-dynamodb'; -import { App } from '@aws-cdk/core'; +import { App, RemovalPolicy } from '@aws-cdk/core'; import { GlobalTable } from '../lib'; const app = new App(); new GlobalTable(app, 'globdynamodbinteg', { partitionKey: { name: 'hashKey', type: AttributeType.STRING }, tableName: 'integrationtest', - regions: [ "us-east-1", "us-east-2", "us-west-2" ] + regions: ["us-east-1", "us-east-2", "us-west-2"], + removalPolicy: RemovalPolicy.DESTROY, }); app.synth(); From 3659d17b2b1ff3a57c85b11be26f11f20704d8f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Wed, 26 Jun 2019 10:02:38 +0200 Subject: [PATCH 4/6] Fix test --- .../@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts | 4 ++-- .../test/integ.dynamodb.global.expected.json | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts b/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts index a1cf49f9f2eef..25d3d874c56fd 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts @@ -45,7 +45,7 @@ export class GlobalTable extends cdk.Construct { // need to set this stream specification, otherwise global tables don't work // And no way to set a default value in an interface - const stackProps: dynamodb.TableProps = { + const regionalTableProps: dynamodb.TableProps = { ...props, removalPolicy: props.removalPolicy, stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES, @@ -55,7 +55,7 @@ export class GlobalTable extends cdk.Construct { // in each region we'll deploy a separate stack with a DynamoDB Table with identical properties in the individual stacks for (const reg of props.regions) { const regionalStack = new cdk.Stack(this, id + "-" + reg, { env: { region: reg } }); - const regionalTable = new dynamodb.Table(regionalStack, id + '-GlobalTable-' + reg, stackProps); + const regionalTable = new dynamodb.Table(regionalStack, `${id}-GlobalTable-${reg}`, regionalTableProps); this._regionalTables.push(regionalTable); } diff --git a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json index a9ba8bef0f046..8f895c2d9dec7 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json @@ -25,7 +25,7 @@ }, "TableName": "integrationtest" }, - "DeletionPolicy": "Retain" + "DeletionPolicy": "Delete" } } }, @@ -55,7 +55,7 @@ }, "TableName": "integrationtest" }, - "DeletionPolicy": "Retain" + "DeletionPolicy": "Delete" } } }, @@ -85,7 +85,7 @@ }, "TableName": "integrationtest" }, - "DeletionPolicy": "Retain" + "DeletionPolicy": "Delete" } } }, From 4018170bc9cb856b76ffa28f083d11fe5de52c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Wed, 26 Jun 2019 10:37:09 +0200 Subject: [PATCH 5/6] Fix other test --- .../test/integ.dynamodb.expected.json | 3 ++- .../@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.ts | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.expected.json index 49a5de5ac5898..ad443bb55d208 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.expected.json @@ -134,7 +134,8 @@ "StreamSpecification": { "StreamViewType": "NEW_IMAGE" } - } + }, + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.ts index f7402d883b58f..88de34945f75d 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.ts @@ -14,7 +14,8 @@ class DynamoEventSourceTest extends cdk.Stack { name: 'id', type: dynamodb.AttributeType.STRING }, - stream: dynamodb.StreamViewType.NEW_IMAGE + stream: dynamodb.StreamViewType.NEW_IMAGE, + removalPolicy: cdk.RemovalPolicy.DESTROY, }); fn.addEventSource(new DynamoEventSource(queue, { @@ -26,4 +27,4 @@ class DynamoEventSourceTest extends cdk.Stack { const app = new cdk.App(); new DynamoEventSourceTest(app, 'lambda-event-source-dynamodb'); -app.synth(); \ No newline at end of file +app.synth(); From ef9e5d4ef2c00e3336cdad9ac3e3205395b983bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Wed, 26 Jun 2019 11:48:26 +0200 Subject: [PATCH 6/6] Fix decdk test --- packages/@aws-cdk/custom-resources/package-lock.json | 2 +- packages/decdk/package.json | 2 +- packages/decdk/test/__snapshots__/synth.test.js.snap | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/custom-resources/package-lock.json b/packages/@aws-cdk/custom-resources/package-lock.json index c375dfec4cf92..703d185f4f3cd 100644 --- a/packages/@aws-cdk/custom-resources/package-lock.json +++ b/packages/@aws-cdk/custom-resources/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aws-cdk/custom-resources", - "version": "0.35.0", + "version": "0.36.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/decdk/package.json b/packages/decdk/package.json index 76ec30f9c74ca..224910bbe128d 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -162,4 +162,4 @@ "engines": { "node": ">= 8.10.0" } -} +} \ No newline at end of file diff --git a/packages/decdk/test/__snapshots__/synth.test.js.snap b/packages/decdk/test/__snapshots__/synth.test.js.snap index 12f454af5a20e..31b9df6d66d08 100644 --- a/packages/decdk/test/__snapshots__/synth.test.js.snap +++ b/packages/decdk/test/__snapshots__/synth.test.js.snap @@ -1322,6 +1322,7 @@ Object { "Type": "AWS::SNS::Subscription", }, "TableCD117FA1": Object { + "DeletionPolicy": "Retain", "Properties": Object { "AttributeDefinitions": Array [ Object {