From 55b92a5f2b144562d2da4278ad590ab38c330929 Mon Sep 17 00:00:00 2001 From: Ross Date: Sat, 18 Jan 2025 17:41:14 +0000 Subject: [PATCH] feat(dynamodb): recovery period in days for dynamodb table v1 --- ...efaultTestDeployAssert4E6713E1.assets.json | 19 +++ ...aultTestDeployAssert4E6713E1.template.json | 36 +++++ ...ynamodb-point-in-time-recovery.assets.json | 19 +++ ...amodb-point-in-time-recovery.template.json | 65 ++++++++ .../cdk.out | 1 + .../integ.json | 12 ++ .../manifest.json | 113 +++++++++++++ .../tree.json | 152 ++++++++++++++++++ .../integ.dynamodb.point-in-time-recovery.ts | 28 ++++ packages/aws-cdk-lib/aws-dynamodb/README.md | 9 ++ .../aws-cdk-lib/aws-dynamodb/lib/table.ts | 35 +++- .../aws-dynamodb/test/dynamodb.test.ts | 78 ++++++++- 12 files changed, 563 insertions(+), 4 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/IntegDefaultTestDeployAssert4E6713E1.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/aws-cdk-dynamodb-point-in-time-recovery.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/aws-cdk-dynamodb-point-in-time-recovery.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json new file mode 100644 index 0000000000000..9c02a36fd8387 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json @@ -0,0 +1,19 @@ +{ + "version": "39.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "IntegDefaultTestDeployAssert4E6713E1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/IntegDefaultTestDeployAssert4E6713E1.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/IntegDefaultTestDeployAssert4E6713E1.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/IntegDefaultTestDeployAssert4E6713E1.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/aws-cdk-dynamodb-point-in-time-recovery.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/aws-cdk-dynamodb-point-in-time-recovery.assets.json new file mode 100644 index 0000000000000..251d469705ad3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/aws-cdk-dynamodb-point-in-time-recovery.assets.json @@ -0,0 +1,19 @@ +{ + "version": "39.0.0", + "files": { + "ee4dc88de2a043fab3bf727d1e606ac6c8ff89dbb652e38b369494bdd1c9750f": { + "source": { + "path": "aws-cdk-dynamodb-point-in-time-recovery.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "ee4dc88de2a043fab3bf727d1e606ac6c8ff89dbb652e38b369494bdd1c9750f.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/aws-cdk-dynamodb-point-in-time-recovery.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/aws-cdk-dynamodb-point-in-time-recovery.template.json new file mode 100644 index 0000000000000..fe6cbc17e05d7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/aws-cdk-dynamodb-point-in-time-recovery.template.json @@ -0,0 +1,65 @@ +{ + "Resources": { + "TableTest143E55AA2": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "PointInTimeRecoverySpecification": { + "PointInTimeRecoveryEnabled": true, + "RecoveryPeriodInDays": 35 + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/cdk.out new file mode 100644 index 0000000000000..91e1a8b9901d5 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"39.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/integ.json new file mode 100644 index 0000000000000..759c8de0b85cc --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "39.0.0", + "testCases": { + "Integ/DefaultTest": { + "stacks": [ + "aws-cdk-dynamodb-point-in-time-recovery" + ], + "assertionStack": "Integ/DefaultTest/DeployAssert", + "assertionStackName": "IntegDefaultTestDeployAssert4E6713E1" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/manifest.json new file mode 100644 index 0000000000000..951288332856e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/manifest.json @@ -0,0 +1,113 @@ +{ + "version": "39.0.0", + "artifacts": { + "aws-cdk-dynamodb-point-in-time-recovery.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-dynamodb-point-in-time-recovery.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-dynamodb-point-in-time-recovery": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-dynamodb-point-in-time-recovery.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/ee4dc88de2a043fab3bf727d1e606ac6c8ff89dbb652e38b369494bdd1c9750f.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-dynamodb-point-in-time-recovery.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-dynamodb-point-in-time-recovery.assets" + ], + "metadata": { + "/aws-cdk-dynamodb-point-in-time-recovery/TableTest1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TableTest143E55AA2" + } + ], + "/aws-cdk-dynamodb-point-in-time-recovery/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-dynamodb-point-in-time-recovery/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-dynamodb-point-in-time-recovery" + }, + "IntegDefaultTestDeployAssert4E6713E1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "IntegDefaultTestDeployAssert4E6713E1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "IntegDefaultTestDeployAssert4E6713E1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "IntegDefaultTestDeployAssert4E6713E1.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "IntegDefaultTestDeployAssert4E6713E1.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "IntegDefaultTestDeployAssert4E6713E1.assets" + ], + "metadata": { + "/Integ/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Integ/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Integ/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/tree.json new file mode 100644 index 0000000000000..c08fa715cfbd6 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.js.snapshot/tree.json @@ -0,0 +1,152 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-cdk-dynamodb-point-in-time-recovery": { + "id": "aws-cdk-dynamodb-point-in-time-recovery", + "path": "aws-cdk-dynamodb-point-in-time-recovery", + "children": { + "TableTest1": { + "id": "TableTest1", + "path": "aws-cdk-dynamodb-point-in-time-recovery/TableTest1", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-dynamodb-point-in-time-recovery/TableTest1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::DynamoDB::Table", + "aws:cdk:cloudformation:props": { + "attributeDefinitions": [ + { + "attributeName": "id", + "attributeType": "S" + } + ], + "keySchema": [ + { + "attributeName": "id", + "keyType": "HASH" + } + ], + "pointInTimeRecoverySpecification": { + "pointInTimeRecoveryEnabled": true, + "recoveryPeriodInDays": 35 + }, + "provisionedThroughput": { + "readCapacityUnits": 5, + "writeCapacityUnits": 5 + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_dynamodb.CfnTable", + "version": "0.0.0" + } + }, + "ScalingRole": { + "id": "ScalingRole", + "path": "aws-cdk-dynamodb-point-in-time-recovery/TableTest1/ScalingRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_dynamodb.Table", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-dynamodb-point-in-time-recovery/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-dynamodb-point-in-time-recovery/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "Integ": { + "id": "Integ", + "path": "Integ", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "Integ/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "Integ/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "Integ/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "Integ/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "Integ/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.ts new file mode 100644 index 0000000000000..c4a8f560a15fe --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.point-in-time-recovery.ts @@ -0,0 +1,28 @@ +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { App, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib'; +import { AttributeType, Table } from 'aws-cdk-lib/aws-dynamodb'; +import { Construct } from 'constructs'; + +export class TestStack extends Stack { + + readonly table: Table; + + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + this.table = new Table(this, 'TableTest1', { + partitionKey: { + name: 'id', + type: AttributeType.STRING, + }, + pointInTimeRecovery: true, + recoveryPeriodInDays: 35, + removalPolicy: RemovalPolicy.DESTROY, + }); + } +} + +const app = new App(); +const stack = new TestStack(app, 'aws-cdk-dynamodb-point-in-time-recovery', {}); + +new IntegTest(app, 'Integ', { testCases: [stack] }); diff --git a/packages/aws-cdk-lib/aws-dynamodb/README.md b/packages/aws-cdk-lib/aws-dynamodb/README.md index 133c1b9efa296..587095e34743e 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/README.md +++ b/packages/aws-cdk-lib/aws-dynamodb/README.md @@ -631,6 +631,15 @@ const table = new dynamodb.TableV2(this, 'Table', { }); ``` +`recoveryPeriodInDays` specifies the number of preceding days for which continuous backups are taken and maintained. If this property is set without configuring `pointInTimeRecovery` then point-in-time recovery will be enabled by default. + +```ts +const table = new dynamodb.TableV2(this, 'Table', { + partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, + recoveryPeriodInDays: 35, +}); +``` + ## Table Class You can configure a `TableV2` instance with table classes: diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts index 55ed1082a717a..4b22f7dd2b539 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts @@ -286,10 +286,20 @@ export interface TableOptions extends SchemaOptions { /** * Whether point-in-time recovery is enabled. - * @default - point-in-time recovery is disabled + * + * @default - point-in-time recovery is true if `recoveryPeriodInDays` is set, otherwise it is disabled. */ readonly pointInTimeRecovery?: boolean; + /** + * The number of preceding days for which continuous backups are taken and maintained. + * + * Your table data is only recoverable to any point-in-time from within the configured recovery period. + * + * @default - recovery period in days is not configured. + */ + readonly recoveryPeriodInDays?: number; + /** * Whether server-side encryption with an AWS managed customer master key is enabled. * @@ -1209,7 +1219,7 @@ export class Table extends TableBase { attributeDefinitions: this.attributeDefinitions, globalSecondaryIndexes: Lazy.any({ produce: () => this.globalSecondaryIndexes }, { omitEmptyArray: true }), localSecondaryIndexes: Lazy.any({ produce: () => this.localSecondaryIndexes }, { omitEmptyArray: true }), - pointInTimeRecoverySpecification: props.pointInTimeRecovery != null ? { pointInTimeRecoveryEnabled: props.pointInTimeRecovery } : undefined, + pointInTimeRecoverySpecification: this.renderPointInTimeRecoverySpecification(props.pointInTimeRecovery, props.recoveryPeriodInDays), billingMode: this.billingMode === BillingMode.PAY_PER_REQUEST ? this.billingMode : undefined, provisionedThroughput: this.billingMode === BillingMode.PAY_PER_REQUEST ? undefined : { readCapacityUnits: props.readCapacity || 5, @@ -1233,7 +1243,7 @@ export class Table extends TableBase { resourcePolicy: props.resourcePolicy ? { policyDocument: props.resourcePolicy } : undefined, - warmThroughput: props.warmThroughput?? undefined, + warmThroughput: props.warmThroughput ?? undefined, }); this.table.applyRemovalPolicy(props.removalPolicy); @@ -1788,6 +1798,25 @@ export class Table extends TableBase { }, }; } + + private renderPointInTimeRecoverySpecification( + pointInTimeRecovery?: boolean, + recoveryPeriodInDays?: number, + ): CfnTable.PointInTimeRecoverySpecificationProperty | undefined { + if (pointInTimeRecovery == null && recoveryPeriodInDays === undefined) return undefined; + + let pointInTimeRecoverySpecification: CfnTable.PointInTimeRecoverySpecificationProperty | undefined; + + if (recoveryPeriodInDays !== undefined) { + pointInTimeRecoverySpecification = { pointInTimeRecoveryEnabled: true, recoveryPeriodInDays }; + } + + if (pointInTimeRecovery != null) { + pointInTimeRecoverySpecification = { ...pointInTimeRecoverySpecification, pointInTimeRecoveryEnabled: pointInTimeRecovery }; + } + + return pointInTimeRecoverySpecification; + } } /** diff --git a/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts b/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts index d190bbb14f622..af2eb629a96bf 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts @@ -340,6 +340,7 @@ testDeprecated('when specifying every property', () => { readCapacity: 42, writeCapacity: 1337, pointInTimeRecovery: true, + recoveryPeriodInDays: 35, serverSideEncryption: true, billingMode: BillingMode.PROVISIONED, stream: StreamViewType.KEYS_ONLY, @@ -365,7 +366,7 @@ testDeprecated('when specifying every property', () => { ReadCapacityUnits: 42, WriteCapacityUnits: 1337, }, - PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true }, + PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true, RecoveryPeriodInDays: 35 }, SSESpecification: { SSEEnabled: true }, StreamSpecification: { StreamViewType: 'KEYS_ONLY' }, TableName: 'MyTable', @@ -381,6 +382,81 @@ testDeprecated('when specifying every property', () => { ); }); +describe('point in time recovery specification', () => { + let stack: Stack; + + beforeEach(() => { + stack = new Stack(); + }); + + test('when specifying pointInTimeRecovery = true without recoveryPeriodInDays', () => { + const table = new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + pointInTimeRecovery: true, + }); + Tags.of(table).add('Environment', 'Production'); + + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { + PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true }, + }); + }); + + test('when specifying pointInTimeRecovery = false without recoveryPeriodInDays', () => { + const table = new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + pointInTimeRecovery: false, + }); + Tags.of(table).add('Environment', 'Production'); + + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { + PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: false }, + }); + }); + + test('when specifying recoveryPeriodInDays without pointInTimeRecovery', () => { + const table = new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + recoveryPeriodInDays: 1, + }); + Tags.of(table).add('Environment', 'Production'); + + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { + PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true, RecoveryPeriodInDays: 1 }, + }); + }); + + test('when specifying pointInTimeRecovery = true and recoveryPeriodInDays', () => { + const table = new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + pointInTimeRecovery: true, + recoveryPeriodInDays: 1, + }); + Tags.of(table).add('Environment', 'Production'); + + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { + PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true, RecoveryPeriodInDays: 1 }, + }); + }); + + test('when specifying pointInTimeRecovery = false and recoveryPeriodInDays', () => { + const table = new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + pointInTimeRecovery: false, + recoveryPeriodInDays: 1, + }); + Tags.of(table).add('Environment', 'Production'); + + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', { + PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: false, RecoveryPeriodInDays: 1 }, + }); + }); +}); + test('when specifying sse with customer managed CMK', () => { const stack = new Stack(); const table = new Table(stack, CONSTRUCT_NAME, {