Skip to content

Commit

Permalink
Adds support for DB2
Browse files Browse the repository at this point in the history
  • Loading branch information
Cédric MILLET committed Dec 28, 2023
1 parent 607dccb commit 867b88c
Show file tree
Hide file tree
Showing 6 changed files with 286 additions and 2 deletions.
152 changes: 152 additions & 0 deletions packages/aws-cdk-lib/aws-rds/lib/instance-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,132 @@ class MariaDbInstanceEngine extends InstanceEngineBase {
}
}

interface Db2InstanceEngineBaseProps {
readonly engineType: string;
readonly version?: EngineVersion;
}

abstract class Db2InstanceEngineBase extends InstanceEngineBase {
constructor(props: Db2InstanceEngineBaseProps) {
super({
...props,
singleUserRotationApplication: secretsmanager.SecretRotationApplication.DB2_ROTATION_SINGLE_USER,
multiUserRotationApplication: secretsmanager.SecretRotationApplication.DB2_ROTATION_MULTI_USER,
parameterGroupFamily: props.version ? `${props.engineType}-${props.version.majorVersion}` : undefined,
features: {
s3Import: 'S3_INTEGRATION',
s3Export: 'S3_INTEGRATION',
},
});
}

public bindToInstance(scope: Construct, options: InstanceEngineBindOptions): InstanceEngineConfig {
const config = super.bindToInstance(scope, options);

let optionGroup = options.optionGroup;
if (options.s3ImportRole || options.s3ExportRole) {
if (!optionGroup) {
optionGroup = new OptionGroup(scope, 'InstanceOptionGroup', {
engine: this,
configurations: [],
});
}
// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-s3-integration.html
optionGroup.addConfiguration({
name: 'S3_INTEGRATION',
version: '1.0',
});
}

return {
...config,
optionGroup,
};
}
}

/**
* Properties for DB2 Standard Edition instance engines.
* Used in `DatabaseInstanceEngine.db2Se`.
*/
export interface Db2SeInstanceEngineProps extends Db2InstanceEngineProps {
}

class Db2SeInstanceEngine extends Db2InstanceEngineBase {
constructor(version?: Db2EngineVersion) {
super({
engineType: 'db2-se',
version: version
? {
fullVersion: version.db2FullVersion,
majorVersion: version.db2MajorVersion,
}
: undefined,
});
}
}

/**
* Properties for DB2 Advanced Edition instance engines.
* Used in `DatabaseInstanceEngine.db2Ae`.
*/
export interface Db2AeInstanceEngineProps extends Db2InstanceEngineProps {
}

class Db2AeInstanceEngine extends Db2InstanceEngineBase {
constructor(version?: Db2EngineVersion) {
super({
engineType: 'db2-ae',
version: version
? {
fullVersion: version.db2FullVersion,
majorVersion: version.db2MajorVersion,
}
: undefined,
});
}
}

/**
* The versions for the DB2 instance engines
* (those returned by `DatabaseInstanceEngine.mariaDb`).
*/
export class Db2EngineVersion {
/** Version "11.5". */
public static readonly VER_11_5 = Db2EngineVersion.of('11.5', '11.5');

/**
* Create a new Db2EngineVersion with an arbitrary version.
*
* @param db2FullVersion the full version string,
* for example "10.5.28"
* @param db2MajorVersion the major version of the engine,
* for example "10.5"
*/
public static of(db2FullVersion: string, db2MajorVersion: string): Db2EngineVersion {
return new Db2EngineVersion(db2FullVersion, db2MajorVersion);
}

/** The full version string, for example, "10.5.28". */
public readonly db2FullVersion: string;
/** The major version of the engine, for example, "10.5". */
public readonly db2MajorVersion: string;

private constructor(db2FullVersion: string, db2MajorVersion: string) {
this.db2FullVersion = db2FullVersion;
this.db2MajorVersion = db2MajorVersion;
}
}

/**
* Properties for DB2 instance engines.
* Used in `DatabaseInstanceEngine.mariaDb`.
*/
export interface Db2InstanceEngineProps {
/** The exact version of the engine to use. */
readonly version: Db2EngineVersion;
}

