Skip to content

Commit

Permalink
Add DB version pre-flight checks
Browse files Browse the repository at this point in the history
  • Loading branch information
ddneilson committed Nov 18, 2020
1 parent 25355ae commit d1ae157
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 0 deletions.
25 changes: 25 additions & 0 deletions packages/aws-rfdk/lib/deadline/lib/database-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import * as path from 'path';
import {
CfnDBCluster,
CfnDBInstance,
IDatabaseCluster,
} from '@aws-cdk/aws-docdb';
Expand All @@ -22,6 +23,7 @@ import {
ISecret,
} from '@aws-cdk/aws-secretsmanager';
import {
Annotations,
IConstruct,
Stack,
} from '@aws-cdk/core';
Expand Down Expand Up @@ -163,6 +165,10 @@ class DocDBDatabaseConnection extends DatabaseConnection {
constructor(private readonly props: DocDBConnectionOptions) {
super();

if (!this.isCompatibleDocDBVersion()) {
Annotations.of(props.database).addError('engineVersion must be 3.6.0 to be compatible with Deadline');
}

this.containerEnvironment = {
// The container must fetch the credentials from Secrets Manager
DB_CREDENTIALS_URI: this.props.login.secretArn,
Expand Down Expand Up @@ -256,6 +262,25 @@ class DocDBDatabaseConnection extends DatabaseConnection {
throw new Error('The internal implementation of the AWS CDK\'s DocumentDB cluster construct may have changed. Please update to a newer RFDK for an updated implementation, or file a ticket if this is the latest release.');
}
}

/**
* Deadline is only compatible with MongoDB 3.6. This function attempts to determine whether
* the given DocDB version is compatible.
*/
protected isCompatibleDocDBVersion(): boolean {
// The defaultChild of a DocDB DatabaseCluster is a CfnDBCluster, but we only have this
// child if the customer didn't import from attributes. We can check the DB version by
// checking the value of the engineVersion property of that object.
if (this.props.database.node.defaultChild) {
const cluster = this.props.database.node.defaultChild! as CfnDBCluster;
if (cluster.engineVersion === '3.6.0') {
return true;
}
return false;
}

return true; // No information, assume it's compatible.
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/aws-rfdk/lib/deadline/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ export interface RepositoryProps {

/**
* Specify the database where the deadline schema needs to be initialized.
* Note that Deadline supports only databases that are compatible with MongoDB 3.6.
*
* @default A Document DB Cluster will be created with a single db.r5.large instance.
*/
Expand Down
137 changes: 137 additions & 0 deletions packages/aws-rfdk/lib/deadline/test/database-connection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
import {
PrivateHostedZone,
} from '@aws-cdk/aws-route53';
import { Secret } from '@aws-cdk/aws-secretsmanager';
import {
Duration,
Stack,
Expand Down Expand Up @@ -77,6 +78,7 @@ describe('DocumentDB', () => {
backup: {
retention: Duration.days(15),
},
engineVersion: '3.6.0',
});

if (!database.secret) {
Expand Down Expand Up @@ -264,6 +266,141 @@ describe('DocumentDB', () => {

});

describe('DocumentDB Version Checks', () => {
let stack: Stack;
let vpc: Vpc;
beforeEach(() => {
stack = new Stack();
vpc = new Vpc(stack, 'VPC');
});

test('Compatible version', () => {
// GIVEN
const database = new DatabaseCluster(stack, 'DbCluster', {
masterUser: {
username: 'master',
},
instanceProps: {
instanceType: InstanceType.of(
InstanceClass.R5,
InstanceSize.XLARGE,
),
vpc,
vpcSubnets: {
onePerAz: true,
subnetType: SubnetType.PRIVATE,
},
},
backup: {
retention: Duration.days(15),
},
engineVersion: '3.6.0',
});

// WHEN
DatabaseConnection.forDocDB({database, login: database.secret!});

// THEN
expect(database.node.metadata.length).toBe(0);
});

test('When from attributes', () => {
// GIVEN
const sg = new SecurityGroup(stack, 'SG', {
vpc,
});
const secret = new Secret(stack, 'Secret');
const database = DatabaseCluster.fromDatabaseClusterAttributes(stack, 'DbCluster', {
clusterEndpointAddress: '1.2.3.4',
clusterIdentifier: 'foo',
instanceEndpointAddresses: [ '1.2.3.5' ],
instanceIdentifiers: [ 'i0' ],
port: 27001,
readerEndpointAddress: '1.2.3.6',
securityGroup: sg,
});

// WHEN
DatabaseConnection.forDocDB({database, login: secret});

// THEN
expect(database.node.metadata.length).toBe(0);
});

test('No engineVersion given', () => {
// GIVEN
const database = new DatabaseCluster(stack, 'DbCluster', {
masterUser: {
username: 'master',
},
instanceProps: {
instanceType: InstanceType.of(
InstanceClass.R5,
InstanceSize.XLARGE,
),
vpc,
vpcSubnets: {
onePerAz: true,
subnetType: SubnetType.PRIVATE,
},
},
backup: {
retention: Duration.days(15),
},
});

// WHEN
DatabaseConnection.forDocDB({database, login: database.secret!});

// THEN
expect(database.node.metadata).toEqual(
expect.arrayContaining([
expect.objectContaining({
type: 'aws:cdk:error',
data: 'engineVersion must be 3.6.0 to be compatible with Deadline',
}),
]),
);
});

test('engineVersion not 3.6.0', () => {
// GIVEN
const database = new DatabaseCluster(stack, 'DbCluster', {
masterUser: {
username: 'master',
},
instanceProps: {
instanceType: InstanceType.of(
InstanceClass.R5,
InstanceSize.XLARGE,
),
vpc,
vpcSubnets: {
onePerAz: true,
subnetType: SubnetType.PRIVATE,
},
},
backup: {
retention: Duration.days(15),
},
engineVersion: '4.0.0',
});

// WHEN
DatabaseConnection.forDocDB({database, login: database.secret!});

// THEN
expect(database.node.metadata).toEqual(
expect.arrayContaining([
expect.objectContaining({
type: 'aws:cdk:error',
data: 'engineVersion must be 3.6.0 to be compatible with Deadline',
}),
]),
);
});
});

describe('MongoDB', () => {
let stack: Stack;
let vpc: Vpc;
Expand Down

0 comments on commit d1ae157

Please sign in to comment.