From e3300f0aa8aa12c67c046e85e7ee4743ecd6afe1 Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Fri, 1 Nov 2024 21:34:43 -0500 Subject: [PATCH 1/3] chore(pipes-targets): remove dependency with pipes-sources (#31986) Update the integration test cases for both pipes-sources and pipes-targets modules to add comments explained why we use TestTarget, and TestSource instead of using real classes, and this to avoid the circular dependencies, as we need to depend on each module on the other so we can implement these test cases. These Test classes should be replaced before graduating the pipes alpha modules. --- .../test/integ.dynamodb.ts | 2 ++ .../test/integ.kinesis.ts | 2 ++ .../aws-pipes-sources-alpha/test/integ.sqs.ts | 2 ++ .../aws-pipes-targets-alpha/package.json | 3 +-- .../test/integ.api-destination.ts | 24 +++++++++++++++--- .../test/integ.cloudwatch-logs.ts | 24 +++++++++++++++--- .../test/integ.event-bridge.ts | 24 +++++++++++++++--- .../test/integ.kinesis.ts | 24 +++++++++++++++--- .../test/integ.lambda.ts | 24 +++++++++++++++--- .../test/integ.sagemaker.ts | 25 ++++++++++++++++--- .../aws-pipes-targets-alpha/test/integ.sqs.ts | 24 +++++++++++++++--- .../test/integ.stepfunctions.ts | 25 ++++++++++++++++--- 12 files changed, 176 insertions(+), 27 deletions(-) diff --git a/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.dynamodb.ts b/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.dynamodb.ts index f440c77625976..0f7a763ec67d0 100644 --- a/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.dynamodb.ts +++ b/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.dynamodb.ts @@ -17,6 +17,8 @@ const table = new ddb.TableV2(stack, 'MyTable', { const dlqQueue = new cdk.aws_sqs.Queue(stack, 'DlqQueue'); const targetQueue = new cdk.aws_sqs.Queue(stack, 'TargetQueue'); +// When this module is promoted from alpha, TestTarget should +// be replaced with SqsTarget from @aws-cdk/aws-pipes-targets-alpha class TestTarget implements ITarget { targetArn: string; diff --git a/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.kinesis.ts b/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.kinesis.ts index c2e3d8c60b588..7d771b9e36bc5 100644 --- a/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.kinesis.ts +++ b/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.kinesis.ts @@ -9,6 +9,8 @@ const stack = new cdk.Stack(app, 'aws-cdk-pipes-sources-kinesis'); const sourceKinesisStream = new cdk.aws_kinesis.Stream(stack, 'SourceKinesisStream'); const targetQueue = new cdk.aws_sqs.Queue(stack, 'TargetQueue'); +// When this module is promoted from alpha, TestTarget should +// be replaced with SqsTarget from @aws-cdk/aws-pipes-targets-alpha class TestTarget implements ITarget { targetArn: string; diff --git a/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.sqs.ts b/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.sqs.ts index 346e98751b791..c31a3daf720f7 100644 --- a/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.sqs.ts +++ b/packages/@aws-cdk/aws-pipes-sources-alpha/test/integ.sqs.ts @@ -9,6 +9,8 @@ const stack = new cdk.Stack(app, 'aws-cdk-pipes-sources-sqs'); const sourceQueue = new cdk.aws_sqs.Queue(stack, 'SourceQueue'); const targetQueue = new cdk.aws_sqs.Queue(stack, 'TargetQueue'); +// When this module is promoted from alpha, TestTarget should +// be replaced with SqsTarget from @aws-cdk/aws-pipes-targets-alpha class TestTarget implements ITarget { targetArn: string; inputTransformation: InputTransformation = InputTransformation.fromEventPath('$.body'); diff --git a/packages/@aws-cdk/aws-pipes-targets-alpha/package.json b/packages/@aws-cdk/aws-pipes-targets-alpha/package.json index f51ecef876d3f..1ff59f74dc7a6 100644 --- a/packages/@aws-cdk/aws-pipes-targets-alpha/package.json +++ b/packages/@aws-cdk/aws-pipes-targets-alpha/package.json @@ -89,8 +89,7 @@ "aws-cdk-lib": "0.0.0", "constructs": "^10.0.0", "@aws-cdk/aws-pipes-alpha": "0.0.0", - "@aws-cdk/integ-tests-alpha": "0.0.0", - "@aws-cdk/aws-pipes-sources-alpha": "0.0.0" + "@aws-cdk/integ-tests-alpha": "0.0.0" }, "dependencies": {}, "peerDependencies": { diff --git a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.api-destination.ts b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.api-destination.ts index 51468d4b63500..17454520f7333 100644 --- a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.api-destination.ts +++ b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.api-destination.ts @@ -1,5 +1,4 @@ -import { Pipe } from '@aws-cdk/aws-pipes-alpha'; -import { SqsSource } from '@aws-cdk/aws-pipes-sources-alpha'; +import { IPipe, ISource, Pipe, SourceConfig } from '@aws-cdk/aws-pipes-alpha'; import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests-alpha'; import * as cdk from 'aws-cdk-lib'; import * as apigwv2 from 'aws-cdk-lib/aws-apigatewayv2'; @@ -19,6 +18,25 @@ const sourceQueue = new cdk.aws_sqs.Queue(stack, 'SourceQueue'); * --> API Gateway HTTP API --> Lambda function */ +// When this module is promoted from alpha, TestSource should +// be replaced with SqsSource from @aws-cdk/aws-pipes-sources-alpha +class TestSource implements ISource { + sourceArn: string; + sourceParameters = undefined; + constructor(private readonly queue: cdk.aws_sqs.Queue) { + this.queue = queue; + this.sourceArn = queue.queueArn; + } + bind(_pipe: IPipe): SourceConfig { + return { + sourceParameters: this.sourceParameters, + }; + } + grantRead(pipeRole: cdk.aws_iam.IRole): void { + this.queue.grantConsumeMessages(pipeRole); + } +} + const fn = new lambda.Function(stack, 'ConnectHandler', { runtime: lambda.Runtime.NODEJS_LATEST, handler: 'index.handler', @@ -53,7 +71,7 @@ const destination = new cdk.aws_events.ApiDestination(stack, 'MyDestination', { }); new Pipe(stack, 'Pipe', { - source: new SqsSource(sourceQueue), + source: new TestSource(sourceQueue), target: new ApiDestinationTarget(destination, { headerParameters: { 'x-header': 'myheader', diff --git a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.cloudwatch-logs.ts b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.cloudwatch-logs.ts index 503dcbc3aee49..3eae628c41e35 100644 --- a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.cloudwatch-logs.ts +++ b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.cloudwatch-logs.ts @@ -1,5 +1,4 @@ -import { InputTransformation, Pipe } from '@aws-cdk/aws-pipes-alpha'; -import { SqsSource } from '@aws-cdk/aws-pipes-sources-alpha'; +import { InputTransformation, IPipe, ISource, Pipe, SourceConfig } from '@aws-cdk/aws-pipes-alpha'; import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests-alpha'; import * as cdk from 'aws-cdk-lib'; import { CloudWatchLogsTarget } from '../lib'; @@ -18,13 +17,32 @@ const targetLogGroup = new cdk.aws_logs.LogGroup(stack, 'TargetLogGroup'); const logStreamName = 'Mexico'; const body = 'Cozumel'; +// When this module is promoted from alpha, TestSource should +// be replaced with SqsSource from @aws-cdk/aws-pipes-sources-alpha +class TestSource implements ISource { + sourceArn: string; + sourceParameters = undefined; + constructor(private readonly queue: cdk.aws_sqs.Queue) { + this.queue = queue; + this.sourceArn = queue.queueArn; + } + bind(_pipe: IPipe): SourceConfig { + return { + sourceParameters: this.sourceParameters, + }; + } + grantRead(pipeRole: cdk.aws_iam.IRole): void { + this.queue.grantConsumeMessages(pipeRole); + } +} + new cdk.aws_logs.LogStream(stack, 'TargetLogStream', { logGroup: targetLogGroup, logStreamName: logStreamName, }); new Pipe(stack, 'Pipe', { - source: new SqsSource(sourceQueue), + source: new TestSource(sourceQueue), target: new CloudWatchLogsTarget(targetLogGroup, { logStreamName, inputTransformation: InputTransformation.fromEventPath('$.body'), diff --git a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.event-bridge.ts b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.event-bridge.ts index efa5fb85d23f4..2546569e3f101 100644 --- a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.event-bridge.ts +++ b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.event-bridge.ts @@ -1,5 +1,4 @@ -import { Pipe } from '@aws-cdk/aws-pipes-alpha'; -import { SqsSource } from '@aws-cdk/aws-pipes-sources-alpha'; +import { IPipe, ISource, Pipe, SourceConfig } from '@aws-cdk/aws-pipes-alpha'; import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests-alpha'; import * as cdk from 'aws-cdk-lib'; import { EventBridgeTarget } from '../lib/event-bridge'; @@ -9,8 +8,27 @@ const stack = new cdk.Stack(app, 'aws-cdk-pipes-targets-event-bridge'); const sourceQueue = new cdk.aws_sqs.Queue(stack, 'SourceQueue'); const targetEventBus = new cdk.aws_events.EventBus(stack, 'TargetEventBus'); +// When this module is promoted from alpha, TestSource should +// be replaced with SqsSource from @aws-cdk/aws-pipes-sources-alpha +class TestSource implements ISource { + sourceArn: string; + sourceParameters = undefined; + constructor(private readonly queue: cdk.aws_sqs.Queue) { + this.queue = queue; + this.sourceArn = queue.queueArn; + } + bind(_pipe: IPipe): SourceConfig { + return { + sourceParameters: this.sourceParameters, + }; + } + grantRead(pipeRole: cdk.aws_iam.IRole): void { + this.queue.grantConsumeMessages(pipeRole); + } +} + new Pipe(stack, 'Pipe', { - source: new SqsSource(sourceQueue), + source: new TestSource(sourceQueue), target: new EventBridgeTarget(targetEventBus, {}), }); diff --git a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.kinesis.ts b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.kinesis.ts index 13ff7777cf958..ed109c4bf71ee 100644 --- a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.kinesis.ts +++ b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.kinesis.ts @@ -1,5 +1,4 @@ -import { Pipe } from '@aws-cdk/aws-pipes-alpha'; -import { SqsSource } from '@aws-cdk/aws-pipes-sources-alpha'; +import { IPipe, ISource, Pipe, SourceConfig } from '@aws-cdk/aws-pipes-alpha'; import { IntegTest } from '@aws-cdk/integ-tests-alpha'; import * as cdk from 'aws-cdk-lib'; import { KinesisTarget } from '../lib/kinesis'; @@ -9,8 +8,27 @@ const stack = new cdk.Stack(app, 'aws-cdk-pipes-targets-kinesis'); const sourceQueue = new cdk.aws_sqs.Queue(stack, 'SourceQueue'); const targetStream = new cdk.aws_kinesis.Stream(stack, 'TargetStream'); +// When this module is promoted from alpha, TestSource should +// be replaced with SqsSource from @aws-cdk/aws-pipes-sources-alpha +class TestSource implements ISource { + sourceArn: string; + sourceParameters = undefined; + constructor(private readonly queue: cdk.aws_sqs.Queue) { + this.queue = queue; + this.sourceArn = queue.queueArn; + } + bind(_pipe: IPipe): SourceConfig { + return { + sourceParameters: this.sourceParameters, + }; + } + grantRead(pipeRole: cdk.aws_iam.IRole): void { + this.queue.grantConsumeMessages(pipeRole); + } +} + new Pipe(stack, 'Pipe', { - source: new SqsSource(sourceQueue), + source: new TestSource(sourceQueue), target: new KinesisTarget(targetStream, { partitionKey: 'pk', }), diff --git a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.lambda.ts b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.lambda.ts index 6f8afe6b8376b..8c4d8f863fdfe 100644 --- a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.lambda.ts +++ b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.lambda.ts @@ -1,7 +1,6 @@ import { randomUUID } from 'crypto'; import * as path from 'path'; -import { Pipe } from '@aws-cdk/aws-pipes-alpha'; -import { SqsSource } from '@aws-cdk/aws-pipes-sources-alpha'; +import { IPipe, ISource, Pipe, SourceConfig } from '@aws-cdk/aws-pipes-alpha'; import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests-alpha'; import * as cdk from 'aws-cdk-lib'; import * as iam from 'aws-cdk-lib/aws-iam'; @@ -20,6 +19,25 @@ const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-pipes-lambda-target'); const sourceQueue = new cdk.aws_sqs.Queue(stack, 'SourceQueue'); +// When this module is promoted from alpha, TestSource should +// be replaced with SqsSource from @aws-cdk/aws-pipes-sources-alpha +class TestSource implements ISource { + sourceArn: string; + sourceParameters = undefined; + constructor(private readonly queue: cdk.aws_sqs.Queue) { + this.queue = queue; + this.sourceArn = queue.queueArn; + } + bind(_pipe: IPipe): SourceConfig { + return { + sourceParameters: this.sourceParameters, + }; + } + grantRead(pipeRole: cdk.aws_iam.IRole): void { + this.queue.grantConsumeMessages(pipeRole); + } +} + const functionName = 'TestCdkPipesTargetLambdaFunction'; const targetFunction = new lambda.Function(stack, 'TargetLambdaFunction', { code: lambda.AssetCode.fromAsset( @@ -40,7 +58,7 @@ targetFunction.addToRolePolicy( ); new Pipe(stack, 'Pipe', { - source: new SqsSource(sourceQueue), + source: new TestSource(sourceQueue), target: new LambdaFunction(targetFunction, {}), }); diff --git a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.sagemaker.ts b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.sagemaker.ts index 5a9e459dec879..13e06e573522f 100644 --- a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.sagemaker.ts +++ b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.sagemaker.ts @@ -1,6 +1,4 @@ -import { Pipe } from '@aws-cdk/aws-pipes-alpha'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { SqsSource } from '@aws-cdk/aws-pipes-sources-alpha'; +import { IPipe, ISource, Pipe, SourceConfig } from '@aws-cdk/aws-pipes-alpha'; import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests-alpha'; import * as cdk from 'aws-cdk-lib'; import * as iam from 'aws-cdk-lib/aws-iam'; @@ -20,6 +18,25 @@ const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-pipes-targets-sagemaker'); const sourceQueue = new cdk.aws_sqs.Queue(stack, 'SourceQueue'); +// When this module is promoted from alpha, TestSource should +// be replaced with SqsSource from @aws-cdk/aws-pipes-sources-alpha +class TestSource implements ISource { + sourceArn: string; + sourceParameters = undefined; + constructor(private readonly queue: cdk.aws_sqs.Queue) { + this.queue = queue; + this.sourceArn = queue.queueArn; + } + bind(_pipe: IPipe): SourceConfig { + return { + sourceParameters: this.sourceParameters, + }; + } + grantRead(pipeRole: cdk.aws_iam.IRole): void { + this.queue.grantConsumeMessages(pipeRole); + } +} + interface FakePipelineProps { readonly pipelineName: string; } @@ -122,7 +139,7 @@ const targetPipeline = new FakePipeline(stack, 'Pipeline', { }); new Pipe(stack, 'Pipe', { - source: new SqsSource(sourceQueue), + source: new TestSource(sourceQueue), target: new SageMakerTarget(targetPipeline, { pipelineParameters: { foor: 'bar', diff --git a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.sqs.ts b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.sqs.ts index eb7bbab00d627..4eb9f9dffab1c 100644 --- a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.sqs.ts +++ b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.sqs.ts @@ -1,6 +1,5 @@ import { randomUUID } from 'crypto'; -import { InputTransformation, Pipe } from '@aws-cdk/aws-pipes-alpha'; -import { SqsSource } from '@aws-cdk/aws-pipes-sources-alpha'; +import { InputTransformation, IPipe, ISource, Pipe, SourceConfig } from '@aws-cdk/aws-pipes-alpha'; import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests-alpha'; import * as cdk from 'aws-cdk-lib'; import { SqsTarget } from '../lib'; @@ -10,8 +9,27 @@ const stack = new cdk.Stack(app, 'aws-cdk-pipes-targets'); const sourceQueue = new cdk.aws_sqs.Queue(stack, 'SourceQueue'); const targetQueue = new cdk.aws_sqs.Queue(stack, 'TargetQueue'); +// When this module is promoted from alpha, TestSource should +// be replaced with SqsSource from @aws-cdk/aws-pipes-sources-alpha +class TestSource implements ISource { + sourceArn: string; + sourceParameters = undefined; + constructor(private readonly queue: cdk.aws_sqs.Queue) { + this.queue = queue; + this.sourceArn = queue.queueArn; + } + bind(_pipe: IPipe): SourceConfig { + return { + sourceParameters: this.sourceParameters, + }; + } + grantRead(pipeRole: cdk.aws_iam.IRole): void { + this.queue.grantConsumeMessages(pipeRole); + } +} + new Pipe(stack, 'Pipe', { - source: new SqsSource(sourceQueue), + source: new TestSource(sourceQueue), target: new SqsTarget(targetQueue, { inputTransformation: InputTransformation.fromEventPath('$.body'), diff --git a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.stepfunctions.ts b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.stepfunctions.ts index 10f3fe44a0b67..34caa42815871 100644 --- a/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.stepfunctions.ts +++ b/packages/@aws-cdk/aws-pipes-targets-alpha/test/integ.stepfunctions.ts @@ -1,5 +1,4 @@ -import { InputTransformation, Pipe } from '@aws-cdk/aws-pipes-alpha'; -import { SqsSource } from '@aws-cdk/aws-pipes-sources-alpha'; +import { InputTransformation, IPipe, ISource, Pipe, SourceConfig } from '@aws-cdk/aws-pipes-alpha'; import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests-alpha'; import * as cdk from 'aws-cdk-lib'; import * as ssm from 'aws-cdk-lib/aws-ssm'; @@ -16,6 +15,26 @@ import { SfnStateMachine } from '../lib/stepfunctions'; const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-pipes-sfn-target'); const sourceQueue = new cdk.aws_sqs.Queue(stack, 'SourceQueue'); + +// When this module is promoted from alpha, TestSource should +// be replaced with SqsSource from @aws-cdk/aws-pipes-sources-alpha +class TestSource implements ISource { + sourceArn: string; + sourceParameters = undefined; + constructor(private readonly queue: cdk.aws_sqs.Queue) { + this.queue = queue; + this.sourceArn = queue.queueArn; + } + bind(_pipe: IPipe): SourceConfig { + return { + sourceParameters: this.sourceParameters, + }; + } + grantRead(pipeRole: cdk.aws_iam.IRole): void { + this.queue.grantConsumeMessages(pipeRole); + } +} + const parameterName = 'MyPipeParameter'; new ssm.StringParameter(stack, 'MyParameter', { parameterName, @@ -38,7 +57,7 @@ const targetStateMachine = new sfn.StateMachine(stack, 'TargetStateMachine', { }); new Pipe(stack, 'Pipe', { - source: new SqsSource(sourceQueue), + source: new TestSource(sourceQueue), target: new SfnStateMachine(targetStateMachine, { inputTransformation: InputTransformation.fromObject({ body: '<$.body>' }), From d0b7bf271b4215fb8981883b52c3d5ab0a46c465 Mon Sep 17 00:00:00 2001 From: Kazuho Cryer-Shinozuka Date: Sat, 2 Nov 2024 12:08:42 +0900 Subject: [PATCH 2/3] chore(neptune): engine version 1.3.4.0 (#31989) ### Issue # (if applicable) None ### Reason for this change Neptune had released engine version 1.3.4.0. https://docs.aws.amazon.com/neptune/latest/userguide/engine-releases-1.3.4.0.html ### Description of changes Add `v1_3_4_0` member to `EngineVersion` class ### Description of how you validated changes None ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-neptune-alpha/lib/cluster.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/@aws-cdk/aws-neptune-alpha/lib/cluster.ts b/packages/@aws-cdk/aws-neptune-alpha/lib/cluster.ts index 089333b436237..252ba0f923f40 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/lib/cluster.ts +++ b/packages/@aws-cdk/aws-neptune-alpha/lib/cluster.ts @@ -104,6 +104,10 @@ export class EngineVersion { * Neptune engine version 1.3.3.0 */ public static readonly V1_3_3_0 = new EngineVersion('1.3.3.0'); + /** + * Neptune engine version 1.3.4.0 + */ + public static readonly V1_3_4_0 = new EngineVersion('1.3.4.0'); /** * Constructor for specifying a custom engine version From 796c6d170a91d9f5fa96f3915a6fb6a7f7bddff3 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Fri, 1 Nov 2024 20:39:49 -0700 Subject: [PATCH 3/3] fix(dynamoDB): make TableV2 taggable (#31867) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Issue # (if applicable) Closes #30631 ### Reason for this change The [`AWS::DynamoDB::GlobalTable`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-globaltable.html) resource does not natively support tags. However, at the L2 level (`TableV2`), the [`tags`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb.TableV2.html#tags) option is available when creating this resource, which may give customers the impression that it is taggable. When customers apply tags using the aspect at the `TableV2` level, it’s likely they intend to tag all replicas, as each replica has its own `tags` property as well. This behavior also aligns with the related [construct documentation](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb.TableV2.html#tags). ### Description of changes - Enable tagging for `TableV2` - If a tag key is defined in the replica `tags` properties, it will take precedence over the `TagAspect` for that key, as it is more specific. - Keep the `tags` property behavior in `TableV2` - Update the description doc on it to reflect that it only applies to the default replica table ### Description of how you validated changes - added new unit test cases - deployed related integration test cases ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-cdk-global-table.assets.json | 2 +- ...efaultTestDeployAssertA2A9E81F.assets.json | 2 +- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 4 +- .../tree.json | 6 +- .../aws-cdk-global-table.assets.json | 6 +- .../aws-cdk-global-table.template.json | 32 +++++- ...efaultTestDeployAssertA2A9E81F.assets.json | 2 +- .../integ.table-v2-global.js.snapshot/cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 34 +++++- .../tree.json | 36 +++++- .../test/integ.table-v2-global.ts | 7 +- .../aws-cdk-lib/aws-dynamodb/lib/table-v2.ts | 40 ++++++- .../aws-dynamodb/test/table-v2.test.ts | 105 +++++++++++++++++- 16 files changed, 254 insertions(+), 30 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/aws-cdk-global-table.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/aws-cdk-global-table.assets.json index aa94a2c7845ca..edf92583f5036 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/aws-cdk-global-table.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/aws-cdk-global-table.assets.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "38.0.1", "files": { "cc5278f2745ed14e48839e10ba3e84d52a026101a039e164e937d90f16b69c34": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.assets.json index 0a9ffc385b09a..a01b555c8d324 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.assets.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "38.0.1", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/cdk.out index 1f0068d32659a..c6e612584e352 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"36.0.0"} \ No newline at end of file +{"version":"38.0.1"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/integ.json index 15437c63539c9..2aacd3080724d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "38.0.1", "testCases": { "aws-cdk-global-table-integ/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/manifest.json index f36374c4697b1..b5799752cf772 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "38.0.1", "artifacts": { "aws-cdk-global-table.assets": { "type": "cdk:asset-manifest", @@ -16,6 +16,7 @@ "templateFile": "aws-cdk-global-table.template.json", "terminationProtection": false, "validateOnSynth": false, + "notificationArns": [], "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1/cc5278f2745ed14e48839e10ba3e84d52a026101a039e164e937d90f16b69c34.json", @@ -90,6 +91,7 @@ "templateFile": "awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.template.json", "terminationProtection": false, "validateOnSynth": false, + "notificationArns": [], "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", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/tree.json index 963c19fb401dd..ff85fbcbd863f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.ondemand.js.snapshot/tree.json @@ -231,7 +231,7 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_dynamodb.TableBaseV2", + "fqn": "aws-cdk-lib.aws_dynamodb.TableV2", "version": "0.0.0" } }, @@ -270,7 +270,7 @@ "path": "aws-cdk-global-table-integ/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.3.0" + "version": "10.4.2" } }, "DeployAssert": { @@ -316,7 +316,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.3.0" + "version": "10.4.2" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/aws-cdk-global-table.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/aws-cdk-global-table.assets.json index 419f067b36e9e..929f0476cdfd0 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/aws-cdk-global-table.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/aws-cdk-global-table.assets.json @@ -1,7 +1,7 @@ { - "version": "36.0.0", + "version": "38.0.1", "files": { - "a38411fa5a0afe5343485b65f2c16b2b258cbf8f67e1bf8dc53f06668c3b91d2": { + "f76e4db697eb7d6e297e40f4bafd35a109a7849082124cc1946d6efb31becfbd": { "source": { "path": "aws-cdk-global-table.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-us-east-1": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", - "objectKey": "a38411fa5a0afe5343485b65f2c16b2b258cbf8f67e1bf8dc53f06668c3b91d2.json", + "objectKey": "f76e4db697eb7d6e297e40f4bafd35a109a7849082124cc1946d6efb31becfbd.json", "region": "us-east-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/aws-cdk-global-table.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/aws-cdk-global-table.template.json index 5c42c0eccbdd0..8fda8662e31e9 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/aws-cdk-global-table.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/aws-cdk-global-table.template.json @@ -16,7 +16,13 @@ "KeyId": "alias/aws/kinesis" } ] - } + }, + "Tags": [ + { + "Key": "stage", + "Value": "IntegTest" + } + ] }, "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" @@ -148,6 +154,14 @@ "Region": "us-east-2", "TableClass": "STANDARD_INFREQUENT_ACCESS", "Tags": [ + { + "Key": "stage", + "Value": "IntegTest" + }, + { + "Key": "tagAspectKey", + "Value": "tagAspectValue" + }, { "Key": "USE2ReplicaTagKey", "Value": "USE2ReplicaTagValue" @@ -184,6 +198,14 @@ "Region": "us-west-2", "TableClass": "STANDARD", "Tags": [ + { + "Key": "stage", + "Value": "IntegTest" + }, + { + "Key": "tagAspectKey", + "Value": "tagAspectValue" + }, { "Key": "USW2ReplicaTagKey", "Value": "USW2ReplicaTagValue" @@ -231,6 +253,14 @@ "Region": "us-east-1", "TableClass": "STANDARD_INFREQUENT_ACCESS", "Tags": [ + { + "Key": "stage", + "Value": "IntegTest" + }, + { + "Key": "tagAspectKey", + "Value": "tagAspectValue" + }, { "Key": "primaryTableTagKey", "Value": "primaryTableTagValue" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.assets.json index 0a9ffc385b09a..a01b555c8d324 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.assets.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "38.0.1", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/cdk.out index 1f0068d32659a..c6e612584e352 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"36.0.0"} \ No newline at end of file +{"version":"38.0.1"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/integ.json index 15437c63539c9..2aacd3080724d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "38.0.1", "testCases": { "aws-cdk-global-table-integ/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/manifest.json index fe3ce6aaeb327..cdfdbcd507e22 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "38.0.1", "artifacts": { "aws-cdk-global-table.assets": { "type": "cdk:asset-manifest", @@ -15,10 +15,14 @@ "properties": { "templateFile": "aws-cdk-global-table.template.json", "terminationProtection": false, + "tags": { + "stage": "IntegTest" + }, "validateOnSynth": false, + "notificationArns": [], "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1/a38411fa5a0afe5343485b65f2c16b2b258cbf8f67e1bf8dc53f06668c3b91d2.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1/f76e4db697eb7d6e297e40f4bafd35a109a7849082124cc1946d6efb31becfbd.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -34,6 +38,17 @@ "aws-cdk-global-table.assets" ], "metadata": { + "/aws-cdk-global-table": [ + { + "type": "aws:cdk:stack-tags", + "data": [ + { + "Key": "stage", + "Value": "IntegTest" + } + ] + } + ], "/aws-cdk-global-table/Stream/Resource": [ { "type": "aws:cdk:logicalId", @@ -89,7 +104,11 @@ "properties": { "templateFile": "awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.template.json", "terminationProtection": false, + "tags": { + "stage": "IntegTest" + }, "validateOnSynth": false, + "notificationArns": [], "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", @@ -108,6 +127,17 @@ "awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.assets" ], "metadata": { + "/aws-cdk-global-table-integ/DefaultTest/DeployAssert": [ + { + "type": "aws:cdk:stack-tags", + "data": [ + { + "Key": "stage", + "Value": "IntegTest" + } + ] + } + ], "/aws-cdk-global-table-integ/DefaultTest/DeployAssert/BootstrapVersion": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/tree.json index e162d51c8274f..7d72d600d5a9f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/tree.json @@ -31,7 +31,13 @@ "KeyId": "alias/aws/kinesis" } ] - } + }, + "tags": [ + { + "key": "stage", + "value": "IntegTest" + } + ] } }, "constructInfo": { @@ -187,6 +193,14 @@ } }, "tags": [ + { + "key": "stage", + "value": "IntegTest" + }, + { + "key": "tagAspectKey", + "value": "tagAspectValue" + }, { "key": "USE2ReplicaTagKey", "value": "USE2ReplicaTagValue" @@ -223,6 +237,14 @@ "readCapacityUnits": 10 }, "tags": [ + { + "key": "stage", + "value": "IntegTest" + }, + { + "key": "tagAspectKey", + "value": "tagAspectValue" + }, { "key": "USW2ReplicaTagKey", "value": "USW2ReplicaTagValue" @@ -270,6 +292,14 @@ "readCapacityUnits": 10 }, "tags": [ + { + "key": "stage", + "value": "IntegTest" + }, + { + "key": "tagAspectKey", + "value": "tagAspectValue" + }, { "key": "primaryTableTagKey", "value": "primaryTableTagValue" @@ -347,7 +377,7 @@ "path": "aws-cdk-global-table-integ/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.3.0" + "version": "10.4.2" } }, "DeployAssert": { @@ -393,7 +423,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.3.0" + "version": "10.4.2" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.ts index 8cf849249f998..de8d987c23e91 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.ts @@ -1,5 +1,5 @@ import { IntegTest } from '@aws-cdk/integ-tests-alpha'; -import { App, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib'; +import { App, RemovalPolicy, Stack, StackProps, Tags } from 'aws-cdk-lib'; import { AttributeType, Billing, Capacity, TableV2, TableClass, TableEncryptionV2 } from 'aws-cdk-lib/aws-dynamodb'; import { Stream } from 'aws-cdk-lib/aws-kinesis'; import { Construct } from 'constructs'; @@ -10,7 +10,7 @@ class TestStack extends Stack { const stream = new Stream(this, 'Stream'); - new TableV2(this, 'GlobalTable', { + const globalTable = new TableV2(this, 'GlobalTable', { tableName: 'my-global-table', partitionKey: { name: 'pk', type: AttributeType.STRING }, sortKey: { name: 'sk', type: AttributeType.NUMBER }, @@ -68,10 +68,13 @@ class TestStack extends Stack { ], tags: [{ key: 'primaryTableTagKey', value: 'primaryTableTagValue' }], }); + + Tags.of(globalTable).add('tagAspectKey', 'tagAspectValue'); } } const app = new App(); +Tags.of(app).add('stage', 'IntegTest'); new IntegTest(app, 'aws-cdk-global-table-integ', { testCases: [new TestStack(app, 'aws-cdk-global-table', { env: { region: 'us-east-1' } })], regions: ['us-east-1'], diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts index b6507d3f7deb1..ac79fb6fad792 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts @@ -4,15 +4,30 @@ import { Capacity } from './capacity'; import { CfnGlobalTable } from './dynamodb.generated'; import { TableEncryptionV2 } from './encryption'; import { + Attribute, + BillingMode, + LocalSecondaryIndexProps, + ProjectionType, + SecondaryIndexProps, StreamViewType, - Attribute, TableClass, LocalSecondaryIndexProps, - SecondaryIndexProps, BillingMode, ProjectionType, + TableClass, } from './shared'; -import { TableBaseV2, ITableV2 } from './table-v2-base'; +import { ITableV2, TableBaseV2 } from './table-v2-base'; import { PolicyDocument } from '../../aws-iam'; import { IStream } from '../../aws-kinesis'; import { IKey, Key } from '../../aws-kms'; -import { ArnFormat, CfnTag, FeatureFlags, Lazy, PhysicalName, RemovalPolicy, Stack, Token } from '../../core'; +import { + ArnFormat, + CfnTag, + FeatureFlags, + Lazy, + PhysicalName, + RemovalPolicy, + Stack, + TagManager, + TagType, + Token, +} from '../../core'; import * as cxapi from '../../cx-api'; const HASH_KEY_TYPE = 'HASH'; @@ -145,7 +160,7 @@ export interface TableOptionsV2 { readonly kinesisStream?: IStream; /** - * Tags to be applied to the table or replica table + * Tags to be applied to the primary table (default replica table). * * @default - no tags */ @@ -483,6 +498,8 @@ export class TableV2 extends TableBaseV2 { protected readonly region: string; + protected readonly tags: TagManager; + private readonly billingMode: string; private readonly partitionKey: Attribute; private readonly hasSortKey: boolean; @@ -516,6 +533,7 @@ export class TableV2 extends TableBaseV2 { this.partitionKey = props.partitionKey; this.hasSortKey = props.sortKey !== undefined; this.region = this.stack.region; + this.tags = new TagManager(TagType.STANDARD, CfnGlobalTable.CFN_RESOURCE_TYPE_NAME); this.encryption = props.encryption; this.encryptionKey = this.encryption?.tableKey; @@ -665,6 +683,7 @@ export class TableV2 extends TableBaseV2 { private configureReplicaTable(props: ReplicaTableProps): CfnGlobalTable.ReplicaSpecificationProperty { const pointInTimeRecovery = props.pointInTimeRecovery ?? this.tableOptions.pointInTimeRecovery; const contributorInsights = props.contributorInsights ?? this.tableOptions.contributorInsights; + /* * Feature flag set as the following may be a breaking change. * @see https://github.com/aws/aws-cdk/pull/31097 @@ -674,6 +693,15 @@ export class TableV2 extends TableBaseV2 { ? (props.region === this.region ? this.tableOptions.resourcePolicy : props.resourcePolicy) || undefined : props.resourcePolicy ?? this.tableOptions.resourcePolicy; + const propTags: Record = (props.tags ?? []).reduce((p, item) => + ({ ...p, [item.key]: item.value }), {}, + ); + + const tags: CfnTag[] = Object.entries({ + ...this.tags.tagValues(), + ...propTags, + }).map(([k, v]) => ({ key: k, value: v })); + return { region: props.region, globalSecondaryIndexes: this.configureReplicaGlobalSecondaryIndexes(props.globalSecondaryIndexOptions), @@ -692,7 +720,7 @@ export class TableV2 extends TableBaseV2 { readProvisionedThroughputSettings: props.readCapacity ? props.readCapacity._renderReadCapacity() : this.readProvisioning, - tags: props.tags, + tags: tags.length === 0 ? undefined : tags, readOnDemandThroughputSettings: props.maxReadRequestUnits ? { maxReadRequestUnits: props.maxReadRequestUnits } : this.maxReadRequestUnits diff --git a/packages/aws-cdk-lib/aws-dynamodb/test/table-v2.test.ts b/packages/aws-cdk-lib/aws-dynamodb/test/table-v2.test.ts index 63bbf3319b73e..a4c9c66808ff2 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/test/table-v2.test.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/test/table-v2.test.ts @@ -2,7 +2,7 @@ import { Match, Template } from '../../assertions'; import { ArnPrincipal, PolicyDocument, PolicyStatement } from '../../aws-iam'; import { Stream } from '../../aws-kinesis'; import { Key } from '../../aws-kms'; -import { CfnDeletionPolicy, Lazy, RemovalPolicy, Stack } from '../../core'; +import { CfnDeletionPolicy, Lazy, RemovalPolicy, Stack, Tags } from '../../core'; import { AttributeType, Billing, Capacity, GlobalSecondaryIndexPropsV2, TableV2, LocalSecondaryIndexProps, ProjectionType, StreamViewType, TableClass, TableEncryptionV2, @@ -1293,6 +1293,107 @@ describe('replica tables', () => { }); }); + test('with TagAspect', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); + + // WHEN + const table = new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + replicas: [{ + region: 'us-west-1', + }], + }); + + Tags.of(table).add('tagKey', 'tagValue'); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { + Replicas: [ + { + Region: 'us-west-1', + Tags: [{ Key: 'tagKey', Value: 'tagValue' }], + }, + { + Region: 'us-east-1', + Tags: [{ Key: 'tagKey', Value: 'tagValue' }], + }, + ], + }); + }); + + test('with TagAspect on parent scope', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); + + // WHEN + new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + replicas: [{ + region: 'us-west-1', + }], + }); + + Tags.of(stack).add('stage', 'Prod'); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { + Replicas: [ + { + Region: 'us-west-1', + Tags: [{ Key: 'stage', Value: 'Prod' }], + }, + { + Region: 'us-east-1', + Tags: [{ Key: 'stage', Value: 'Prod' }], + }, + ], + }); + }); + + test('replica tags override tag aspect tags', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); + + // WHEN + const table = new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + replicas: [{ + region: 'us-west-1', + tags: [{ key: 'tableTagProperty', value: 'replicaW1TagPropertyValue' }], + }, { + region: 'us-west-2', + }], + tags: [{ key: 'tableTagProperty', value: 'defaultReplicaTagPropertyValue' }], + }); + + Tags.of(table).add('tableTagProperty', 'tagAspectValue'); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { + Replicas: [ + { + Region: 'us-west-1', + Tags: [ + { Key: 'tableTagProperty', Value: 'replicaW1TagPropertyValue' }, + ], + }, + { + Region: 'us-west-2', + Tags: [ + { Key: 'tableTagProperty', Value: 'tagAspectValue' }, + ], + }, + { + Region: 'us-east-1', + Tags: [ + { Key: 'tableTagProperty', Value: 'defaultReplicaTagPropertyValue' }, + ], + }, + ], + }); + }); + test('with per-replica kinesis stream', () => { // GIVEN const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); @@ -3007,4 +3108,4 @@ test('Resource policy test', () => { }, ], }); -}); \ No newline at end of file +});