Skip to content

Commit

Permalink
feat(aws-rds): add support for parameter groups (#729)
Browse files Browse the repository at this point in the history
Now supports (Cluster) Parameter Groups. This is required to support
Aurora 5.7 engines (in particular, PostgreSQL with Aurora).

Fixes #719.
  • Loading branch information
rix0rrr committed Sep 17, 2018
1 parent bba2e5b commit 2541508
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 6 deletions.
9 changes: 7 additions & 2 deletions packages/@aws-cdk/aws-neptune/lib/index.ts
Expand Up @@ -74,7 +74,12 @@ export interface NeptuneDatabaseProps {
*/
preferredMaintenanceWindow?: string;

// Additional parameters to the database engine go here
/**
* Parameter group with Neptune settings
*
* @default No parameter group
*/
parameterGroup?: rds.ClusterParameterGroupRef;
}

/**
Expand Down Expand Up @@ -125,8 +130,8 @@ export class NeptuneDatabase extends cdk.Construct implements ec2.IConnectable {
instanceIdentifierBase: props.instanceIdentifierBase,
defaultDatabaseName: props.defaultDatabaseName,
kmsKeyArn: props.kmsKeyArn,
parameters: {}, // Additional parameters go here
preferredMaintenanceWindow: props.preferredMaintenanceWindow,
parameterGroup: props.parameterGroup,
});

this.clusterIdentifier = this.cluster.clusterIdentifier;
Expand Down
48 changes: 48 additions & 0 deletions packages/@aws-cdk/aws-rds/lib/cluster-parameter-group-ref.ts
@@ -0,0 +1,48 @@
import cdk = require('@aws-cdk/cdk');
import { DBClusterParameterGroupName } from './rds.generated';

/**
* A cluster parameter group
*/
export abstract class ClusterParameterGroupRef extends cdk.Construct {
/**
* Import a parameter group
*/
public static import(parent: cdk.Construct, id: string, props: ClusterParameterGroupRefProps): ClusterParameterGroupRef {
return new ImportedClusterParameterGroup(parent, id, props);
}

/**
* Name of this parameter group
*/
public abstract readonly parameterGroupName: DBClusterParameterGroupName;

/**
* Export this parameter group
*/
public export(): ClusterParameterGroupRefProps {
return {
parameterGroupName: new DBClusterParameterGroupName(
new cdk.Output(this, 'ParameterGroupName', { value: this.parameterGroupName }).makeImportValue())
};
}
}

/**
* Properties to reference a cluster parameter group
*/
export interface ClusterParameterGroupRefProps {
parameterGroupName: DBClusterParameterGroupName;
}

/**
* An imported cluster parameter group
*/
class ImportedClusterParameterGroup extends ClusterParameterGroupRef {
public readonly parameterGroupName: DBClusterParameterGroupName;

constructor(parent: cdk.Construct, id: string, props: ClusterParameterGroupRefProps) {
super(parent, id);
this.parameterGroupName = props.parameterGroupName;
}
}
77 changes: 77 additions & 0 deletions packages/@aws-cdk/aws-rds/lib/cluster-parameter-group.ts
@@ -0,0 +1,77 @@
import cdk = require('@aws-cdk/cdk');
import { ClusterParameterGroupRef } from './cluster-parameter-group-ref';
import { Parameters } from './props';
import { cloudformation, DBClusterParameterGroupName } from './rds.generated';

/**
* Properties for a cluster parameter group
*/
export interface ClusterParameterGroupProps {
/**
* Database family of this parameter group
*/
family: string;

/**
* Description for this parameter group
*/
description: string;

/**
* The parameters in this parameter group
*/
parameters?: Parameters;
}

/**
* Defina a cluster parameter group
*/
export class ClusterParameterGroup extends ClusterParameterGroupRef {
public readonly parameterGroupName: DBClusterParameterGroupName;
private readonly parameters: Parameters = {};

constructor(parent: cdk.Construct, id: string, props: ClusterParameterGroupProps) {
super(parent, id);

const resource = new cloudformation.DBClusterParameterGroupResource(this, 'Resource', {
description: props.description,
family: props.family,
parameters: new cdk.Token(() => this.parameters),
});

for (const [key, value] of Object.entries(props.parameters || {})) {
this.setParameter(key, value);
}

this.parameterGroupName = resource.ref;
}

/**
* Set a single parameter in this parameter group
*/
public setParameter(key: string, value: string | undefined) {
if (value === undefined && key in this.parameters) {
delete this.parameters[key];
}
if (value !== undefined) {
this.parameters[key] = value;
}
}

/**
* Remove a previously-set parameter from this parameter group
*/
public removeParameter(key: string) {
this.setParameter(key, undefined);
}

/**
* Validate this construct
*/
public validate(): string[] {
if (Object.keys(this.parameters).length === 0) {
return ['At least one parameter required, call setParameter().'];
}
return [];
}
}
8 changes: 6 additions & 2 deletions packages/@aws-cdk/aws-rds/lib/cluster.ts
@@ -1,8 +1,9 @@
import ec2 = require('@aws-cdk/aws-ec2');
import kms = require('@aws-cdk/aws-kms');
import cdk = require('@aws-cdk/cdk');
import { ClusterParameterGroupRef } from './cluster-parameter-group-ref';
import { DatabaseClusterRef, Endpoint } from './cluster-ref';
import { BackupProps, DatabaseClusterEngine, InstanceProps, Login, Parameters } from './props';
import { BackupProps, DatabaseClusterEngine, InstanceProps, Login } from './props';
import { cloudformation, DBClusterEndpointAddress, DBClusterEndpointPort, DBClusterName, DBInstanceId } from './rds.generated';

/**
Expand Down Expand Up @@ -84,8 +85,10 @@ export interface DatabaseClusterProps {

/**
* Additional parameters to pass to the database engine
*
* @default No parameter group
*/
parameters?: Parameters;
parameterGroup?: ClusterParameterGroupRef;
}

