Skip to content

Commit 6ec9829

Browse files
authored
feat(rds): isFromLegacyInstanceProps migration flag with ClusterInstance.serverlessV2 (#26472)
**Context** A recent feature release #25437 has added support for Aurora Serverless V2 cluster instances. This change also introduced a new approach for defining cluster instances, deprecating `instanceProps` in the process. The new approach uses `ClusterInstance.provisioned()` and `ClusterInstance.serverlessV2()` to define instances and their parameters on a per-instance basis. A migration flag `isFromLegacyInstanceProps` has also been added to the `ClusterInstance.provisioned()` constructor props to allow for migration to this new approach without destructive changes to the generated CFN template. **Bug** Because the `DatabaseCluster` construct has not previously had official support for Serverless V2 instances, the same migration flag has not been made available for `ClusterInstance.serverlessV2()`. This ignores the fact that many people have already provisioned serverless v2 instances using a common workaround described here #20197 (comment). People who have used this method previously have no clean migration path. This has been previously raised in #25942. **Fix** This fix simply exposes the `isFromLegacyInstanceProps` flag on **both** `ProvisionedClusterInstanceProps` and `ServerlessV2ClusterInstanceProps`. The behaviour for this flag is already implemented and applied across both instance types, so this is a type-only change. I have however added a test to capture this upgrade path for Serverless V2 instances from the common workaround. Closes #25942. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 27dc8ff commit 6ec9829

File tree

2 files changed

+128
-56
lines changed

2 files changed

+128
-56
lines changed

packages/aws-cdk-lib/aws-rds/lib/aurora-cluster-instance.ts

+48-55
Original file line numberDiff line numberDiff line change
@@ -128,53 +128,6 @@ export interface ProvisionedClusterInstanceProps extends ClusterInstanceOptions
128128
* @default 2
129129
*/
130130
readonly promotionTier?: number;
131-
132-
/**
133-
* Only used for migrating existing clusters from using `instanceProps` to `writer` and `readers`
134-
*
135-
* @example
136-
* // existing cluster
137-
* declare const vpc: ec2.Vpc;
138-
* const cluster = new rds.DatabaseCluster(this, 'Database', {
139-
* engine: rds.DatabaseClusterEngine.auroraMysql({
140-
* version: rds.AuroraMysqlEngineVersion.VER_3_03_0,
141-
* }),
142-
* instances: 2,
143-
* instanceProps: {
144-
* instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL),
145-
* vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
146-
* vpc,
147-
* },
148-
* });
149-
*
150-
* // migration
151-
*
152-
* const instanceProps = {
153-
* instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL),
154-
* isFromLegacyInstanceProps: true,
155-
* };
156-
*
157-
* const myCluster = new rds.DatabaseCluster(this, 'Database', {
158-
* engine: rds.DatabaseClusterEngine.auroraMysql({
159-
* version: rds.AuroraMysqlEngineVersion.VER_3_03_0,
160-
* }),
161-
* vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
162-
* vpc,
163-
* writer: rds.ClusterInstance.provisioned('Instance1', {
164-
* instanceType: instanceProps.instanceType,
165-
* isFromLegacyInstanceProps: instanceProps.isFromLegacyInstanceProps,
166-
* }),
167-
* readers: [
168-
* rds.ClusterInstance.provisioned('Instance2', {
169-
* instanceType: instanceProps.instanceType,
170-
* isFromLegacyInstanceProps: instanceProps.isFromLegacyInstanceProps,
171-
* }),
172-
* ],
173-
* });
174-
*
175-
* @default false
176-
*/
177-
readonly isFromLegacyInstanceProps?: boolean;
178131
}
179132

180133
/**
@@ -199,7 +152,7 @@ export interface ServerlessV2ClusterInstanceProps extends ClusterInstanceOptions
199152
/**
200153
* Common options for creating cluster instances (both serverless and provisioned)
201154
*/
202-
export interface ClusterInstanceProps extends ClusterInstanceOptions{
155+
export interface ClusterInstanceProps extends ClusterInstanceOptions {
203156
/**
204157
* The type of cluster instance to create. Can be either
205158
* provisioned or serverless v2
@@ -218,13 +171,6 @@ export interface ClusterInstanceProps extends ClusterInstanceOptions{
218171
* @default 2
219172
*/
220173
readonly promotionTier?: number;
221-
222-
/**
223-
* Only used for migrating existing clusters from using `instanceProps` to `writer` and `readers`
224-
*
225-
* @default false
226-
*/
227-
readonly isFromLegacyInstanceProps?: boolean;
228174
}
229175

230176
/**
@@ -299,6 +245,53 @@ export interface ClusterInstanceOptions {
299245
* @default the cluster parameter group is used
300246
*/
301247
readonly parameterGroup?: IParameterGroup;
248+
249+
/**
250+
* Only used for migrating existing clusters from using `instanceProps` to `writer` and `readers`
251+
*
252+
* @example
253+
* // existing cluster
254+
* declare const vpc: ec2.Vpc;
255+
* const cluster = new rds.DatabaseCluster(this, 'Database', {
256+
* engine: rds.DatabaseClusterEngine.auroraMysql({
257+
* version: rds.AuroraMysqlEngineVersion.VER_3_03_0,
258+
* }),
259+
* instances: 2,
260+
* instanceProps: {
261+
* instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL),
262+
* vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
263+
* vpc,
264+
* },
265+
* });
266+
*
267+
* // migration
268+
*
269+
* const instanceProps = {
270+
* instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL),
271+
* isFromLegacyInstanceProps: true,
272+
* };
273+
*
274+
* const myCluster = new rds.DatabaseCluster(this, 'Database', {
275+
* engine: rds.DatabaseClusterEngine.auroraMysql({
276+
* version: rds.AuroraMysqlEngineVersion.VER_3_03_0,
277+
* }),
278+
* vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
279+
* vpc,
280+
* writer: rds.ClusterInstance.provisioned('Instance1', {
281+
* instanceType: instanceProps.instanceType,
282+
* isFromLegacyInstanceProps: instanceProps.isFromLegacyInstanceProps,
283+
* }),
284+
* readers: [
285+
* rds.ClusterInstance.provisioned('Instance2', {
286+
* instanceType: instanceProps.instanceType,
287+
* isFromLegacyInstanceProps: instanceProps.isFromLegacyInstanceProps,
288+
* }),
289+
* ],
290+
* });
291+
*
292+
* @default false
293+
*/
294+
readonly isFromLegacyInstanceProps?: boolean;
302295
}
303296