/**
* The versions for the MySQL instance engines
* (those returned by `DatabaseInstanceEngine.mysql`).
Expand Down Expand Up @@ -2139,6 +2265,22 @@ class SqlServerEeInstanceEngine extends SqlServerInstanceEngineBase {
* secret rotation.
*/
export class DatabaseInstanceEngine {
/**
* The unversioned 'db2-se' instance engine.
*
* NOTE: using unversioned engines is an availability risk.
* We recommend using versioned engines created using the `db2Se()` methods
*/
public static readonly DB2_SE: IInstanceEngine = new Db2SeInstanceEngine();

/**
* The unversioned 'db2-ae' instance engine.
*
* NOTE: using unversioned engines is an availability risk.
* We recommend using versioned engines created using the `db2Ae()` methods
*/
public static readonly DB2_AE: IInstanceEngine = new Db2AeInstanceEngine();

/**
* The unversioned 'mariadb' instance engine.
*
Expand Down Expand Up @@ -2241,6 +2383,16 @@ export class DatabaseInstanceEngine {
*/
public static readonly SQL_SERVER_WEB: IInstanceEngine = new SqlServerWebInstanceEngine();

/** Creates a new DB2 Standard Edition instance engine. */
public static db2Se(props: Db2SeInstanceEngineProps): IInstanceEngine {
return new Db2SeInstanceEngine(props.version);
}

/** Creates a new DB2 Advanced Edition instance engine. */
public static db2Ae(props: Db2AeInstanceEngineProps): IInstanceEngine {
return new Db2AeInstanceEngine(props.version);
}

/** Creates a new MariaDB instance engine. */
public static mariaDb(props: MariaDbInstanceEngineProps): IInstanceEngine {
return new MariaDbInstanceEngine(props.version);
Expand Down
28 changes: 28 additions & 0 deletions packages/aws-cdk-lib/aws-rds/test/db2/db2.instance-engine.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Template } from '../../../assertions';
import * as core from '../../../core';
import * as rds from '../../lib';

describe('DB2 server instance engine', () => {
describe('DB2 instance engine versions', () => {
test("has MajorEngineVersion ending in '11.5' for major version 11.5", () => {
const stack = new core.Stack();
new rds.OptionGroup(stack, 'OptionGroup', {
engine: rds.DatabaseInstanceEngine.db2Se({
version: rds.Db2EngineVersion.VER_11_5,
}),
configurations: [
{
name: 'DB2_BACKUP_RESTORE',
settings: {
IAM_ROLE_ARN: 'some-role-arn',
},
},
],
});

Template.fromStack(stack).hasResourceProperties('AWS::RDS::OptionGroup', {
MajorEngineVersion: '11.5',
});
});
});
});
74 changes: 74 additions & 0 deletions packages/aws-cdk-lib/aws-rds/test/instance-engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ describe('instance engine', () => {
expect(family).toEqual(undefined);
});

test('default parameterGroupFamily for versionless DB2 SE instance engine is not defined', () => {
const engine = rds.DatabaseInstanceEngine.DB2_SE;

const family = engine.parameterGroupFamily;

expect(family).toEqual(undefined);
});

test('default parameterGroupFamily for versionless DB2 AE instance engine is not defined', () => {
const engine = rds.DatabaseInstanceEngine.DB2_AE;

const family = engine.parameterGroupFamily;

expect(family).toEqual(undefined);
});

test('default parameterGroupFamily for versionless Oracle EE instance engine is not defined', () => {
const engine = rds.DatabaseInstanceEngine.ORACLE_EE;

Expand Down Expand Up @@ -262,4 +278,62 @@ describe('instance engine', () => {
expect(engineConfig.features?.s3Export).toEqual('s3Export');
});
});

describe('DB2 engine bindToInstance', () => {

test('returns s3 integration feature', () => {
const engine = rds.DatabaseInstanceEngine.db2Se({ version: rds.Db2EngineVersion.VER_11_5 });

const engineConfig = engine.bindToInstance(new cdk.Stack(), {});
expect(engineConfig.features?.s3Import).toEqual('S3_INTEGRATION');
expect(engineConfig.features?.s3Export).toEqual('S3_INTEGRATION');
});

test('s3 import/export - creates an option group if needed', () => {
const stack = new cdk.Stack();
const engine = rds.DatabaseInstanceEngine.db2Se({ version: rds.Db2EngineVersion.VER_11_5 });

const engineConfig = engine.bindToInstance(stack, {
optionGroup: undefined,
s3ImportRole: new iam.Role(stack, 'ImportRole', { assumedBy: new iam.AccountRootPrincipal() }),
});

expect(engineConfig.optionGroup).toBeDefined();
Template.fromStack(stack).hasResourceProperties('AWS::RDS::OptionGroup', {
EngineName: 'db2-se',
OptionConfigurations: [{
OptionName: 'S3_INTEGRATION',
OptionVersion: '1.0',
}],
});
});

test('s3 import/export - appends to an existing option group if it exists', () => {
const stack = new cdk.Stack();
const engine = rds.DatabaseInstanceEngine.db2Ae({ version: rds.Db2EngineVersion.VER_11_5 });
const optionGroup = new rds.OptionGroup(stack, 'OptionGroup', {
engine,
configurations: [{
name: 'MY_OPTION_CONFIG',
}],
});

const engineConfig = engine.bindToInstance(stack, {
optionGroup,
s3ImportRole: new iam.Role(stack, 'ImportRole', { assumedBy: new iam.AccountRootPrincipal() }),
});

expect(engineConfig.optionGroup).toEqual(optionGroup);
Template.fromStack(stack).hasResourceProperties('AWS::RDS::OptionGroup', {
EngineName: 'db2-ae',
OptionConfigurations: [{
OptionName: 'MY_OPTION_CONFIG',
},
{
OptionName: 'S3_INTEGRATION',
OptionVersion: '1.0',
}],
});
});
});
});
6 changes: 4 additions & 2 deletions packages/aws-cdk-lib/aws-rds/test/instance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,8 @@ describe('instance', () => {
const tzSupportedEngines = [rds.DatabaseInstanceEngine.SQL_SERVER_EE, rds.DatabaseInstanceEngine.SQL_SERVER_EX,
rds.DatabaseInstanceEngine.SQL_SERVER_SE, rds.DatabaseInstanceEngine.SQL_SERVER_WEB];
const tzUnsupportedEngines = [rds.DatabaseInstanceEngine.MYSQL, rds.DatabaseInstanceEngine.POSTGRES,
rds.DatabaseInstanceEngine.ORACLE_EE, rds.DatabaseInstanceEngine.MARIADB];
rds.DatabaseInstanceEngine.ORACLE_EE, rds.DatabaseInstanceEngine.MARIADB, rds.DatabaseInstanceEngine.DB2_SE,
rds.DatabaseInstanceEngine.DB2_AE];

// THEN
tzSupportedEngines.forEach((engine) => {
Expand Down Expand Up @@ -1349,7 +1350,8 @@ describe('instance', () => {
test('throws when domain is set for mariadb database engine', () => {
const domainSupportedEngines = [rds.DatabaseInstanceEngine.SQL_SERVER_EE, rds.DatabaseInstanceEngine.SQL_SERVER_EX,
rds.DatabaseInstanceEngine.SQL_SERVER_SE, rds.DatabaseInstanceEngine.SQL_SERVER_WEB, rds.DatabaseInstanceEngine.MYSQL,
rds.DatabaseInstanceEngine.POSTGRES, rds.DatabaseInstanceEngine.ORACLE_EE];
rds.DatabaseInstanceEngine.POSTGRES, rds.DatabaseInstanceEngine.ORACLE_EE, rds.DatabaseInstanceEngine.DB2_SE,
rds.DatabaseInstanceEngine.DB2_AE];
const domainUnsupportedEngines = [rds.DatabaseInstanceEngine.MARIADB];

// THEN
Expand Down
16 changes: 16 additions & 0 deletions packages/aws-cdk-lib/aws-secretsmanager/lib/rotation-schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,16 @@ export class HostedRotation implements ec2.IConnectable {
return new HostedRotation(HostedRotationType.ORACLE_MULTI_USER, options, options.masterSecret);
}

/** DB2 Single User */
public static db2SingleUser(options: SingleUserHostedRotationOptions = {}) {
return new HostedRotation(HostedRotationType.DB2_SINGLE_USER, options);
}

/** DB2 Multi User */
public static db2MultiUser(options: MultiUserHostedRotationOptions) {
return new HostedRotation(HostedRotationType.DB2_MULTI_USER, options, options.masterSecret);
}

/** MariaDB Single User */
public static mariaDbSingleUser(options: SingleUserHostedRotationOptions = {}) {
return new HostedRotation(HostedRotationType.MARIADB_SINGLE_USER, options);
Expand Down Expand Up @@ -411,6 +421,12 @@ export class HostedRotationType {
/** MongoDB Multi User */
public static readonly MONGODB_MULTI_USER = new HostedRotationType('MongoDBMultiUser', true);

/** DB2 Single User */
public static readonly DB2_SINGLE_USER = new HostedRotationType('Db2SingleUser');

/** DB2 Multi User */
public static readonly DB2_MULTI_USER = new HostedRotationType('Db2MultiUser', true);

/**
* @param name The type of rotation
* @param isMultiUser Whether the rotation uses the mutli user scheme
Expand Down
12 changes: 12 additions & 0 deletions packages/aws-cdk-lib/aws-secretsmanager/lib/secret-rotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ export class SecretRotationApplication {
isMultiUser: true,
});

/**
* Conducts an AWS SecretsManager secret rotation for RDS DB2 using the single user rotation scheme
*/
public static readonly DB2_ROTATION_SINGLE_USER = new SecretRotationApplication('SecretsManagerRDSDb2RotationSingleUser', '1.1.367');

/**
* Conducts an AWS SecretsManager secret rotation for RDS DB2 using the multi user rotation scheme
*/
public static readonly DB2_ROTATION_MULTI_USER = new SecretRotationApplication('SecretsManagerRDSDb2RotationMultiUser', '1.1.367', {
isMultiUser: true,
});

/**
* Conducts an AWS SecretsManager secret rotation for RDS PostgreSQL using the single user rotation scheme
*/
Expand Down

0 comments on commit 867b88c

Please sign in to comment.