Skip to content

Commit 9c1b0c1

Browse files
authored
feat(rds): performance insights for DatabaseCluster instances (#10092)
Adds the EnablePerformanceInsights and related props to `InstanceProps` for instances within a cluster. _Note:_ I opted not to try to coalesce `InstanceProps`, `DatabaseInstanceNewProps`, and `DatabaseInstanceSourceProps` in this PR; there are a ton of overlapping properties, but it's not immediately clear which fields are relevant for cluster instances vs standalone instances. I think investigating and validiting how to combine these is a significantly larger task. fixes #7957 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent b72daf3 commit 9c1b0c1

File tree

5 files changed

+194
-28
lines changed

5 files changed

+194
-28
lines changed

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

+17-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref';
1010
import { DatabaseSecret } from './database-secret';
1111
import { Endpoint } from './endpoint';
1212
import { IParameterGroup } from './parameter-group';
13-
import { BackupProps, InstanceProps, Login, RotationMultiUserOptions } from './props';
13+
import { BackupProps, InstanceProps, Login, PerformanceInsightRetention, RotationMultiUserOptions } from './props';
1414
import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy';
1515
import { CfnDBCluster, CfnDBInstance, CfnDBSubnetGroup } from './rds.generated';
1616

@@ -563,8 +563,9 @@ export class DatabaseCluster extends DatabaseClusterBase {
563563
throw new Error('At least one instance is required');
564564
}
565565

566+
const instanceProps = props.instanceProps;
566567
// Get the actual subnet objects so we can depend on internet connectivity.
567-
const internetConnected = props.instanceProps.vpc.selectSubnets(props.instanceProps.vpcSubnets).internetConnectivityEstablished;
568+
const internetConnected = instanceProps.vpc.selectSubnets(instanceProps.vpcSubnets).internetConnectivityEstablished;
568569

569570
let monitoringRole;
570571
if (props.monitoringInterval && props.monitoringInterval.toSeconds()) {
@@ -576,15 +577,21 @@ export class DatabaseCluster extends DatabaseClusterBase {
576577
});
577578
}
578579

