Skip to content

Commit bab7413

Browse files
authored
feat(rds): instance engine lifecycle support (#34719)
### Issue # (if applicable) Closes #34492 ### Reason for this change Cluster has this param but Instance doesn't ### Description of changes - Instance engine lifecycle support - Move enum EngineLifecycleSupport to props as it is shared across cluster and instance ### Describe any new or updated permissions being added ### Description of how you validated changes Unit + Integ ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 76af7dc commit bab7413

30 files changed

+4679
-117
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/* eslint-disable no-console */
2+
/// <reference path="../../../../../../../node_modules/aws-cdk-lib/custom-resources/lib/provider-framework/types.d.ts" />
3+
import { RDS } from '@aws-sdk/client-rds'; // eslint-disable-line import/no-extraneous-dependencies
4+
5+
export async function onEventHandler(event: AWSCDKAsyncCustomResource.OnEventRequest): Promise<AWSCDKAsyncCustomResource.OnEventResponse> {
6+
console.log('Event: %j', event);
7+
8+
const rds = new RDS();
9+
10+
const physicalResourceId = `${event.ResourceProperties.DBInstanceIdentifier}-${event.ResourceProperties.DBInstanceIdentifier}`;
11+
12+
if (event.RequestType === 'Create' || event.RequestType === 'Update') {
13+
const data = await rds.createDBSnapshot({
14+
DBInstanceIdentifier: event.ResourceProperties.DBInstanceIdentifier,
15+
DBSnapshotIdentifier: event.ResourceProperties.DBSnapshotIdentifier,
16+
});
17+
return {
18+
PhysicalResourceId: physicalResourceId,
19+
Data: {
20+
DBSnapshotArn: data.DBSnapshot?.DBSnapshotArn,
21+
},
22+
};
23+
}
24+
25+
if (event.RequestType === 'Delete') {
26+
await rds.deleteDBSnapshot({
27+
DBSnapshotIdentifier: event.ResourceProperties.DBSnapshotIdentifier,
28+
});
29+
}
30+
31+
return {
32+
PhysicalResourceId: `${event.ResourceProperties.DBInstanceIdentifier}-${event.ResourceProperties.DBInstanceIdentifier}`,
33+
};
34+
}
35+
36+
export async function isCompleteHandler(event: AWSCDKAsyncCustomResource.IsCompleteRequest): Promise<AWSCDKAsyncCustomResource.IsCompleteResponse> {
37+
console.log('Event: %j', event);
38+
39+
const snapshotStatus = await tryGetSnapshotStatus(event.ResourceProperties.DBSnapshotIdentifier);
40+
41+
switch (event.RequestType) {
42+
case 'Create':
43+
case 'Update':
44+
return { IsComplete: snapshotStatus === 'available' };
45+
case 'Delete':
46+
return { IsComplete: snapshotStatus === undefined };
47+
}
48+
}
49+
50+
async function tryGetSnapshotStatus(identifier: string): Promise<string | undefined> {
51+
try {
52+
const rds = new RDS();
53+
const data = await rds.describeDBSnapshots({
54+
DBSnapshotIdentifier: identifier,
55+
});
56+
return data.DBSnapshots?.[0].Status;
57+
} catch (err: any) {
58+
if (err.name === 'DBSnapshotNotFoundFault') {
59+
return undefined;
60+
}
61+
throw err;
62+
}
63+
}

packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-snapshot.js.snapshot/ClusterSnapshotIntegDefaultTestDeployAssert647D4685.assets.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-snapshot.js.snapshot/cdk-integ-cluster-snapshot.assets.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-snapshot.js.snapshot/cdk-integ-cluster-snapshot.template.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@
548548
"Statement": [
549549
{
550550
"Action": [
551+
"rds:AddTagsToResource",
551552
"rds:CreateDBClusterSnapshot",
552553
"rds:DeleteDBClusterSnapshot"
553554
],
@@ -625,7 +626,7 @@
625626
"Arn"
626627
]
627628
},
628-
"Runtime": "nodejs18.x"
629+
"Runtime": "nodejs22.x"
629630
},
630631
"DependsOn": [
631632
"SnapshoterOnEventHandlerServiceRoleDefaultPolicyAF0DFD57",
@@ -744,7 +745,7 @@
744745
"Arn"
745746
]
746747
},
747-
"Runtime": "nodejs18.x"
748+
"Runtime": "nodejs22.x"
748749
},
749750
"DependsOn": [
750751
"SnapshoterIsCompleteHandlerServiceRoleDefaultPolicyA43EB222",

packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-snapshot.js.snapshot/cdk.out

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-snapshot.js.snapshot/integ.json

Lines changed: 7 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-snapshot.js.snapshot/manifest.json

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-snapshot.js.snapshot/tree.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
import * as path from 'path';
21
import * as ec2 from 'aws-cdk-lib/aws-ec2';
3-
import * as iam from 'aws-cdk-lib/aws-iam';
4-
import * as lambda from 'aws-cdk-lib/aws-lambda';
5-
import { App, ArnFormat, CustomResource, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib';
6-
import * as cr from 'aws-cdk-lib/custom-resources';
2+
import { App, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib';
73
import { Construct } from 'constructs';
84
import * as rds from 'aws-cdk-lib/aws-rds';
95
import { ClusterInstance } from 'aws-cdk-lib/aws-rds';
106
import { IntegTest } from '@aws-cdk/integ-tests-alpha';
11-
import { STANDARD_NODEJS_RUNTIME } from '../../config';
7+
import { ClusterSnapshoter } from './snapshoter';
128

139
class TestStack extends Stack {
1410
constructor(scope: Construct, id: string, props?: StackProps) {
@@ -34,7 +30,7 @@ class TestStack extends Stack {
3430
removalPolicy: RemovalPolicy.DESTROY,
3531
});
3632

37-
const snapshoter = new Snapshoter(this, 'Snapshoter', {
33+
const snapshoter = new ClusterSnapshoter(this, 'Snapshoter', {
3834
cluster,
3935
snapshotIdentifier: 'cdk-integ-cluster-snapshot',
4036
});
@@ -58,69 +54,6 @@ class TestStack extends Stack {
5854
}
5955
}
6056

61-
interface SnapshoterProps {
62-
readonly cluster: rds.IDatabaseCluster;
63-
readonly snapshotIdentifier: string;
64-
}
65-
66-
class Snapshoter extends Construct {
67-
public readonly snapshotArn: string;
68-
69-
constructor(scope: Construct, id: string, props: SnapshoterProps) {
70-
super(scope, id);
71-
72-
const clusterArn = Stack.of(this).formatArn({
73-
service: 'rds',
74-
resource: 'cluster',
75-
resourceName: props.cluster.clusterIdentifier,
76-
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
77-
});
78-
79-
const snapshotArn = Stack.of(this).formatArn({
80-
service: 'rds',
81-
resource: 'cluster-snapshot',
82-
resourceName: props.snapshotIdentifier,
83-
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
84-
});
85-
86-
const code = lambda.Code.fromAsset(path.join(__dirname, 'snapshot-handler'), { exclude: ['*.ts'] });
87-
const onEventHandler = new lambda.Function(this, 'OnEventHandler', {
88-
code,
89-
runtime: STANDARD_NODEJS_RUNTIME,
90-
handler: 'index.onEventHandler',
91-
});
92-
onEventHandler.addToRolePolicy(new iam.PolicyStatement({
93-
actions: ['rds:CreateDBClusterSnapshot', 'rds:DeleteDBClusterSnapshot'],
94-
resources: [clusterArn, snapshotArn],
95-
}));
96-
97-
const isCompleteHandler = new lambda.Function(this, 'IsCompleteHandler', {
98-
code,
99-
runtime: STANDARD_NODEJS_RUNTIME,
100-
handler: 'index.isCompleteHandler',
101-
});
102-
isCompleteHandler.addToRolePolicy(new iam.PolicyStatement({
103-
actions: ['rds:DescribeDBClusterSnapshots'],
104-
resources: [clusterArn, snapshotArn],
105-
}));
106-
107-
const provider = new cr.Provider(this, 'SnapshotProvider', {
108-
onEventHandler,
109-
isCompleteHandler,
110-
});
111-
112-
const customResource = new CustomResource(this, 'Snapshot', {
113-
resourceType: 'Custom::Snapshoter',
114-
serviceToken: provider.serviceToken,
115-
properties: {
116-
DBClusterIdentifier: props.cluster.clusterIdentifier,
117-
DBClusterSnapshotIdentifier: props.snapshotIdentifier,
118-
},
119-
});
120-
this.snapshotArn = customResource.getAttString('DBClusterSnapshotArn');
121-
}
122-
}
123-
12457
const app = new App({
12558
postCliContext: {
12659
'@aws-cdk/aws-lambda:useCdkManagedLogGroup': false,
@@ -133,4 +66,3 @@ new IntegTest(app, 'ClusterSnapshotInteg', {
13366
testCases: [stack],
13467
diffAssets: true,
13568
});
136-
app.synth();

0 commit comments

Comments
 (0)