/**
Expand Down Expand Up @@ -155,6 +158,7 @@ export class DatabaseCluster extends DatabaseClusterRef {
dbSubnetGroupName: subnetGroup.ref,
vpcSecurityGroupIds: [this.securityGroupId],
port: props.port,
dbClusterParameterGroupName: props.parameterGroup && props.parameterGroup.parameterGroupName,
// Admin
masterUsername: props.masterUser.username,
masterUserPassword: props.masterUser.password,
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-rds/lib/index.ts
Expand Up @@ -2,6 +2,8 @@ export * from './cluster';
export * from './cluster-ref';
export * from './instance';
export * from './props';
export * from './cluster-parameter-group';
export * from './cluster-parameter-group-ref';

// AWS::RDS CloudFormation Resources:
export * from './rds.generated';
13 changes: 13 additions & 0 deletions packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json
Expand Up @@ -305,6 +305,16 @@
}
}
},
"ParamsA8366201": {
"Type": "AWS::RDS::DBClusterParameterGroup",
"Properties": {
"Description": "A nice parameter group",
"Family": "aurora5.6",
"Parameters": {
"character_set_database": "utf8mb4"
}
}
},
"DatabaseSubnets56F17B9A": {
"Type": "AWS::RDS::DBSubnetGroup",
"Properties": {
Expand Down Expand Up @@ -360,6 +370,9 @@
"Type": "AWS::RDS::DBCluster",
"Properties": {
"Engine": "aurora",
"DBClusterParameterGroupName": {
"Ref": "ParamsA8366201"
},
"DBSubnetGroupName": {
"Ref": "DatabaseSubnets56F17B9A"
},
Expand Down
10 changes: 9 additions & 1 deletion packages/@aws-cdk/aws-rds/test/integ.cluster.ts
@@ -1,12 +1,19 @@
import ec2 = require('@aws-cdk/aws-ec2');
import cdk = require('@aws-cdk/cdk');
import { DatabaseCluster, DatabaseClusterEngine, Password, Username } from '../lib';
import { ClusterParameterGroup } from '../lib/cluster-parameter-group';

const app = new cdk.App(process.argv);
const stack = new cdk.Stack(app, 'aws-cdk-rds-integ');

const vpc = new ec2.VpcNetwork(stack, 'VPC', { maxAZs: 2 });

const params = new ClusterParameterGroup(stack, 'Params', {
family: 'aurora5.6',
description: 'A nice parameter group',
});
params.setParameter('character_set_database', 'utf8mb4');

const cluster = new DatabaseCluster(stack, 'Database', {
engine: DatabaseClusterEngine.Aurora,
masterUser: {
Expand All @@ -17,7 +24,8 @@ const cluster = new DatabaseCluster(stack, 'Database', {
instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.Burstable2, ec2.InstanceSize.Small),
vpcPlacement: { subnetsToUse: ec2.SubnetType.Public },
vpc
}
},
parameterGroup: params,
});

cluster.connections.allowDefaultPortFromAnyIpv4('Open to the world');
Expand Down
36 changes: 35 additions & 1 deletion packages/@aws-cdk/aws-rds/test/test.cluster.ts
Expand Up @@ -2,7 +2,7 @@ import { expect, haveResource } from '@aws-cdk/assert';
import ec2 = require('@aws-cdk/aws-ec2');
import cdk = require('@aws-cdk/cdk');
import { Test } from 'nodeunit';
import { DatabaseCluster, DatabaseClusterEngine, DatabaseClusterRef, Password, Username } from '../lib';
import { ClusterParameterGroup, DatabaseCluster, DatabaseClusterEngine, DatabaseClusterRef, Password, Username } from '../lib';

export = {
'check that instantiation works'(test: Test) {
Expand Down Expand Up @@ -88,6 +88,40 @@ export = {

test.done();
},

'cluster with parameter group'(test: Test) {
// GIVEN
const stack = testStack();
const vpc = new ec2.VpcNetwork(stack, 'VPC');

// WHEN
const group = new ClusterParameterGroup(stack, 'Params', {
family: 'hello',
description: 'bye',
parameters: {
param: 'value'
}
});
new DatabaseCluster(stack, 'Database', {
engine: DatabaseClusterEngine.Aurora,
masterUser: {
username: new Username('admin'),
password: new Password('tooshort'),
},
instanceProps: {
instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.Burstable2, ec2.InstanceSize.Small),
vpc
},
parameterGroup: group
});

// THEN
expect(stack).to(haveResource('AWS::RDS::DBCluster', {
DBClusterParameterGroupName: { Ref: 'ParamsA8366201' },
}));

test.done();
},
};

function testStack() {
Expand Down

0 comments on commit 2541508

Please sign in to comment.