579-
const instanceType = props.instanceProps.instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM);
580-
const instanceParameterGroupConfig = props.instanceProps.parameterGroup?.bindToInstance({});
580+
const enablePerformanceInsights = instanceProps.enablePerformanceInsights
581+
|| instanceProps.performanceInsightRetention !== undefined || instanceProps.performanceInsightEncryptionKey !== undefined;
582+
if (enablePerformanceInsights && instanceProps.enablePerformanceInsights === false) {
583+
throw new Error('`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set');
584+
}
585+
586+
const instanceType = instanceProps.instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM);
587+
const instanceParameterGroupConfig = instanceProps.parameterGroup?.bindToInstance({});
581588
for (let i = 0; i < instanceCount; i++) {
582589
const instanceIndex = i + 1;
583590
const instanceIdentifier = props.instanceIdentifierBase != null ? `${props.instanceIdentifierBase}${instanceIndex}` :
584591
props.clusterIdentifier != null ? `${props.clusterIdentifier}instance${instanceIndex}` :
585592
undefined;
586593

587-
const publiclyAccessible = props.instanceProps.vpcSubnets && props.instanceProps.vpcSubnets.subnetType === ec2.SubnetType.PUBLIC;
594+
const publiclyAccessible = instanceProps.vpcSubnets && instanceProps.vpcSubnets.subnetType === ec2.SubnetType.PUBLIC;
588595

589596
const instance = new CfnDBInstance(this, `Instance${instanceIndex}`, {
590597
// Link to cluster
@@ -595,6 +602,11 @@ export class DatabaseCluster extends DatabaseClusterBase {
595602
// Instance properties
596603
dbInstanceClass: databaseInstanceType(instanceType),
597604
publiclyAccessible,
605+
enablePerformanceInsights: enablePerformanceInsights || instanceProps.enablePerformanceInsights, // fall back to undefined if not set
606+
performanceInsightsKmsKeyId: instanceProps.performanceInsightEncryptionKey?.keyArn,
607+
performanceInsightsRetentionPeriod: enablePerformanceInsights
608+
? (instanceProps.performanceInsightRetention || PerformanceInsightRetention.DEFAULT)
609+
: undefined,
598610
// This is already set on the Cluster. Unclear to me whether it should be repeated or not. Better yes.
599611
dbSubnetGroupName: subnetGroup.ref,
600612
dbParameterGroupName: instanceParameterGroupConfig?.parameterGroupName,

packages/@aws-cdk/aws-rds/lib/instance.ts

+11-22
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { Endpoint } from './endpoint';
1010
import { IInstanceEngine } from './instance-engine';
1111
import { IOptionGroup } from './option-group';
1212
import { IParameterGroup } from './parameter-group';
13-
import { RotationMultiUserOptions } from './props';
13+
import { PerformanceInsightRetention, RotationMultiUserOptions } from './props';
1414
import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy';
1515
import { CfnDBInstance, CfnDBInstanceProps, CfnDBSubnetGroup } from './rds.generated';
1616

@@ -243,21 +243,6 @@ export enum StorageType {
243243
IO1 = 'io1'
244244
}
245245

246-
/**
247-
* The retention period for Performance Insight.
248-
*/
249-
export enum PerformanceInsightRetention {
250-
/**
251-
* Default retention period of 7 days.
252-
*/
253-
DEFAULT = 7,
254-
255-
/**
256-
* Long term retention period of 2 years.
257-
*/
258-
LONG_TERM = 731
259-
}
260-
261246
/**
262247
* Construction properties for a DatabaseInstanceNew
263248
*/
@@ -415,7 +400,7 @@ export interface DatabaseInstanceNewProps {
415400
/**
416401
* Whether to enable Performance Insights for the DB instance.
417402
*
418-
* @default false
403+
* @default - false, unless ``performanceInsightRentention`` or ``performanceInsightEncryptionKey`` is set.
419404
*/
420405
readonly enablePerformanceInsights?: boolean;
421406

@@ -584,6 +569,12 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
584569
this.cloudwatchLogsRetentionRole = props.cloudwatchLogsRetentionRole;
585570
this.enableIamAuthentication = props.iamAuthentication;
586571

572+
const enablePerformanceInsights = props.enablePerformanceInsights
573+
|| props.performanceInsightRetention !== undefined || props.performanceInsightEncryptionKey !== undefined;
574+
if (enablePerformanceInsights && props.enablePerformanceInsights === false) {
575+
throw new Error('`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set');
576+
}
577+
587578
if (props.domain) {
588579
this.domainId = props.domain;
589580
this.domainRole = props.domainRole || new iam.Role(this, 'RDSDirectoryServiceRole', {
@@ -606,16 +597,14 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
606597
deletionProtection,
607598
enableCloudwatchLogsExports: this.cloudwatchLogsExports,
608599
enableIamDatabaseAuthentication: Lazy.anyValue({ produce: () => this.enableIamAuthentication }),
609-
enablePerformanceInsights: props.enablePerformanceInsights,
600+
enablePerformanceInsights: enablePerformanceInsights || props.enablePerformanceInsights, // fall back to undefined if not set,
610601
iops,
611602
monitoringInterval: props.monitoringInterval && props.monitoringInterval.toSeconds(),
612603
monitoringRoleArn: monitoringRole && monitoringRole.roleArn,
613604
multiAz: props.multiAz,
614605
optionGroupName: props.optionGroup && props.optionGroup.optionGroupName,
615-
performanceInsightsKmsKeyId: props.enablePerformanceInsights
616-
? props.performanceInsightEncryptionKey && props.performanceInsightEncryptionKey.keyArn
617-
: undefined,
618-
performanceInsightsRetentionPeriod: props.enablePerformanceInsights
606+
performanceInsightsKmsKeyId: props.performanceInsightEncryptionKey?.keyArn,
607+
performanceInsightsRetentionPeriod: enablePerformanceInsights
619608
? (props.performanceInsightRetention || PerformanceInsightRetention.DEFAULT)
620609
: undefined,
621610
port: props.port ? props.port.toString() : undefined,

packages/@aws-cdk/aws-rds/lib/props.ts

+36
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,27 @@ export interface InstanceProps {
4242
* @default no parameter group
4343
*/
4444
readonly parameterGroup?: IParameterGroup;
45+
46+
/**
47+
* Whether to enable Performance Insights for the DB instance.
48+
*
49+
* @default - false, unless ``performanceInsightRentention`` or ``performanceInsightEncryptionKey`` is set.
50+
*/
51+
readonly enablePerformanceInsights?: boolean;
52+
53+
/**
54+
* The amount of time, in days, to retain Performance Insights data.
55+
*
56+
* @default 7
57+
*/
58+
readonly performanceInsightRetention?: PerformanceInsightRetention;
59+
60+
/**
61+
* The AWS KMS key for encryption of Performance Insights data.
62+
*
63+
* @default - default master key
64+
*/
65+
readonly performanceInsightEncryptionKey?: kms.IKey;
4566
}
4667

4768
/**
@@ -127,3 +148,18 @@ export interface RotationMultiUserOptions {
127148
*/
128149
readonly automaticallyAfter?: Duration;
129150
}
151+
152+
/**
153+
* The retention period for Performance Insight.
154+
*/
155+
export enum PerformanceInsightRetention {
156+
/**
157+
* Default retention period of 7 days.
158+
*/
159+
DEFAULT = 7,
160+
161+
/**
162+
* Long term retention period of 2 years.
163+
*/
164+
LONG_TERM = 731
165+
}

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

+78-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as logs from '@aws-cdk/aws-logs';
66
import * as s3 from '@aws-cdk/aws-s3';
77
import * as cdk from '@aws-cdk/core';
88
import { Test } from 'nodeunit';
9-
import { AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, DatabaseCluster, DatabaseClusterEngine, ParameterGroup } from '../lib';
9+
import { AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, DatabaseCluster, DatabaseClusterEngine, ParameterGroup, PerformanceInsightRetention } from '../lib';
1010

1111
export = {
1212
'creating a Cluster also creates 2 DB Instances'(test: Test) {
@@ -293,6 +293,83 @@ export = {
293293

294294
},
295295

296+
'performance insights': {
297+
'cluster with all performance insights properties'(test: Test) {
298+
// GIVEN
299+
const stack = testStack();
300+
const vpc = new ec2.Vpc(stack, 'VPC');
301+
302+
// WHEN
303+
new DatabaseCluster(stack, 'Database', {
304+
engine: DatabaseClusterEngine.AURORA,
305+
masterUser: {
306+
username: 'admin',
307+
},
308+
instanceProps: {
309+
vpc,
310+
enablePerformanceInsights: true,
311+
performanceInsightRetention: PerformanceInsightRetention.LONG_TERM,
312+
performanceInsightEncryptionKey: new kms.Key(stack, 'Key'),
313+
},
314+
});
315+
316+
expect(stack).to(haveResource('AWS::RDS::DBInstance', {
317+
EnablePerformanceInsights: true,
318+
PerformanceInsightsRetentionPeriod: 731,
319+
PerformanceInsightsKMSKeyId: { 'Fn::GetAtt': ['Key961B73FD', 'Arn'] },
320+
}));
321+
322+
test.done();
323+
},
324+
325+
'setting performance insights fields enables performance insights'(test: Test) {
326+
// GIVEN
327+
const stack = testStack();
328+
const vpc = new ec2.Vpc(stack, 'VPC');
329+
330+
// WHEN
331+
new DatabaseCluster(stack, 'Database', {
332+
engine: DatabaseClusterEngine.AURORA,
333+
masterUser: {
334+
username: 'admin',
335+
},
336+
instanceProps: {
337+
vpc,
338+
performanceInsightRetention: PerformanceInsightRetention.LONG_TERM,
339+
},
340+
});
341+
342+
expect(stack).to(haveResource('AWS::RDS::DBInstance', {
343+
EnablePerformanceInsights: true,
344+
PerformanceInsightsRetentionPeriod: 731,
345+
}));
346+
347+
test.done();
348+
},
349+
350+
'throws if performance insights fields are set but performance insights is disabled'(test: Test) {
351+
// GIVEN
352+
const stack = testStack();
353+
const vpc = new ec2.Vpc(stack, 'VPC');
354+
355+
test.throws(() => {
356+
new DatabaseCluster(stack, 'Database', {
357+
engine: DatabaseClusterEngine.AURORA,
358+
masterUser: {
359+
username: 'admin',
360+
},
361+
instanceProps: {
362+
vpc,
363+
enablePerformanceInsights: false,
364+
performanceInsightRetention: PerformanceInsightRetention.DEFAULT,
365+
},
366+
});
367+
}, /`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set/);
368+
369+
test.done();
370+
},
371+
},
372+
296373
'create a cluster using a specific version of MySQL'(test: Test) {
297374
// GIVEN
298375
const stack = testStack();

packages/@aws-cdk/aws-rds/test/test.instance.ts

+52
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ABSENT, countResources, expect, haveResource, ResourcePart, haveResourc
22
import * as ec2 from '@aws-cdk/aws-ec2';
33
import * as targets from '@aws-cdk/aws-events-targets';
44
import { ManagedPolicy, Role, ServicePrincipal, AccountPrincipal } from '@aws-cdk/aws-iam';
5+
import * as kms from '@aws-cdk/aws-kms';
56
import * as lambda from '@aws-cdk/aws-lambda';
67
import * as logs from '@aws-cdk/aws-logs';
78
import * as cdk from '@aws-cdk/core';
@@ -911,4 +912,55 @@ export = {
911912

912913
test.done();
913914
},
915+
916+
'performance insights': {
917+
'instance with all performance insights properties'(test: Test) {
918+
new rds.DatabaseInstance(stack, 'Instance', {
919+
engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }),
920+
masterUsername: 'admin',
921+
vpc,
922+
enablePerformanceInsights: true,
923+
performanceInsightRetention: rds.PerformanceInsightRetention.LONG_TERM,
924+
performanceInsightEncryptionKey: new kms.Key(stack, 'Key'),
925+
});
926+
927+
expect(stack).to(haveResource('AWS::RDS::DBInstance', {
928+
EnablePerformanceInsights: true,
929+
PerformanceInsightsRetentionPeriod: 731,
930+
PerformanceInsightsKMSKeyId: { 'Fn::GetAtt': ['Key961B73FD', 'Arn'] },
931+
}));
932+
933+
test.done();
934+
},
935+
936+
'setting performance insights fields enables performance insights'(test: Test) {
937+
new rds.DatabaseInstance(stack, 'Instance', {
938+
engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }),
939+
masterUsername: 'admin',
940+
vpc,
941+
performanceInsightRetention: rds.PerformanceInsightRetention.LONG_TERM,
942+
});
943+
944+
expect(stack).to(haveResource('AWS::RDS::DBInstance', {
945+
EnablePerformanceInsights: true,
946+
PerformanceInsightsRetentionPeriod: 731,
947+
}));
948+
949+
test.done();
950+
},
951+
952+
'throws if performance insights fields are set but performance insights is disabled'(test: Test) {
953+
test.throws(() => {
954+
new rds.DatabaseInstance(stack, 'Instance', {
955+
engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }),
956+
masterUsername: 'admin',
957+
vpc,
958+
enablePerformanceInsights: false,
959+
performanceInsightRetention: rds.PerformanceInsightRetention.DEFAULT,
960+
});
961+
}, /`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set/);
962+
963+
test.done();
964+
},
965+
},
914966
};

0 commit comments

Comments
 (0)