304297
/**

packages/aws-cdk-lib/aws-rds/test/cluster.test.ts

+80-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ describe('cluster new api', () => {
207207
});
208208

209209
describe('migrate from instanceProps', () => {
210-
test('template contains no changes', () => {
210+
test('template contains no changes (provisioned instances)', () => {
211211
// GIVEN
212212
const stack1 = testStack();
213213
const stack2 = testStack();
@@ -268,6 +268,85 @@ describe('cluster new api', () => {
268268
test1Template,
269269
).toEqual(Template.fromStack(stack2).toJSON());
270270
});
271+
272+
test('template contains no changes (serverless instances)', () => {
273+
// GIVEN
274+
const stack1 = testStack();
275+
const stack2 = testStack();
276+
277+
function createCase(stack: Stack) {
278+
const vpc = new ec2.Vpc(stack, 'VPC');
279+
280+
// WHEN
281+
const pg = new ParameterGroup(stack, 'pg', {
282+
engine: DatabaseClusterEngine.AURORA,
283+
});
284+
const sg = new ec2.SecurityGroup(stack, 'sg', {
285+
vpc,
286+
});
287+
const instanceProps = {
288+
instanceType: new ec2.InstanceType('serverless'),
289+
vpc,
290+
allowMajorVersionUpgrade: true,
291+
autoMinorVersionUpgrade: true,
292+
deleteAutomatedBackups: true,
293+
enablePerformanceInsights: true,
294+
parameterGroup: pg,
295+
securityGroups: [sg],
296+
};
297+
return instanceProps;
298+
}
299+
const test1 = createCase(stack1);
300+
const test2 = createCase(stack2);
301+
302+
// Create serverless cluster using workaround described here:
303+
// https://github.com/aws/aws-cdk/issues/20197#issuecomment-1284485844
304+
const workaroundCluster = new DatabaseCluster(stack1, 'Database', {
305+
engine: DatabaseClusterEngine.AURORA,
306+
instanceProps: test1,
307+
iamAuthentication: true,
308+
});
309+
310+
cdk.Aspects.of(workaroundCluster).add({
311+
visit(node) {
312+
if (node instanceof CfnDBCluster) {
313+
node.serverlessV2ScalingConfiguration = {
314+
minCapacity: 1,
315+
maxCapacity: 12,
316+
};
317+
}
318+
},
319+
});
320+
321+
// Create serverless cluster using new/official approach.
322+
// This should provide a non-breaking migration path from the workaround.
323+
new DatabaseCluster(stack2, 'Database', {
324+
engine: DatabaseClusterEngine.AURORA,
325+
vpc: test2.vpc,
326+
securityGroups: test2.securityGroups,
327+
writer: ClusterInstance.serverlessV2('Instance1', {
328+
...test2,
329+
isFromLegacyInstanceProps: true,
330+
}),
331+
readers: [
332+
ClusterInstance.serverlessV2('Instance2', {
333+
...test2,
334+
scaleWithWriter: true,
335+
isFromLegacyInstanceProps: true,
336+
}),
337+
],
338+
iamAuthentication: true,
339+
serverlessV2MinCapacity: 1,
340+
serverlessV2MaxCapacity: 12,
341+
});
342+
343+
// THEN
344+
const test1Template = Template.fromStack(stack1).toJSON();
345+
// deleteAutomatedBackups is not needed on the instance, it is set on the cluster
346+
delete test1Template.Resources.DatabaseInstance1844F58FD.Properties.DeleteAutomatedBackups;
347+
delete test1Template.Resources.DatabaseInstance2AA380DEE.Properties.DeleteAutomatedBackups;
348+
expect(test1Template).toEqual(Template.fromStack(stack2).toJSON());
349+
});
271350
});
272351

273352
describe('creates a writer instance', () => {

0 commit comments

Comments
 (0)