From 25355ae6013bb90adc5006c18e1aef2314918ab8 Mon Sep 17 00:00:00 2001 From: Daniel Neilson Date: Thu, 12 Nov 2020 18:52:50 +0000 Subject: [PATCH 1/4] fix(deadline): Lock down docdb engine to version 3.6.0 --- .../python/package/lib/storage_tier.py | 1 + .../All-In-AWS-Infrastructure-Basic/ts/lib/storage-tier.ts | 1 + integ/lib/storage-struct.ts | 1 + packages/aws-rfdk/lib/deadline/lib/repository.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/examples/deadline/All-In-AWS-Infrastructure-Basic/python/package/lib/storage_tier.py b/examples/deadline/All-In-AWS-Infrastructure-Basic/python/package/lib/storage_tier.py index f83025410..4eeec6acd 100644 --- a/examples/deadline/All-In-AWS-Infrastructure-Basic/python/package/lib/storage_tier.py +++ b/examples/deadline/All-In-AWS-Infrastructure-Basic/python/package/lib/storage_tier.py @@ -130,6 +130,7 @@ def __init__(self, scope: Construct, stack_id: str, *, props: StorageTierDocDBPr # It is recommended that when creating your render farm you use at least 2 instances for redundancy. instances=1, master_user=Login(username='adminuser'), + engine_version='3.6.0', backup=BackupProps( # We recommend setting the retention of your backups to 15 days # for security reasons. The default retention is just one day. diff --git a/examples/deadline/All-In-AWS-Infrastructure-Basic/ts/lib/storage-tier.ts b/examples/deadline/All-In-AWS-Infrastructure-Basic/ts/lib/storage-tier.ts index 46efb8fea..421ba3353 100644 --- a/examples/deadline/All-In-AWS-Infrastructure-Basic/ts/lib/storage-tier.ts +++ b/examples/deadline/All-In-AWS-Infrastructure-Basic/ts/lib/storage-tier.ts @@ -116,6 +116,7 @@ export class StorageTierDocDB extends StorageTier { masterUser: { username: 'adminuser', }, + engineVersion: '3.6.0', backup: { // We recommend setting the retention of your backups to 15 days // for security reasons. The default retention is just one day. diff --git a/integ/lib/storage-struct.ts b/integ/lib/storage-struct.ts index ca7b79dd0..d6d0106a2 100644 --- a/integ/lib/storage-struct.ts +++ b/integ/lib/storage-struct.ts @@ -95,6 +95,7 @@ export class StorageStruct extends Construct { masterUser: { username: 'DocDBUser', }, + engineVersion: '3.6.0', backup: { retention: Duration.days(15), }, diff --git a/packages/aws-rfdk/lib/deadline/lib/repository.ts b/packages/aws-rfdk/lib/deadline/lib/repository.ts index 354ae1b15..efd94d503 100644 --- a/packages/aws-rfdk/lib/deadline/lib/repository.ts +++ b/packages/aws-rfdk/lib/deadline/lib/repository.ts @@ -490,6 +490,7 @@ export class Repository extends Construct implements IRepository { const instances = props.documentDbInstanceCount ?? Repository.DEFAULT_NUM_DOCDB_INSTANCES; const dbCluster = new DatabaseCluster(this, 'DocumentDatabase', { masterUser: {username: 'DocDBUser'}, + engineVersion: '3.6.0', instanceProps: { instanceType: InstanceType.of(InstanceClass.R5, InstanceSize.LARGE), vpc: props.vpc, From d1ae1573641dd7888d897b10909608dd349d02e4 Mon Sep 17 00:00:00 2001 From: Daniel Neilson Date: Wed, 18 Nov 2020 16:10:00 +0000 Subject: [PATCH 2/4] Add DB version pre-flight checks --- .../lib/deadline/lib/database-connection.ts | 25 ++++ .../aws-rfdk/lib/deadline/lib/repository.ts | 1 + .../deadline/test/database-connection.test.ts | 137 ++++++++++++++++++ 3 files changed, 163 insertions(+) diff --git a/packages/aws-rfdk/lib/deadline/lib/database-connection.ts b/packages/aws-rfdk/lib/deadline/lib/database-connection.ts index c90004d4d..8eb59eec5 100644 --- a/packages/aws-rfdk/lib/deadline/lib/database-connection.ts +++ b/packages/aws-rfdk/lib/deadline/lib/database-connection.ts @@ -5,6 +5,7 @@ import * as path from 'path'; import { + CfnDBCluster, CfnDBInstance, IDatabaseCluster, } from '@aws-cdk/aws-docdb'; @@ -22,6 +23,7 @@ import { ISecret, } from '@aws-cdk/aws-secretsmanager'; import { + Annotations, IConstruct, Stack, } from '@aws-cdk/core'; @@ -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, @@ -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. + } } /** diff --git a/packages/aws-rfdk/lib/deadline/lib/repository.ts b/packages/aws-rfdk/lib/deadline/lib/repository.ts index efd94d503..ab5c65585 100644 --- a/packages/aws-rfdk/lib/deadline/lib/repository.ts +++ b/packages/aws-rfdk/lib/deadline/lib/repository.ts @@ -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. */ diff --git a/packages/aws-rfdk/lib/deadline/test/database-connection.test.ts b/packages/aws-rfdk/lib/deadline/test/database-connection.test.ts index 4d25c4cf6..113c18037 100644 --- a/packages/aws-rfdk/lib/deadline/test/database-connection.test.ts +++ b/packages/aws-rfdk/lib/deadline/test/database-connection.test.ts @@ -31,6 +31,7 @@ import { import { PrivateHostedZone, } from '@aws-cdk/aws-route53'; +import { Secret } from '@aws-cdk/aws-secretsmanager'; import { Duration, Stack, @@ -77,6 +78,7 @@ describe('DocumentDB', () => { backup: { retention: Duration.days(15), }, + engineVersion: '3.6.0', }); if (!database.secret) { @@ -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; From eb871fe353be9be3549be15723ec1798ad62a4dc Mon Sep 17 00:00:00 2001 From: Daniel Neilson Date: Wed, 18 Nov 2020 19:02:50 +0000 Subject: [PATCH 3/4] Clarify that Deadline requires MongoDB 3.6-compatible database --- packages/aws-rfdk/lib/deadline/lib/database-connection.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/aws-rfdk/lib/deadline/lib/database-connection.ts b/packages/aws-rfdk/lib/deadline/lib/database-connection.ts index 8eb59eec5..8c1cb2471 100644 --- a/packages/aws-rfdk/lib/deadline/lib/database-connection.ts +++ b/packages/aws-rfdk/lib/deadline/lib/database-connection.ts @@ -82,6 +82,7 @@ export interface MongoDbInstanceConnectionOptions { export abstract class DatabaseConnection { /** * Creates a DatabaseConnection which allows Deadline to connect to Amazon DocumentDB. + * Note: Deadline officially supports only databases that are compatible with MongoDB 3.6. * * Resources Deployed * ------------------------ @@ -93,6 +94,7 @@ export abstract class DatabaseConnection { /** * Creates a DatabaseConnection which allows Deadline to connect to MongoDB. + * Note: Deadline officially supports only databases that are compatible with MongoDB 3.6. * * Resources Deployed * ------------------------ @@ -273,10 +275,7 @@ class DocDBDatabaseConnection extends DatabaseConnection { // 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 cluster.engineVersion?.startsWith('3.6') ?? false; } return true; // No information, assume it's compatible. From f9c83eb1d73da08eef8d71ec7a185ba2a4027939 Mon Sep 17 00:00:00 2001 From: Daniel Neilson Date: Thu, 19 Nov 2020 16:11:13 +0000 Subject: [PATCH 4/4] More MongoDB3.6-only clarifications. --- packages/aws-rfdk/lib/deadline/lib/database-connection.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/aws-rfdk/lib/deadline/lib/database-connection.ts b/packages/aws-rfdk/lib/deadline/lib/database-connection.ts index 8c1cb2471..8cefbdcb8 100644 --- a/packages/aws-rfdk/lib/deadline/lib/database-connection.ts +++ b/packages/aws-rfdk/lib/deadline/lib/database-connection.ts @@ -44,7 +44,8 @@ import { export interface DocDBConnectionOptions { /** - * The Document DB Cluster this connection is for + * The Document DB Cluster this connection is for. + * Note: Deadline officially supports only databases that are compatible with MongoDB 3.6. */ readonly database: IDatabaseCluster; @@ -61,6 +62,7 @@ export interface DocDBConnectionOptions { export interface MongoDbInstanceConnectionOptions { /** * The MongoDB database to connect to. + * Note: Deadline officially supports only databases that are compatible with MongoDB 3.6. */ readonly database: IMongoDb;