From 2c88e7c380688262ab67219a0b99438e58637756 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Wed, 25 Jun 2025 15:10:35 +0100 Subject: [PATCH 01/18] feat(dynamodb): Adding ContributorInsightsMode feature --- .../aws-cdk-lib/aws-dynamodb/lib/shared.ts | 32 ++ .../aws-cdk-lib/aws-dynamodb/lib/table-v2.ts | 47 ++- .../aws-cdk-lib/aws-dynamodb/lib/table.ts | 36 ++- .../aws-dynamodb/test/dynamodb.test.ts | 101 +++++++ .../aws-dynamodb/test/table-v2.test.ts | 279 ++++++++++++++++++ 5 files changed, 482 insertions(+), 13 deletions(-) diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts index 579999426640d..4c180c49353d4 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts @@ -157,6 +157,38 @@ export enum BillingMode { PROVISIONED = 'PROVISIONED', } +/** + * DynamoDB's Contributor Insights Mode + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-dynamodb-table-contributorinsightsspecification.html + */ +export enum ContributorInsightsMode { + /** + * Emits metrics for all read and write requests, whether successful or throttled. + */ + ACCESSED_AND_THROTTLED_KEYS = 'ACCESSED_AND_THROTTLED_KEYS', + + /** + * Emits metrics for read and write requests that were throttled. + */ + THROTTLED_KEYS = 'THROTTLED_KEYS', +} + +/** + * Reference to ContributorInsightsSpecification + */ +export interface ContributorInsightsSpecification { + /** + * Indicates whether contributor insights is enabled. + * @default false + */ + readonly enabled: boolean; + /** + * Indicates the type of metrics captured by contributor insights. + * @default ACCESSED_AND_THROTTLED_KEYS + */ + readonly contributorInsightsMode?: ContributorInsightsMode; +} + /** * The set of attributes that are projected into the index * 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 4b6f168148e2f..c14d4910f76a1 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts @@ -16,6 +16,7 @@ import { TableClass, WarmThroughput, MultiRegionConsistency, + ContributorInsightsSpecification, } from './shared'; import { ITableV2, TableBaseV2 } from './table-v2-base'; import { PolicyDocument } from '../../aws-iam'; @@ -51,11 +52,18 @@ export interface ReplicaGlobalSecondaryIndexOptions { /** * Whether CloudWatch contributor insights is enabled for a specific global secondary * index on a replica table. - * + * @deprecated use `contributorInsightsSpecification` instead * @default - inherited from the primary table */ readonly contributorInsights?: boolean; + /** + * Whether CloudWatch contributor insights is enabled and what mode is selected + * for a specific global secondary index on a replica table. + * @default - contributor insights is not enabled + */ + readonly contributorInsightsSpecification?: ContributorInsightsSpecification; + /** * The read capacity for a specific global secondary index on a replica table. * @@ -141,11 +149,17 @@ export interface GlobalSecondaryIndexPropsV2 extends SecondaryIndexProps { export interface TableOptionsV2 { /** * Whether CloudWatch contributor insights is enabled. - * + * @deprecated use `contributorInsightsSpecification` instead * @default false */ readonly contributorInsights?: boolean; + /** + * Whether CloudWatch contributor insights is enabled and what mode is selected + * @default - contributor insights is not enabled + */ + readonly contributorInsightsSpecification?: ContributorInsightsSpecification; + /** * Whether deletion protection is enabled. * @@ -752,7 +766,7 @@ export class TableV2 extends TableBaseV2 { } private configureReplicaTable(props: ReplicaTableProps): CfnGlobalTable.ReplicaSpecificationProperty { - const contributorInsights = props.contributorInsights ?? this.tableOptions.contributorInsights; + const contributorInsightsSpecification = this.validateCCI(props); // Determine if Point-In-Time Recovery (PITR) is enabled based on the provided property or table options (deprecated options). const pointInTimeRecovery = props.pointInTimeRecovery ?? this.tableOptions.pointInTimeRecovery; @@ -796,9 +810,7 @@ export class TableV2 extends TableBaseV2 { kinesisStreamSpecification: props.kinesisStream ? { streamArn: props.kinesisStream.streamArn } : undefined, - contributorInsightsSpecification: contributorInsights !== undefined - ? { enabled: contributorInsights } - : undefined, + contributorInsightsSpecification: contributorInsightsSpecification, pointInTimeRecoverySpecification: pointInTimeRecoverySpecification, readProvisionedThroughputSettings: props.readCapacity ? props.readCapacity._renderReadCapacity() @@ -875,13 +887,14 @@ export class TableV2 extends TableBaseV2 { ? { maxReadRequestUnits: maxReadRequestUnits } : undefined; + const contributorInsightsSpecification = this.validateCCI(options[indexName]) || + (contributorInsights !== undefined ? { enabled: contributorInsights } as ContributorInsightsSpecification : undefined); + replicaGlobalSecondaryIndexes.push({ indexName, readProvisionedThroughputSettings, readOnDemandThroughputSettings, - contributorInsightsSpecification: contributorInsights !== undefined - ? { enabled: contributorInsights } - : undefined, + contributorInsightsSpecification: contributorInsightsSpecification, }); } @@ -1134,4 +1147,20 @@ export class TableV2 extends TableBaseV2 { } } } + + private validateCCI (props: TablePropsV2 | ReplicaTableProps | ReplicaGlobalSecondaryIndexOptions): ContributorInsightsSpecification | undefined { + const contributorInsights = + props?.contributorInsights ?? this.tableOptions?.contributorInsights; + + const contributorInsightsSpecification = props?.contributorInsightsSpecification || this.tableOptions?.contributorInsightsSpecification; + + if (contributorInsightsSpecification !== undefined && contributorInsights !== undefined) { + throw new ValidationError('`contributorInsightsSpecification` and `contributorInsights` are set. Use `contributorInsightsSpecification` only.', this); + } + + return contributorInsightsSpecification ?? + (contributorInsights !== undefined + ? { enabled: contributorInsights } + : undefined); + } } diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts index 165691e9f742d..85688ae22b920 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts @@ -9,6 +9,7 @@ import { Operation, OperationsMetricOptions, SystemErrorsForOperationsMetricOptions, Attribute, BillingMode, ProjectionType, ITable, SecondaryIndexProps, TableClass, LocalSecondaryIndexProps, TableEncryption, StreamViewType, WarmThroughput, PointInTimeRecoverySpecification, + ContributorInsightsSpecification, } from './shared'; import * as appscaling from '../../aws-applicationautoscaling'; import * as cloudwatch from '../../aws-cloudwatch'; @@ -419,11 +420,17 @@ export interface TableOptions extends SchemaOptions { /** * Whether CloudWatch contributor insights is enabled. - * + * @deprecated use `contributorInsightsSpecification instead * @default false */ readonly contributorInsightsEnabled?: boolean; + /** + * Whether CloudWatch contributor insights is enabled and what mode is selected + * @default - contributor insights is not enabled + */ + readonly contributorInsightsSpecification?: ContributorInsightsSpecification; + /** * Enables deletion protection for the table. * @@ -520,10 +527,16 @@ export interface GlobalSecondaryIndexProps extends SecondaryIndexProps, SchemaOp /** * Whether CloudWatch contributor insights is enabled for the specified global secondary index. - * + * @deprecated use `contributorInsightsSpecification` instead * @default false */ readonly contributorInsightsEnabled?: boolean; + + /** + * Whether CloudWatch contributor insights is enabled and what mode is selected + * @default - contributor insights is not enabled + */ + readonly contributorInsightsSpecification?: ContributorInsightsSpecification; } /** @@ -1214,6 +1227,8 @@ export class Table extends TableBase { const pointInTimeRecoverySpecification = this.validatePitr(props); + const contributorInsightsSpecification = this.validateCCI(props); + let streamSpecification: CfnTable.StreamSpecificationProperty | undefined; if (props.replicationRegions) { if (props.stream && props.stream !== StreamViewType.NEW_AND_OLD_IMAGES) { @@ -1260,7 +1275,7 @@ export class Table extends TableBase { streamSpecification, tableClass: props.tableClass, timeToLiveSpecification: props.timeToLiveAttribute ? { attributeName: props.timeToLiveAttribute, enabled: true } : undefined, - contributorInsightsSpecification: props.contributorInsightsEnabled !== undefined ? { enabled: props.contributorInsightsEnabled } : undefined, + contributorInsightsSpecification: contributorInsightsSpecification, kinesisStreamSpecification: kinesisStreamSpecification, deletionProtectionEnabled: props.deletionProtection, importSourceSpecification: this.renderImportSourceSpecification(props.importSource), @@ -1315,8 +1330,10 @@ export class Table extends TableBase { const gsiKeySchema = this.buildIndexKeySchema(props.partitionKey, props.sortKey); const gsiProjection = this.buildIndexProjection(props); + const contributorInsightsSpecification = this.validateCCI(props); + this.globalSecondaryIndexes.push({ - contributorInsightsSpecification: props.contributorInsightsEnabled !== undefined ? { enabled: props.contributorInsightsEnabled } : undefined, + contributorInsightsSpecification: contributorInsightsSpecification, indexName: props.indexName, keySchema: gsiKeySchema, projection: gsiProjection, @@ -1586,6 +1603,17 @@ export class Table extends TableBase { : undefined); } + private validateCCI (props: TableProps | GlobalSecondaryIndexProps): ContributorInsightsSpecification | undefined { + if (props.contributorInsightsSpecification !==undefined && props.contributorInsightsEnabled !== undefined) { + throw new ValidationError('`contributorInsightsSpecification` and `contributorInsightsEnabled` are set. Use `contributorInsightsSpecification` only.', this); + } + + return props.contributorInsightsSpecification ?? + (props.contributorInsightsEnabled !== undefined + ? { enabled: props.contributorInsightsEnabled } + : undefined); + } + private buildIndexKeySchema(partitionKey: Attribute, sortKey?: Attribute): CfnTable.KeySchemaProperty[] { this.registerAttribute(partitionKey); const indexKeySchema: CfnTable.KeySchemaProperty[] = [ 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 e097c1b1e5514..cdec3afd0a8b9 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts @@ -26,6 +26,7 @@ import { InputCompressionType, InputFormat, ApproximateCreationDateTimePrecision, + ContributorInsightsMode, } from '../lib'; import { ReplicaProvider } from '../lib/replica-provider'; @@ -4119,3 +4120,103 @@ test('Kinesis Stream - precision timestamp', () => { }, }); }); + +test('Contributor Insights Specification - table', () => { + const stack = new Stack(); + + const table = new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + }); + + Template.fromStack(stack).hasResourceProperties('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 }, + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + }, + }, + ); +}); + +test('Contributor Insights Specification - index', () => { + const stack = new Stack(); + + const table = new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + }); + + table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.THROTTLED_KEYS, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'gsiHashKey', AttributeType: 'S' }, + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' }, + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + }, + GlobalSecondaryIndexes: [ + { + IndexName: 'MyGSI', + KeySchema: [ + { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, + ], + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'THROTTLED_KEYS', + }, + }, + ], + }, + ); +}); + +test('ContributorInsightsSpecification && ContributorInsightsEnabled', () => { + const stack = new Stack(); + + expect(() => { + new Table(stack, 'Table', { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + contributorInsightsEnabled: true, + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + }); + }).toThrow('`contributorInsightsSpecification` and `contributorInsightsEnabled` are set. Use `contributorInsightsSpecification` only.'); +}); 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 d83b484cb79b1..3219646eb60c9 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 @@ -7,6 +7,7 @@ import { AttributeType, Billing, Capacity, GlobalSecondaryIndexPropsV2, TableV2, LocalSecondaryIndexProps, ProjectionType, StreamViewType, TableClass, TableEncryptionV2, MultiRegionConsistency, + ContributorInsightsMode, } from '../lib'; describe('table', () => { @@ -3410,3 +3411,281 @@ describe('MRSC global tables validation', () => { }); }); }); + +test('Contributor Insights Specification - tableV2', () => { + const stack = new Stack(); + + const table = new TableV2(stack, 'TableV2', { + partitionKey: { name: 'hashKey', type: AttributeType.STRING }, + sortKey: { name: 'sortKey', type: AttributeType.NUMBER }, + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' }, + ], + Replicas: [ + { + Region: { + Ref: 'AWS::Region', + }, + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + }, + }, + ], + }, + ); +}); + +test('ContributorInsightsSpecification && ContributorInsights - v2', () => { + const stack = new Stack(); + + expect(() => { + const table = new TableV2(stack, 'Tablev2', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + sortKey: { name: 'sk', type: AttributeType.STRING }, + contributorInsights: true, + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + }); + + Template.fromStack(stack); + }).toThrow('`contributorInsightsSpecification` and `contributorInsights` are set. Use `contributorInsightsSpecification` only.'); +}); + +describe('MRSC global tables', () => { + test('with witness region', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); + + // WHEN + new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + replicas: [{ region: 'us-east-1' }], + witnessRegion: 'us-east-2', + multiRegionConsistency: MultiRegionConsistency.STRONG, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { + Replicas: [ + { Region: 'us-east-1' }, + { Region: 'us-west-2' }, + ], + GlobalTableWitnesses: [ + { Region: 'us-east-2' }, + ], + }); + }); + + test('without witness region should not have GlobalTableWitnesses property', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); + + // WHEN + new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + replicas: [{ region: 'us-east-1' }], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { + Replicas: [ + { Region: 'us-east-1' }, + { Region: 'us-west-2' }, + ], + }); + // Verify that GlobalTableWitnesses is not present in the template + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', + Match.not(Match.objectLike({ + GlobalTableWitnesses: Match.anyValue(), + })), + ); + }); + + test('with witness region and strong consistency requirements', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); + + // WHEN + new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + sortKey: { name: 'sk', type: AttributeType.STRING }, + replicas: [{ region: 'us-east-1' }], + witnessRegion: 'us-east-2', + multiRegionConsistency: MultiRegionConsistency.STRONG, + billing: Billing.provisioned({ + readCapacity: Capacity.fixed(10), + writeCapacity: Capacity.autoscaled({ minCapacity: 10, maxCapacity: 100 }), + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { + KeySchema: [ + { AttributeName: 'pk', KeyType: 'HASH' }, + { AttributeName: 'sk', KeyType: 'RANGE' }, + ], + AttributeDefinitions: [ + { AttributeName: 'pk', AttributeType: 'S' }, + { AttributeName: 'sk', AttributeType: 'S' }, + ], + BillingMode: 'PROVISIONED', + Replicas: [ + { + Region: 'us-east-1', + ReadProvisionedThroughputSettings: { + ReadCapacityUnits: 10, + }, + }, + { + Region: 'us-west-2', + ReadProvisionedThroughputSettings: { + ReadCapacityUnits: 10, + }, + }, + ], + GlobalTableWitnesses: [ + { Region: 'us-east-2' }, + ], + }); + }); +}); +describe('MRSC global tables validation', () => { + test('throws when witness region is used with eventual consistency', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); + + // WHEN / THEN - Error should be thrown during construction + expect(() => { + new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + replicas: [{ region: 'us-east-1' }], + witnessRegion: 'us-east-2', + // multiRegionConsistency defaults to EVENTUAL + }); + }).toThrow('Witness region cannot be specified for a Multi-Region Eventual Consistency (MREC) Global Table - Witness regions are only supported for Multi-Region Strong Consistency (MRSC) Global Tables.'); + }); + + test('validates regions are in same region set for STRONG consistency', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); + + // WHEN / THEN - Error should be thrown during construction + expect(() => { + new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + replicas: [{ region: 'eu-west-1' }], + witnessRegion: 'us-east-2', + multiRegionConsistency: MultiRegionConsistency.STRONG, + }); + }).toThrow("Region 'eu-west-1' is not in the same region set (US) as the primary region 'us-west-2'. All regions must be within the same region set for MRSC global tables with STRONG consistency. Supported US regions: us-east-1, us-east-2, us-west-2"); + }); + + test('validates exactly 2 replicas with witness for STRONG consistency', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'eu-west-1' } }); + + // WHEN / THEN - Error should be thrown during construction + expect(() => { + new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + replicas: [{ region: 'eu-west-2' }, { region: 'eu-west-3' }], // Too many replicas + witnessRegion: 'eu-central-1', // Use same region set + multiRegionConsistency: MultiRegionConsistency.STRONG, + }); + }).toThrow("MRSC global table with witness region must have exactly 2 replicas (including primary), but found 3. Current configuration: primary region 'eu-west-1', replica regions [eu-west-2, eu-west-3], witness region 'eu-central-1'"); + }); + + test('allows valid STRONG consistency configuration with witness', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); + + // WHEN + new TableV2(stack, 'Table', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + replicas: [{ region: 'us-east-1' }], + witnessRegion: 'us-east-2', + multiRegionConsistency: MultiRegionConsistency.STRONG, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { + MultiRegionConsistency: 'STRONG', + Replicas: [ + { Region: 'us-east-1' }, + { Region: 'us-west-2' }, + ], + GlobalTableWitnesses: [ + { Region: 'us-east-2' }, + ], + }); + }); +test('Contributor Insights Specification - tableV2', () => { + const stack = new Stack(); + + const table = new TableV2(stack, 'TableV2', { + partitionKey: { name: 'hashKey', type: AttributeType.STRING }, + sortKey: { name: 'sortKey', type: AttributeType.NUMBER }, + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' }, + ], + Replicas: [ + { + Region: { + Ref: 'AWS::Region', + }, + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + }, + }, + ], + }, + ); +}); + +test('ContributorInsightsSpecification && ContributorInsights - v2', () => { + const stack = new Stack(); + + expect(() => { + const table = new TableV2(stack, 'Tablev2', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + sortKey: { name: 'sk', type: AttributeType.STRING }, + contributorInsights: true, + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + }); + + Template.fromStack(stack); + }).toThrow('`contributorInsightsSpecification` and `contributorInsights` are set. Use `contributorInsightsSpecification` only.'); +}); \ No newline at end of file From 09fcb26c34e2bc431a7216052a540cded16b61c3 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Thu, 26 Jun 2025 12:45:40 +0100 Subject: [PATCH 02/18] feat(dynamodb): Adding ContributorInsightsMode feature --- .../us-east-1/aws-dynamodb-globaltable.json | 641 ++++++++++++++++++ .../us-east-1/aws-dynamodb-table.json | 591 ++++++++++++++++ 2 files changed, 1232 insertions(+) create mode 100644 tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-globaltable.json create mode 100644 tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-table.json diff --git a/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-globaltable.json b/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-globaltable.json new file mode 100644 index 0000000000000..6d2f3eb1cba73 --- /dev/null +++ b/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-globaltable.json @@ -0,0 +1,641 @@ +{ + "typeName" : "AWS::DynamoDB::GlobalTable", + "description" : "Version: None. Resource Type definition for AWS::DynamoDB::GlobalTable", + "additionalProperties" : false, + "properties" : { + "Arn" : { + "type" : "string" + }, + "StreamArn" : { + "type" : "string" + }, + "AttributeDefinitions" : { + "type" : "array", + "uniqueItems" : true, + "insertionOrder": false, + "items" : { + "$ref" : "#/definitions/AttributeDefinition" + }, + "minItems": 1 + }, + "BillingMode" : { + "type" : "string" + }, + "GlobalSecondaryIndexes" : { + "type" : "array", + "uniqueItems" : true, + "insertionOrder": false, + "items" : { + "$ref" : "#/definitions/GlobalSecondaryIndex" + } + }, + "KeySchema" : { + "type" : "array", + "uniqueItems" : true, + "items" : { + "$ref" : "#/definitions/KeySchema" + }, + "minItems": 1, + "maxItems": 2 + }, + "LocalSecondaryIndexes" : { + "type" : "array", + "uniqueItems" : true, + "insertionOrder": false, + "items" : { + "$ref" : "#/definitions/LocalSecondaryIndex" + } + }, + "WriteProvisionedThroughputSettings" : { + "$ref" : "#/definitions/WriteProvisionedThroughputSettings" + }, + "WriteOnDemandThroughputSettings" : { + "$ref" : "#/definitions/WriteOnDemandThroughputSettings" + }, + "WarmThroughput" : { + "$ref" : "#/definitions/WarmThroughput" + }, + "Replicas" : { + "type" : "array", + "uniqueItems" : true, + "insertionOrder": false, + "items" : { + "$ref" : "#/definitions/ReplicaSpecification" + }, + "minItems": 1 + }, + "SSESpecification" : { + "$ref" : "#/definitions/SSESpecification" + }, + "StreamSpecification" : { + "$ref" : "#/definitions/StreamSpecification" + }, + "TableName" : { + "type" : "string" + }, + "TableId" : { + "type" : "string" + }, + "TimeToLiveSpecification" : { + "$ref" : "#/definitions/TimeToLiveSpecification" + } + }, + "definitions" : { + "StreamSpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "StreamViewType" : { + "type" : "string" + } + }, + "required" : [ "StreamViewType" ] + }, + "ResourcePolicy" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "PolicyDocument": { + "type": "object" + } + }, + "required" : [ "PolicyDocument" ] + }, + "ReplicaStreamSpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "ResourcePolicy": { + "$ref": "#/definitions/ResourcePolicy" + } + }, + "required" : [ "ResourcePolicy" ] + }, + "KinesisStreamSpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "StreamArn" : { + "type" : "string", + "relationshipRef": { + "typeName": "AWS::Kinesis::Stream", + "propertyPath": "/properties/Arn" + } + }, + "ApproximateCreationDateTimePrecision" : { + "type": "string", + "enum": [ + "MICROSECOND", + "MILLISECOND" + ] + } + }, + "required" : [ "StreamArn" ] + }, + "KeySchema" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "AttributeName" : { + "type" : "string", + "minLength": 1, + "maxLength": 255 + }, + "KeyType" : { + "type" : "string" + } + }, + "required" : [ "KeyType", "AttributeName" ] + }, + "PointInTimeRecoverySpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "PointInTimeRecoveryEnabled" : { + "type" : "boolean" + } + } + }, + "ReplicaSpecification": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "Region" : { + "type" : "string" + }, + "GlobalSecondaryIndexes": { + "type" : "array", + "uniqueItems" : true, + "insertionOrder": false, + "items" : { + "$ref": "#/definitions/ReplicaGlobalSecondaryIndexSpecification" + } + }, + "ContributorInsightsSpecification": { + "$ref": "#/definitions/ContributorInsightsSpecification" + }, + "PointInTimeRecoverySpecification" : { + "$ref" : "#/definitions/PointInTimeRecoverySpecification" + }, + "TableClass" : { + "type" : "string" + }, + "DeletionProtectionEnabled" : { + "type" : "boolean" + }, + "SSESpecification": { + "$ref": "#/definitions/ReplicaSSESpecification" + }, + "Tags" : { + "type": "array", + "insertionOrder": false, + "uniqueItems": true, + "items": { + "$ref": "#/definitions/Tag" + } + }, + "ReadProvisionedThroughputSettings": { + "$ref": "#/definitions/ReadProvisionedThroughputSettings" + }, + "ReadOnDemandThroughputSettings": { + "$ref": "#/definitions/ReadOnDemandThroughputSettings" + }, + "KinesisStreamSpecification": { + "$ref": "#/definitions/KinesisStreamSpecification" + }, + "ResourcePolicy": { + "$ref": "#/definitions/ResourcePolicy" + }, + "ReplicaStreamSpecification": { + "$ref": "#/definitions/ReplicaStreamSpecification" + } + }, + "required" : [ "Region" ] + + }, + "TimeToLiveSpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "AttributeName" : { + "type" : "string" + }, + "Enabled" : { + "type" : "boolean" + } + }, + "required" : [ "Enabled" ] + }, + "LocalSecondaryIndex" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "IndexName" : { + "type" : "string", + "minLength": 3, + "maxLength": 255 + }, + "KeySchema" : { + "type" : "array", + "uniqueItems" : true, + "items" : { + "$ref" : "#/definitions/KeySchema" + }, + "maxItems": 2 + }, + "Projection" : { + "$ref" : "#/definitions/Projection" + } + }, + "required" : [ "IndexName", "Projection", "KeySchema" ] + }, + "GlobalSecondaryIndex" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "IndexName" : { + "type" : "string", + "minLength": 3, + "maxLength": 255 + }, + "KeySchema" : { + "type" : "array", + "uniqueItems" : true, + "items" : { + "$ref" : "#/definitions/KeySchema" + }, + "minItems": 1, + "maxItems": 2 + }, + "Projection" : { + "$ref" : "#/definitions/Projection" + }, + "WriteProvisionedThroughputSettings" : { + "$ref" : "#/definitions/WriteProvisionedThroughputSettings" + }, + "WriteOnDemandThroughputSettings" : { + "$ref" : "#/definitions/WriteOnDemandThroughputSettings" + }, + "WarmThroughput": { + "$ref": "#/definitions/WarmThroughput" + } + }, + "required" : [ "IndexName", "Projection", "KeySchema" ] + }, + "SSESpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "SSEEnabled" : { + "type" : "boolean" + }, + "SSEType" : { + "type" : "string" + } + }, + "required" : [ "SSEEnabled" ] + }, + "ReplicaSSESpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "KMSMasterKeyId" : { + "type" : "string", + "anyOf": [{ + "relationshipRef": { + "typeName": "AWS::KMS::Key", + "propertyPath": "/properties/Arn" + }},{ + "relationshipRef": { + "typeName": "AWS::KMS::Key", + "propertyPath": "/properties/KeyId" + }},{ + "relationshipRef": { + "typeName": "AWS::KMS::Alias", + "propertyPath": "/properties/AliasName" + } + }] + } + }, + "required" : [ "KMSMasterKeyId" ] + }, + "AttributeDefinition" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "AttributeName" : { + "type" : "string", + "minLength": 1, + "maxLength": 255 + }, + "AttributeType" : { + "type" : "string" + } + }, + "required" : [ "AttributeName", "AttributeType" ] + }, + "Tag" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "Key" : { + "type" : "string" + }, + "Value" : { + "type" : "string" + } + }, + "required" : [ "Value", "Key" ] + }, + "Projection" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "NonKeyAttributes" : { + "type" : "array", + "uniqueItems" : true, + "insertionOrder": false, + "items" : { + "type" : "string" + }, + "maxItems": 20 + }, + "ProjectionType" : { + "type" : "string" + } + } + }, + "ReplicaGlobalSecondaryIndexSpecification": { + "type": "object", + "additionalProperties": false, + "properties": { + "IndexName" : { + "type" : "string", + "minLength": 3, + "maxLength": 255 + }, + "ContributorInsightsSpecification": { + "$ref": "#/definitions/ContributorInsightsSpecification" + }, + "ReadProvisionedThroughputSettings": { + "$ref": "#/definitions/ReadProvisionedThroughputSettings" + }, + "ReadOnDemandThroughputSettings": { + "$ref": "#/definitions/ReadOnDemandThroughputSettings" + } + }, + "required" : [ "IndexName" ] + }, + "ContributorInsightsSpecification": { + "type": "object", + "additionalProperties": false, + "properties": { + "Enabled": { + "type": "boolean" + }, + "ContributorInsightsMode": { + "type": "string", + "enum": [ + "ACCESSED_AND_THROTTLED_KEYS", + "THROTTLED_KEYS" + ] + } + }, + "required" : [ "Enabled" ] + }, + "ReadProvisionedThroughputSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "ReadCapacityUnits" : { + "type" : "integer", + "minimum": 1 + }, + "ReadCapacityAutoScalingSettings": { + "$ref" : "#/definitions/CapacityAutoScalingSettings" + } + } + }, + "WriteProvisionedThroughputSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "WriteCapacityAutoScalingSettings": { + "$ref": "#/definitions/CapacityAutoScalingSettings" + } + } + }, + "ReadOnDemandThroughputSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "MaxReadRequestUnits" : { + "type" : "integer", + "minimum": 1 + } + } + }, + "WriteOnDemandThroughputSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "MaxWriteRequestUnits" : { + "type" : "integer", + "minimum": 1 + } + } + }, + "CapacityAutoScalingSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "MinCapacity": { + "type": "integer", + "minimum": 1 + }, + "MaxCapacity": { + "type": "integer", + "minimum": 1 + }, + "SeedCapacity": { + "type": "integer", + "minimum": 1 + }, + "TargetTrackingScalingPolicyConfiguration" : { + "$ref": "#/definitions/TargetTrackingScalingPolicyConfiguration" + } + }, + "required": [ "MinCapacity", "MaxCapacity", "TargetTrackingScalingPolicyConfiguration" ] + }, + "TargetTrackingScalingPolicyConfiguration": { + "type": "object", + "additionalProperties": false, + "properties": { + "DisableScaleIn": { + "type": "boolean" + }, + "ScaleInCooldown": { + "type": "integer", + "minimum": 0 + }, + "ScaleOutCooldown": { + "type": "integer", + "minimum": 0 + }, + "TargetValue": { + "type": "number", + "format": "double" + } + }, + "required": [ "TargetValue" ] + }, + "WarmThroughput" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "ReadUnitsPerSecond" : { + "type" : "integer", + "minimum": 1 + }, + "WriteUnitsPerSecond" : { + "type" : "integer", + "minimum": 1 + } + }, + "anyOf": [ + {"required": ["ReadUnitsPerSecond"]}, + {"required": ["WriteUnitsPerSecond"]} + ] + } + }, + "required" : [ "KeySchema", "AttributeDefinitions", "Replicas" ], + "readOnlyProperties" : [ "/properties/Arn", "/properties/StreamArn", "/properties/TableId" ], + "createOnlyProperties" : [ "/properties/LocalSecondaryIndexes", "/properties/TableName", "/properties/KeySchema" ], + "primaryIdentifier" : [ "/properties/TableName" ], + "additionalIdentifiers" : [[ "/properties/Arn"], ["/properties/StreamArn" ]], + "writeOnlyProperties": [ + "/properties/Replicas/*/ReadProvisionedThroughputSettings/ReadCapacityAutoScalingSettings/SeedCapacity", + "/properties/Replicas/*/GlobalSecondaryIndexes/*/ReadProvisionedThroughputSettings/ReadCapacityAutoScalingSettings/SeedCapacity", + "/properties/WriteProvisionedThroughputSettings/WriteCapacityAutoScalingSettings/SeedCapacity", + "/properties/GlobalSecondaryIndexes/*/WriteProvisionedThroughputSettings/WriteCapacityAutoScalingSettings/SeedCapacity" + ], + "handlers": { + "create": { + "permissions": [ + "dynamodb:CreateTable", + "dynamodb:CreateTableReplica", + "dynamodb:Describe*", + "dynamodb:UpdateTimeToLive", + "dynamodb:UpdateContributorInsights", + "dynamodb:UpdateContinuousBackups", + "dynamodb:ListTagsOfResource", + "dynamodb:Query", + "dynamodb:Scan", + "dynamodb:UpdateItem", + "dynamodb:PutItem", + "dynamodb:GetItem", + "dynamodb:DeleteItem", + "dynamodb:BatchWriteItem", + "dynamodb:TagResource", + "dynamodb:EnableKinesisStreamingDestination", + "dynamodb:DisableKinesisStreamingDestination", + "dynamodb:UpdateTableReplicaAutoScaling", + "dynamodb:TagResource", + "dynamodb:GetResourcePolicy", + "dynamodb:PutResourcePolicy", + "application-autoscaling:DeleteScalingPolicy", + "application-autoscaling:DeleteScheduledAction", + "application-autoscaling:DeregisterScalableTarget", + "application-autoscaling:Describe*", + "application-autoscaling:PutScalingPolicy", + "application-autoscaling:PutScheduledAction", + "application-autoscaling:RegisterScalableTarget", + "kinesis:ListStreams", + "kinesis:DescribeStream", + "kinesis:PutRecords", + "kms:CreateGrant", + "kms:DescribeKey", + "kms:ListAliases", + "kms:Decrypt", + "kms:RevokeGrant", + "cloudwatch:PutMetricData", + "iam:CreateServiceLinkedRole" + ] + }, + "read": { + "permissions": [ + "dynamodb:Describe*", + "dynamodb:GetResourcePolicy", + "application-autoscaling:Describe*", + "cloudwatch:PutMetricData", + "dynamodb:ListTagsOfResource", + "kms:DescribeKey" + ] + }, + "update": { + "permissions": [ + "dynamodb:Describe*", + "dynamodb:CreateTableReplica", + "dynamodb:UpdateTable", + "dynamodb:UpdateTimeToLive", + "dynamodb:UpdateContinuousBackups", + "dynamodb:UpdateContributorInsights", + "dynamodb:ListTagsOfResource", + "dynamodb:Query", + "dynamodb:Scan", + "dynamodb:UpdateItem", + "dynamodb:PutItem", + "dynamodb:GetItem", + "dynamodb:DeleteItem", + "dynamodb:BatchWriteItem", + "dynamodb:DeleteTable", + "dynamodb:DeleteTableReplica", + "dynamodb:UpdateItem", + "dynamodb:TagResource", + "dynamodb:UntagResource", + "dynamodb:EnableKinesisStreamingDestination", + "dynamodb:DisableKinesisStreamingDestination", + "dynamodb:UpdateTableReplicaAutoScaling", + "dynamodb:UpdateKinesisStreamingDestination", + "dynamodb:GetResourcePolicy", + "dynamodb:PutResourcePolicy", + "dynamodb:DeleteResourcePolicy", + "application-autoscaling:DeleteScalingPolicy", + "application-autoscaling:DeleteScheduledAction", + "application-autoscaling:DeregisterScalableTarget", + "application-autoscaling:Describe*", + "application-autoscaling:PutScalingPolicy", + "application-autoscaling:PutScheduledAction", + "application-autoscaling:RegisterScalableTarget", + "kinesis:ListStreams", + "kinesis:DescribeStream", + "kinesis:PutRecords", + "kms:CreateGrant", + "kms:DescribeKey", + "kms:ListAliases", + "kms:RevokeGrant", + "cloudwatch:PutMetricData" + ], + "timeoutInMinutes": 1200 + }, + "delete": { + "permissions": [ + "dynamodb:Describe*", + "dynamodb:DeleteTable", + "application-autoscaling:DeleteScalingPolicy", + "application-autoscaling:DeleteScheduledAction", + "application-autoscaling:DeregisterScalableTarget", + "application-autoscaling:Describe*", + "application-autoscaling:PutScalingPolicy", + "application-autoscaling:PutScheduledAction", + "application-autoscaling:RegisterScalableTarget" + ] + }, + "list": { + "permissions": [ + "dynamodb:ListTables", + "cloudwatch:PutMetricData" + ] + } + } +} diff --git a/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-table.json b/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-table.json new file mode 100644 index 0000000000000..93e92f2c64b46 --- /dev/null +++ b/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-table.json @@ -0,0 +1,591 @@ +{ + "typeName" : "AWS::DynamoDB::Table", + "description" : "Version: None. Resource Type definition for AWS::DynamoDB::Table", + "additionalProperties" : false, + "nonPublicProperties": [ + "/properties/DynamoDBEndpoint" + ], + "properties" : { + "Arn" : { + "type" : "string" + }, + "StreamArn" : { + "type" : "string" + }, + "AttributeDefinitions" : { + "type" : "array", + "uniqueItems" : true, + "items" : { + "$ref" : "#/definitions/AttributeDefinition" + } + }, + "BillingMode" : { + "type" : "string" + }, + "DynamoDBEndpoint" : { + "type" : "string" + }, + "DeletionProtectionEnabled" : { + "type" : "boolean" + }, + "GlobalSecondaryIndexes" : { + "type" : "array", + "uniqueItems" : false, + "items" : { + "$ref" : "#/definitions/GlobalSecondaryIndex" + } + }, + "KeySchema" : { + "oneOf": [ + { + "type" : "array", + "uniqueItems" : true, + "items" : { + "$ref" : "#/definitions/KeySchema" + } + }, + { + "type": "object" + } + ] + }, + "LocalSecondaryIndexes" : { + "type" : "array", + "uniqueItems" : false, + "items" : { + "$ref" : "#/definitions/LocalSecondaryIndex" + } + }, + "OnDemandThroughput" : { + "$ref" : "#/definitions/OnDemandThroughput" + }, + "WarmThroughput" : { + "$ref" : "#/definitions/WarmThroughput" + }, + "PointInTimeRecoverySpecification" : { + "$ref" : "#/definitions/PointInTimeRecoverySpecification" + }, + "TableClass" : { + "type" : "string" + }, + "ProvisionedThroughput" : { + "$ref" : "#/definitions/ProvisionedThroughput" + }, + "SSESpecification" : { + "$ref" : "#/definitions/SSESpecification" + }, + "StreamSpecification" : { + "$ref" : "#/definitions/StreamSpecification" + }, + "TableName" : { + "type" : "string" + }, + "Tags" : { + "type" : "array", + "uniqueItems" : false, + "items" : { + "$ref" : "#/definitions/Tag" + } + }, + "TimeToLiveSpecification" : { + "$ref" : "#/definitions/TimeToLiveSpecification" + }, + "ContributorInsightsSpecification": { + "$ref": "#/definitions/ContributorInsightsSpecification" + }, + "KinesisStreamSpecification": { + "$ref": "#/definitions/KinesisStreamSpecification" + }, + "ImportSourceSpecification" : { + "$ref": "#/definitions/ImportSourceSpecification" + }, + "ResourcePolicy": { + "$ref": "#/definitions/ResourcePolicy" + } + }, + "propertyTransform": { + "/properties/SSESpecification/KMSMasterKeyId": "$join([\"arn:aws(-[a-z]{1,4}){0,2}:kms:[a-z]{2,4}(-[a-z]{1,4})?-[a-z]{1,10}-[0-9]:[0-9]{12}:key\\/\", SSESpecification.KMSMasterKeyId]) $OR $join([\"arn:aws(-[a-z]{1,4}){0,2}:kms:[a-z]{2,4}(-[a-z]{1,4})?-[a-z]{1,10}-[0-9]:[0-9]{12}:key\\/\", KMSMasterKeyId])" + }, + "definitions" : { + "StreamSpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "StreamViewType" : { + "type" : "string" + }, + "ResourcePolicy": { + "$ref": "#/definitions/ResourcePolicy" + } + }, + "required" : [ "StreamViewType" ] + }, + "DeprecatedKeySchema" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "HashKeyElement" : { + "$ref" : "#/definitions/DeprecatedHashKeyElement" + } + }, + "required" : [ "HashKeyElement" ] + }, + "DeprecatedHashKeyElement" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "AttributeType" : { + "type" : "string" + }, + "AttributeName" : { + "type" : "string" + } + }, + "required" : [ "AttributeType", "AttributeName" ] + }, + "KeySchema" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "AttributeName" : { + "type" : "string" + }, + "KeyType" : { + "type" : "string" + } + }, + "required" : [ "KeyType", "AttributeName" ] + }, + "PointInTimeRecoverySpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "PointInTimeRecoveryEnabled" : { + "type" : "boolean" + } + } + }, + "KinesisStreamSpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "StreamArn" : { + "type" : "string", + "relationshipRef": { + "typeName": "AWS::Kinesis::Stream", + "propertyPath": "/properties/Arn" + } + }, + "ApproximateCreationDateTimePrecision" : { + "type": "string", + "enum": [ + "MICROSECOND", + "MILLISECOND" + ] + } + }, + "required" : [ "StreamArn" ] + }, + "TimeToLiveSpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "AttributeName" : { + "type" : "string" + }, + "Enabled" : { + "type" : "boolean" + } + }, + "required" : [ "Enabled" ] + }, + "LocalSecondaryIndex" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "IndexName" : { + "type" : "string" + }, + "KeySchema" : { + "type" : "array", + "uniqueItems" : true, + "items" : { + "$ref" : "#/definitions/KeySchema" + } + }, + "Projection" : { + "$ref" : "#/definitions/Projection" + } + }, + "required" : [ "IndexName", "Projection", "KeySchema" ] + }, + "GlobalSecondaryIndex" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "IndexName" : { + "type" : "string" + }, + "KeySchema" : { + "type" : "array", + "uniqueItems" : true, + "items" : { + "$ref" : "#/definitions/KeySchema" + } + }, + "Projection" : { + "$ref" : "#/definitions/Projection" + }, + "ProvisionedThroughput" : { + "$ref" : "#/definitions/ProvisionedThroughput" + }, + "OnDemandThroughput" : { + "$ref" : "#/definitions/OnDemandThroughput" + }, + "WarmThroughput" : { + "$ref" : "#/definitions/WarmThroughput" + }, + "ContributorInsightsSpecification": { + "$ref": "#/definitions/ContributorInsightsSpecification" + } + }, + "required" : [ "IndexName", "Projection", "KeySchema" ] + }, + "OnDemandThroughput" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "MaxReadRequestUnits" : { + "type" : "integer", + "minimum": 1 + }, + "MaxWriteRequestUnits" : { + "type" : "integer", + "minimum": 1 + } + } + }, + "WarmThroughput" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "ReadUnitsPerSecond" : { + "type" : "integer", + "minimum": 1 + }, + "WriteUnitsPerSecond" : { + "type" : "integer", + "minimum": 1 + } + }, + "anyOf": [ + {"required": ["ReadUnitsPerSecond"]}, + {"required": ["WriteUnitsPerSecond"]} + ] + }, + "SSESpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "KMSMasterKeyId" : { + "type" : "string", + "anyOf": [{ + "relationshipRef": { + "typeName": "AWS::KMS::Key", + "propertyPath": "/properties/Arn" + }},{ + "relationshipRef": { + "typeName": "AWS::KMS::Key", + "propertyPath": "/properties/KeyId" + }}, { + "relationshipRef": { + "typeName": "AWS::KMS::Alias", + "propertyPath": "/properties/AliasName" + } + }] + }, + "SSEEnabled" : { + "type" : "boolean" + }, + "SSEType" : { + "type" : "string" + } + }, + "required" : [ "SSEEnabled" ] + }, + "AttributeDefinition" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "AttributeName" : { + "type" : "string" + }, + "AttributeType" : { + "type" : "string" + } + }, + "required" : [ "AttributeName", "AttributeType" ] + }, + "ProvisionedThroughput" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "ReadCapacityUnits" : { + "type" : "integer" + }, + "WriteCapacityUnits" : { + "type" : "integer" + } + }, + "required" : [ "WriteCapacityUnits", "ReadCapacityUnits" ] + }, + "Tag" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "Key" : { + "type" : "string" + }, + "Value" : { + "type" : "string" + } + }, + "required" : [ "Value", "Key" ] + }, + "Projection" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "NonKeyAttributes" : { + "type" : "array", + "uniqueItems" : false, + "items" : { + "type" : "string" + } + }, + "ProjectionType" : { + "type" : "string" + } + } + }, + "ContributorInsightsSpecification": { + "type": "object", + "additionalProperties": false, + "properties": { + "Enabled": { + "type": "boolean" + }, + "ContributorInsightsMode": { + "type": "string", + "enum": [ + "ACCESSED_AND_THROTTLED_KEYS", + "THROTTLED_KEYS" + ] + } + }, + "required" : [ "Enabled" ] + }, + "ImportSourceSpecification" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "S3BucketSource" : { + "$ref" : "#/definitions/S3BucketSource" + }, + "InputFormat" : { + "type" : "string" + }, + "InputFormatOptions" : { + "$ref" : "#/definitions/InputFormatOptions" + }, + "InputCompressionType" : { + "type" : "string" + } + }, + "required" : [ + "S3BucketSource", + "InputFormat" + ] + }, + "S3BucketSource" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "S3BucketOwner" : { + "type" : "string" + }, + "S3Bucket" : { + "type" : "string", + "relationshipRef": { + "typeName": "AWS::S3::Bucket", + "propertyPath": "/properties/BucketName" + } + }, + "S3KeyPrefix" : { + "type" : "string" + } + }, + "required" : [ + "S3Bucket" + ] + }, + "InputFormatOptions" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "Csv" : { + "$ref" : "#/definitions/Csv" + } + } + }, + "Csv" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "HeaderList" : { + "type" : "array", + "uniqueItems" : true, + "items" : { + "type" : "string" + } + }, + "Delimiter" : { + "type" : "string" + } + } + }, + "ResourcePolicy": { + "type": "object", + "additionalProperties": false, + "properties": { + "PolicyDocument": { + "type": "object" + } + }, + "required": [ + "PolicyDocument" + ] + } + }, + "tagging": { + "taggable": true, + "tagOnCreate": true, + "tagUpdatable": true, + "cloudFormationSystemTags": false, + "tagProperty": "/properties/Tags", + "permissions": [ + "dynamodb:TagResource", + "dynamodb:UntagResource", + "dynamodb:ListTagsOfResource" + ] + }, + "required" : [ "KeySchema" ], + "readOnlyProperties" : [ "/properties/Arn", "/properties/StreamArn" ], + "createOnlyProperties" : [ + "/properties/TableName", + "/properties/DynamoDBEndpoint", + "/properties/ImportSourceSpecification" + ], + "conditionalCreateOnlyProperties": [ + "/properties/KeySchema" + ], + "primaryIdentifier" : [ "/properties/TableName" ], + "writeOnlyProperties": [ + "/properties/ImportSourceSpecification" + ], + "handlers": { + "create": { + "permissions": [ + "dynamodb:CreateTable", + "dynamodb:DescribeImport", + "dynamodb:DescribeTable", + "dynamodb:DescribeTimeToLive", + "dynamodb:UpdateTimeToLive", + "dynamodb:UpdateContributorInsights", + "dynamodb:UpdateContinuousBackups", + "dynamodb:DescribeContinuousBackups", + "dynamodb:DescribeContributorInsights", + "dynamodb:EnableKinesisStreamingDestination", + "dynamodb:DisableKinesisStreamingDestination", + "dynamodb:DescribeKinesisStreamingDestination", + "dynamodb:ImportTable", + "dynamodb:ListTagsOfResource", + "dynamodb:TagResource", + "dynamodb:UpdateTable", + "dynamodb:GetResourcePolicy", + "dynamodb:PutResourcePolicy", + "kinesis:DescribeStream", + "kinesis:PutRecords", + "iam:CreateServiceLinkedRole", + "kms:CreateGrant", + "kms:Decrypt", + "kms:DescribeKey", + "kms:ListAliases", + "kms:Encrypt", + "kms:RevokeGrant", + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:PutRetentionPolicy", + "s3:GetObject", + "s3:GetObjectMetadata", + "s3:ListBucket" + ], + "timeoutInMinutes": 720 + }, + "read": { + "permissions": [ + "dynamodb:DescribeTable", + "dynamodb:DescribeContinuousBackups", + "dynamodb:DescribeContributorInsights", + "dynamodb:DescribeKinesisStreamingDestination", + "dynamodb:ListTagsOfResource", + "dynamodb:GetResourcePolicy" + ] + }, + "update": { + "permissions": [ + "dynamodb:UpdateTable", + "dynamodb:DescribeTable", + "dynamodb:DescribeTimeToLive", + "dynamodb:UpdateTimeToLive", + "dynamodb:UpdateContinuousBackups", + "dynamodb:UpdateContributorInsights", + "dynamodb:UpdateKinesisStreamingDestination", + "dynamodb:DescribeContinuousBackups", + "dynamodb:DescribeKinesisStreamingDestination", + "dynamodb:ListTagsOfResource", + "dynamodb:TagResource", + "dynamodb:UntagResource", + "dynamodb:DescribeContributorInsights", + "dynamodb:EnableKinesisStreamingDestination", + "dynamodb:DisableKinesisStreamingDestination", + "dynamodb:GetResourcePolicy", + "dynamodb:PutResourcePolicy", + "dynamodb:DeleteResourcePolicy", + "kinesis:DescribeStream", + "kinesis:PutRecords", + "iam:CreateServiceLinkedRole", + "kms:CreateGrant", + "kms:DescribeKey", + "kms:ListAliases", + "kms:RevokeGrant" + ], + "timeoutInMinutes": 720 + }, + "delete": { + "permissions": [ + "dynamodb:DeleteTable", + "dynamodb:DescribeTable" + ], + "timeoutInMinutes": 720 + }, + "list": { + "permissions": [ + "dynamodb:ListTables" + ] + } + } +} From 0248aa22d2279a9cf45f8de8fb1d0b308190bec2 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Thu, 26 Jun 2025 14:25:50 +0100 Subject: [PATCH 03/18] Fixing linting issues --- .../aws-dynamodb/test/table-v2.test.ts | 171 +----------------- 1 file changed, 2 insertions(+), 169 deletions(-) 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 3219646eb60c9..9ac1ce46406ad 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 @@ -3340,6 +3340,7 @@ describe('MRSC global tables', () => { }); }); }); + describe('MRSC global tables validation', () => { test('throws when witness region is used with eventual consistency', () => { // GIVEN @@ -3467,174 +3468,6 @@ test('ContributorInsightsSpecification && ContributorInsights - v2', () => { }).toThrow('`contributorInsightsSpecification` and `contributorInsights` are set. Use `contributorInsightsSpecification` only.'); }); -describe('MRSC global tables', () => { - test('with witness region', () => { - // GIVEN - const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); - - // WHEN - new TableV2(stack, 'Table', { - partitionKey: { name: 'pk', type: AttributeType.STRING }, - replicas: [{ region: 'us-east-1' }], - witnessRegion: 'us-east-2', - multiRegionConsistency: MultiRegionConsistency.STRONG, - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { - Replicas: [ - { Region: 'us-east-1' }, - { Region: 'us-west-2' }, - ], - GlobalTableWitnesses: [ - { Region: 'us-east-2' }, - ], - }); - }); - - test('without witness region should not have GlobalTableWitnesses property', () => { - // GIVEN - const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); - - // WHEN - new TableV2(stack, 'Table', { - partitionKey: { name: 'pk', type: AttributeType.STRING }, - replicas: [{ region: 'us-east-1' }], - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { - Replicas: [ - { Region: 'us-east-1' }, - { Region: 'us-west-2' }, - ], - }); - // Verify that GlobalTableWitnesses is not present in the template - Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', - Match.not(Match.objectLike({ - GlobalTableWitnesses: Match.anyValue(), - })), - ); - }); - - test('with witness region and strong consistency requirements', () => { - // GIVEN - const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); - - // WHEN - new TableV2(stack, 'Table', { - partitionKey: { name: 'pk', type: AttributeType.STRING }, - sortKey: { name: 'sk', type: AttributeType.STRING }, - replicas: [{ region: 'us-east-1' }], - witnessRegion: 'us-east-2', - multiRegionConsistency: MultiRegionConsistency.STRONG, - billing: Billing.provisioned({ - readCapacity: Capacity.fixed(10), - writeCapacity: Capacity.autoscaled({ minCapacity: 10, maxCapacity: 100 }), - }), - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { - KeySchema: [ - { AttributeName: 'pk', KeyType: 'HASH' }, - { AttributeName: 'sk', KeyType: 'RANGE' }, - ], - AttributeDefinitions: [ - { AttributeName: 'pk', AttributeType: 'S' }, - { AttributeName: 'sk', AttributeType: 'S' }, - ], - BillingMode: 'PROVISIONED', - Replicas: [ - { - Region: 'us-east-1', - ReadProvisionedThroughputSettings: { - ReadCapacityUnits: 10, - }, - }, - { - Region: 'us-west-2', - ReadProvisionedThroughputSettings: { - ReadCapacityUnits: 10, - }, - }, - ], - GlobalTableWitnesses: [ - { Region: 'us-east-2' }, - ], - }); - }); -}); -describe('MRSC global tables validation', () => { - test('throws when witness region is used with eventual consistency', () => { - // GIVEN - const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); - - // WHEN / THEN - Error should be thrown during construction - expect(() => { - new TableV2(stack, 'Table', { - partitionKey: { name: 'pk', type: AttributeType.STRING }, - replicas: [{ region: 'us-east-1' }], - witnessRegion: 'us-east-2', - // multiRegionConsistency defaults to EVENTUAL - }); - }).toThrow('Witness region cannot be specified for a Multi-Region Eventual Consistency (MREC) Global Table - Witness regions are only supported for Multi-Region Strong Consistency (MRSC) Global Tables.'); - }); - - test('validates regions are in same region set for STRONG consistency', () => { - // GIVEN - const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); - - // WHEN / THEN - Error should be thrown during construction - expect(() => { - new TableV2(stack, 'Table', { - partitionKey: { name: 'pk', type: AttributeType.STRING }, - replicas: [{ region: 'eu-west-1' }], - witnessRegion: 'us-east-2', - multiRegionConsistency: MultiRegionConsistency.STRONG, - }); - }).toThrow("Region 'eu-west-1' is not in the same region set (US) as the primary region 'us-west-2'. All regions must be within the same region set for MRSC global tables with STRONG consistency. Supported US regions: us-east-1, us-east-2, us-west-2"); - }); - - test('validates exactly 2 replicas with witness for STRONG consistency', () => { - // GIVEN - const stack = new Stack(undefined, 'Stack', { env: { region: 'eu-west-1' } }); - - // WHEN / THEN - Error should be thrown during construction - expect(() => { - new TableV2(stack, 'Table', { - partitionKey: { name: 'pk', type: AttributeType.STRING }, - replicas: [{ region: 'eu-west-2' }, { region: 'eu-west-3' }], // Too many replicas - witnessRegion: 'eu-central-1', // Use same region set - multiRegionConsistency: MultiRegionConsistency.STRONG, - }); - }).toThrow("MRSC global table with witness region must have exactly 2 replicas (including primary), but found 3. Current configuration: primary region 'eu-west-1', replica regions [eu-west-2, eu-west-3], witness region 'eu-central-1'"); - }); - - test('allows valid STRONG consistency configuration with witness', () => { - // GIVEN - const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); - - // WHEN - new TableV2(stack, 'Table', { - partitionKey: { name: 'pk', type: AttributeType.STRING }, - replicas: [{ region: 'us-east-1' }], - witnessRegion: 'us-east-2', - multiRegionConsistency: MultiRegionConsistency.STRONG, - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { - MultiRegionConsistency: 'STRONG', - Replicas: [ - { Region: 'us-east-1' }, - { Region: 'us-west-2' }, - ], - GlobalTableWitnesses: [ - { Region: 'us-east-2' }, - ], - }); - }); test('Contributor Insights Specification - tableV2', () => { const stack = new Stack(); @@ -3688,4 +3521,4 @@ test('ContributorInsightsSpecification && ContributorInsights - v2', () => { Template.fromStack(stack); }).toThrow('`contributorInsightsSpecification` and `contributorInsights` are set. Use `contributorInsightsSpecification` only.'); -}); \ No newline at end of file +}); From 3ff8a96ffc91d58354e2dd36d9744ed2674997cb Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Thu, 26 Jun 2025 14:25:50 +0100 Subject: [PATCH 04/18] Fixing linting issues --- .../test/integ.dynamodb-v2.cci.ts | 49 +++++++++++++ packages/aws-cdk-lib/aws-dynamodb/README.md | 48 ++++++++---- .../aws-dynamodb/test/table-v2.test.ts | 73 +++++++++++++++++++ 3 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts new file mode 100644 index 0000000000000..44ba6ce5968d9 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts @@ -0,0 +1,49 @@ +import { App, Stack, StackProps } from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new App(); + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + new dynamodb.TableV2(this, 'TableV2', { + partitionKey: { name: 'hashKey', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'sortKey', type: dynamodb.AttributeType.NUMBER }, + globalSecondaryIndexes: [ + { + indexName: 'gsi', + partitionKey: { name: 'gsiHashKey', type: dynamodb.AttributeType.STRING }, + }, + ], + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: dynamodb.ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + replicas: [ + { + region: 'eu-west-2', + contributorInsightsSpecification: { + enabled: false, + }, + globalSecondaryIndexOptions: { + gsi: { + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: dynamodb.ContributorInsightsMode.THROTTLED_KEYS, + }, + }, + }, + }, + ], + }); + } +} + +const stack = new TestStack(app, 'CCI-Integ-Test', { env: { region: 'eu-west-1' } }); + +new IntegTest(app, 'table-v2-CCI-test', { + testCases: [stack], +}); diff --git a/packages/aws-cdk-lib/aws-dynamodb/README.md b/packages/aws-cdk-lib/aws-dynamodb/README.md index d0d6a99aa5f53..9e41c6a45658a 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/README.md +++ b/packages/aws-cdk-lib/aws-dynamodb/README.md @@ -17,7 +17,9 @@ By default, `TableV2` will create a single table in the main deployment region r ```ts const table = new dynamodb.TableV2(this, 'Table', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, - contributorInsights: true, + contributorInsightsSpecification: { + enabled: true, + }, tableClass: dynamodb.TableClass.STANDARD_INFREQUENT_ACCESS, pointInTimeRecoverySpecification: { pointInTimeRecoveryEnabled: true, @@ -66,12 +68,12 @@ globalTable.addReplica({ region: 'us-east-2', deletionProtection: true }); ``` The following properties are configurable on a per-replica basis, but will be inherited from the `TableV2` properties if not specified: -* contributorInsights +* contributorInsightsSpecification * deletionProtection * pointInTimeRecoverySpecification * tableClass * readCapacity (only configurable if the `TableV2` billing mode is `PROVISIONED`) -* globalSecondaryIndexes (only `contributorInsights` and `readCapacity`) +* globalSecondaryIndexes (only `contributorInsightsSpecification` and `readCapacity`) The following example shows how to define properties on a per-replica basis: @@ -83,7 +85,9 @@ const stack = new cdk.Stack(app, 'Stack', { env: { region: 'us-west-2' } }); const globalTable = new dynamodb.TableV2(stack, 'GlobalTable', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, - contributorInsights: true, + contributorInsightsSpecification: { + enabled: true, + }, pointInTimeRecoverySpecification: { pointInTimeRecoveryEnabled: true, }, @@ -97,7 +101,9 @@ const globalTable = new dynamodb.TableV2(stack, 'GlobalTable', { }, { region: 'us-east-2', - contributorInsights: false, + contributorInsightsSpecification: { + enabled: false, + }, }, ], }); @@ -443,7 +449,7 @@ const table = new dynamodb.TableV2(this, 'Table', { }); ``` -All `globalSecondaryIndexes` for replica tables are inherited from the primary table. You can configure `contributorInsights` and `readCapacity` for each `globalSecondaryIndex` on a per-replica basis: +All `globalSecondaryIndexes` for replica tables are inherited from the primary table. You can configure `contributorInsightsSpecification` and `readCapacity` for each `globalSecondaryIndex` on a per-replica basis: ```ts import * as cdk from 'aws-cdk-lib'; @@ -453,7 +459,9 @@ const stack = new cdk.Stack(app, 'Stack', { env: { region: 'us-west-2' } }); const globalTable = new dynamodb.TableV2(stack, 'GlobalTable', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, - contributorInsights: true, + contributorInsightsSpecification: { + enabled: true, + }, billing: dynamodb.Billing.provisioned({ readCapacity: dynamodb.Capacity.fixed(10), writeCapacity: dynamodb.Capacity.autoscaled({ maxCapacity: 10 }), @@ -484,7 +492,9 @@ const globalTable = new dynamodb.TableV2(stack, 'GlobalTable', { region: 'us-east-2', globalSecondaryIndexOptions: { gsi2: { - contributorInsights: false, + contributorInsightsSpecification: { + enabled: false, + }, }, }, }, @@ -605,25 +615,37 @@ const table = new dynamodb.TableV2(this, 'Table', { ## Contributor Insights -Enabling `contributorInsights` for `TableV2` will provide information about the most accessed and throttled items in a table or `globalSecondaryIndex`. DynamoDB delivers this information to you via CloudWatch Contributor Insights rules, reports, and graphs of report data. +Enabling `contributorInsightSpecification` for `TableV2` will provide information about the most accessed and throttled or throttled only items in a table or `globalSecondaryIndex`. DynamoDB delivers this information to you via CloudWatch Contributor Insights rules, reports, and graphs of report data. + +- To monitor all traffic on a table or index, set `contributorInsightsMode` to `ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS`. +- To monitor only throttled traffic on a table or index, set `contributorInsightsMode` to `ContributorInsightsMode.THROTTLED_KEYS`. + ```ts const table = new dynamodb.TableV2(this, 'Table', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, - contributorInsights: true, + contributorInsightsSpecfication: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, }); ``` -When you use `Table`, you can enable contributor insights for a table or specific global secondary index by setting `contributorInsightsEnabled` to `true`. +When you use `Table`, you can enable contributor insights for a table or specific global secondary index by setting `contributorInsightsSpecification` parameter `enabled` to `true`. ```ts const table = new dynamodb.Table(this, 'Table', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, - contributorInsightsEnabled: true, // for a table + contributorInsightsSpecfication: { // for a table + enabled: true, + contributorInsightsMode: ContributorInsightsMode.THROTTLED_KEYS, // only emit throttling events + }, }); table.addGlobalSecondaryIndex({ - contributorInsightsEnabled: true, // for a specific global secondary index + contributorInsightsSpecfication: { // for a specific global secondary index + enabled: true, + }, indexName: 'gsi', partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, }); 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 9ac1ce46406ad..ac79bb701ca77 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 @@ -3505,6 +3505,79 @@ test('Contributor Insights Specification - tableV2', () => { ); }); +test('Contributor Insights Specification - index', () => { + const stack = new Stack(undefined, 'Stack', { env: { region: 'eu-west-1' } }); + + const table = new TableV2(stack, 'TableV2', { + partitionKey: { name: 'hashKey', type: AttributeType.STRING }, + sortKey: { name: 'sortKey', type: AttributeType.NUMBER }, + globalSecondaryIndexes: [ + { + indexName: 'gsi1', + partitionKey: { name: 'gsiHashKey', type: AttributeType.STRING }, + }, + ], + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + replicas: [ + { + region: 'eu-west-2', + contributorInsightsSpecification: { + enabled: false, + }, + globalSecondaryIndexOptions: { + gsi1: { + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.THROTTLED_KEYS, + }, + }, + }, + }, + ], + }); + + Template.fromStack(stack).hasResource('AWS::DynamoDB::GlobalTable', { + Properties: Match.objectLike({ + Replicas: Match.arrayWith([ + Match.objectLike({ + Region: 'eu-west-2', + ContributorInsightsSpecification: { + Enabled: false, + }, + GlobalSecondaryIndexes: Match.arrayWith([ + Match.objectLike({ + IndexName: 'gsi1', + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'THROTTLED_KEYS', + }, + }), + ]), + }), + Match.objectLike({ + Region: 'eu-west-1', + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + }, + GlobalSecondaryIndexes: Match.arrayWith([ + Match.objectLike({ + IndexName: 'gsi1', + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + }, + }), + ]), + }), + ]), + }), + }); +}); + test('ContributorInsightsSpecification && ContributorInsights - v2', () => { const stack = new Stack(); From 23dde879f5ba637c575838f99d002b26fa1da6c3 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Thu, 26 Jun 2025 15:56:59 +0100 Subject: [PATCH 05/18] Removing integ test, it can't pass without feature rolled out --- .../test/integ.dynamodb-v2.cci.ts | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts deleted file mode 100644 index 44ba6ce5968d9..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { App, Stack, StackProps } from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; -import { IntegTest } from '@aws-cdk/integ-tests-alpha'; - -const app = new App(); - -class TestStack extends Stack { - constructor(scope: Construct, id: string, props?: StackProps) { - super(scope, id, props); - - new dynamodb.TableV2(this, 'TableV2', { - partitionKey: { name: 'hashKey', type: dynamodb.AttributeType.STRING }, - sortKey: { name: 'sortKey', type: dynamodb.AttributeType.NUMBER }, - globalSecondaryIndexes: [ - { - indexName: 'gsi', - partitionKey: { name: 'gsiHashKey', type: dynamodb.AttributeType.STRING }, - }, - ], - contributorInsightsSpecification: { - enabled: true, - contributorInsightsMode: dynamodb.ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, - }, - replicas: [ - { - region: 'eu-west-2', - contributorInsightsSpecification: { - enabled: false, - }, - globalSecondaryIndexOptions: { - gsi: { - contributorInsightsSpecification: { - enabled: true, - contributorInsightsMode: dynamodb.ContributorInsightsMode.THROTTLED_KEYS, - }, - }, - }, - }, - ], - }); - } -} - -const stack = new TestStack(app, 'CCI-Integ-Test', { env: { region: 'eu-west-1' } }); - -new IntegTest(app, 'table-v2-CCI-test', { - testCases: [stack], -}); From d37548890ca824ae7751f85104dc0b4df569639d Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Fri, 27 Jun 2025 13:50:09 +0100 Subject: [PATCH 06/18] Re-run integ test for global table --- .../aws-cdk-global-table.assets.json | 7 +- .../aws-cdk-global-table.template.json | 3 + ...efaultTestDeployAssertA2A9E81F.assets.json | 3 +- .../integ.table-v2-global.js.snapshot/cdk.out | 2 +- .../integ.json | 5 +- .../manifest.json | 39 +- .../tree.json | 436 +----------------- 7 files changed, 48 insertions(+), 447 deletions(-) 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 929f0476cdfd0..9218b2329c911 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,8 @@ { - "version": "38.0.1", + "version": "44.0.0", "files": { - "f76e4db697eb7d6e297e40f4bafd35a109a7849082124cc1946d6efb31becfbd": { + "4f949044e1b4a2eec2aa2f3450df473b522e62d00f99eba92b9afa6d6b47783c": { + "displayName": "aws-cdk-global-table Template", "source": { "path": "aws-cdk-global-table.template.json", "packaging": "file" @@ -9,7 +10,7 @@ "destinations": { "current_account-us-east-1": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", - "objectKey": "f76e4db697eb7d6e297e40f4bafd35a109a7849082124cc1946d6efb31becfbd.json", + "objectKey": "4f949044e1b4a2eec2aa2f3450df473b522e62d00f99eba92b9afa6d6b47783c.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 8fda8662e31e9..5b823b6eb02f6 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 @@ -174,6 +174,9 @@ }, "GlobalSecondaryIndexes": [ { + "ContributorInsightsSpecification": { + "Enabled": true + }, "IndexName": "gsi1", "ReadProvisionedThroughputSettings": { "ReadCapacityUnits": 15 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 a01b555c8d324..84b8ea26450a7 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,7 +1,8 @@ { - "version": "38.0.1", + "version": "44.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F Template", "source": { "path": "awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F.template.json", "packaging": "file" 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 c6e612584e352..b3a26d44a5f73 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":"38.0.1"} \ No newline at end of file +{"version":"44.0.0"} \ 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 2aacd3080724d..aaf722a3b52e6 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": "38.0.1", + "version": "44.0.0", "testCases": { "aws-cdk-global-table-integ/DefaultTest": { "stacks": [ @@ -12,5 +12,6 @@ "assertionStack": "aws-cdk-global-table-integ/DefaultTest/DeployAssert", "assertionStackName": "awscdkglobaltableintegDefaultTestDeployAssertA2A9E81F" } - } + }, + "minimumCliVersion": "2.1018.0" } \ 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/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/manifest.json index cdfdbcd507e22..a7edc9f03587f 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": "38.0.1", + "version": "44.0.0", "artifacts": { "aws-cdk-global-table.assets": { "type": "cdk:asset-manifest", @@ -19,10 +19,9 @@ "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/f76e4db697eb7d6e297e40f4bafd35a109a7849082124cc1946d6efb31becfbd.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1/4f949044e1b4a2eec2aa2f3450df473b522e62d00f99eba92b9afa6d6b47783c.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -49,6 +48,12 @@ ] } ], + "/aws-cdk-global-table/Stream": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], "/aws-cdk-global-table/Stream/Resource": [ { "type": "aws:cdk:logicalId", @@ -62,6 +67,30 @@ } ], "/aws-cdk-global-table/GlobalTable": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, { "type": "aws:cdk:hasPhysicalName", "data": { @@ -108,7 +137,6 @@ "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", @@ -159,5 +187,6 @@ "file": "tree.json" } } - } + }, + "minimumCliVersion": "2.1018.0" } \ 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/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-v2-global.js.snapshot/tree.json index 7d72d600d5a9f..f3e37bc5eac0f 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 @@ -1,435 +1 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "aws-cdk-global-table": { - "id": "aws-cdk-global-table", - "path": "aws-cdk-global-table", - "children": { - "Stream": { - "id": "Stream", - "path": "aws-cdk-global-table/Stream", - "children": { - "Resource": { - "id": "Resource", - "path": "aws-cdk-global-table/Stream/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::Kinesis::Stream", - "aws:cdk:cloudformation:props": { - "retentionPeriodHours": 24, - "shardCount": 1, - "streamEncryption": { - "Fn::If": [ - "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", - { - "Ref": "AWS::NoValue" - }, - { - "EncryptionType": "KMS", - "KeyId": "alias/aws/kinesis" - } - ] - }, - "tags": [ - { - "key": "stage", - "value": "IntegTest" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_kinesis.CfnStream", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_kinesis.Stream", - "version": "0.0.0" - } - }, - "AwsCdkKinesisEncryptedStreamsUnsupportedRegions": { - "id": "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", - "path": "aws-cdk-global-table/AwsCdkKinesisEncryptedStreamsUnsupportedRegions", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnCondition", - "version": "0.0.0" - } - }, - "GlobalTable": { - "id": "GlobalTable", - "path": "aws-cdk-global-table/GlobalTable", - "children": { - "Resource": { - "id": "Resource", - "path": "aws-cdk-global-table/GlobalTable/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::DynamoDB::GlobalTable", - "aws:cdk:cloudformation:props": { - "attributeDefinitions": [ - { - "attributeName": "pk", - "attributeType": "S" - }, - { - "attributeName": "sk", - "attributeType": "N" - } - ], - "billingMode": "PROVISIONED", - "globalSecondaryIndexes": [ - { - "indexName": "gsi1", - "keySchema": [ - { - "attributeName": "pk", - "keyType": "HASH" - } - ], - "projection": { - "projectionType": "ALL" - }, - "writeProvisionedThroughputSettings": { - "writeCapacityAutoScalingSettings": { - "minCapacity": 1, - "maxCapacity": 20, - "seedCapacity": 10, - "targetTrackingScalingPolicyConfiguration": { - "targetValue": 60 - } - } - } - }, - { - "indexName": "gsi2", - "keySchema": [ - { - "attributeName": "pk", - "keyType": "HASH" - } - ], - "projection": { - "projectionType": "ALL" - }, - "writeProvisionedThroughputSettings": { - "writeCapacityAutoScalingSettings": { - "minCapacity": 1, - "maxCapacity": 30, - "targetTrackingScalingPolicyConfiguration": { - "targetValue": 70 - } - } - } - } - ], - "keySchema": [ - { - "attributeName": "pk", - "keyType": "HASH" - }, - { - "attributeName": "sk", - "keyType": "RANGE" - } - ], - "localSecondaryIndexes": [ - { - "indexName": "lsi", - "keySchema": [ - { - "attributeName": "pk", - "keyType": "HASH" - }, - { - "attributeName": "sk", - "keyType": "RANGE" - } - ], - "projection": { - "projectionType": "ALL" - } - } - ], - "replicas": [ - { - "region": "us-east-2", - "globalSecondaryIndexes": [ - { - "indexName": "gsi1", - "readProvisionedThroughputSettings": { - "readCapacityUnits": 10 - }, - "contributorInsightsSpecification": { - "enabled": true - } - }, - { - "indexName": "gsi2", - "readProvisionedThroughputSettings": { - "readCapacityUnits": 10 - }, - "contributorInsightsSpecification": { - "enabled": false - } - } - ], - "tableClass": "STANDARD_INFREQUENT_ACCESS", - "contributorInsightsSpecification": { - "enabled": true - }, - "pointInTimeRecoverySpecification": { - "pointInTimeRecoveryEnabled": true - }, - "readProvisionedThroughputSettings": { - "readCapacityAutoScalingSettings": { - "minCapacity": 5, - "maxCapacity": 25, - "targetTrackingScalingPolicyConfiguration": { - "targetValue": 70 - } - } - }, - "tags": [ - { - "key": "stage", - "value": "IntegTest" - }, - { - "key": "tagAspectKey", - "value": "tagAspectValue" - }, - { - "key": "USE2ReplicaTagKey", - "value": "USE2ReplicaTagValue" - } - ] - }, - { - "region": "us-west-2", - "globalSecondaryIndexes": [ - { - "indexName": "gsi1", - "readProvisionedThroughputSettings": { - "readCapacityUnits": 15 - } - }, - { - "indexName": "gsi2", - "readProvisionedThroughputSettings": { - "readCapacityUnits": 10 - }, - "contributorInsightsSpecification": { - "enabled": true - } - } - ], - "tableClass": "STANDARD", - "contributorInsightsSpecification": { - "enabled": false - }, - "pointInTimeRecoverySpecification": { - "pointInTimeRecoveryEnabled": true - }, - "readProvisionedThroughputSettings": { - "readCapacityUnits": 10 - }, - "tags": [ - { - "key": "stage", - "value": "IntegTest" - }, - { - "key": "tagAspectKey", - "value": "tagAspectValue" - }, - { - "key": "USW2ReplicaTagKey", - "value": "USW2ReplicaTagValue" - } - ] - }, - { - "region": "us-east-1", - "globalSecondaryIndexes": [ - { - "indexName": "gsi1", - "readProvisionedThroughputSettings": { - "readCapacityUnits": 10 - }, - "contributorInsightsSpecification": { - "enabled": true - } - }, - { - "indexName": "gsi2", - "readProvisionedThroughputSettings": { - "readCapacityUnits": 10 - }, - "contributorInsightsSpecification": { - "enabled": true - } - } - ], - "tableClass": "STANDARD_INFREQUENT_ACCESS", - "kinesisStreamSpecification": { - "streamArn": { - "Fn::GetAtt": [ - "Stream790BDEE4", - "Arn" - ] - } - }, - "contributorInsightsSpecification": { - "enabled": true - }, - "pointInTimeRecoverySpecification": { - "pointInTimeRecoveryEnabled": true - }, - "readProvisionedThroughputSettings": { - "readCapacityUnits": 10 - }, - "tags": [ - { - "key": "stage", - "value": "IntegTest" - }, - { - "key": "tagAspectKey", - "value": "tagAspectValue" - }, - { - "key": "primaryTableTagKey", - "value": "primaryTableTagValue" - } - ] - } - ], - "sseSpecification": { - "sseEnabled": true, - "sseType": "KMS" - }, - "streamSpecification": { - "streamViewType": "NEW_AND_OLD_IMAGES" - }, - "tableName": "my-global-table", - "timeToLiveSpecification": { - "attributeName": "attr", - "enabled": true - }, - "writeProvisionedThroughputSettings": { - "writeCapacityAutoScalingSettings": { - "minCapacity": 1, - "maxCapacity": 20, - "seedCapacity": 10, - "targetTrackingScalingPolicyConfiguration": { - "targetValue": 60 - } - } - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_dynamodb.CfnGlobalTable", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_dynamodb.TableV2", - "version": "0.0.0" - } - }, - "BootstrapVersion": { - "id": "BootstrapVersion", - "path": "aws-cdk-global-table/BootstrapVersion", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnParameter", - "version": "0.0.0" - } - }, - "CheckBootstrapVersion": { - "id": "CheckBootstrapVersion", - "path": "aws-cdk-global-table/CheckBootstrapVersion", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnRule", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.Stack", - "version": "0.0.0" - } - }, - "aws-cdk-global-table-integ": { - "id": "aws-cdk-global-table-integ", - "path": "aws-cdk-global-table-integ", - "children": { - "DefaultTest": { - "id": "DefaultTest", - "path": "aws-cdk-global-table-integ/DefaultTest", - "children": { - "Default": { - "id": "Default", - "path": "aws-cdk-global-table-integ/DefaultTest/Default", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.4.2" - } - }, - "DeployAssert": { - "id": "DeployAssert", - "path": "aws-cdk-global-table-integ/DefaultTest/DeployAssert", - "children": { - "BootstrapVersion": { - "id": "BootstrapVersion", - "path": "aws-cdk-global-table-integ/DefaultTest/DeployAssert/BootstrapVersion", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnParameter", - "version": "0.0.0" - } - }, - "CheckBootstrapVersion": { - "id": "CheckBootstrapVersion", - "path": "aws-cdk-global-table-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 +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"aws-cdk-global-table":{"id":"aws-cdk-global-table","path":"aws-cdk-global-table","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"Stream":{"id":"Stream","path":"aws-cdk-global-table/Stream","constructInfo":{"fqn":"aws-cdk-lib.aws_kinesis.Stream","version":"0.0.0","metadata":["*"]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-global-table/Stream/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_kinesis.CfnStream","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Kinesis::Stream","aws:cdk:cloudformation:props":{"retentionPeriodHours":24,"shardCount":1,"streamEncryption":{"Fn::If":["AwsCdkKinesisEncryptedStreamsUnsupportedRegions",{"Ref":"AWS::NoValue"},{"EncryptionType":"KMS","KeyId":"alias/aws/kinesis"}]},"tags":[{"key":"stage","value":"IntegTest"}]}}}}},"AwsCdkKinesisEncryptedStreamsUnsupportedRegions":{"id":"AwsCdkKinesisEncryptedStreamsUnsupportedRegions","path":"aws-cdk-global-table/AwsCdkKinesisEncryptedStreamsUnsupportedRegions","constructInfo":{"fqn":"aws-cdk-lib.CfnCondition","version":"0.0.0"}},"GlobalTable":{"id":"GlobalTable","path":"aws-cdk-global-table/GlobalTable","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.TableBaseV2","version":"0.0.0","metadata":["*","*","*","*","*","*"]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-global-table/GlobalTable/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.CfnGlobalTable","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::DynamoDB::GlobalTable","aws:cdk:cloudformation:props":{"attributeDefinitions":[{"attributeName":"pk","attributeType":"S"},{"attributeName":"sk","attributeType":"N"}],"billingMode":"PROVISIONED","globalSecondaryIndexes":[{"indexName":"gsi1","keySchema":[{"attributeName":"pk","keyType":"HASH"}],"projection":{"projectionType":"ALL"},"writeProvisionedThroughputSettings":{"writeCapacityAutoScalingSettings":{"minCapacity":1,"maxCapacity":20,"seedCapacity":10,"targetTrackingScalingPolicyConfiguration":{"targetValue":60}}}},{"indexName":"gsi2","keySchema":[{"attributeName":"pk","keyType":"HASH"}],"projection":{"projectionType":"ALL"},"writeProvisionedThroughputSettings":{"writeCapacityAutoScalingSettings":{"minCapacity":1,"maxCapacity":30,"targetTrackingScalingPolicyConfiguration":{"targetValue":70}}}}],"keySchema":[{"attributeName":"pk","keyType":"HASH"},{"attributeName":"sk","keyType":"RANGE"}],"localSecondaryIndexes":[{"indexName":"lsi","keySchema":[{"attributeName":"pk","keyType":"HASH"},{"attributeName":"sk","keyType":"RANGE"}],"projection":{"projectionType":"ALL"}}],"replicas":[{"region":"us-east-2","globalSecondaryIndexes":[{"indexName":"gsi1","readProvisionedThroughputSettings":{"readCapacityUnits":10},"contributorInsightsSpecification":{"enabled":true}},{"indexName":"gsi2","readProvisionedThroughputSettings":{"readCapacityUnits":10},"contributorInsightsSpecification":{"enabled":false}}],"tableClass":"STANDARD_INFREQUENT_ACCESS","contributorInsightsSpecification":{"enabled":true},"pointInTimeRecoverySpecification":{"pointInTimeRecoveryEnabled":true},"readProvisionedThroughputSettings":{"readCapacityAutoScalingSettings":{"minCapacity":5,"maxCapacity":25,"targetTrackingScalingPolicyConfiguration":{"targetValue":70}}},"tags":[{"key":"stage","value":"IntegTest"},{"key":"tagAspectKey","value":"tagAspectValue"},{"key":"USE2ReplicaTagKey","value":"USE2ReplicaTagValue"}]},{"region":"us-west-2","globalSecondaryIndexes":[{"indexName":"gsi1","readProvisionedThroughputSettings":{"readCapacityUnits":15},"contributorInsightsSpecification":{"enabled":true}},{"indexName":"gsi2","readProvisionedThroughputSettings":{"readCapacityUnits":10},"contributorInsightsSpecification":{"enabled":true}}],"tableClass":"STANDARD","contributorInsightsSpecification":{"enabled":false},"pointInTimeRecoverySpecification":{"pointInTimeRecoveryEnabled":true},"readProvisionedThroughputSettings":{"readCapacityUnits":10},"tags":[{"key":"stage","value":"IntegTest"},{"key":"tagAspectKey","value":"tagAspectValue"},{"key":"USW2ReplicaTagKey","value":"USW2ReplicaTagValue"}]},{"region":"us-east-1","globalSecondaryIndexes":[{"indexName":"gsi1","readProvisionedThroughputSettings":{"readCapacityUnits":10},"contributorInsightsSpecification":{"enabled":true}},{"indexName":"gsi2","readProvisionedThroughputSettings":{"readCapacityUnits":10},"contributorInsightsSpecification":{"enabled":true}}],"tableClass":"STANDARD_INFREQUENT_ACCESS","kinesisStreamSpecification":{"streamArn":{"Fn::GetAtt":["Stream790BDEE4","Arn"]}},"contributorInsightsSpecification":{"enabled":true},"pointInTimeRecoverySpecification":{"pointInTimeRecoveryEnabled":true},"readProvisionedThroughputSettings":{"readCapacityUnits":10},"tags":[{"key":"stage","value":"IntegTest"},{"key":"tagAspectKey","value":"tagAspectValue"},{"key":"primaryTableTagKey","value":"primaryTableTagValue"}]}],"sseSpecification":{"sseEnabled":true,"sseType":"KMS"},"streamSpecification":{"streamViewType":"NEW_AND_OLD_IMAGES"},"tableName":"my-global-table","timeToLiveSpecification":{"attributeName":"attr","enabled":true},"writeProvisionedThroughputSettings":{"writeCapacityAutoScalingSettings":{"minCapacity":1,"maxCapacity":20,"seedCapacity":10,"targetTrackingScalingPolicyConfiguration":{"targetValue":60}}}}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"aws-cdk-global-table/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"aws-cdk-global-table/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"aws-cdk-global-table-integ":{"id":"aws-cdk-global-table-integ","path":"aws-cdk-global-table-integ","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"aws-cdk-global-table-integ/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"aws-cdk-global-table-integ/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"aws-cdk-global-table-integ/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"aws-cdk-global-table-integ/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"aws-cdk-global-table-integ/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file From cf0b363b40bb8e7c931a099a166f779ffb671435 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Fri, 27 Jun 2025 15:48:28 +0100 Subject: [PATCH 07/18] Fixing Typo --- packages/aws-cdk-lib/aws-dynamodb/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/aws-cdk-lib/aws-dynamodb/README.md b/packages/aws-cdk-lib/aws-dynamodb/README.md index 9e41c6a45658a..11a9d1c2d1ac2 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/README.md +++ b/packages/aws-cdk-lib/aws-dynamodb/README.md @@ -624,7 +624,7 @@ Enabling `contributorInsightSpecification` for `TableV2` will provide informatio ```ts const table = new dynamodb.TableV2(this, 'Table', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, - contributorInsightsSpecfication: { + contributorInsightsSpecification: { enabled: true, contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, @@ -636,14 +636,14 @@ When you use `Table`, you can enable contributor insights for a table or specifi ```ts const table = new dynamodb.Table(this, 'Table', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, - contributorInsightsSpecfication: { // for a table + contributorInsightsSpecification: { // for a table enabled: true, contributorInsightsMode: ContributorInsightsMode.THROTTLED_KEYS, // only emit throttling events }, }); table.addGlobalSecondaryIndex({ - contributorInsightsSpecfication: { // for a specific global secondary index + contributorInsightsSpecification: { // for a specific global secondary index enabled: true, }, indexName: 'gsi', From 7855b56c131c0ca0c0d10adb5c9a9a143a54b409 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Fri, 27 Jun 2025 18:06:55 +0100 Subject: [PATCH 08/18] Fixing README --- packages/aws-cdk-lib/aws-dynamodb/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/aws-dynamodb/README.md b/packages/aws-cdk-lib/aws-dynamodb/README.md index 11a9d1c2d1ac2..ede93dee0769d 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/README.md +++ b/packages/aws-cdk-lib/aws-dynamodb/README.md @@ -626,7 +626,7 @@ const table = new dynamodb.TableV2(this, 'Table', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + contributorInsightsMode: dynamodb.ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, }); ``` @@ -638,7 +638,7 @@ const table = new dynamodb.Table(this, 'Table', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, contributorInsightsSpecification: { // for a table enabled: true, - contributorInsightsMode: ContributorInsightsMode.THROTTLED_KEYS, // only emit throttling events + contributorInsightsMode: dynamodb.ContributorInsightsMode.THROTTLED_KEYS, // only emit throttling events }, }); From 12e924ac69b811978bb094f0f8cddef9fd587211 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Wed, 25 Jun 2025 15:10:35 +0100 Subject: [PATCH 09/18] feat(dynamodb): Adding ContributorInsightsMode feature --- .../aws-cdk-lib/aws-dynamodb/lib/table-v2.ts | 9 +- .../aws-dynamodb/test/table-v2.test.ts | 127 ------------------ 2 files changed, 8 insertions(+), 128 deletions(-) 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 c14d4910f76a1..ec4336ad15a5e 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts @@ -17,6 +17,7 @@ import { WarmThroughput, MultiRegionConsistency, ContributorInsightsSpecification, + ContributorInsightsSpecification, } from './shared'; import { ITableV2, TableBaseV2 } from './table-v2-base'; import { PolicyDocument } from '../../aws-iam'; @@ -149,7 +150,7 @@ export interface GlobalSecondaryIndexPropsV2 extends SecondaryIndexProps { export interface TableOptionsV2 { /** * Whether CloudWatch contributor insights is enabled. - * @deprecated use `contributorInsightsSpecification` instead + * @deprecated use `contributorInsightsSpecification` instead @deprecated use `contributorInsightsSpecification` instead * @default false */ readonly contributorInsights?: boolean; @@ -160,6 +161,12 @@ export interface TableOptionsV2 { */ readonly contributorInsightsSpecification?: ContributorInsightsSpecification; + /** + * Whether CloudWatch contributor insights is enabled and what mode is selected + * @default - contributor insights is not enabled + */ + readonly contributorInsightsSpecification?: ContributorInsightsSpecification; + /** * Whether deletion protection is enabled. * 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 ac79bb701ca77..d3f74f37e7cc0 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 @@ -3468,130 +3468,3 @@ test('ContributorInsightsSpecification && ContributorInsights - v2', () => { }).toThrow('`contributorInsightsSpecification` and `contributorInsights` are set. Use `contributorInsightsSpecification` only.'); }); -test('Contributor Insights Specification - tableV2', () => { - const stack = new Stack(); - - const table = new TableV2(stack, 'TableV2', { - partitionKey: { name: 'hashKey', type: AttributeType.STRING }, - sortKey: { name: 'sortKey', type: AttributeType.NUMBER }, - contributorInsightsSpecification: { - enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, - }, - }); - - Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' }, - ], - Replicas: [ - { - Region: { - Ref: 'AWS::Region', - }, - ContributorInsightsSpecification: { - Enabled: true, - ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', - }, - }, - ], - }, - ); -}); - -test('Contributor Insights Specification - index', () => { - const stack = new Stack(undefined, 'Stack', { env: { region: 'eu-west-1' } }); - - const table = new TableV2(stack, 'TableV2', { - partitionKey: { name: 'hashKey', type: AttributeType.STRING }, - sortKey: { name: 'sortKey', type: AttributeType.NUMBER }, - globalSecondaryIndexes: [ - { - indexName: 'gsi1', - partitionKey: { name: 'gsiHashKey', type: AttributeType.STRING }, - }, - ], - contributorInsightsSpecification: { - enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, - }, - replicas: [ - { - region: 'eu-west-2', - contributorInsightsSpecification: { - enabled: false, - }, - globalSecondaryIndexOptions: { - gsi1: { - contributorInsightsSpecification: { - enabled: true, - contributorInsightsMode: ContributorInsightsMode.THROTTLED_KEYS, - }, - }, - }, - }, - ], - }); - - Template.fromStack(stack).hasResource('AWS::DynamoDB::GlobalTable', { - Properties: Match.objectLike({ - Replicas: Match.arrayWith([ - Match.objectLike({ - Region: 'eu-west-2', - ContributorInsightsSpecification: { - Enabled: false, - }, - GlobalSecondaryIndexes: Match.arrayWith([ - Match.objectLike({ - IndexName: 'gsi1', - ContributorInsightsSpecification: { - Enabled: true, - ContributorInsightsMode: 'THROTTLED_KEYS', - }, - }), - ]), - }), - Match.objectLike({ - Region: 'eu-west-1', - ContributorInsightsSpecification: { - Enabled: true, - ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', - }, - GlobalSecondaryIndexes: Match.arrayWith([ - Match.objectLike({ - IndexName: 'gsi1', - ContributorInsightsSpecification: { - Enabled: true, - ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', - }, - }), - ]), - }), - ]), - }), - }); -}); - -test('ContributorInsightsSpecification && ContributorInsights - v2', () => { - const stack = new Stack(); - - expect(() => { - const table = new TableV2(stack, 'Tablev2', { - partitionKey: { name: 'pk', type: AttributeType.STRING }, - sortKey: { name: 'sk', type: AttributeType.STRING }, - contributorInsights: true, - contributorInsightsSpecification: { - enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, - }, - }); - - Template.fromStack(stack); - }).toThrow('`contributorInsightsSpecification` and `contributorInsights` are set. Use `contributorInsightsSpecification` only.'); -}); From 4dc94f0c8a770999eb78b108dcae739597bb382d Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Thu, 26 Jun 2025 14:25:50 +0100 Subject: [PATCH 10/18] Fixing linting issues --- .../aws-cdk-lib/aws-dynamodb/lib/table-v2.ts | 7 -- .../aws-dynamodb/test/table-v2.test.ts | 73 +++++++++++++++++++ 2 files changed, 73 insertions(+), 7 deletions(-) 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 ec4336ad15a5e..00bd5ad6027a4 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts @@ -17,7 +17,6 @@ import { WarmThroughput, MultiRegionConsistency, ContributorInsightsSpecification, - ContributorInsightsSpecification, } from './shared'; import { ITableV2, TableBaseV2 } from './table-v2-base'; import { PolicyDocument } from '../../aws-iam'; @@ -161,12 +160,6 @@ export interface TableOptionsV2 { */ readonly contributorInsightsSpecification?: ContributorInsightsSpecification; - /** - * Whether CloudWatch contributor insights is enabled and what mode is selected - * @default - contributor insights is not enabled - */ - readonly contributorInsightsSpecification?: ContributorInsightsSpecification; - /** * Whether deletion protection is enabled. * 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 d3f74f37e7cc0..ba308175a52bf 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 @@ -3450,6 +3450,79 @@ test('Contributor Insights Specification - tableV2', () => { ); }); +test('Contributor Insights Specification - index', () => { + const stack = new Stack(undefined, 'Stack', { env: { region: 'eu-west-1' } }); + + const table = new TableV2(stack, 'TableV2', { + partitionKey: { name: 'hashKey', type: AttributeType.STRING }, + sortKey: { name: 'sortKey', type: AttributeType.NUMBER }, + globalSecondaryIndexes: [ + { + indexName: 'gsi1', + partitionKey: { name: 'gsiHashKey', type: AttributeType.STRING }, + }, + ], + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + replicas: [ + { + region: 'eu-west-2', + contributorInsightsSpecification: { + enabled: false, + }, + globalSecondaryIndexOptions: { + gsi1: { + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: ContributorInsightsMode.THROTTLED_KEYS, + }, + }, + }, + }, + ], + }); + + Template.fromStack(stack).hasResource('AWS::DynamoDB::GlobalTable', { + Properties: Match.objectLike({ + Replicas: Match.arrayWith([ + Match.objectLike({ + Region: 'eu-west-2', + ContributorInsightsSpecification: { + Enabled: false, + }, + GlobalSecondaryIndexes: Match.arrayWith([ + Match.objectLike({ + IndexName: 'gsi1', + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'THROTTLED_KEYS', + }, + }), + ]), + }), + Match.objectLike({ + Region: 'eu-west-1', + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + }, + GlobalSecondaryIndexes: Match.arrayWith([ + Match.objectLike({ + IndexName: 'gsi1', + ContributorInsightsSpecification: { + Enabled: true, + ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + }, + }), + ]), + }), + ]), + }), + }); +}); + test('ContributorInsightsSpecification && ContributorInsights - v2', () => { const stack = new Stack(); From d06ced5cfbd8f134ed7e776db43d7c394ae82626 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Tue, 15 Jul 2025 19:46:56 +0100 Subject: [PATCH 11/18] adding interface to avoid union types, update readme --- packages/aws-cdk-lib/aws-dynamodb/README.md | 3 +++ .../aws-cdk-lib/aws-dynamodb/lib/table-v2.ts | 25 ++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/aws-cdk-lib/aws-dynamodb/README.md b/packages/aws-cdk-lib/aws-dynamodb/README.md index ede93dee0769d..b1cb705e86293 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/README.md +++ b/packages/aws-cdk-lib/aws-dynamodb/README.md @@ -617,6 +617,9 @@ const table = new dynamodb.TableV2(this, 'Table', { Enabling `contributorInsightSpecification` for `TableV2` will provide information about the most accessed and throttled or throttled only items in a table or `globalSecondaryIndex`. DynamoDB delivers this information to you via CloudWatch Contributor Insights rules, reports, and graphs of report data. +By default, Contributor Insights for DynamoDB monitors all requests, including both the most accessed and most throttled items. +To limit the scope to only the most accessed or only the most throttled items, use the optional `contributorInsightsMode` parameter. + - To monitor all traffic on a table or index, set `contributorInsightsMode` to `ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS`. - To monitor only throttled traffic on a table or index, set `contributorInsightsMode` to `ContributorInsightsMode.THROTTLED_KEYS`. 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 00bd5ad6027a4..9be0fa7a31b70 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts @@ -48,7 +48,7 @@ const MAX_NON_KEY_ATTRIBUTES = 100; /** * Options used to configure global secondary indexes on a replica table. */ -export interface ReplicaGlobalSecondaryIndexOptions { +export interface ReplicaGlobalSecondaryIndexOptions extends IContributorInsightsConfigurable { /** * Whether CloudWatch contributor insights is enabled for a specific global secondary * index on a replica table. @@ -143,13 +143,30 @@ export interface GlobalSecondaryIndexPropsV2 extends SecondaryIndexProps { readonly warmThroughput?: WarmThroughput; } +/** + * Common interface for types that can configure contributor insights + * @internal + */ +interface IContributorInsightsConfigurable { + /** + * Whether CloudWatch contributor insights is enabled. + * @deprecated use `contributorInsightsSpecification` instead + */ + readonly contributorInsights?: boolean; + + /** + * Whether CloudWatch contributor insights is enabled and what mode is selected + */ + readonly contributorInsightsSpecification?: ContributorInsightsSpecification; +} + /** * Options used to configure a DynamoDB table. */ -export interface TableOptionsV2 { +export interface TableOptionsV2 extends IContributorInsightsConfigurable { /** * Whether CloudWatch contributor insights is enabled. - * @deprecated use `contributorInsightsSpecification` instead @deprecated use `contributorInsightsSpecification` instead + * @deprecated use `contributorInsightsSpecification` instead * @default false */ readonly contributorInsights?: boolean; @@ -1148,7 +1165,7 @@ export class TableV2 extends TableBaseV2 { } } - private validateCCI (props: TablePropsV2 | ReplicaTableProps | ReplicaGlobalSecondaryIndexOptions): ContributorInsightsSpecification | undefined { + private validateCCI (props: IContributorInsightsConfigurable): ContributorInsightsSpecification | undefined { const contributorInsights = props?.contributorInsights ?? this.tableOptions?.contributorInsights; From 77fbf2c2ec4333511b92ab3f2b5cd53fb3cd418c Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Thu, 17 Jul 2025 11:29:59 +0100 Subject: [PATCH 12/18] Remove union type from Table, additional tests --- .../aws-cdk-lib/aws-dynamodb/lib/table.ts | 19 +++++++++- .../aws-dynamodb/test/dynamodb.test.ts | 29 +++++++++++++++ .../aws-dynamodb/test/table-v2.test.ts | 35 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts index 85688ae22b920..f073f6a9ab0a0 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts @@ -232,6 +232,23 @@ export enum ApproximateCreationDateTimePrecision { MICROSECOND = 'MICROSECOND', } +/** + * Common interface for types that can configure contributor insights + * @internal + */ +interface IContributorInsightsConfigurable { + /** + * Whether CloudWatch contributor insights is enabled. + * @deprecated use `contributorInsightsSpecification` instead + */ + readonly contributorInsightsEnabled?: boolean; + + /** + * Whether CloudWatch contributor insights is enabled and what mode is selected + */ + readonly contributorInsightsSpecification?: ContributorInsightsSpecification; +} + /** * Properties of a DynamoDB Table * @@ -1603,7 +1620,7 @@ export class Table extends TableBase { : undefined); } - private validateCCI (props: TableProps | GlobalSecondaryIndexProps): ContributorInsightsSpecification | undefined { + private validateCCI (props: IContributorInsightsConfigurable): ContributorInsightsSpecification | undefined { if (props.contributorInsightsSpecification !==undefined && props.contributorInsightsEnabled !== undefined) { throw new ValidationError('`contributorInsightsSpecification` and `contributorInsightsEnabled` are set. Use `contributorInsightsSpecification` only.', this); } 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 cdec3afd0a8b9..bcd3534570a66 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts @@ -4152,6 +4152,35 @@ test('Contributor Insights Specification - table', () => { ); }); +test('Contributor Insights Specification - table - without mode', () => { + const stack = new Stack(); + + const table = new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + contributorInsightsSpecification: { + enabled: true, + }, + }); + + Template.fromStack(stack).hasResourceProperties('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 }, + ContributorInsightsSpecification: { + Enabled: true, + }, + }, + ); +}); + test('Contributor Insights Specification - index', () => { const stack = new Stack(); 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 ba308175a52bf..97f56163f61aa 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 @@ -3450,6 +3450,41 @@ test('Contributor Insights Specification - tableV2', () => { ); }); +test('Contributor Insights Specification - tableV2 - without mode', () => { + const stack = new Stack(); + + const table = new TableV2(stack, 'TableV2', { + partitionKey: { name: 'hashKey', type: AttributeType.STRING }, + sortKey: { name: 'sortKey', type: AttributeType.NUMBER }, + contributorInsightsSpecification: { + enabled: true, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' }, + ], + Replicas: [ + { + Region: { + Ref: 'AWS::Region', + }, + ContributorInsightsSpecification: { + Enabled: true, + }, + }, + ], + }, + ); +}); + test('Contributor Insights Specification - index', () => { const stack = new Stack(undefined, 'Stack', { env: { region: 'eu-west-1' } }); From f5148c72d2047a57cd1918ef9bd304d681b4735f Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Wed, 23 Jul 2025 15:41:06 +0100 Subject: [PATCH 13/18] Updating integ tests with new CCI spec --- .../integ.dynamodb.contirubtor-insights-for-gsi.ts | 8 ++++++-- .../test/aws-dynamodb/test/integ.table-v2-global.ts | 12 +++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.contirubtor-insights-for-gsi.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.contirubtor-insights-for-gsi.ts index 7e1968ba12fc4..2aeaf866ed4ae 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.contirubtor-insights-for-gsi.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.contirubtor-insights-for-gsi.ts @@ -24,12 +24,16 @@ const table = new Table(stack, TABLE, { }); table.addGlobalSecondaryIndex({ - contributorInsightsEnabled: true, + contributorInsightsSpecification: { + enabled: true, + }, indexName: GSI_TEST_CASE_1, partitionKey: GSI_PARTITION_KEY, }); table.addGlobalSecondaryIndex({ - contributorInsightsEnabled: false, + contributorInsightsSpecification: { + enabled: false, + }, indexName: GSI_TEST_CASE_2, partitionKey: GSI_PARTITION_KEY, }); 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 de8d987c23e91..e4d646fe55acd 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 @@ -19,7 +19,9 @@ class TestStack extends Stack { writeCapacity: Capacity.autoscaled({ maxCapacity: 20, targetUtilizationPercent: 60, seedCapacity: 10 }), }), encryption: TableEncryptionV2.awsManagedKey(), - contributorInsights: true, + contributorInsightsSpecification: { + enabled: true, + }, pointInTimeRecovery: true, tableClass: TableClass.STANDARD_INFREQUENT_ACCESS, timeToLiveAttribute: 'attr', @@ -49,7 +51,9 @@ class TestStack extends Stack { readCapacity: Capacity.autoscaled({ minCapacity: 5, maxCapacity: 25 }), globalSecondaryIndexOptions: { gsi2: { - contributorInsights: false, + contributorInsightsSpecification: { + enabled: false, + }, }, }, tags: [{ key: 'USE2ReplicaTagKey', value: 'USE2ReplicaTagValue' }], @@ -57,7 +61,9 @@ class TestStack extends Stack { { region: 'us-west-2', tableClass: TableClass.STANDARD, - contributorInsights: false, + contributorInsightsSpecification: { + enabled: false, + }, globalSecondaryIndexOptions: { gsi1: { readCapacity: Capacity.fixed(15), From 11408b4c0a33465ed3d3f8216af556571ecf0347 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Thu, 21 Aug 2025 11:52:52 +0100 Subject: [PATCH 14/18] Removing temp schemas --- .../test/integ.dynamodb-v2.cci.ts | 49 ++ .../us-east-1/aws-dynamodb-globaltable.json | 641 ------------------ .../us-east-1/aws-dynamodb-table.json | 591 ---------------- 3 files changed, 49 insertions(+), 1232 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts delete mode 100644 tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-globaltable.json delete mode 100644 tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-table.json diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts new file mode 100644 index 0000000000000..44ba6ce5968d9 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts @@ -0,0 +1,49 @@ +import { App, Stack, StackProps } from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new App(); + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + new dynamodb.TableV2(this, 'TableV2', { + partitionKey: { name: 'hashKey', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'sortKey', type: dynamodb.AttributeType.NUMBER }, + globalSecondaryIndexes: [ + { + indexName: 'gsi', + partitionKey: { name: 'gsiHashKey', type: dynamodb.AttributeType.STRING }, + }, + ], + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: dynamodb.ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + replicas: [ + { + region: 'eu-west-2', + contributorInsightsSpecification: { + enabled: false, + }, + globalSecondaryIndexOptions: { + gsi: { + contributorInsightsSpecification: { + enabled: true, + contributorInsightsMode: dynamodb.ContributorInsightsMode.THROTTLED_KEYS, + }, + }, + }, + }, + ], + }); + } +} + +const stack = new TestStack(app, 'CCI-Integ-Test', { env: { region: 'eu-west-1' } }); + +new IntegTest(app, 'table-v2-CCI-test', { + testCases: [stack], +}); diff --git a/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-globaltable.json b/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-globaltable.json deleted file mode 100644 index 6d2f3eb1cba73..0000000000000 --- a/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-globaltable.json +++ /dev/null @@ -1,641 +0,0 @@ -{ - "typeName" : "AWS::DynamoDB::GlobalTable", - "description" : "Version: None. Resource Type definition for AWS::DynamoDB::GlobalTable", - "additionalProperties" : false, - "properties" : { - "Arn" : { - "type" : "string" - }, - "StreamArn" : { - "type" : "string" - }, - "AttributeDefinitions" : { - "type" : "array", - "uniqueItems" : true, - "insertionOrder": false, - "items" : { - "$ref" : "#/definitions/AttributeDefinition" - }, - "minItems": 1 - }, - "BillingMode" : { - "type" : "string" - }, - "GlobalSecondaryIndexes" : { - "type" : "array", - "uniqueItems" : true, - "insertionOrder": false, - "items" : { - "$ref" : "#/definitions/GlobalSecondaryIndex" - } - }, - "KeySchema" : { - "type" : "array", - "uniqueItems" : true, - "items" : { - "$ref" : "#/definitions/KeySchema" - }, - "minItems": 1, - "maxItems": 2 - }, - "LocalSecondaryIndexes" : { - "type" : "array", - "uniqueItems" : true, - "insertionOrder": false, - "items" : { - "$ref" : "#/definitions/LocalSecondaryIndex" - } - }, - "WriteProvisionedThroughputSettings" : { - "$ref" : "#/definitions/WriteProvisionedThroughputSettings" - }, - "WriteOnDemandThroughputSettings" : { - "$ref" : "#/definitions/WriteOnDemandThroughputSettings" - }, - "WarmThroughput" : { - "$ref" : "#/definitions/WarmThroughput" - }, - "Replicas" : { - "type" : "array", - "uniqueItems" : true, - "insertionOrder": false, - "items" : { - "$ref" : "#/definitions/ReplicaSpecification" - }, - "minItems": 1 - }, - "SSESpecification" : { - "$ref" : "#/definitions/SSESpecification" - }, - "StreamSpecification" : { - "$ref" : "#/definitions/StreamSpecification" - }, - "TableName" : { - "type" : "string" - }, - "TableId" : { - "type" : "string" - }, - "TimeToLiveSpecification" : { - "$ref" : "#/definitions/TimeToLiveSpecification" - } - }, - "definitions" : { - "StreamSpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "StreamViewType" : { - "type" : "string" - } - }, - "required" : [ "StreamViewType" ] - }, - "ResourcePolicy" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "PolicyDocument": { - "type": "object" - } - }, - "required" : [ "PolicyDocument" ] - }, - "ReplicaStreamSpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "ResourcePolicy": { - "$ref": "#/definitions/ResourcePolicy" - } - }, - "required" : [ "ResourcePolicy" ] - }, - "KinesisStreamSpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "StreamArn" : { - "type" : "string", - "relationshipRef": { - "typeName": "AWS::Kinesis::Stream", - "propertyPath": "/properties/Arn" - } - }, - "ApproximateCreationDateTimePrecision" : { - "type": "string", - "enum": [ - "MICROSECOND", - "MILLISECOND" - ] - } - }, - "required" : [ "StreamArn" ] - }, - "KeySchema" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "AttributeName" : { - "type" : "string", - "minLength": 1, - "maxLength": 255 - }, - "KeyType" : { - "type" : "string" - } - }, - "required" : [ "KeyType", "AttributeName" ] - }, - "PointInTimeRecoverySpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "PointInTimeRecoveryEnabled" : { - "type" : "boolean" - } - } - }, - "ReplicaSpecification": { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "Region" : { - "type" : "string" - }, - "GlobalSecondaryIndexes": { - "type" : "array", - "uniqueItems" : true, - "insertionOrder": false, - "items" : { - "$ref": "#/definitions/ReplicaGlobalSecondaryIndexSpecification" - } - }, - "ContributorInsightsSpecification": { - "$ref": "#/definitions/ContributorInsightsSpecification" - }, - "PointInTimeRecoverySpecification" : { - "$ref" : "#/definitions/PointInTimeRecoverySpecification" - }, - "TableClass" : { - "type" : "string" - }, - "DeletionProtectionEnabled" : { - "type" : "boolean" - }, - "SSESpecification": { - "$ref": "#/definitions/ReplicaSSESpecification" - }, - "Tags" : { - "type": "array", - "insertionOrder": false, - "uniqueItems": true, - "items": { - "$ref": "#/definitions/Tag" - } - }, - "ReadProvisionedThroughputSettings": { - "$ref": "#/definitions/ReadProvisionedThroughputSettings" - }, - "ReadOnDemandThroughputSettings": { - "$ref": "#/definitions/ReadOnDemandThroughputSettings" - }, - "KinesisStreamSpecification": { - "$ref": "#/definitions/KinesisStreamSpecification" - }, - "ResourcePolicy": { - "$ref": "#/definitions/ResourcePolicy" - }, - "ReplicaStreamSpecification": { - "$ref": "#/definitions/ReplicaStreamSpecification" - } - }, - "required" : [ "Region" ] - - }, - "TimeToLiveSpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "AttributeName" : { - "type" : "string" - }, - "Enabled" : { - "type" : "boolean" - } - }, - "required" : [ "Enabled" ] - }, - "LocalSecondaryIndex" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "IndexName" : { - "type" : "string", - "minLength": 3, - "maxLength": 255 - }, - "KeySchema" : { - "type" : "array", - "uniqueItems" : true, - "items" : { - "$ref" : "#/definitions/KeySchema" - }, - "maxItems": 2 - }, - "Projection" : { - "$ref" : "#/definitions/Projection" - } - }, - "required" : [ "IndexName", "Projection", "KeySchema" ] - }, - "GlobalSecondaryIndex" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "IndexName" : { - "type" : "string", - "minLength": 3, - "maxLength": 255 - }, - "KeySchema" : { - "type" : "array", - "uniqueItems" : true, - "items" : { - "$ref" : "#/definitions/KeySchema" - }, - "minItems": 1, - "maxItems": 2 - }, - "Projection" : { - "$ref" : "#/definitions/Projection" - }, - "WriteProvisionedThroughputSettings" : { - "$ref" : "#/definitions/WriteProvisionedThroughputSettings" - }, - "WriteOnDemandThroughputSettings" : { - "$ref" : "#/definitions/WriteOnDemandThroughputSettings" - }, - "WarmThroughput": { - "$ref": "#/definitions/WarmThroughput" - } - }, - "required" : [ "IndexName", "Projection", "KeySchema" ] - }, - "SSESpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "SSEEnabled" : { - "type" : "boolean" - }, - "SSEType" : { - "type" : "string" - } - }, - "required" : [ "SSEEnabled" ] - }, - "ReplicaSSESpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "KMSMasterKeyId" : { - "type" : "string", - "anyOf": [{ - "relationshipRef": { - "typeName": "AWS::KMS::Key", - "propertyPath": "/properties/Arn" - }},{ - "relationshipRef": { - "typeName": "AWS::KMS::Key", - "propertyPath": "/properties/KeyId" - }},{ - "relationshipRef": { - "typeName": "AWS::KMS::Alias", - "propertyPath": "/properties/AliasName" - } - }] - } - }, - "required" : [ "KMSMasterKeyId" ] - }, - "AttributeDefinition" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "AttributeName" : { - "type" : "string", - "minLength": 1, - "maxLength": 255 - }, - "AttributeType" : { - "type" : "string" - } - }, - "required" : [ "AttributeName", "AttributeType" ] - }, - "Tag" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "Key" : { - "type" : "string" - }, - "Value" : { - "type" : "string" - } - }, - "required" : [ "Value", "Key" ] - }, - "Projection" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "NonKeyAttributes" : { - "type" : "array", - "uniqueItems" : true, - "insertionOrder": false, - "items" : { - "type" : "string" - }, - "maxItems": 20 - }, - "ProjectionType" : { - "type" : "string" - } - } - }, - "ReplicaGlobalSecondaryIndexSpecification": { - "type": "object", - "additionalProperties": false, - "properties": { - "IndexName" : { - "type" : "string", - "minLength": 3, - "maxLength": 255 - }, - "ContributorInsightsSpecification": { - "$ref": "#/definitions/ContributorInsightsSpecification" - }, - "ReadProvisionedThroughputSettings": { - "$ref": "#/definitions/ReadProvisionedThroughputSettings" - }, - "ReadOnDemandThroughputSettings": { - "$ref": "#/definitions/ReadOnDemandThroughputSettings" - } - }, - "required" : [ "IndexName" ] - }, - "ContributorInsightsSpecification": { - "type": "object", - "additionalProperties": false, - "properties": { - "Enabled": { - "type": "boolean" - }, - "ContributorInsightsMode": { - "type": "string", - "enum": [ - "ACCESSED_AND_THROTTLED_KEYS", - "THROTTLED_KEYS" - ] - } - }, - "required" : [ "Enabled" ] - }, - "ReadProvisionedThroughputSettings": { - "type": "object", - "additionalProperties": false, - "properties": { - "ReadCapacityUnits" : { - "type" : "integer", - "minimum": 1 - }, - "ReadCapacityAutoScalingSettings": { - "$ref" : "#/definitions/CapacityAutoScalingSettings" - } - } - }, - "WriteProvisionedThroughputSettings": { - "type": "object", - "additionalProperties": false, - "properties": { - "WriteCapacityAutoScalingSettings": { - "$ref": "#/definitions/CapacityAutoScalingSettings" - } - } - }, - "ReadOnDemandThroughputSettings": { - "type": "object", - "additionalProperties": false, - "properties": { - "MaxReadRequestUnits" : { - "type" : "integer", - "minimum": 1 - } - } - }, - "WriteOnDemandThroughputSettings": { - "type": "object", - "additionalProperties": false, - "properties": { - "MaxWriteRequestUnits" : { - "type" : "integer", - "minimum": 1 - } - } - }, - "CapacityAutoScalingSettings": { - "type": "object", - "additionalProperties": false, - "properties": { - "MinCapacity": { - "type": "integer", - "minimum": 1 - }, - "MaxCapacity": { - "type": "integer", - "minimum": 1 - }, - "SeedCapacity": { - "type": "integer", - "minimum": 1 - }, - "TargetTrackingScalingPolicyConfiguration" : { - "$ref": "#/definitions/TargetTrackingScalingPolicyConfiguration" - } - }, - "required": [ "MinCapacity", "MaxCapacity", "TargetTrackingScalingPolicyConfiguration" ] - }, - "TargetTrackingScalingPolicyConfiguration": { - "type": "object", - "additionalProperties": false, - "properties": { - "DisableScaleIn": { - "type": "boolean" - }, - "ScaleInCooldown": { - "type": "integer", - "minimum": 0 - }, - "ScaleOutCooldown": { - "type": "integer", - "minimum": 0 - }, - "TargetValue": { - "type": "number", - "format": "double" - } - }, - "required": [ "TargetValue" ] - }, - "WarmThroughput" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "ReadUnitsPerSecond" : { - "type" : "integer", - "minimum": 1 - }, - "WriteUnitsPerSecond" : { - "type" : "integer", - "minimum": 1 - } - }, - "anyOf": [ - {"required": ["ReadUnitsPerSecond"]}, - {"required": ["WriteUnitsPerSecond"]} - ] - } - }, - "required" : [ "KeySchema", "AttributeDefinitions", "Replicas" ], - "readOnlyProperties" : [ "/properties/Arn", "/properties/StreamArn", "/properties/TableId" ], - "createOnlyProperties" : [ "/properties/LocalSecondaryIndexes", "/properties/TableName", "/properties/KeySchema" ], - "primaryIdentifier" : [ "/properties/TableName" ], - "additionalIdentifiers" : [[ "/properties/Arn"], ["/properties/StreamArn" ]], - "writeOnlyProperties": [ - "/properties/Replicas/*/ReadProvisionedThroughputSettings/ReadCapacityAutoScalingSettings/SeedCapacity", - "/properties/Replicas/*/GlobalSecondaryIndexes/*/ReadProvisionedThroughputSettings/ReadCapacityAutoScalingSettings/SeedCapacity", - "/properties/WriteProvisionedThroughputSettings/WriteCapacityAutoScalingSettings/SeedCapacity", - "/properties/GlobalSecondaryIndexes/*/WriteProvisionedThroughputSettings/WriteCapacityAutoScalingSettings/SeedCapacity" - ], - "handlers": { - "create": { - "permissions": [ - "dynamodb:CreateTable", - "dynamodb:CreateTableReplica", - "dynamodb:Describe*", - "dynamodb:UpdateTimeToLive", - "dynamodb:UpdateContributorInsights", - "dynamodb:UpdateContinuousBackups", - "dynamodb:ListTagsOfResource", - "dynamodb:Query", - "dynamodb:Scan", - "dynamodb:UpdateItem", - "dynamodb:PutItem", - "dynamodb:GetItem", - "dynamodb:DeleteItem", - "dynamodb:BatchWriteItem", - "dynamodb:TagResource", - "dynamodb:EnableKinesisStreamingDestination", - "dynamodb:DisableKinesisStreamingDestination", - "dynamodb:UpdateTableReplicaAutoScaling", - "dynamodb:TagResource", - "dynamodb:GetResourcePolicy", - "dynamodb:PutResourcePolicy", - "application-autoscaling:DeleteScalingPolicy", - "application-autoscaling:DeleteScheduledAction", - "application-autoscaling:DeregisterScalableTarget", - "application-autoscaling:Describe*", - "application-autoscaling:PutScalingPolicy", - "application-autoscaling:PutScheduledAction", - "application-autoscaling:RegisterScalableTarget", - "kinesis:ListStreams", - "kinesis:DescribeStream", - "kinesis:PutRecords", - "kms:CreateGrant", - "kms:DescribeKey", - "kms:ListAliases", - "kms:Decrypt", - "kms:RevokeGrant", - "cloudwatch:PutMetricData", - "iam:CreateServiceLinkedRole" - ] - }, - "read": { - "permissions": [ - "dynamodb:Describe*", - "dynamodb:GetResourcePolicy", - "application-autoscaling:Describe*", - "cloudwatch:PutMetricData", - "dynamodb:ListTagsOfResource", - "kms:DescribeKey" - ] - }, - "update": { - "permissions": [ - "dynamodb:Describe*", - "dynamodb:CreateTableReplica", - "dynamodb:UpdateTable", - "dynamodb:UpdateTimeToLive", - "dynamodb:UpdateContinuousBackups", - "dynamodb:UpdateContributorInsights", - "dynamodb:ListTagsOfResource", - "dynamodb:Query", - "dynamodb:Scan", - "dynamodb:UpdateItem", - "dynamodb:PutItem", - "dynamodb:GetItem", - "dynamodb:DeleteItem", - "dynamodb:BatchWriteItem", - "dynamodb:DeleteTable", - "dynamodb:DeleteTableReplica", - "dynamodb:UpdateItem", - "dynamodb:TagResource", - "dynamodb:UntagResource", - "dynamodb:EnableKinesisStreamingDestination", - "dynamodb:DisableKinesisStreamingDestination", - "dynamodb:UpdateTableReplicaAutoScaling", - "dynamodb:UpdateKinesisStreamingDestination", - "dynamodb:GetResourcePolicy", - "dynamodb:PutResourcePolicy", - "dynamodb:DeleteResourcePolicy", - "application-autoscaling:DeleteScalingPolicy", - "application-autoscaling:DeleteScheduledAction", - "application-autoscaling:DeregisterScalableTarget", - "application-autoscaling:Describe*", - "application-autoscaling:PutScalingPolicy", - "application-autoscaling:PutScheduledAction", - "application-autoscaling:RegisterScalableTarget", - "kinesis:ListStreams", - "kinesis:DescribeStream", - "kinesis:PutRecords", - "kms:CreateGrant", - "kms:DescribeKey", - "kms:ListAliases", - "kms:RevokeGrant", - "cloudwatch:PutMetricData" - ], - "timeoutInMinutes": 1200 - }, - "delete": { - "permissions": [ - "dynamodb:Describe*", - "dynamodb:DeleteTable", - "application-autoscaling:DeleteScalingPolicy", - "application-autoscaling:DeleteScheduledAction", - "application-autoscaling:DeregisterScalableTarget", - "application-autoscaling:Describe*", - "application-autoscaling:PutScalingPolicy", - "application-autoscaling:PutScheduledAction", - "application-autoscaling:RegisterScalableTarget" - ] - }, - "list": { - "permissions": [ - "dynamodb:ListTables", - "cloudwatch:PutMetricData" - ] - } - } -} diff --git a/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-table.json b/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-table.json deleted file mode 100644 index 93e92f2c64b46..0000000000000 --- a/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-dynamodb-table.json +++ /dev/null @@ -1,591 +0,0 @@ -{ - "typeName" : "AWS::DynamoDB::Table", - "description" : "Version: None. Resource Type definition for AWS::DynamoDB::Table", - "additionalProperties" : false, - "nonPublicProperties": [ - "/properties/DynamoDBEndpoint" - ], - "properties" : { - "Arn" : { - "type" : "string" - }, - "StreamArn" : { - "type" : "string" - }, - "AttributeDefinitions" : { - "type" : "array", - "uniqueItems" : true, - "items" : { - "$ref" : "#/definitions/AttributeDefinition" - } - }, - "BillingMode" : { - "type" : "string" - }, - "DynamoDBEndpoint" : { - "type" : "string" - }, - "DeletionProtectionEnabled" : { - "type" : "boolean" - }, - "GlobalSecondaryIndexes" : { - "type" : "array", - "uniqueItems" : false, - "items" : { - "$ref" : "#/definitions/GlobalSecondaryIndex" - } - }, - "KeySchema" : { - "oneOf": [ - { - "type" : "array", - "uniqueItems" : true, - "items" : { - "$ref" : "#/definitions/KeySchema" - } - }, - { - "type": "object" - } - ] - }, - "LocalSecondaryIndexes" : { - "type" : "array", - "uniqueItems" : false, - "items" : { - "$ref" : "#/definitions/LocalSecondaryIndex" - } - }, - "OnDemandThroughput" : { - "$ref" : "#/definitions/OnDemandThroughput" - }, - "WarmThroughput" : { - "$ref" : "#/definitions/WarmThroughput" - }, - "PointInTimeRecoverySpecification" : { - "$ref" : "#/definitions/PointInTimeRecoverySpecification" - }, - "TableClass" : { - "type" : "string" - }, - "ProvisionedThroughput" : { - "$ref" : "#/definitions/ProvisionedThroughput" - }, - "SSESpecification" : { - "$ref" : "#/definitions/SSESpecification" - }, - "StreamSpecification" : { - "$ref" : "#/definitions/StreamSpecification" - }, - "TableName" : { - "type" : "string" - }, - "Tags" : { - "type" : "array", - "uniqueItems" : false, - "items" : { - "$ref" : "#/definitions/Tag" - } - }, - "TimeToLiveSpecification" : { - "$ref" : "#/definitions/TimeToLiveSpecification" - }, - "ContributorInsightsSpecification": { - "$ref": "#/definitions/ContributorInsightsSpecification" - }, - "KinesisStreamSpecification": { - "$ref": "#/definitions/KinesisStreamSpecification" - }, - "ImportSourceSpecification" : { - "$ref": "#/definitions/ImportSourceSpecification" - }, - "ResourcePolicy": { - "$ref": "#/definitions/ResourcePolicy" - } - }, - "propertyTransform": { - "/properties/SSESpecification/KMSMasterKeyId": "$join([\"arn:aws(-[a-z]{1,4}){0,2}:kms:[a-z]{2,4}(-[a-z]{1,4})?-[a-z]{1,10}-[0-9]:[0-9]{12}:key\\/\", SSESpecification.KMSMasterKeyId]) $OR $join([\"arn:aws(-[a-z]{1,4}){0,2}:kms:[a-z]{2,4}(-[a-z]{1,4})?-[a-z]{1,10}-[0-9]:[0-9]{12}:key\\/\", KMSMasterKeyId])" - }, - "definitions" : { - "StreamSpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "StreamViewType" : { - "type" : "string" - }, - "ResourcePolicy": { - "$ref": "#/definitions/ResourcePolicy" - } - }, - "required" : [ "StreamViewType" ] - }, - "DeprecatedKeySchema" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "HashKeyElement" : { - "$ref" : "#/definitions/DeprecatedHashKeyElement" - } - }, - "required" : [ "HashKeyElement" ] - }, - "DeprecatedHashKeyElement" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "AttributeType" : { - "type" : "string" - }, - "AttributeName" : { - "type" : "string" - } - }, - "required" : [ "AttributeType", "AttributeName" ] - }, - "KeySchema" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "AttributeName" : { - "type" : "string" - }, - "KeyType" : { - "type" : "string" - } - }, - "required" : [ "KeyType", "AttributeName" ] - }, - "PointInTimeRecoverySpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "PointInTimeRecoveryEnabled" : { - "type" : "boolean" - } - } - }, - "KinesisStreamSpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "StreamArn" : { - "type" : "string", - "relationshipRef": { - "typeName": "AWS::Kinesis::Stream", - "propertyPath": "/properties/Arn" - } - }, - "ApproximateCreationDateTimePrecision" : { - "type": "string", - "enum": [ - "MICROSECOND", - "MILLISECOND" - ] - } - }, - "required" : [ "StreamArn" ] - }, - "TimeToLiveSpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "AttributeName" : { - "type" : "string" - }, - "Enabled" : { - "type" : "boolean" - } - }, - "required" : [ "Enabled" ] - }, - "LocalSecondaryIndex" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "IndexName" : { - "type" : "string" - }, - "KeySchema" : { - "type" : "array", - "uniqueItems" : true, - "items" : { - "$ref" : "#/definitions/KeySchema" - } - }, - "Projection" : { - "$ref" : "#/definitions/Projection" - } - }, - "required" : [ "IndexName", "Projection", "KeySchema" ] - }, - "GlobalSecondaryIndex" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "IndexName" : { - "type" : "string" - }, - "KeySchema" : { - "type" : "array", - "uniqueItems" : true, - "items" : { - "$ref" : "#/definitions/KeySchema" - } - }, - "Projection" : { - "$ref" : "#/definitions/Projection" - }, - "ProvisionedThroughput" : { - "$ref" : "#/definitions/ProvisionedThroughput" - }, - "OnDemandThroughput" : { - "$ref" : "#/definitions/OnDemandThroughput" - }, - "WarmThroughput" : { - "$ref" : "#/definitions/WarmThroughput" - }, - "ContributorInsightsSpecification": { - "$ref": "#/definitions/ContributorInsightsSpecification" - } - }, - "required" : [ "IndexName", "Projection", "KeySchema" ] - }, - "OnDemandThroughput" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "MaxReadRequestUnits" : { - "type" : "integer", - "minimum": 1 - }, - "MaxWriteRequestUnits" : { - "type" : "integer", - "minimum": 1 - } - } - }, - "WarmThroughput" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "ReadUnitsPerSecond" : { - "type" : "integer", - "minimum": 1 - }, - "WriteUnitsPerSecond" : { - "type" : "integer", - "minimum": 1 - } - }, - "anyOf": [ - {"required": ["ReadUnitsPerSecond"]}, - {"required": ["WriteUnitsPerSecond"]} - ] - }, - "SSESpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "KMSMasterKeyId" : { - "type" : "string", - "anyOf": [{ - "relationshipRef": { - "typeName": "AWS::KMS::Key", - "propertyPath": "/properties/Arn" - }},{ - "relationshipRef": { - "typeName": "AWS::KMS::Key", - "propertyPath": "/properties/KeyId" - }}, { - "relationshipRef": { - "typeName": "AWS::KMS::Alias", - "propertyPath": "/properties/AliasName" - } - }] - }, - "SSEEnabled" : { - "type" : "boolean" - }, - "SSEType" : { - "type" : "string" - } - }, - "required" : [ "SSEEnabled" ] - }, - "AttributeDefinition" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "AttributeName" : { - "type" : "string" - }, - "AttributeType" : { - "type" : "string" - } - }, - "required" : [ "AttributeName", "AttributeType" ] - }, - "ProvisionedThroughput" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "ReadCapacityUnits" : { - "type" : "integer" - }, - "WriteCapacityUnits" : { - "type" : "integer" - } - }, - "required" : [ "WriteCapacityUnits", "ReadCapacityUnits" ] - }, - "Tag" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "Key" : { - "type" : "string" - }, - "Value" : { - "type" : "string" - } - }, - "required" : [ "Value", "Key" ] - }, - "Projection" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "NonKeyAttributes" : { - "type" : "array", - "uniqueItems" : false, - "items" : { - "type" : "string" - } - }, - "ProjectionType" : { - "type" : "string" - } - } - }, - "ContributorInsightsSpecification": { - "type": "object", - "additionalProperties": false, - "properties": { - "Enabled": { - "type": "boolean" - }, - "ContributorInsightsMode": { - "type": "string", - "enum": [ - "ACCESSED_AND_THROTTLED_KEYS", - "THROTTLED_KEYS" - ] - } - }, - "required" : [ "Enabled" ] - }, - "ImportSourceSpecification" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "S3BucketSource" : { - "$ref" : "#/definitions/S3BucketSource" - }, - "InputFormat" : { - "type" : "string" - }, - "InputFormatOptions" : { - "$ref" : "#/definitions/InputFormatOptions" - }, - "InputCompressionType" : { - "type" : "string" - } - }, - "required" : [ - "S3BucketSource", - "InputFormat" - ] - }, - "S3BucketSource" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "S3BucketOwner" : { - "type" : "string" - }, - "S3Bucket" : { - "type" : "string", - "relationshipRef": { - "typeName": "AWS::S3::Bucket", - "propertyPath": "/properties/BucketName" - } - }, - "S3KeyPrefix" : { - "type" : "string" - } - }, - "required" : [ - "S3Bucket" - ] - }, - "InputFormatOptions" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "Csv" : { - "$ref" : "#/definitions/Csv" - } - } - }, - "Csv" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "HeaderList" : { - "type" : "array", - "uniqueItems" : true, - "items" : { - "type" : "string" - } - }, - "Delimiter" : { - "type" : "string" - } - } - }, - "ResourcePolicy": { - "type": "object", - "additionalProperties": false, - "properties": { - "PolicyDocument": { - "type": "object" - } - }, - "required": [ - "PolicyDocument" - ] - } - }, - "tagging": { - "taggable": true, - "tagOnCreate": true, - "tagUpdatable": true, - "cloudFormationSystemTags": false, - "tagProperty": "/properties/Tags", - "permissions": [ - "dynamodb:TagResource", - "dynamodb:UntagResource", - "dynamodb:ListTagsOfResource" - ] - }, - "required" : [ "KeySchema" ], - "readOnlyProperties" : [ "/properties/Arn", "/properties/StreamArn" ], - "createOnlyProperties" : [ - "/properties/TableName", - "/properties/DynamoDBEndpoint", - "/properties/ImportSourceSpecification" - ], - "conditionalCreateOnlyProperties": [ - "/properties/KeySchema" - ], - "primaryIdentifier" : [ "/properties/TableName" ], - "writeOnlyProperties": [ - "/properties/ImportSourceSpecification" - ], - "handlers": { - "create": { - "permissions": [ - "dynamodb:CreateTable", - "dynamodb:DescribeImport", - "dynamodb:DescribeTable", - "dynamodb:DescribeTimeToLive", - "dynamodb:UpdateTimeToLive", - "dynamodb:UpdateContributorInsights", - "dynamodb:UpdateContinuousBackups", - "dynamodb:DescribeContinuousBackups", - "dynamodb:DescribeContributorInsights", - "dynamodb:EnableKinesisStreamingDestination", - "dynamodb:DisableKinesisStreamingDestination", - "dynamodb:DescribeKinesisStreamingDestination", - "dynamodb:ImportTable", - "dynamodb:ListTagsOfResource", - "dynamodb:TagResource", - "dynamodb:UpdateTable", - "dynamodb:GetResourcePolicy", - "dynamodb:PutResourcePolicy", - "kinesis:DescribeStream", - "kinesis:PutRecords", - "iam:CreateServiceLinkedRole", - "kms:CreateGrant", - "kms:Decrypt", - "kms:DescribeKey", - "kms:ListAliases", - "kms:Encrypt", - "kms:RevokeGrant", - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - "logs:PutRetentionPolicy", - "s3:GetObject", - "s3:GetObjectMetadata", - "s3:ListBucket" - ], - "timeoutInMinutes": 720 - }, - "read": { - "permissions": [ - "dynamodb:DescribeTable", - "dynamodb:DescribeContinuousBackups", - "dynamodb:DescribeContributorInsights", - "dynamodb:DescribeKinesisStreamingDestination", - "dynamodb:ListTagsOfResource", - "dynamodb:GetResourcePolicy" - ] - }, - "update": { - "permissions": [ - "dynamodb:UpdateTable", - "dynamodb:DescribeTable", - "dynamodb:DescribeTimeToLive", - "dynamodb:UpdateTimeToLive", - "dynamodb:UpdateContinuousBackups", - "dynamodb:UpdateContributorInsights", - "dynamodb:UpdateKinesisStreamingDestination", - "dynamodb:DescribeContinuousBackups", - "dynamodb:DescribeKinesisStreamingDestination", - "dynamodb:ListTagsOfResource", - "dynamodb:TagResource", - "dynamodb:UntagResource", - "dynamodb:DescribeContributorInsights", - "dynamodb:EnableKinesisStreamingDestination", - "dynamodb:DisableKinesisStreamingDestination", - "dynamodb:GetResourcePolicy", - "dynamodb:PutResourcePolicy", - "dynamodb:DeleteResourcePolicy", - "kinesis:DescribeStream", - "kinesis:PutRecords", - "iam:CreateServiceLinkedRole", - "kms:CreateGrant", - "kms:DescribeKey", - "kms:ListAliases", - "kms:RevokeGrant" - ], - "timeoutInMinutes": 720 - }, - "delete": { - "permissions": [ - "dynamodb:DeleteTable", - "dynamodb:DescribeTable" - ], - "timeoutInMinutes": 720 - }, - "list": { - "permissions": [ - "dynamodb:ListTables" - ] - } - } -} From 024552d4af1aeda5c66f03eed6b2935febe40c03 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Thu, 21 Aug 2025 15:56:14 +0100 Subject: [PATCH 15/18] Changing mode based on CFN change in schema --- .../CCI-Integ-Test.assets.json | 21 + .../CCI-Integ-Test.template.json | 120 ++++ .../integ.dynamodb-v2.cci.js.snapshot/cdk.out | 1 + .../integ.json | 13 + .../manifest.json | 602 ++++++++++++++++++ ...efaultTestDeployAssertAA263ACC.assets.json | 20 + ...aultTestDeployAssertAA263ACC.template.json | 36 ++ .../tree.json | 1 + .../test/integ.dynamodb-v2.cci.ts | 4 +- .../CCI-Integ-Test-TableV1.assets.json | 21 + .../CCI-Integ-Test-TableV1.template.json | 73 +++ .../integ.dynamodb.cci.js.snapshot/cdk.out | 1 + .../integ.dynamodb.cci.js.snapshot/integ.json | 13 + .../manifest.json | 600 +++++++++++++++++ ...efaultTestDeployAssertDBB26C85.assets.json | 20 + ...aultTestDeployAssertDBB26C85.template.json | 36 ++ .../integ.dynamodb.cci.js.snapshot/tree.json | 1 + .../aws-dynamodb/test/integ.dynamodb.cci.ts | 27 + .../aws-cdk-lib/aws-dynamodb/lib/shared.ts | 2 +- .../aws-dynamodb/test/dynamodb.test.ts | 14 +- .../aws-dynamodb/test/table-v2.test.ts | 16 +- 21 files changed, 1624 insertions(+), 18 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/CCI-Integ-Test.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/CCI-Integ-Test.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tablev2CCItestDefaultTestDeployAssertAA263ACC.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tablev2CCItestDefaultTestDeployAssertAA263ACC.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/CCI-Integ-Test-TableV1.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/CCI-Integ-Test-TableV1.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tablev1CCItestDefaultTestDeployAssertDBB26C85.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tablev1CCItestDefaultTestDeployAssertDBB26C85.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/CCI-Integ-Test.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/CCI-Integ-Test.assets.json new file mode 100644 index 0000000000000..c4399b00ee161 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/CCI-Integ-Test.assets.json @@ -0,0 +1,21 @@ +{ + "version": "48.0.0", + "files": { + "7f9710fa9aec7f69afe9933a284d4f49af3532b86617d16428e4a76db826605f": { + "displayName": "CCI-Integ-Test Template", + "source": { + "path": "CCI-Integ-Test.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-eu-west-1-fc8ce685": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-eu-west-1", + "objectKey": "7f9710fa9aec7f69afe9933a284d4f49af3532b86617d16428e4a76db826605f.json", + "region": "eu-west-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-eu-west-1" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/CCI-Integ-Test.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/CCI-Integ-Test.template.json new file mode 100644 index 0000000000000..9a80c5d2f73ac --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/CCI-Integ-Test.template.json @@ -0,0 +1,120 @@ +{ + "Resources": { + "TableV26B253703": { + "Type": "AWS::DynamoDB::GlobalTable", + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "hashKey", + "AttributeType": "S" + }, + { + "AttributeName": "sortKey", + "AttributeType": "N" + }, + { + "AttributeName": "gsiHashKey", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST", + "GlobalSecondaryIndexes": [ + { + "IndexName": "gsi", + "KeySchema": [ + { + "AttributeName": "gsiHashKey", + "KeyType": "HASH" + } + ], + "Projection": { + "ProjectionType": "ALL" + } + } + ], + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "sortKey", + "KeyType": "RANGE" + } + ], + "Replicas": [ + { + "ContributorInsightsSpecification": { + "Enabled": false + }, + "GlobalSecondaryIndexes": [ + { + "ContributorInsightsSpecification": { + "Enabled": true, + "Mode": "THROTTLED_KEYS" + }, + "IndexName": "gsi" + } + ], + "Region": "eu-west-2" + }, + { + "ContributorInsightsSpecification": { + "Enabled": true, + "Mode": "ACCESSED_AND_THROTTLED_KEYS" + }, + "GlobalSecondaryIndexes": [ + { + "ContributorInsightsSpecification": { + "Enabled": true, + "Mode": "ACCESSED_AND_THROTTLED_KEYS" + }, + "IndexName": "gsi" + } + ], + "Region": "eu-west-1" + } + ], + "StreamSpecification": { + "StreamViewType": "NEW_AND_OLD_IMAGES" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + } + }, + "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-v2.cci.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/cdk.out new file mode 100644 index 0000000000000..523a9aac37cbf --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"48.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/integ.json new file mode 100644 index 0000000000000..9667739505632 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "48.0.0", + "testCases": { + "table-v2-CCI-test/DefaultTest": { + "stacks": [ + "CCI-Integ-Test" + ], + "assertionStack": "table-v2-CCI-test/DefaultTest/DeployAssert", + "assertionStackName": "tablev2CCItestDefaultTestDeployAssertAA263ACC" + } + }, + "minimumCliVersion": "2.1025.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/manifest.json new file mode 100644 index 0000000000000..0490dd3afcd8f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/manifest.json @@ -0,0 +1,602 @@ +{ + "version": "48.0.0", + "artifacts": { + "CCI-Integ-Test.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "CCI-Integ-Test.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "CCI-Integ-Test": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/eu-west-1", + "properties": { + "templateFile": "CCI-Integ-Test.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-eu-west-1", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-eu-west-1", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-eu-west-1/7f9710fa9aec7f69afe9933a284d4f49af3532b86617d16428e4a76db826605f.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "CCI-Integ-Test.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-eu-west-1", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "CCI-Integ-Test.assets" + ], + "metadata": { + "/CCI-Integ-Test/TableV2": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/CCI-Integ-Test/TableV2/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TableV26B253703" + } + ], + "/CCI-Integ-Test/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/CCI-Integ-Test/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "CCI-Integ-Test" + }, + "tablev2CCItestDefaultTestDeployAssertAA263ACC.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "tablev2CCItestDefaultTestDeployAssertAA263ACC.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "tablev2CCItestDefaultTestDeployAssertAA263ACC": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "tablev2CCItestDefaultTestDeployAssertAA263ACC.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": [ + "tablev2CCItestDefaultTestDeployAssertAA263ACC.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": [ + "tablev2CCItestDefaultTestDeployAssertAA263ACC.assets" + ], + "metadata": { + "/table-v2-CCI-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/table-v2-CCI-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "table-v2-CCI-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-lib/feature-flag-report": { + "type": "cdk:feature-flag-report", + "properties": { + "module": "aws-cdk-lib", + "flags": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": { + "recommendedValue": true, + "explanation": "Pass signingProfileName to CfnSigningProfile" + }, + "@aws-cdk/core:newStyleStackSynthesis": { + "recommendedValue": true, + "explanation": "Switch to new stack synthesis method which enables CI/CD", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:stackRelativeExports": { + "recommendedValue": true, + "explanation": "Name exports based on the construct paths relative to the stack, rather than the global construct path", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": { + "recommendedValue": true, + "explanation": "Force lowercasing of RDS Cluster names in CDK", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": { + "recommendedValue": true, + "explanation": "Allow adding/removing multiple UsagePlanKeys independently", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeVersionProps": { + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeLayerVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`." + }, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": { + "recommendedValue": true, + "explanation": "Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:checkSecretUsage": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations" + }, + "@aws-cdk/core:target-partitions": { + "recommendedValue": [ + "aws", + "aws-cn" + ], + "explanation": "What regions to include in lookup tables of environment agnostic stacks" + }, + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": { + "userValue": true, + "recommendedValue": true, + "explanation": "ECS extensions will automatically add an `awslogs` driver if no logging is specified" + }, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names." + }, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": { + "userValue": true, + "recommendedValue": true, + "explanation": "ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID." + }, + "@aws-cdk/aws-iam:minimizePolicies": { + "userValue": true, + "recommendedValue": true, + "explanation": "Minimize IAM policies by combining Statements" + }, + "@aws-cdk/core:validateSnapshotRemovalPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Error on snapshot removal policies on resources that do not support it." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate key aliases that include the stack name" + }, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist." + }, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict KMS key policy for encrypted Queues a bit more" + }, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make default CloudWatch Role behavior safe for multiple API Gateways in one environment" + }, + "@aws-cdk/core:enablePartitionLiterals": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make ARNs concrete if AWS partition is known" + }, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": { + "userValue": true, + "recommendedValue": true, + "explanation": "Event Rules may only push to encrypted SQS queues in the same account" + }, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": { + "userValue": true, + "recommendedValue": true, + "explanation": "Avoid setting the \"ECS\" deployment controller when adding a circuit breaker" + }, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature to by default create default policy names for imported roles that depend on the stack the role is in." + }, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use S3 Bucket Policy instead of ACLs for Server Access Logging" + }, + "@aws-cdk/aws-route53-patters:useCertificate": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use the official `Certificate` resource instead of `DnsValidatedCertificate`" + }, + "@aws-cdk/customresources:installLatestAwsSdkDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "Whether to install the latest SDK by default in AwsCustomResource" + }, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use unique resource name for Database Proxy" + }, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Remove CloudWatch alarms from deployment group" + }, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include authorizer configuration in the calculation of the API deployment logical ID." + }, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": { + "userValue": true, + "recommendedValue": true, + "explanation": "Define user data for a launch template by default when a machine image is provided." + }, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": { + "userValue": true, + "recommendedValue": true, + "explanation": "SecretTargetAttachments uses the ResourcePolicy of the attached Secret." + }, + "@aws-cdk/aws-redshift:columnId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Whether to use an ID to track Redshift column changes" + }, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable AmazonEMRServicePolicy_v2 managed policies" + }, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict access to the VPC default security group" + }, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a unique id for each RequestValidator added to a method" + }, + "@aws-cdk/aws-kms:aliasNameRef": { + "userValue": true, + "recommendedValue": true, + "explanation": "KMS Alias name and keyArn will have implicit reference to KMS Key" + }, + "@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable grant methods on Aliases imported by name to use kms:ResourceAliases condition" + }, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a launch template when creating an AutoScalingGroup" + }, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include the stack prefix in the stack name generation process" + }, + "@aws-cdk/aws-efs:denyAnonymousAccess": { + "userValue": true, + "recommendedValue": true, + "explanation": "EFS denies anonymous clients accesses" + }, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables support for Multi-AZ with Standby deployment for opensearch domains" + }, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables aws-lambda-nodejs.Function to use the latest available NodeJs runtime as the default" + }, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, mount targets will have a stable logicalId that is linked to the associated subnet." + }, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a scope of InstanceParameterGroup for AuroraClusterInstance with each parameters will change." + }, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, will always use the arn for identifiers for CfnSourceApiAssociation in the GraphqlApi construct rather than id." + }, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, creating an RDS database cluster from a snapshot will only render credentials for snapshot credentials." + }, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the CodeCommit source action is using the default branch name 'main'." + }, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the logical ID of a Lambda permission for a Lambda action includes an alarm ID." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default value for crossAccountKeys to false." + }, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default pipeline type to V2." + }, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, IAM Policy created from KMS key grant will reduce the resource scope to this key only." + }, + "@aws-cdk/pipelines:reduceAssetRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from PipelineAssetsFileRole trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-eks:nodegroupNameAttribute": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, nodegroupName attribute of the provisioned EKS NodeGroup will not have the cluster name prefix." + }, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default volume type of the EBS volume will be GP3" + }, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, remove default deployment alarm settings" + }, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default" + }, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack." + }, + "@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": { + "recommendedValue": true, + "explanation": "When enabled, use new props for S3 URI field in task definition of state machine for bedrock invoke model.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:explicitStackTags": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, stack tags need to be assigned explicitly on a Stack." + }, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": { + "userValue": false, + "recommendedValue": false, + "explanation": "When set to true along with canContainersAccessInstanceRole=false in ECS cluster, new updated commands will be added to UserData to block container accessing IMDS. **Applicable to Linux only. IMPORTANT: See [details.](#aws-cdkaws-ecsenableImdsBlockingDeprecatedFeature)**" + }, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, CDK synth will throw exception if canContainersAccessInstanceRole is false. **IMPORTANT: See [details.](#aws-cdkaws-ecsdisableEcsImdsBlocking)**" + }, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, we will only grant the necessary permissions when users specify cloudwatch log group through logConfiguration" + }, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled will allow you to specify a resource policy per replica, and not copy the source table policy to all replicas" + }, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, initOptions.timeout and resourceSignalTimeout values will be summed together." + }, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a Lambda authorizer Permission created when using GraphqlApi will be properly scoped with a SourceArn." + }, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the value of property `instanceResourceId` in construct `DatabaseInstanceReadReplica` will be set to the correct value which is `DbiResourceId` instead of currently `DbInstanceArn`" + }, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CFN templates added with `cfn-include` will error if the template contains Resource Update or Create policies with CFN Intrinsics that include non-primitive values." + }, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, both `@aws-sdk` and `@smithy` packages will be excluded from the Lambda Node.js 18.x runtime to prevent version mismatches in bundled applications." + }, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resource of IAM Run Ecs policy generated by SFN EcsRunTask will reference the definition, instead of constructing ARN." + }, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the BastionHost construct will use the latest Amazon Linux 2023 AMI, instead of Amazon Linux 2." + }, + "@aws-cdk/core:aspectStabilization": { + "recommendedValue": true, + "explanation": "When enabled, a stabilization loop will be run when invoking Aspects during synthesis.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, use a new method for DNS Name of user pool domain target without creating a custom resource." + }, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default security group ingress rules will allow IPv6 ingress from anywhere" + }, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default behaviour of OIDC provider will reject unauthorized connections" + }, + "@aws-cdk/core:enableAdditionalMetadataCollection": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will expand the scope of usage data collected to better inform CDK development and improve communication for security concerns and emerging issues." + }, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": { + "userValue": false, + "recommendedValue": false, + "explanation": "[Deprecated] When enabled, Lambda will create new inline policies with AddToRolePolicy instead of adding to the Default Policy Statement" + }, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will automatically generate a unique role name that is used for s3 object replication." + }, + "@aws-cdk/pipelines:reduceStageRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from Stage addActions trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-events:requireEventBusPolicySid": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, grantPutEventsTo() will use resource policies with Statement IDs for service principals." + }, + "@aws-cdk/core:aspectPrioritiesMutating": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, Aspects added by the construct library on your behalf will be given a priority of MUTATING." + }, + "@aws-cdk/aws-dynamodb:retainTableReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, table replica will be default to the removal policy of source table unless specified otherwise." + }, + "@aws-cdk/cognito:logUserPoolClientSecretValue": { + "recommendedValue": false, + "explanation": "When disabled, the value of the user pool client secret will not be logged in the custom resource lambda function logs." + }, + "@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": { + "recommendedValue": true, + "explanation": "When enabled, scopes down the trust policy for the cross-account action role", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resultWriterV2 property of DistributedMap will be used insted of resultWriter" + }, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": { + "userValue": true, + "recommendedValue": true, + "explanation": "Add an S3 trust policy to a KMS key resource policy for SNS subscriptions." + }, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the EgressOnlyGateway resource is only created if private subnets are defined in the dual-stack VPC." + }, + "@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": { + "recommendedValue": false, + "explanation": "When enabled, use resource IDs for VPC V2 migration" + }, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, setting any combination of options for BlockPublicAccess will automatically set true for any options not defined." + }, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK creates and manages loggroup for the lambda function" + } + } + } + } + }, + "minimumCliVersion": "2.1025.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tablev2CCItestDefaultTestDeployAssertAA263ACC.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tablev2CCItestDefaultTestDeployAssertAA263ACC.assets.json new file mode 100644 index 0000000000000..97f7acddc42b5 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tablev2CCItestDefaultTestDeployAssertAA263ACC.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "tablev2CCItestDefaultTestDeployAssertAA263ACC Template", + "source": { + "path": "tablev2CCItestDefaultTestDeployAssertAA263ACC.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-d8d86b35": { + "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-v2.cci.js.snapshot/tablev2CCItestDefaultTestDeployAssertAA263ACC.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tablev2CCItestDefaultTestDeployAssertAA263ACC.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tablev2CCItestDefaultTestDeployAssertAA263ACC.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-v2.cci.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tree.json new file mode 100644 index 0000000000000..e0034b63a389c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"CCI-Integ-Test":{"id":"CCI-Integ-Test","path":"CCI-Integ-Test","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"TableV2":{"id":"TableV2","path":"CCI-Integ-Test/TableV2","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*","*","*"]},"children":{"Resource":{"id":"Resource","path":"CCI-Integ-Test/TableV2/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.CfnGlobalTable","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::DynamoDB::GlobalTable","aws:cdk:cloudformation:props":{"attributeDefinitions":[{"attributeName":"hashKey","attributeType":"S"},{"attributeName":"sortKey","attributeType":"N"},{"attributeName":"gsiHashKey","attributeType":"S"}],"billingMode":"PAY_PER_REQUEST","globalSecondaryIndexes":[{"indexName":"gsi","keySchema":[{"attributeName":"gsiHashKey","keyType":"HASH"}],"projection":{"projectionType":"ALL"}}],"keySchema":[{"attributeName":"hashKey","keyType":"HASH"},{"attributeName":"sortKey","keyType":"RANGE"}],"replicas":[{"region":"eu-west-2","globalSecondaryIndexes":[{"indexName":"gsi","contributorInsightsSpecification":{"enabled":true,"mode":"THROTTLED_KEYS"}}],"contributorInsightsSpecification":{"enabled":false}},{"region":"eu-west-1","globalSecondaryIndexes":[{"indexName":"gsi","contributorInsightsSpecification":{"enabled":true,"mode":"ACCESSED_AND_THROTTLED_KEYS"}}],"contributorInsightsSpecification":{"enabled":true,"mode":"ACCESSED_AND_THROTTLED_KEYS"}}],"streamSpecification":{"streamViewType":"NEW_AND_OLD_IMAGES"}}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"CCI-Integ-Test/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"CCI-Integ-Test/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"table-v2-CCI-test":{"id":"table-v2-CCI-test","path":"table-v2-CCI-test","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"table-v2-CCI-test/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"table-v2-CCI-test/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"table-v2-CCI-test/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"table-v2-CCI-test/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"table-v2-CCI-test/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts index 44ba6ce5968d9..a657fc3cb1b9e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb-v2.cci.ts @@ -20,7 +20,7 @@ class TestStack extends Stack { ], contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: dynamodb.ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + mode: dynamodb.ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, replicas: [ { @@ -32,7 +32,7 @@ class TestStack extends Stack { gsi: { contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: dynamodb.ContributorInsightsMode.THROTTLED_KEYS, + mode: dynamodb.ContributorInsightsMode.THROTTLED_KEYS, }, }, }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/CCI-Integ-Test-TableV1.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/CCI-Integ-Test-TableV1.assets.json new file mode 100644 index 0000000000000..3e219ee37f424 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/CCI-Integ-Test-TableV1.assets.json @@ -0,0 +1,21 @@ +{ + "version": "48.0.0", + "files": { + "54c014693be4516cd0b495b05171f2ae07daa7dde672676af6d5a0615b32300f": { + "displayName": "CCI-Integ-Test-TableV1 Template", + "source": { + "path": "CCI-Integ-Test-TableV1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-eu-west-1-29121961": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-eu-west-1", + "objectKey": "54c014693be4516cd0b495b05171f2ae07daa7dde672676af6d5a0615b32300f.json", + "region": "eu-west-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-eu-west-1" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/CCI-Integ-Test-TableV1.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/CCI-Integ-Test-TableV1.template.json new file mode 100644 index 0000000000000..77ad3da72e2f4 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/CCI-Integ-Test-TableV1.template.json @@ -0,0 +1,73 @@ +{ + "Resources": { + "TableV26B253703": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "hashKey", + "AttributeType": "S" + }, + { + "AttributeName": "sortKey", + "AttributeType": "N" + } + ], + "ContributorInsightsSpecification": { + "Enabled": true, + "Mode": "ACCESSED_AND_THROTTLED_KEYS" + }, + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "sortKey", + "KeyType": "RANGE" + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + } + }, + "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.cci.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/cdk.out new file mode 100644 index 0000000000000..523a9aac37cbf --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"48.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/integ.json new file mode 100644 index 0000000000000..d20f9fa2150f7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "48.0.0", + "testCases": { + "table-v1-CCI-test/DefaultTest": { + "stacks": [ + "CCI-Integ-Test-TableV1" + ], + "assertionStack": "table-v1-CCI-test/DefaultTest/DeployAssert", + "assertionStackName": "tablev1CCItestDefaultTestDeployAssertDBB26C85" + } + }, + "minimumCliVersion": "2.1025.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/manifest.json new file mode 100644 index 0000000000000..714ec3de57e49 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/manifest.json @@ -0,0 +1,600 @@ +{ + "version": "48.0.0", + "artifacts": { + "CCI-Integ-Test-TableV1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "CCI-Integ-Test-TableV1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "CCI-Integ-Test-TableV1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/eu-west-1", + "properties": { + "templateFile": "CCI-Integ-Test-TableV1.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-eu-west-1", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-eu-west-1", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-eu-west-1/54c014693be4516cd0b495b05171f2ae07daa7dde672676af6d5a0615b32300f.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "CCI-Integ-Test-TableV1.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-eu-west-1", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "CCI-Integ-Test-TableV1.assets" + ], + "metadata": { + "/CCI-Integ-Test-TableV1/TableV2": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/CCI-Integ-Test-TableV1/TableV2/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TableV26B253703" + } + ], + "/CCI-Integ-Test-TableV1/TableV2/ScalingRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/CCI-Integ-Test-TableV1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/CCI-Integ-Test-TableV1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "CCI-Integ-Test-TableV1" + }, + "tablev1CCItestDefaultTestDeployAssertDBB26C85.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "tablev1CCItestDefaultTestDeployAssertDBB26C85.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "tablev1CCItestDefaultTestDeployAssertDBB26C85": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "tablev1CCItestDefaultTestDeployAssertDBB26C85.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": [ + "tablev1CCItestDefaultTestDeployAssertDBB26C85.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": [ + "tablev1CCItestDefaultTestDeployAssertDBB26C85.assets" + ], + "metadata": { + "/table-v1-CCI-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/table-v1-CCI-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "table-v1-CCI-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-lib/feature-flag-report": { + "type": "cdk:feature-flag-report", + "properties": { + "module": "aws-cdk-lib", + "flags": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": { + "recommendedValue": true, + "explanation": "Pass signingProfileName to CfnSigningProfile" + }, + "@aws-cdk/core:newStyleStackSynthesis": { + "recommendedValue": true, + "explanation": "Switch to new stack synthesis method which enables CI/CD", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:stackRelativeExports": { + "recommendedValue": true, + "explanation": "Name exports based on the construct paths relative to the stack, rather than the global construct path", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": { + "recommendedValue": true, + "explanation": "Force lowercasing of RDS Cluster names in CDK", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": { + "recommendedValue": true, + "explanation": "Allow adding/removing multiple UsagePlanKeys independently", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeVersionProps": { + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeLayerVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`." + }, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": { + "recommendedValue": true, + "explanation": "Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:checkSecretUsage": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations" + }, + "@aws-cdk/core:target-partitions": { + "recommendedValue": [ + "aws", + "aws-cn" + ], + "explanation": "What regions to include in lookup tables of environment agnostic stacks" + }, + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": { + "userValue": true, + "recommendedValue": true, + "explanation": "ECS extensions will automatically add an `awslogs` driver if no logging is specified" + }, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names." + }, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": { + "userValue": true, + "recommendedValue": true, + "explanation": "ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID." + }, + "@aws-cdk/aws-iam:minimizePolicies": { + "userValue": true, + "recommendedValue": true, + "explanation": "Minimize IAM policies by combining Statements" + }, + "@aws-cdk/core:validateSnapshotRemovalPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Error on snapshot removal policies on resources that do not support it." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate key aliases that include the stack name" + }, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist." + }, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict KMS key policy for encrypted Queues a bit more" + }, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make default CloudWatch Role behavior safe for multiple API Gateways in one environment" + }, + "@aws-cdk/core:enablePartitionLiterals": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make ARNs concrete if AWS partition is known" + }, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": { + "userValue": true, + "recommendedValue": true, + "explanation": "Event Rules may only push to encrypted SQS queues in the same account" + }, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": { + "userValue": true, + "recommendedValue": true, + "explanation": "Avoid setting the \"ECS\" deployment controller when adding a circuit breaker" + }, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature to by default create default policy names for imported roles that depend on the stack the role is in." + }, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use S3 Bucket Policy instead of ACLs for Server Access Logging" + }, + "@aws-cdk/aws-route53-patters:useCertificate": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use the official `Certificate` resource instead of `DnsValidatedCertificate`" + }, + "@aws-cdk/customresources:installLatestAwsSdkDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "Whether to install the latest SDK by default in AwsCustomResource" + }, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use unique resource name for Database Proxy" + }, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Remove CloudWatch alarms from deployment group" + }, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include authorizer configuration in the calculation of the API deployment logical ID." + }, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": { + "userValue": true, + "recommendedValue": true, + "explanation": "Define user data for a launch template by default when a machine image is provided." + }, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": { + "userValue": true, + "recommendedValue": true, + "explanation": "SecretTargetAttachments uses the ResourcePolicy of the attached Secret." + }, + "@aws-cdk/aws-redshift:columnId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Whether to use an ID to track Redshift column changes" + }, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable AmazonEMRServicePolicy_v2 managed policies" + }, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict access to the VPC default security group" + }, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a unique id for each RequestValidator added to a method" + }, + "@aws-cdk/aws-kms:aliasNameRef": { + "userValue": true, + "recommendedValue": true, + "explanation": "KMS Alias name and keyArn will have implicit reference to KMS Key" + }, + "@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable grant methods on Aliases imported by name to use kms:ResourceAliases condition" + }, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a launch template when creating an AutoScalingGroup" + }, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include the stack prefix in the stack name generation process" + }, + "@aws-cdk/aws-efs:denyAnonymousAccess": { + "userValue": true, + "recommendedValue": true, + "explanation": "EFS denies anonymous clients accesses" + }, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables support for Multi-AZ with Standby deployment for opensearch domains" + }, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables aws-lambda-nodejs.Function to use the latest available NodeJs runtime as the default" + }, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, mount targets will have a stable logicalId that is linked to the associated subnet." + }, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a scope of InstanceParameterGroup for AuroraClusterInstance with each parameters will change." + }, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, will always use the arn for identifiers for CfnSourceApiAssociation in the GraphqlApi construct rather than id." + }, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, creating an RDS database cluster from a snapshot will only render credentials for snapshot credentials." + }, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the CodeCommit source action is using the default branch name 'main'." + }, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the logical ID of a Lambda permission for a Lambda action includes an alarm ID." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default value for crossAccountKeys to false." + }, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default pipeline type to V2." + }, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, IAM Policy created from KMS key grant will reduce the resource scope to this key only." + }, + "@aws-cdk/pipelines:reduceAssetRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from PipelineAssetsFileRole trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-eks:nodegroupNameAttribute": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, nodegroupName attribute of the provisioned EKS NodeGroup will not have the cluster name prefix." + }, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default volume type of the EBS volume will be GP3" + }, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, remove default deployment alarm settings" + }, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default" + }, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack." + }, + "@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": { + "recommendedValue": true, + "explanation": "When enabled, use new props for S3 URI field in task definition of state machine for bedrock invoke model.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:explicitStackTags": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, stack tags need to be assigned explicitly on a Stack." + }, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": { + "userValue": false, + "recommendedValue": false, + "explanation": "When set to true along with canContainersAccessInstanceRole=false in ECS cluster, new updated commands will be added to UserData to block container accessing IMDS. **Applicable to Linux only. IMPORTANT: See [details.](#aws-cdkaws-ecsenableImdsBlockingDeprecatedFeature)**" + }, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, CDK synth will throw exception if canContainersAccessInstanceRole is false. **IMPORTANT: See [details.](#aws-cdkaws-ecsdisableEcsImdsBlocking)**" + }, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, we will only grant the necessary permissions when users specify cloudwatch log group through logConfiguration" + }, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled will allow you to specify a resource policy per replica, and not copy the source table policy to all replicas" + }, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, initOptions.timeout and resourceSignalTimeout values will be summed together." + }, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a Lambda authorizer Permission created when using GraphqlApi will be properly scoped with a SourceArn." + }, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the value of property `instanceResourceId` in construct `DatabaseInstanceReadReplica` will be set to the correct value which is `DbiResourceId` instead of currently `DbInstanceArn`" + }, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CFN templates added with `cfn-include` will error if the template contains Resource Update or Create policies with CFN Intrinsics that include non-primitive values." + }, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, both `@aws-sdk` and `@smithy` packages will be excluded from the Lambda Node.js 18.x runtime to prevent version mismatches in bundled applications." + }, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resource of IAM Run Ecs policy generated by SFN EcsRunTask will reference the definition, instead of constructing ARN." + }, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the BastionHost construct will use the latest Amazon Linux 2023 AMI, instead of Amazon Linux 2." + }, + "@aws-cdk/core:aspectStabilization": { + "recommendedValue": true, + "explanation": "When enabled, a stabilization loop will be run when invoking Aspects during synthesis.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, use a new method for DNS Name of user pool domain target without creating a custom resource." + }, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default security group ingress rules will allow IPv6 ingress from anywhere" + }, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default behaviour of OIDC provider will reject unauthorized connections" + }, + "@aws-cdk/core:enableAdditionalMetadataCollection": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will expand the scope of usage data collected to better inform CDK development and improve communication for security concerns and emerging issues." + }, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": { + "userValue": false, + "recommendedValue": false, + "explanation": "[Deprecated] When enabled, Lambda will create new inline policies with AddToRolePolicy instead of adding to the Default Policy Statement" + }, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will automatically generate a unique role name that is used for s3 object replication." + }, + "@aws-cdk/pipelines:reduceStageRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from Stage addActions trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-events:requireEventBusPolicySid": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, grantPutEventsTo() will use resource policies with Statement IDs for service principals." + }, + "@aws-cdk/core:aspectPrioritiesMutating": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, Aspects added by the construct library on your behalf will be given a priority of MUTATING." + }, + "@aws-cdk/aws-dynamodb:retainTableReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, table replica will be default to the removal policy of source table unless specified otherwise." + }, + "@aws-cdk/cognito:logUserPoolClientSecretValue": { + "recommendedValue": false, + "explanation": "When disabled, the value of the user pool client secret will not be logged in the custom resource lambda function logs." + }, + "@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": { + "recommendedValue": true, + "explanation": "When enabled, scopes down the trust policy for the cross-account action role", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resultWriterV2 property of DistributedMap will be used insted of resultWriter" + }, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": { + "userValue": true, + "recommendedValue": true, + "explanation": "Add an S3 trust policy to a KMS key resource policy for SNS subscriptions." + }, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the EgressOnlyGateway resource is only created if private subnets are defined in the dual-stack VPC." + }, + "@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": { + "recommendedValue": false, + "explanation": "When enabled, use resource IDs for VPC V2 migration" + }, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, setting any combination of options for BlockPublicAccess will automatically set true for any options not defined." + }, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK creates and manages loggroup for the lambda function" + } + } + } + } + }, + "minimumCliVersion": "2.1025.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tablev1CCItestDefaultTestDeployAssertDBB26C85.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tablev1CCItestDefaultTestDeployAssertDBB26C85.assets.json new file mode 100644 index 0000000000000..c65c5e99d4450 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tablev1CCItestDefaultTestDeployAssertDBB26C85.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "tablev1CCItestDefaultTestDeployAssertDBB26C85 Template", + "source": { + "path": "tablev1CCItestDefaultTestDeployAssertDBB26C85.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-d8d86b35": { + "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.cci.js.snapshot/tablev1CCItestDefaultTestDeployAssertDBB26C85.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tablev1CCItestDefaultTestDeployAssertDBB26C85.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tablev1CCItestDefaultTestDeployAssertDBB26C85.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.cci.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tree.json new file mode 100644 index 0000000000000..c672b78801aab --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"CCI-Integ-Test-TableV1":{"id":"CCI-Integ-Test-TableV1","path":"CCI-Integ-Test-TableV1","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"TableV2":{"id":"TableV2","path":"CCI-Integ-Test-TableV1/TableV2","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]},"children":{"Resource":{"id":"Resource","path":"CCI-Integ-Test-TableV1/TableV2/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_dynamodb.CfnTable","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::DynamoDB::Table","aws:cdk:cloudformation:props":{"attributeDefinitions":[{"attributeName":"hashKey","attributeType":"S"},{"attributeName":"sortKey","attributeType":"N"}],"contributorInsightsSpecification":{"enabled":true,"mode":"ACCESSED_AND_THROTTLED_KEYS"},"keySchema":[{"attributeName":"hashKey","keyType":"HASH"},{"attributeName":"sortKey","keyType":"RANGE"}],"provisionedThroughput":{"readCapacityUnits":5,"writeCapacityUnits":5}}}},"ScalingRole":{"id":"ScalingRole","path":"CCI-Integ-Test-TableV1/TableV2/ScalingRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"CCI-Integ-Test-TableV1/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"CCI-Integ-Test-TableV1/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"table-v1-CCI-test":{"id":"table-v1-CCI-test","path":"table-v1-CCI-test","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"table-v1-CCI-test/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"table-v1-CCI-test/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"table-v1-CCI-test/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"table-v1-CCI-test/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"table-v1-CCI-test/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.ts new file mode 100644 index 0000000000000..9343c7bcb17a6 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.dynamodb.cci.ts @@ -0,0 +1,27 @@ +import { App, Stack, StackProps } from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new App(); + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + new dynamodb.Table(this, 'TableV2', { + partitionKey: { name: 'hashKey', type: dynamodb.AttributeType.STRING }, + sortKey: { name: 'sortKey', type: dynamodb.AttributeType.NUMBER }, + contributorInsightsSpecification: { + enabled: true, + mode: dynamodb.ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + }, + }); + } +} + +const stack = new TestStack(app, 'CCI-Integ-Test-TableV1', { env: { region: 'eu-west-1' } }); + +new IntegTest(app, 'table-v1-CCI-test', { + testCases: [stack], +}); diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts index 4c180c49353d4..06dc8add8e673 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts @@ -186,7 +186,7 @@ export interface ContributorInsightsSpecification { * Indicates the type of metrics captured by contributor insights. * @default ACCESSED_AND_THROTTLED_KEYS */ - readonly contributorInsightsMode?: ContributorInsightsMode; + readonly mode?: ContributorInsightsMode; } /** 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 bcd3534570a66..3e0a3b6a352f2 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/test/dynamodb.test.ts @@ -4129,7 +4129,7 @@ test('Contributor Insights Specification - table', () => { sortKey: TABLE_SORT_KEY, contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + mode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, }); @@ -4146,7 +4146,7 @@ test('Contributor Insights Specification - table', () => { ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, ContributorInsightsSpecification: { Enabled: true, - ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + Mode: 'ACCESSED_AND_THROTTLED_KEYS', }, }, ); @@ -4189,7 +4189,7 @@ test('Contributor Insights Specification - index', () => { sortKey: TABLE_SORT_KEY, contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + mode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, }); @@ -4198,7 +4198,7 @@ test('Contributor Insights Specification - index', () => { partitionKey: GSI_PARTITION_KEY, contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: ContributorInsightsMode.THROTTLED_KEYS, + mode: ContributorInsightsMode.THROTTLED_KEYS, }, }); @@ -4216,7 +4216,7 @@ test('Contributor Insights Specification - index', () => { ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, ContributorInsightsSpecification: { Enabled: true, - ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + Mode: 'ACCESSED_AND_THROTTLED_KEYS', }, GlobalSecondaryIndexes: [ { @@ -4226,7 +4226,7 @@ test('Contributor Insights Specification - index', () => { ], ContributorInsightsSpecification: { Enabled: true, - ContributorInsightsMode: 'THROTTLED_KEYS', + Mode: 'THROTTLED_KEYS', }, }, ], @@ -4244,7 +4244,7 @@ test('ContributorInsightsSpecification && ContributorInsightsEnabled', () => { contributorInsightsEnabled: true, contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + mode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, }); }).toThrow('`contributorInsightsSpecification` and `contributorInsightsEnabled` are set. Use `contributorInsightsSpecification` only.'); 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 97f56163f61aa..5e430b8be4779 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 @@ -3421,7 +3421,7 @@ test('Contributor Insights Specification - tableV2', () => { sortKey: { name: 'sortKey', type: AttributeType.NUMBER }, contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + mode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, }); @@ -3442,7 +3442,7 @@ test('Contributor Insights Specification - tableV2', () => { }, ContributorInsightsSpecification: { Enabled: true, - ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + Mode: 'ACCESSED_AND_THROTTLED_KEYS', }, }, ], @@ -3499,7 +3499,7 @@ test('Contributor Insights Specification - index', () => { ], contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + mode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, replicas: [ { @@ -3511,7 +3511,7 @@ test('Contributor Insights Specification - index', () => { gsi1: { contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: ContributorInsightsMode.THROTTLED_KEYS, + mode: ContributorInsightsMode.THROTTLED_KEYS, }, }, }, @@ -3532,7 +3532,7 @@ test('Contributor Insights Specification - index', () => { IndexName: 'gsi1', ContributorInsightsSpecification: { Enabled: true, - ContributorInsightsMode: 'THROTTLED_KEYS', + Mode: 'THROTTLED_KEYS', }, }), ]), @@ -3541,14 +3541,14 @@ test('Contributor Insights Specification - index', () => { Region: 'eu-west-1', ContributorInsightsSpecification: { Enabled: true, - ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + Mode: 'ACCESSED_AND_THROTTLED_KEYS', }, GlobalSecondaryIndexes: Match.arrayWith([ Match.objectLike({ IndexName: 'gsi1', ContributorInsightsSpecification: { Enabled: true, - ContributorInsightsMode: 'ACCESSED_AND_THROTTLED_KEYS', + Mode: 'ACCESSED_AND_THROTTLED_KEYS', }, }), ]), @@ -3568,7 +3568,7 @@ test('ContributorInsightsSpecification && ContributorInsights - v2', () => { contributorInsights: true, contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + mode: ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, }); From 92ac435a92233bd640bbfe6f707a6a83c9bf96b9 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Thu, 21 Aug 2025 17:00:01 +0100 Subject: [PATCH 16/18] Changing mode in README to align with schema change on CFN --- packages/aws-cdk-lib/aws-dynamodb/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/aws-cdk-lib/aws-dynamodb/README.md b/packages/aws-cdk-lib/aws-dynamodb/README.md index b1cb705e86293..e58f899f3aad5 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/README.md +++ b/packages/aws-cdk-lib/aws-dynamodb/README.md @@ -618,10 +618,10 @@ const table = new dynamodb.TableV2(this, 'Table', { Enabling `contributorInsightSpecification` for `TableV2` will provide information about the most accessed and throttled or throttled only items in a table or `globalSecondaryIndex`. DynamoDB delivers this information to you via CloudWatch Contributor Insights rules, reports, and graphs of report data. By default, Contributor Insights for DynamoDB monitors all requests, including both the most accessed and most throttled items. -To limit the scope to only the most accessed or only the most throttled items, use the optional `contributorInsightsMode` parameter. +To limit the scope to only the most accessed or only the most throttled items, use the optional `mode` parameter. -- To monitor all traffic on a table or index, set `contributorInsightsMode` to `ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS`. -- To monitor only throttled traffic on a table or index, set `contributorInsightsMode` to `ContributorInsightsMode.THROTTLED_KEYS`. +- To monitor all traffic on a table or index, set `mode` to `ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS`. +- To monitor only throttled traffic on a table or index, set `mode` to `ContributorInsightsMode.THROTTLED_KEYS`. ```ts @@ -629,7 +629,7 @@ const table = new dynamodb.TableV2(this, 'Table', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, contributorInsightsSpecification: { enabled: true, - contributorInsightsMode: dynamodb.ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, + mode: dynamodb.ContributorInsightsMode.ACCESSED_AND_THROTTLED_KEYS, }, }); ``` @@ -641,7 +641,7 @@ const table = new dynamodb.Table(this, 'Table', { partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, contributorInsightsSpecification: { // for a table enabled: true, - contributorInsightsMode: dynamodb.ContributorInsightsMode.THROTTLED_KEYS, // only emit throttling events + mode: dynamodb.ContributorInsightsMode.THROTTLED_KEYS, // only emit throttling events }, }); From 36b73d2d19663afe69f028931406c9bcbff85f1a Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Tue, 26 Aug 2025 14:50:30 +0100 Subject: [PATCH 17/18] Adding CCI validation to shared file --- packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts | 17 ++++++++++++++++- .../aws-cdk-lib/aws-dynamodb/lib/table-v2.ts | 16 ++++------------ packages/aws-cdk-lib/aws-dynamodb/lib/table.ts | 12 +++--------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts index 06dc8add8e673..4eaf184e31f42 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts @@ -1,7 +1,8 @@ +import { Construct } from 'constructs'; import * as cloudwatch from '../../aws-cloudwatch'; import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; -import { IResource } from '../../core'; +import { IResource, ValidationError } from '../../core'; /** * Supported DynamoDB table operations. @@ -527,3 +528,17 @@ export interface ITable extends IResource { */ metricSuccessfulRequestLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; } + +export function validateContributorInsights( + contributorInsights: boolean | undefined, + contributorInsightsSpecification: ContributorInsightsSpecification | undefined, + deprecatedPropertyName: string, + construct: Construct, +): ContributorInsightsSpecification | undefined { + if (contributorInsightsSpecification !== undefined && contributorInsights !== undefined) { + throw new ValidationError(`\`contributorInsightsSpecification\` and \`${deprecatedPropertyName}\` are set. Use \`contributorInsightsSpecification\` only.`, construct); + } + + return contributorInsightsSpecification ?? + (contributorInsights !== undefined ? { enabled: contributorInsights } : undefined); +} 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 9be0fa7a31b70..379bb11e74fb4 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts @@ -17,6 +17,7 @@ import { WarmThroughput, MultiRegionConsistency, ContributorInsightsSpecification, + validateContributorInsights, } from './shared'; import { ITableV2, TableBaseV2 } from './table-v2-base'; import { PolicyDocument } from '../../aws-iam'; @@ -1165,19 +1166,10 @@ export class TableV2 extends TableBaseV2 { } } - private validateCCI (props: IContributorInsightsConfigurable): ContributorInsightsSpecification | undefined { - const contributorInsights = - props?.contributorInsights ?? this.tableOptions?.contributorInsights; - + private validateCCI(props: IContributorInsightsConfigurable): ContributorInsightsSpecification | undefined { + const contributorInsights = props?.contributorInsights ?? this.tableOptions?.contributorInsights; const contributorInsightsSpecification = props?.contributorInsightsSpecification || this.tableOptions?.contributorInsightsSpecification; - if (contributorInsightsSpecification !== undefined && contributorInsights !== undefined) { - throw new ValidationError('`contributorInsightsSpecification` and `contributorInsights` are set. Use `contributorInsightsSpecification` only.', this); - } - - return contributorInsightsSpecification ?? - (contributorInsights !== undefined - ? { enabled: contributorInsights } - : undefined); + return validateContributorInsights(contributorInsights, contributorInsightsSpecification, 'contributorInsights', this); } } diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts index f073f6a9ab0a0..4a8c65e324932 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table.ts @@ -10,6 +10,7 @@ import { Attribute, BillingMode, ProjectionType, ITable, SecondaryIndexProps, TableClass, LocalSecondaryIndexProps, TableEncryption, StreamViewType, WarmThroughput, PointInTimeRecoverySpecification, ContributorInsightsSpecification, + validateContributorInsights, } from './shared'; import * as appscaling from '../../aws-applicationautoscaling'; import * as cloudwatch from '../../aws-cloudwatch'; @@ -1620,15 +1621,8 @@ export class Table extends TableBase { : undefined); } - private validateCCI (props: IContributorInsightsConfigurable): ContributorInsightsSpecification | undefined { - if (props.contributorInsightsSpecification !==undefined && props.contributorInsightsEnabled !== undefined) { - throw new ValidationError('`contributorInsightsSpecification` and `contributorInsightsEnabled` are set. Use `contributorInsightsSpecification` only.', this); - } - - return props.contributorInsightsSpecification ?? - (props.contributorInsightsEnabled !== undefined - ? { enabled: props.contributorInsightsEnabled } - : undefined); + private validateCCI(props: IContributorInsightsConfigurable): ContributorInsightsSpecification | undefined { + return validateContributorInsights(props.contributorInsightsEnabled, props.contributorInsightsSpecification, 'contributorInsightsEnabled', this); } private buildIndexKeySchema(partitionKey: Attribute, sortKey?: Attribute): CfnTable.KeySchemaProperty[] { From 2dbb41eed447b8bbec0a9a69f9d458f022bb7e98 Mon Sep 17 00:00:00 2001 From: Jorge Diaz Date: Tue, 26 Aug 2025 19:26:23 +0200 Subject: [PATCH 18/18] fix missing rossetta dependency --- packages/@aws-cdk/aws-pipes-sources-alpha/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-pipes-sources-alpha/package.json b/packages/@aws-cdk/aws-pipes-sources-alpha/package.json index ef9afecdd51d6..d64253b9fef2f 100644 --- a/packages/@aws-cdk/aws-pipes-sources-alpha/package.json +++ b/packages/@aws-cdk/aws-pipes-sources-alpha/package.json @@ -115,6 +115,8 @@ ] }, "jsiiRosetta": { - "exampleDependencies": {} + "exampleDependencies": { + "@aws-cdk/aws-pipes-targets-alpha": "^0.0.0" + } } }