Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rds): limitless database cluster #32151

Merged
merged 21 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as cdk from 'aws-cdk-lib';
import { AuroraPostgresEngineVersion, ClusterScailabilityType, DatabaseCluster, DatabaseClusterEngine, DBClusterStorageType } from 'aws-cdk-lib/aws-rds';
import { IntegTest } from '@aws-cdk/integ-tests-alpha';

class TestStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const vpc = new ec2.Vpc(this, 'Vpc');

new DatabaseCluster(this, 'DatabaseCluster', {
engine: DatabaseClusterEngine.auroraPostgres({
version: AuroraPostgresEngineVersion.VER_16_4_LIMITLESS,
}),
vpc,
clusterScailabilityType: ClusterScailabilityType.LIMITLESS,
enablePerformanceInsights: true,
monitoringInterval: cdk.Duration.days(40),
storageType: DBClusterStorageType.AURORA_IOPT1,
cloudwatchLogsExports: ['postgresql'],
});
}
}

const app = new cdk.App();
const stack = new TestStack(app, 'LimitlessClusterStack');

new IntegTest(app, 'LimitlessClusterInteg', {
testCases: [stack],
});
2 changes: 2 additions & 0 deletions packages/aws-cdk-lib/aws-rds/lib/cluster-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,8 @@ export class AuroraPostgresEngineVersion {
public static readonly VER_16_3 = AuroraPostgresEngineVersion.of('16.3', '16', { s3Import: true, s3Export: true });
/** Version "16.4". */
public static readonly VER_16_4 = AuroraPostgresEngineVersion.of('16.4', '16', { s3Import: true, s3Export: true });
/** Version "16.4 limitless" */
public static readonly VER_16_4_LIMITLESS = AuroraPostgresEngineVersion.of('16.4-limitless', '16', { s3Import: true, s3Export: true });

/**
* Create a new AuroraPostgresEngineVersion with an arbitrary version.
Expand Down
78 changes: 68 additions & 10 deletions packages/aws-cdk-lib/aws-rds/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,15 @@ interface DatabaseClusterBaseProps {
* @default true
*/
readonly autoMinorVersionUpgrade?: boolean;

/**
* Specifies the scalability mode of the Aurora DB cluster.
*
* Set LIMITLESS if you want to use a limitless database; otherwise, set it to STANDARD.
*
* @default ClusterScailabilityType.STANDARD
*/
readonly clusterScailabilityType?: ClusterScailabilityType;
}

/**
Expand Down Expand Up @@ -462,6 +471,24 @@ export enum InstanceUpdateBehaviour {
ROLLING = 'ROLLING',
}

/**
* The scalability mode of the Aurora DB cluster.
*/
export enum ClusterScailabilityType {
/**
* The cluster uses normal DB instance creation.
*/
STANDARD = 'standard',

/**
* The cluster operates as an Aurora Limitless Database,
* allowing you to create a DB shard group for horizontal scaling (sharding) capabilities.
*
* @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/limitless.html
*/
LIMITLESS = 'limitless',
}

/**
* A new or imported clustered database.
*/
Expand Down Expand Up @@ -752,6 +779,30 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase {
throw new Error('`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set');
}

if (props.clusterScailabilityType === ClusterScailabilityType.LIMITLESS) {
if (!props.enablePerformanceInsights) {
throw new Error('Performance Insights must be enabled for Aurora Limitless Database.');
}
if (!props.monitoringInterval) {
throw new Error('Enhanced monitoring must be set for Aurora Limitless Database. Please set `monitoringInterval`.');
}
if (props.monitoringInterval.toMilliseconds() < Duration.days(31).toMilliseconds()) {
throw new Error('Enhanced monitoring interval must be at least 31 days for Aurora Limitless Database.');
}
if (props.writer || props.readers) {
throw new Error('Aurora Limitless Database does not support readers or writer instances.');
}
if (!props.engine.engineVersion?.fullVersion?.endsWith('limitless')) {
throw new Error(`Aurora Limitless Database requires an engine version that supports it., got ${props.engine.engineVersion?.fullVersion}`);
}
if (props.storageType !== DBClusterStorageType.AURORA_IOPT1) {
throw new Error(`Aurora Limitless Database requires I/O optimized storage type, got: ${props.storageType}`);
}
if (props.cloudwatchLogsExports === undefined || props.cloudwatchLogsExports.length === 0) {
throw new Error('Aurora Limitless Database requires CloudWatch Logs exports to be set.');
}
}

this.performanceInsightsEnabled = enablePerformanceInsights;
this.performanceInsightRetention = enablePerformanceInsights
? (props.performanceInsightRetention || PerformanceInsightRetention.DEFAULT)
Expand Down Expand Up @@ -785,6 +836,7 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase {
}),
storageType: props.storageType?.toString(),
enableLocalWriteForwarding: props.enableLocalWriteForwarding,
clusterScalabilityType: props.clusterScailabilityType,
// Admin
backtrackWindow: props.backtrackWindow?.toSeconds(),
backupRetentionPeriod: props.backup?.retention?.toDays(),
Expand Down Expand Up @@ -1199,19 +1251,25 @@ export class DatabaseCluster extends DatabaseClusterNew {
cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT);

setLogRetention(this, props);
if ((props.writer || props.readers) && (props.instances || props.instanceProps)) {
throw new Error('Cannot provide writer or readers if instances or instanceProps are provided');
}

if (!props.instanceProps && !props.writer) {
throw new Error('writer must be provided');
}
// create the instances for only standard aurora clusters
if (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');
}

const createdInstances = props.writer ? this._createInstances(this, props) : legacyCreateInstances(this, props, this.subnetGroup);
this.instanceIdentifiers = createdInstances.instanceIdentifiers;
this.instanceEndpoints = createdInstances.instanceEndpoints;
}
if (!props.instanceProps && !props.writer) {
throw new Error('writer must be provided');
}

const createdInstances = props.writer ? this._createInstances(this, props) : legacyCreateInstances(this, props, this.subnetGroup);
this.instanceIdentifiers = createdInstances.instanceIdentifiers;
this.instanceEndpoints = createdInstances.instanceEndpoints;
} else {
this.instanceIdentifiers = [];
this.instanceEndpoints = [];
}
}
}

/**
Expand Down
21 changes: 21 additions & 0 deletions packages/aws-cdk-lib/aws-rds/test/cluster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, DatabaseSecret,
DatabaseInstanceEngine, SqlServerEngineVersion, SnapshotCredentials, InstanceUpdateBehaviour, NetworkType, ClusterInstance, CaCertificate,
IClusterEngine,
ClusterScailabilityType,
} from '../lib';

describe('cluster new api', () => {
Expand Down Expand Up @@ -164,6 +165,26 @@ describe('cluster new api', () => {
});
});

test('cluster scailability option', () => {
badmintoncryer marked this conversation as resolved.
Show resolved Hide resolved
// GIVEN
const stack = testStack();
const vpc = new ec2.Vpc(stack, 'VPC');

// WHEN
new DatabaseCluster(stack, 'Cluster', {
engine: DatabaseClusterEngine.AURORA_MYSQL,
vpc,
clusterScailabilityType: ClusterScailabilityType.STANDARD,
writer: ClusterInstance.serverlessV2('writer'),
});

// THEN
const template = Template.fromStack(stack);
template.hasResourceProperties('AWS::RDS::DBCluster', {
ClusterScalabilityType: 'standard',
});
});

test('with serverless instances', () => {
// GIVEN
const stack = testStack();
Expand Down
Loading