diff --git a/packages/aws-cdk-lib/aws-rds/README.md b/packages/aws-cdk-lib/aws-rds/README.md index a3862eb036ec4..fd0a8a4ee66e1 100644 --- a/packages/aws-cdk-lib/aws-rds/README.md +++ b/packages/aws-cdk-lib/aws-rds/README.md @@ -1436,7 +1436,7 @@ new rds.DatabaseCluster(this, 'LimitlessDatabaseCluster', { version: rds.AuroraPostgresEngineVersion.VER_16_4_LIMITLESS, }), vpc, - clusterScailabilityType: rds.ClusterScailabilityType.LIMITLESS, + clusterScalabilityType: rds.ClusterScalabilityType.LIMITLESS, // Requires enabling Performance Insights enablePerformanceInsights: true, performanceInsightRetention: rds.PerformanceInsightRetention.MONTHS_1, diff --git a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts index 48521aedd2a1b..a4db78ee99545 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts @@ -450,9 +450,14 @@ interface DatabaseClusterBaseProps { * * Set LIMITLESS if you want to use a limitless database; otherwise, set it to STANDARD. * - * @default ClusterScailabilityType.STANDARD + * @default ClusterScalabilityType.STANDARD */ - readonly clusterScailabilityType?: ClusterScailabilityType; + readonly clusterScalabilityType?: ClusterScalabilityType; + + /** + * @deprecated Use clusterScalabilityType instead. This will be removed in the next major version. + */ + readonly clusterScailabilityType?: ClusterScalabilityType; } /** @@ -492,7 +497,7 @@ export enum InstanceUpdateBehaviour { /** * The scalability mode of the Aurora DB cluster. */ -export enum ClusterScailabilityType { +export enum ClusterScalabilityType { /** * The cluster uses normal DB instance creation. */ @@ -507,6 +512,11 @@ export enum ClusterScailabilityType { LIMITLESS = 'limitless', } +/** + * @deprecated Use ClusterScalabilityType instead. This will be removed in the next major version. + */ +export import ClusterScailabilityType = ClusterScalabilityType; + /** * A new or imported clustered database. */ @@ -802,7 +812,7 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { throw new Error('`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set'); } - if (props.clusterScailabilityType === ClusterScailabilityType.LIMITLESS) { + if (props.clusterScalabilityType === ClusterScalabilityType.LIMITLESS || props.clusterScailabilityType === ClusterScailabilityType.LIMITLESS) { if (!props.enablePerformanceInsights) { throw new Error('Performance Insights must be enabled for Aurora Limitless Database.'); } @@ -877,7 +887,7 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { }), storageType: props.storageType?.toString(), enableLocalWriteForwarding: props.enableLocalWriteForwarding, - clusterScalabilityType: props.clusterScailabilityType, + clusterScalabilityType: props.clusterScalabilityType ?? props.clusterScailabilityType, // Admin backtrackWindow: props.backtrackWindow?.toSeconds(), backupRetentionPeriod: props.backup?.retention?.toDays(), @@ -1287,7 +1297,7 @@ export class DatabaseCluster extends DatabaseClusterNew { setLogRetention(this, props); // create the instances for only standard aurora clusters - if (props.clusterScailabilityType !== ClusterScailabilityType.LIMITLESS) { + if (props.clusterScalabilityType !== ClusterScalabilityType.LIMITLESS && props.clusterScailabilityType !== ClusterScailabilityType.LIMITLESS) { if ((props.writer || props.readers) && (props.instances || props.instanceProps)) { throw new Error('Cannot provide writer or readers if instances or instanceProps are provided'); } diff --git a/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts b/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts index 56a426d9cc9ec..2e34abe06179c 100644 --- a/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts @@ -17,6 +17,7 @@ import { DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, DatabaseSecret, DatabaseInstanceEngine, SqlServerEngineVersion, SnapshotCredentials, InstanceUpdateBehaviour, NetworkType, ClusterInstance, CaCertificate, IClusterEngine, + ClusterScalabilityType, ClusterScailabilityType, DBClusterStorageType, } from '../lib'; @@ -170,6 +171,26 @@ describe('cluster new api', () => { const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + vpc, + clusterScalabilityType: ClusterScalabilityType.STANDARD, + writer: ClusterInstance.serverlessV2('writer'), + }); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::RDS::DBCluster', { + ClusterScalabilityType: 'standard', + }); + }); + + test('cluster scalability option with deprecated misspelling', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + // WHEN new DatabaseCluster(stack, 'Cluster', { engine: DatabaseClusterEngine.AURORA_MYSQL, @@ -419,6 +440,240 @@ describe('cluster new api', () => { }); }); + describe('limitless database', () => { + test('with default options', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_16_4_LIMITLESS, + }), + vpc, + clusterScalabilityType: ClusterScalabilityType.LIMITLESS, + enablePerformanceInsights: true, + performanceInsightRetention: PerformanceInsightRetention.MONTHS_1, + monitoringInterval: cdk.Duration.minutes(1), + enableClusterLevelEnhancedMonitoring: true, + storageType: DBClusterStorageType.AURORA_IOPT1, + cloudwatchLogsExports: ['postgresql'], + }); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::RDS::DBCluster', { + ClusterScalabilityType: 'limitless', + EnableCloudwatchLogsExports: ['postgresql'], + Engine: 'aurora-postgresql', + EngineVersion: '16.4-limitless', + MonitoringInterval: 60, + PerformanceInsightsEnabled: true, + PerformanceInsightsRetentionPeriod: 31, + StorageType: 'aurora-iopt1', + }); + }); + + test.each([false, undefined])('throw error for disabling performance insights', (enablePerformanceInsights) => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // THEN + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_16_4_LIMITLESS, + }), + vpc, + clusterScalabilityType: ClusterScalabilityType.LIMITLESS, + enablePerformanceInsights, + monitoringInterval: cdk.Duration.minutes(1), + enableClusterLevelEnhancedMonitoring: true, + storageType: DBClusterStorageType.AURORA_IOPT1, + cloudwatchLogsExports: ['postgresql'], + }); + }).toThrow('Performance Insights must be enabled for Aurora Limitless Database.'); + }); + + test('throw error for invalid performance insights retention period', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // THEN + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_16_4_LIMITLESS, + }), + vpc, + clusterScalabilityType: ClusterScalabilityType.LIMITLESS, + enablePerformanceInsights: true, + performanceInsightRetention: PerformanceInsightRetention.DEFAULT, + monitoringInterval: cdk.Duration.minutes(1), + enableClusterLevelEnhancedMonitoring: true, + storageType: DBClusterStorageType.AURORA_IOPT1, + cloudwatchLogsExports: ['postgresql'], + }); + }).toThrow('Performance Insights retention period must be set at least 31 days for Aurora Limitless Database.'); + }); + + test('throw error for not specifying monitoring interval', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // THEN + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_16_4_LIMITLESS, + }), + vpc, + clusterScalabilityType: ClusterScalabilityType.LIMITLESS, + enablePerformanceInsights: true, + performanceInsightRetention: PerformanceInsightRetention.MONTHS_1, + monitoringInterval: undefined, + enableClusterLevelEnhancedMonitoring: true, + storageType: DBClusterStorageType.AURORA_IOPT1, + cloudwatchLogsExports: ['postgresql'], + }); + }).toThrow('Cluster level enhanced monitoring must be set for Aurora Limitless Database. Please set \'monitoringInterval\' and enable \'enableClusterLevelEnhancedMonitoring\'.'); + }); + + test.each([false, undefined])('throw error for configuring enhanced monitoring at the instance level', (enableClusterLevelEnhancedMonitoring) => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // THEN + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_16_4_LIMITLESS, + }), + vpc, + clusterScalabilityType: ClusterScalabilityType.LIMITLESS, + enablePerformanceInsights: true, + performanceInsightRetention: PerformanceInsightRetention.MONTHS_1, + monitoringInterval: cdk.Duration.minutes(1), + enableClusterLevelEnhancedMonitoring, + storageType: DBClusterStorageType.AURORA_IOPT1, + cloudwatchLogsExports: ['postgresql'], + instances: 1, + }); + }).toThrow('Cluster level enhanced monitoring must be set for Aurora Limitless Database. Please set \'monitoringInterval\' and enable \'enableClusterLevelEnhancedMonitoring\'.'); + }); + + test('throw error for specifying writer instance', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // THEN + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_16_4_LIMITLESS, + }), + vpc, + clusterScalabilityType: ClusterScalabilityType.LIMITLESS, + enablePerformanceInsights: true, + performanceInsightRetention: PerformanceInsightRetention.MONTHS_1, + monitoringInterval: cdk.Duration.minutes(1), + enableClusterLevelEnhancedMonitoring: true, + storageType: DBClusterStorageType.AURORA_IOPT1, + cloudwatchLogsExports: ['postgresql'], + writer: ClusterInstance.serverlessV2('writer'), + }); + }).toThrow('Aurora Limitless Database does not support readers or writer instances.'); + }); + + test.each([ + DatabaseClusterEngine.auroraMysql({ + version: AuroraMysqlEngineVersion.VER_3_08_0, + }), + DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_16_4, + }), + ])('throw error for invalid engine', (engine) => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // THEN + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine, + vpc, + clusterScalabilityType: ClusterScalabilityType.LIMITLESS, + enablePerformanceInsights: true, + performanceInsightRetention: PerformanceInsightRetention.MONTHS_1, + monitoringInterval: cdk.Duration.minutes(1), + enableClusterLevelEnhancedMonitoring: true, + storageType: DBClusterStorageType.AURORA_IOPT1, + cloudwatchLogsExports: ['postgresql'], + }); + }).toThrow(`Aurora Limitless Database requires an engine version that supports it, got ${engine.engineVersion?.fullVersion}`); + }); + + test('throw error for invalid storage type', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // THEN + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_16_4_LIMITLESS, + }), + vpc, + clusterScalabilityType: ClusterScalabilityType.LIMITLESS, + enablePerformanceInsights: true, + performanceInsightRetention: PerformanceInsightRetention.MONTHS_1, + monitoringInterval: cdk.Duration.minutes(1), + enableClusterLevelEnhancedMonitoring: true, + storageType: DBClusterStorageType.AURORA, + cloudwatchLogsExports: ['postgresql'], + }); + }).toThrow('Aurora Limitless Database requires I/O optimized storage type, got: aurora'); + }); + + test.each([[], undefined])('throw error for invalid cloudwatch log exports', (cloudwatchLogsExports) => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // THEN + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Cluster', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_16_4_LIMITLESS, + }), + vpc, + clusterScalabilityType: ClusterScalabilityType.LIMITLESS, + enablePerformanceInsights: true, + performanceInsightRetention: PerformanceInsightRetention.MONTHS_1, + monitoringInterval: cdk.Duration.minutes(1), + enableClusterLevelEnhancedMonitoring: true, + storageType: DBClusterStorageType.AURORA_IOPT1, + cloudwatchLogsExports, + }); + }).toThrow('Aurora Limitless Database requires CloudWatch Logs exports to be set.'); + }); + }); + test('with serverless instances', () => { // GIVEN const stack = testStack();