Skip to content

Commit

Permalink
Merge branch 'mainline' into docdb_audit_log
Browse files Browse the repository at this point in the history
  • Loading branch information
kozlove-aws committed Aug 10, 2020
2 parents 8ade353 + 715be7c commit 73ed0d6
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 22 deletions.
6 changes: 5 additions & 1 deletion integ/lib/storage-struct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class StorageStruct extends Construct {

deadlineEfs = new FileSystem(this, 'FileSystem', {
vpc,
removalPolicy: RemovalPolicy.DESTROY,
});
deadlineMountableEfs = new MountableEfs(this, {
filesystem: deadlineEfs,
Expand All @@ -89,7 +90,10 @@ export class StorageStruct extends Construct {
logGroupProps: {
logGroupPrefix: Stack.of(this).stackName + '-' + id,
},
databaseRemovalPolicy: RemovalPolicy.DESTROY,
removalPolicy: {
database: RemovalPolicy.DESTROY,
filesystem: RemovalPolicy.DESTROY,
},
});

this.docdb = ( deadlineDatabase || this.repo.node.findChild('DocumentDatabase') as DatabaseCluster );
Expand Down
46 changes: 40 additions & 6 deletions packages/aws-rfdk/lib/deadline/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,29 @@ export interface RepositoryBackupOptions {
readonly databaseRetention?: Duration;
}

/*
* Properties that define the removal policies of resources that are created by the Repository. These define what happens
* to the resources when the stack that defines them is destroyed.
*/
export interface RepositoryRemovalPolicies {
/**
* If this Repository is creating its own Amazon DocumentDB database, then this specifies the retention policy to
* use on the database. If the Repository is not creating a DocumentDB database, because one was given,
* then this property is ignored.
*
* @default RemovalPolicy.RETAIN
*/
readonly database?: RemovalPolicy;

/**
* If this Repository is creating its own Amazon Elastic File System (EFS), then this specifies the retention policy to
* use on the filesystem. If the Repository is not creating an EFS, because one was given, then this property is ignored.
*
* @default RemovalPolicy.RETAIN
*/
readonly filesystem?: RemovalPolicy;
}

/**
* Properties for the Deadline repository
*/
Expand Down Expand Up @@ -268,12 +291,12 @@ export interface RepositoryProps {
readonly database?: DatabaseConnection;

/**
* If this Repository is creating its own DocumentDB database, then this specifies the retention policy to
* use on the database.
* Define the removal policies for the resources that this Repository creates. These define what happens
* to the resoureces when the stack that defines them is destroyed.
*
* @default RemovalPolicy.RETAIN
* @default RemovalPolicy.RETAIN for all resources
*/
readonly databaseRemovalPolicy?: RemovalPolicy;
readonly removalPolicy?: RepositoryRemovalPolicies;

/**
* If this Repository is creating its own DocumentDB database, then this specifies if audit logging will be enabled
Expand Down Expand Up @@ -412,6 +435,12 @@ export class Repository extends Construct implements IRepository {
if (props.database && props.backupOptions?.databaseRetention) {
this.node.addWarning('Backup retention for database will not be applied since a database is not being created by this construct');
}
if (props.fileSystem && props.removalPolicy?.filesystem) {
this.node.addWarning('RemovalPolicy for filesystem will not be applied since a filesystem is not being created by this construct');
}
if (props.database && props.removalPolicy?.database) {
this.node.addWarning('RemovalPolicy for database will not be applied since a database is not being created by this construct');
}

this.version = props.version;

Expand All @@ -422,11 +451,16 @@ export class Repository extends Construct implements IRepository {
vpcSubnets: props.vpcSubnets ?? { subnetType: SubnetType.PRIVATE },
encrypted: true,
lifecyclePolicy: EfsLifecyclePolicy.AFTER_14_DAYS,
removalPolicy: props.removalPolicy?.filesystem ?? RemovalPolicy.RETAIN,
}),
});

if (props.database) {
this.databaseConnection = props.database;
if (props.databaseAuditLogging !== undefined){
this.node.addWarning(`The parameter databaseAuditLogging only has an effect when the Repository is creating its own database.
Please ensure that the Database provided is configured correctly.`);
}
} else {
const databaseAuditLogging = props.databaseAuditLogging ?? true;

Expand Down Expand Up @@ -455,8 +489,8 @@ export class Repository extends Construct implements IRepository {
backup: {
retention: props.backupOptions?.databaseRetention ?? Repository.DEFAULT_DATABASE_RETENTION_PERIOD,
},
parameterGroup: parameterGroup,
removalPolicy: props.databaseRemovalPolicy ?? RemovalPolicy.RETAIN,
parameterGroup,
removalPolicy: props.removalPolicy?.database ?? RemovalPolicy.RETAIN,
});

if (databaseAuditLogging) {
Expand Down
178 changes: 163 additions & 15 deletions packages/aws-rfdk/lib/deadline/test/repository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,116 @@ test('repository mounts repository filesystem', () => {
expect(userData).toMatch(new RegExp(escapeTokenRegex('mountEfs.sh ${Token[TOKEN.\\d+]} /mnt/efs/fs1 rw')));
});

test.each([
[RemovalPolicy.DESTROY, 'Delete'],
[RemovalPolicy.RETAIN, 'Retain'],
[RemovalPolicy.SNAPSHOT, 'Snapshot'],
])('repository honors database removal policy: %p', (policy: RemovalPolicy, expected: string) => {
// WHEN
new Repository(stack, 'repositoryInstaller', {
vpc,
version: deadlineVersion,
removalPolicy: {
database: policy,
},
});

// THEN
expectCDK(stack).to(haveResourceLike('AWS::DocDB::DBCluster', {
DeletionPolicy: expected,
}, ResourcePart.CompleteDefinition));
});

test.each([
[RemovalPolicy.DESTROY, 'Delete'],
[RemovalPolicy.RETAIN, 'Retain'],
[RemovalPolicy.SNAPSHOT, 'Snapshot'],
])('repository honors filesystem removal policy: %p', (policy: RemovalPolicy, expected: string) => {
// WHEN
new Repository(stack, 'repositoryInstaller', {
vpc,
version: deadlineVersion,
removalPolicy: {
filesystem: policy,
},
});

// THEN
expectCDK(stack).to(haveResourceLike('AWS::EFS::FileSystem', {
DeletionPolicy: expected,
}, ResourcePart.CompleteDefinition));
});

test('repository warns if removal policy for filesystem when filesystem provided', () => {
// GIVEN
const testEFS = new EfsFileSystem(stack, 'TestEfsFileSystem', {
vpc,
});
const testFS = new MountableEfs(stack, {
filesystem: testEFS,
});

// WHEN
const repo = new Repository(stack, 'repositoryInstaller', {
vpc,
fileSystem: testFS,
version: deadlineVersion,
removalPolicy: {
filesystem: RemovalPolicy.DESTROY,
},
});

// THEN
expect(repo.node.metadata).toEqual(
expect.arrayContaining([
expect.objectContaining({
type: 'aws:cdk:warning',
data: 'RemovalPolicy for filesystem will not be applied since a filesystem is not being created by this construct',
}),
]),
);
});

test('repository warns if removal policy for database when database provided', () => {
// GIVEN
const fsDatabase = new DatabaseCluster(stack, 'TestDbCluster', {
masterUser: {
username: 'master',
},
instanceProps: {
instanceType: InstanceType.of(
InstanceClass.R4,
InstanceSize.LARGE,
),
vpc,
vpcSubnets: {
onePerAz: true,
subnetType: SubnetType.PRIVATE,
},
},
});

// WHEN
const repo = new Repository(stack, 'repositoryInstaller', {
vpc,
database: DatabaseConnection.forDocDB({ database: fsDatabase, login: fsDatabase.secret! }),
version: deadlineVersion,
removalPolicy: {
database: RemovalPolicy.DESTROY,
},
});

// THEN
expect(repo.node.metadata).toEqual(
expect.arrayContaining([
expect.objectContaining({
type: 'aws:cdk:warning',
data: 'RemovalPolicy for database will not be applied since a database is not being created by this construct',
}),
]),
);
});

test('repository creates deadlineDatabase if none provided', () => {
const testEFS = new EfsFileSystem(stack, 'TestEfsFileSystem', {
vpc,
Expand All @@ -390,12 +500,17 @@ test('repository creates deadlineDatabase if none provided', () => {
expectCDK(stack).to(haveResourceLike('AWS::DocDB::DBCluster', {
EnableCloudwatchLogsExports: [ 'audit' ],
}, ResourcePart.Properties));
expectCDK(stack).to(haveResourceLike('AWS::DocDB::DBClusterParameterGroup', {
Parameters: {
audit_logs: 'enabled',
},
}, ResourcePart.Properties));
expectCDK(stack).to(haveResourceLike('AWS::DocDB::DBInstance', {
AutoMinorVersionUpgrade: true,
}));
});

test('audit log is disabled when it required', () => {
test('disabling Audit logging does not enable Cloudwatch audit logs', () => {
const testEFS = new EfsFileSystem(stack, 'TestEfsFileSystem', {
vpc,
});
Expand All @@ -416,6 +531,53 @@ test('audit log is disabled when it required', () => {
expectCDK(stack).notTo(haveResourceLike('AWS::DocDB::DBCluster', {
EnableCloudwatchLogsExports: [ 'audit' ],
}, ResourcePart.Properties));
expectCDK(stack).notTo(haveResourceLike('AWS::DocDB::DBClusterParameterGroup', {
Parameters: {
audit_logs: 'enabled',
},
}, ResourcePart.Properties));
});

test('repository warns if databaseAuditLogging defined and database is specified', () => {
// GIVEN
const fsDatabase = new DatabaseCluster(stack, 'TestDbCluster', {
masterUser: {
username: 'master',
},
instanceProps: {
instanceType: InstanceType.of(
InstanceClass.R4,
InstanceSize.LARGE,
),
vpc,
vpcSubnets: {
onePerAz: true,
subnetType: SubnetType.PRIVATE,
},
},
});

// WHEN
const repo = new Repository(stack, 'repositoryInstaller', {
vpc,
version: deadlineVersion,
removalPolicy: {
filesystem: RemovalPolicy.DESTROY,
},
database: DatabaseConnection.forDocDB({ database: fsDatabase, login: fsDatabase.secret! }),
databaseAuditLogging: true,
});

// THEN
expect(repo.node.metadata).toEqual(
expect.arrayContaining([
expect.objectContaining({
type: 'aws:cdk:warning',
data: `The parameter databaseAuditLogging only has an effect when the Repository is creating its own database.
Please ensure that the Database provided is configured correctly.`,
}),
]),
);
});

test('honors subnet specification', () => {
Expand Down Expand Up @@ -473,20 +635,6 @@ test('repository honors database instance count', () => {
}));
});

test('repository honors database removal policy', () => {
// WHEN
new Repository(stack, 'repositoryInstaller', {
vpc,
version: deadlineVersion,
databaseRemovalPolicy: RemovalPolicy.DESTROY,
});

// THEN
expectCDK(stack).to(haveResourceLike('AWS::DocDB::DBCluster', {
DeletionPolicy: 'Delete',
}, ResourcePart.CompleteDefinition));
});

test('repository honors database retention period', () => {
// GIVEN
const period = 20;
Expand Down

0 comments on commit 73ed0d6

Please sign in to comment.