Skip to content

Commit 910c8bf

Browse files
rpanfilimergify[bot]
authored andcommitted
feat(rds): add support for monitoring to database cluster (#2828)
Let a user define a monitoring interval period. It will be also possible to specify a monitoring IAM Role to manage instances monitoring, otherwise a valid Role will be auto-generated. This change adds optional props `monitoringInterval` and `monitoringRole` to `DatabaseClusterProps` and optional `monitoringRole` to `DatabaseInstanceProps` closes #2826
1 parent de0a028 commit 910c8bf

File tree

4 files changed

+172
-4
lines changed

4 files changed

+172
-4
lines changed

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import ec2 = require('@aws-cdk/aws-ec2');
2+
import { IRole, ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
23
import kms = require('@aws-cdk/aws-kms');
34
import secretsmanager = require('@aws-cdk/aws-secretsmanager');
4-
import { Construct, RemovalPolicy, Resource, Token } from '@aws-cdk/core';
5+
import { Construct, Duration, RemovalPolicy, Resource, Token } from '@aws-cdk/core';
56
import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref';
67
import { DatabaseSecret } from './database-secret';
78
import { Endpoint } from './endpoint';
@@ -128,6 +129,21 @@ export interface DatabaseClusterProps {
128129
* @default - Retain cluster.
129130
*/
130131
readonly removalPolicy?: RemovalPolicy
132+
133+
/**
134+
* The interval, in seconds, between points when Amazon RDS collects enhanced
135+
* monitoring metrics for the DB instances.
136+
*
137+
* @default no enhanced monitoring
138+
*/
139+
readonly monitoringInterval?: Duration;
140+
141+
/**
142+
* Role that will be used to manage DB instances monitoring.
143+
*
144+
* @default - A role is automatically created for you
145+
*/
146+
readonly monitoringRole?: IRole;
131147
}
132148

133149
/**
@@ -345,6 +361,17 @@ export class DatabaseCluster extends DatabaseClusterBase {
345361

346362
// Get the actual subnet objects so we can depend on internet connectivity.
347363
const internetConnected = props.instanceProps.vpc.selectSubnets(props.instanceProps.vpcSubnets).internetConnectivityEstablished;
364+
365+
let monitoringRole;
366+
if (props.monitoringInterval && props.monitoringInterval.toSeconds()) {
367+
monitoringRole = props.monitoringRole || new Role(this, "MonitoringRole", {
368+
assumedBy: new ServicePrincipal("monitoring.rds.amazonaws.com"),
369+
managedPolicies: [
370+
ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSEnhancedMonitoringRole')
371+
]
372+
});
373+
}
374+
348375
for (let i = 0; i < instanceCount; i++) {
349376
const instanceIndex = i + 1;
350377

@@ -366,6 +393,8 @@ export class DatabaseCluster extends DatabaseClusterBase {
366393
// This is already set on the Cluster. Unclear to me whether it should be repeated or not. Better yes.
367394
dbSubnetGroupName: subnetGroup.ref,
368395
dbParameterGroupName: props.instanceProps.parameterGroup && props.instanceProps.parameterGroup.parameterGroupName,
396+
monitoringInterval: props.monitoringInterval && props.monitoringInterval.toSeconds(),
397+
monitoringRoleArn: monitoringRole && monitoringRole.roleArn
369398
});
370399

371400
instance.applyRemovalPolicy(props.removalPolicy, {

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,13 @@ export interface DatabaseInstanceNewProps {
374374
*/
375375
readonly monitoringInterval?: Duration;
376376

377+
/**
378+
* Role that will be used to manage DB instance monitoring.
379+
*
380+
* @default - A role is automatically created for you
381+
*/
382+
readonly monitoringRole?: iam.IRole;
383+
377384
/**
378385
* Whether to enable Performance Insights for the DB instance.
379386
*
@@ -493,8 +500,8 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
493500
this.securityGroupId = this.securityGroup.securityGroupId;
494501

495502
let monitoringRole;
496-
if (props.monitoringInterval) {
497-
monitoringRole = new iam.Role(this, 'MonitoringRole', {
503+
if (props.monitoringInterval && props.monitoringInterval.toSeconds()) {
504+
monitoringRole = props.monitoringRole || new iam.Role(this, 'MonitoringRole', {
498505
assumedBy: new iam.ServicePrincipal('monitoring.rds.amazonaws.com'),
499506
managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSEnhancedMonitoringRole')],
500507
});

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

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect, haveResource, ResourcePart } from '@aws-cdk/assert';
22
import ec2 = require('@aws-cdk/aws-ec2');
3+
import { ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
34
import kms = require('@aws-cdk/aws-kms');
45
import cdk = require('@aws-cdk/core');
56
import { SecretValue } from '@aws-cdk/core';
@@ -371,6 +372,103 @@ export = {
371372
GroupId: 'sg-123456789',
372373
}));
373374

375+
test.done();
376+
},
377+
378+
"cluster with enabled monitoring"(test: Test) {
379+
// GIVEN
380+
const stack = testStack();
381+
const vpc = new ec2.Vpc(stack, "VPC");
382+
383+
// WHEN
384+
new DatabaseCluster(stack, "Database", {
385+
engine: DatabaseClusterEngine.AURORA,
386+
instances: 1,
387+
masterUser: {
388+
username: "admin"
389+
},
390+
instanceProps: {
391+
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
392+
vpc
393+
},
394+
monitoringInterval: cdk.Duration.minutes(1),
395+
});
396+
397+
// THEN
398+
expect(stack).to(haveResource("AWS::RDS::DBInstance", {
399+
MonitoringInterval: 60,
400+
MonitoringRoleArn: {
401+
"Fn::GetAtt": ["DatabaseMonitoringRole576991DA", "Arn"]
402+
}
403+
}, ResourcePart.Properties));
404+
405+
expect(stack).to(haveResource("AWS::IAM::Role", {
406+
AssumeRolePolicyDocument: {
407+
Statement: [
408+
{
409+
Action: "sts:AssumeRole",
410+
Effect: "Allow",
411+
Principal: {
412+
Service: "monitoring.rds.amazonaws.com"
413+
}
414+
}
415+
],
416+
Version: "2012-10-17"
417+
},
418+
ManagedPolicyArns: [
419+
{
420+
"Fn::Join": [
421+
"",
422+
[
423+
"arn:",
424+
{
425+
Ref: "AWS::Partition"
426+
},
427+
":iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
428+
]
429+
]
430+
}
431+
]
432+
}));
433+
434+
test.done();
435+
},
436+
437+
'create a cluster with imported monitoring role'(test: Test) {
438+
// GIVEN
439+
const stack = testStack();
440+
const vpc = new ec2.Vpc(stack, "VPC");
441+
442+
const monitoringRole = new Role(stack, "MonitoringRole", {
443+
assumedBy: new ServicePrincipal("monitoring.rds.amazonaws.com"),
444+
managedPolicies: [
445+
ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSEnhancedMonitoringRole')
446+
]
447+
});
448+
449+
// WHEN
450+
new DatabaseCluster(stack, "Database", {
451+
engine: DatabaseClusterEngine.AURORA,
452+
instances: 1,
453+
masterUser: {
454+
username: "admin"
455+
},
456+
instanceProps: {
457+
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
458+
vpc
459+
},
460+
monitoringInterval: cdk.Duration.minutes(1),
461+
monitoringRole
462+
});
463+
464+
// THEN
465+
expect(stack).to(haveResource("AWS::RDS::DBInstance", {
466+
MonitoringInterval: 60,
467+
MonitoringRoleArn: {
468+
"Fn::GetAtt": ["MonitoringRole90457BF9", "Arn"]
469+
}
470+
}, ResourcePart.Properties));
471+
374472
test.done();
375473
}
376474
};

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

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { countResources, expect, haveResource, ResourcePart } from '@aws-cdk/assert';
22
import ec2 = require('@aws-cdk/aws-ec2');
33
import targets = require('@aws-cdk/aws-events-targets');
4+
import { ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
45
import lambda = require('@aws-cdk/aws-lambda');
56
import logs = require('@aws-cdk/aws-logs');
67
import cdk = require('@aws-cdk/core');
@@ -512,5 +513,38 @@ export = {
512513
}));
513514

514515
test.done();
515-
}
516+
},
517+
518+
'create an instance with imported monitoring role'(test: Test) {
519+
// GIVEN
520+
const stack = new cdk.Stack();
521+
const vpc = new ec2.Vpc(stack, 'VPC');
522+
523+
const monitoringRole = new Role(stack, "MonitoringRole", {
524+
assumedBy: new ServicePrincipal("monitoring.rds.amazonaws.com"),
525+
managedPolicies: [
526+
ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSEnhancedMonitoringRole')
527+
]
528+
});
529+
530+
// WHEN
531+
new rds.DatabaseInstance(stack, 'Instance', {
532+
engine: rds.DatabaseInstanceEngine.MYSQL,
533+
instanceClass: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
534+
masterUsername: 'admin',
535+
vpc,
536+
monitoringInterval: cdk.Duration.minutes(1),
537+
monitoringRole
538+
});
539+
540+
// THEN
541+
expect(stack).to(haveResource("AWS::RDS::DBInstance", {
542+
MonitoringInterval: 60,
543+
MonitoringRoleArn: {
544+
"Fn::GetAtt": ["MonitoringRole90457BF9", "Arn"]
545+
}
546+
}, ResourcePart.Properties));
547+
548+
test.done();
549+
},
516550
};

0 commit comments

Comments
 (0)