Skip to content

Commit

Permalink
feat(rds): add support for monitoring to database cluster
Browse files Browse the repository at this point in the history
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 aws#2826
  • Loading branch information
rpanfili committed Sep 11, 2019
1 parent 07d25d8 commit 06f1bdb
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 4 deletions.
31 changes: 30 additions & 1 deletion packages/@aws-cdk/aws-rds/lib/cluster.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import ec2 = require('@aws-cdk/aws-ec2');
import { IRole, ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
import kms = require('@aws-cdk/aws-kms');
import secretsmanager = require('@aws-cdk/aws-secretsmanager');
import { Construct, RemovalPolicy, Resource, Token } from '@aws-cdk/core';
import { Construct, Duration, RemovalPolicy, Resource, Token } from '@aws-cdk/core';
import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref';
import { DatabaseSecret } from './database-secret';
import { Endpoint } from './endpoint';
Expand Down Expand Up @@ -128,6 +129,21 @@ export interface DatabaseClusterProps {
* @default - Retain cluster.
*/
readonly removalPolicy?: RemovalPolicy

/**
* The interval, in seconds, between points when Amazon RDS collects enhanced
* monitoring metrics for the DB instances.
*
* @default no enhanced monitoring
*/
readonly monitoringInterval?: Duration;

/**
* Role that will be used to manage DB instances monitoring.
*
* @default - A role is automatically created for you
*/
readonly monitoringRole?: IRole;
}

/**
Expand Down Expand Up @@ -345,6 +361,17 @@ export class DatabaseCluster extends DatabaseClusterBase {

// Get the actual subnet objects so we can depend on internet connectivity.
const internetConnected = props.instanceProps.vpc.selectSubnets(props.instanceProps.vpcSubnets).internetConnectivityEstablished;

let monitoringRole;
if (props.monitoringInterval && props.monitoringInterval.toSeconds()) {
monitoringRole = props.monitoringRole || new Role(this, "MonitoringRole", {
assumedBy: new ServicePrincipal("monitoring.rds.amazonaws.com"),
managedPolicies: [
ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSEnhancedMonitoringRole')
]
});
}

for (let i = 0; i < instanceCount; i++) {
const instanceIndex = i + 1;

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

instance.applyRemovalPolicy(props.removalPolicy, {
Expand Down
11 changes: 9 additions & 2 deletions packages/@aws-cdk/aws-rds/lib/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,13 @@ export interface DatabaseInstanceNewProps {
*/
readonly monitoringInterval?: Duration;

/**
* Role that will be used to manage DB instance monitoring.
*
* @default - A role is automatically created for you
*/
readonly monitoringRole?: iam.IRole;

/**
* Whether to enable Performance Insights for the DB instance.
*
Expand Down Expand Up @@ -493,8 +500,8 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
this.securityGroupId = this.securityGroup.securityGroupId;

let monitoringRole;
if (props.monitoringInterval) {
monitoringRole = new iam.Role(this, 'MonitoringRole', {
if (props.monitoringInterval && props.monitoringInterval.toSeconds()) {
monitoringRole = props.monitoringRole || new iam.Role(this, 'MonitoringRole', {
assumedBy: new iam.ServicePrincipal('monitoring.rds.amazonaws.com'),
managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSEnhancedMonitoringRole')],
});
Expand Down
98 changes: 98 additions & 0 deletions packages/@aws-cdk/aws-rds/test/test.cluster.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect, haveResource, ResourcePart } from '@aws-cdk/assert';
import ec2 = require('@aws-cdk/aws-ec2');
import { ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
import kms = require('@aws-cdk/aws-kms');
import cdk = require('@aws-cdk/core');
import { SecretValue } from '@aws-cdk/core';
Expand Down Expand Up @@ -371,6 +372,103 @@ export = {
GroupId: 'sg-123456789',
}));

test.done();
},

"cluster with enabled monitoring"(test: Test) {
// GIVEN
const stack = testStack();
const vpc = new ec2.Vpc(stack, "VPC");

// WHEN
new DatabaseCluster(stack, "Database", {
engine: DatabaseClusterEngine.AURORA,
instances: 1,
masterUser: {
username: "admin"
},
instanceProps: {
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
vpc
},
monitoringInterval: cdk.Duration.minutes(1),
});

// THEN
expect(stack).to(haveResource("AWS::RDS::DBInstance", {
MonitoringInterval: 60,
MonitoringRoleArn: {
"Fn::GetAtt": ["DatabaseMonitoringRole576991DA", "Arn"]
}
}, ResourcePart.Properties));

expect(stack).to(haveResource("AWS::IAM::Role", {
AssumeRolePolicyDocument: {
Statement: [
{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: {
Service: "monitoring.rds.amazonaws.com"
}
}
],
Version: "2012-10-17"
},
ManagedPolicyArns: [
{
"Fn::Join": [
"",
[
"arn:",
{
Ref: "AWS::Partition"
},
":iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
]
]
}
]
}));

test.done();
},

'create a cluster with imported monitoring role'(test: Test) {
// GIVEN
const stack = testStack();
const vpc = new ec2.Vpc(stack, "VPC");

const monitoringRole = new Role(stack, "MonitoringRole", {
assumedBy: new ServicePrincipal("monitoring.rds.amazonaws.com"),
managedPolicies: [
ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSEnhancedMonitoringRole')
]
});

// WHEN
new DatabaseCluster(stack, "Database", {
engine: DatabaseClusterEngine.AURORA,
instances: 1,
masterUser: {
username: "admin"
},
instanceProps: {
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
vpc
},
monitoringInterval: cdk.Duration.minutes(1),
monitoringRole
});

// THEN
expect(stack).to(haveResource("AWS::RDS::DBInstance", {
MonitoringInterval: 60,
MonitoringRoleArn: {
"Fn::GetAtt": ["MonitoringRole90457BF9", "Arn"]
}
}, ResourcePart.Properties));

test.done();
}
};
Expand Down
36 changes: 35 additions & 1 deletion packages/@aws-cdk/aws-rds/test/test.instance.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { countResources, expect, haveResource, ResourcePart } from '@aws-cdk/assert';
import ec2 = require('@aws-cdk/aws-ec2');
import targets = require('@aws-cdk/aws-events-targets');
import { ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
import lambda = require('@aws-cdk/aws-lambda');
import logs = require('@aws-cdk/aws-logs');
import cdk = require('@aws-cdk/core');
Expand Down Expand Up @@ -512,5 +513,38 @@ export = {
}));

test.done();
}
},

'create an instance with imported monitoring role'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'VPC');

const monitoringRole = new Role(stack, "MonitoringRole", {
assumedBy: new ServicePrincipal("monitoring.rds.amazonaws.com"),
managedPolicies: [
ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSEnhancedMonitoringRole')
]
});

// WHEN
new rds.DatabaseInstance(stack, 'Instance', {
engine: rds.DatabaseInstanceEngine.MYSQL,
instanceClass: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
masterUsername: 'admin',
vpc,
monitoringInterval: cdk.Duration.minutes(1),
monitoringRole
});

// THEN
expect(stack).to(haveResource("AWS::RDS::DBInstance", {
MonitoringInterval: 60,
MonitoringRoleArn: {
"Fn::GetAtt": ["MonitoringRole90457BF9", "Arn"]
}
}, ResourcePart.Properties));

test.done();
},
};

0 comments on commit 06f1bdb

Please sign in to comment.