@studion/infra-code-blocks
Version:
Studion common infra components
198 lines (197 loc) • 8.06 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Database = void 0;
const aws = require("@pulumi/aws");
const pulumi = require("@pulumi/pulumi");
const common_tags_1 = require("../../shared/common-tags");
const database_replica_1 = require("./database-replica");
const ec2_ssm_connect_1 = require("./ec2-ssm-connect");
const merge_with_defaults_1 = require("../../shared/merge-with-defaults");
const password_1 = require("../password");
const defaults = {
multiAz: false,
applyImmediately: false,
skipFinalSnapshot: false,
allocatedStorage: 20,
maxAllocatedStorage: 100,
instanceClass: 'db.t4g.micro',
enableMonitoring: false,
allowMajorVersionUpgrade: false,
autoMinorVersionUpgrade: true,
engineVersion: '18',
};
class Database extends pulumi.ComponentResource {
name;
instance;
vpc;
dbSubnetGroup;
dbSecurityGroup;
password;
kmsKeyId;
monitoringRole;
encryptedSnapshotCopy;
replicas;
ec2SSMConnect;
constructor(name, args, opts = {}) {
super('studion:database:Database', name, {}, {
...opts,
aliases: [...(opts.aliases || []), { type: 'studion:Database' }],
});
this.name = name;
const argsWithDefaults = (0, merge_with_defaults_1.mergeWithDefaults)(defaults, args);
const { vpc, kmsKeyId, enableMonitoring, snapshotIdentifier, replicaConfigs, enableSSMConnect, ssmConnectConfig = {}, } = argsWithDefaults;
this.vpc = pulumi.output(vpc);
this.dbSubnetGroup = this.createSubnetGroup();
this.dbSecurityGroup = this.createSecurityGroup();
this.password = new password_1.Password(`${this.name}-database-password`, { value: args.password }, { parent: this });
this.kmsKeyId = kmsKeyId
? pulumi.output(kmsKeyId)
: this.createEncryptionKey().arn;
if (enableMonitoring) {
this.monitoringRole = this.createMonitoringRole();
}
if (snapshotIdentifier) {
this.encryptedSnapshotCopy =
this.createEncryptedSnapshotCopy(snapshotIdentifier);
}
this.instance = this.createDatabaseInstance(argsWithDefaults);
if (replicaConfigs?.size) {
this.replicas = [];
let previous = this.instance;
for (const [name, config] of replicaConfigs) {
this.replicas.push(this.createDatabaseReplica(name, config, { dependsOn: [previous] }));
previous = this.replicas.at(-1).instance;
}
}
if (enableSSMConnect) {
this.ec2SSMConnect = this.createEc2SSMConnect(ssmConnectConfig);
}
this.registerOutputs();
}
createSubnetGroup() {
return new aws.rds.SubnetGroup(`${this.name}-subnet-group`, {
subnetIds: this.vpc.isolatedSubnetIds,
tags: common_tags_1.commonTags,
}, { parent: this });
}
createSecurityGroup() {
return new aws.ec2.SecurityGroup(`${this.name}-security-group`, {
vpcId: this.vpc.vpcId,
ingress: [
{
protocol: 'tcp',
fromPort: 5432,
toPort: 5432,
cidrBlocks: [this.vpc.vpc.cidrBlock],
},
],
tags: common_tags_1.commonTags,
}, { parent: this });
}
createEncryptionKey() {
return new aws.kms.Key(`${this.name}-rds-key`, {
description: `${this.name} RDS encryption key`,
customerMasterKeySpec: 'SYMMETRIC_DEFAULT',
isEnabled: true,
keyUsage: 'ENCRYPT_DECRYPT',
multiRegion: false,
enableKeyRotation: true,
tags: common_tags_1.commonTags,
}, { parent: this });
}
createMonitoringRole() {
const monitoringRole = new aws.iam.Role(`${this.name}-rds-monitoring`, {
assumeRolePolicy: {
Version: '2012-10-17',
Statement: [
{
Action: 'sts:AssumeRole',
Effect: 'Allow',
Principal: {
Service: 'monitoring.rds.amazonaws.com',
},
},
],
},
}, { parent: this });
new aws.iam.RolePolicyAttachment(`${this.name}-rds-monitoring-role-attachment`, {
role: monitoringRole.name,
policyArn: 'arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole',
}, { parent: this });
return monitoringRole;
}
createEncryptedSnapshotCopy(snapshotIdentifier) {
const sourceDbSnapshotIdentifier = pulumi
.output(snapshotIdentifier)
.apply(snapshotIdentifier => aws.rds.getSnapshot({
dbSnapshotIdentifier: snapshotIdentifier,
})).dbSnapshotArn;
return new aws.rds.SnapshotCopy(`${this.name}-encrypted-snapshot-copy`, {
sourceDbSnapshotIdentifier,
targetDbSnapshotIdentifier: pulumi.interpolate `${snapshotIdentifier}-encrypted-copy`,
kmsKeyId: this.kmsKeyId,
}, { parent: this });
}
createDatabaseReplica(name, config, opts = {}) {
const { enableMonitoring, monitoringRole, ...args } = config;
const resolvedMonitoringRole = enableMonitoring
? monitoringRole || this.monitoringRole
: undefined;
const replica = new database_replica_1.DatabaseReplica(name, {
replicateSourceDb: this.instance.identifier.apply(id => id),
dbSecurityGroup: this.dbSecurityGroup,
monitoringRole: resolvedMonitoringRole,
...args,
}, { ...opts, parent: this });
return replica;
}
createEc2SSMConnect(config = {}) {
return new ec2_ssm_connect_1.Ec2SSMConnect(`${this.name}-ssm-connect`, {
vpc: this.vpc,
...config,
}, { parent: this });
}
createDatabaseInstance(args) {
const stack = pulumi.getStack();
const monitoringOptions = args.enableMonitoring && this.monitoringRole
? {
monitoringInterval: 60,
monitoringRoleArn: this.monitoringRole.arn,
performanceInsightsEnabled: true,
performanceInsightsRetentionPeriod: 7,
}
: {};
const instance = new aws.rds.Instance(`${this.name}-rds`, {
identifierPrefix: `${this.name}-`,
engine: 'postgres',
engineVersion: args.engineVersion,
instanceClass: args.instanceClass,
dbName: args.dbName,
username: args.username,
password: this.password.value,
dbSubnetGroupName: this.dbSubnetGroup.name,
vpcSecurityGroupIds: [this.dbSecurityGroup.id],
allocatedStorage: args.allocatedStorage,
maxAllocatedStorage: args.maxAllocatedStorage,
multiAz: args.multiAz,
applyImmediately: args.applyImmediately,
allowMajorVersionUpgrade: args.allowMajorVersionUpgrade,
autoMinorVersionUpgrade: args.autoMinorVersionUpgrade,
kmsKeyId: this.kmsKeyId,
storageEncrypted: true,
publiclyAccessible: false,
skipFinalSnapshot: args.skipFinalSnapshot,
maintenanceWindow: 'Mon:07:00-Mon:07:30',
finalSnapshotIdentifier: `${this.name}-final-snapshot-${stack}`,
backupWindow: '06:00-06:30',
backupRetentionPeriod: 14,
caCertIdentifier: 'rds-ca-rsa2048-g1',
parameterGroupName: args.parameterGroupName,
snapshotIdentifier: this.encryptedSnapshotCopy?.targetDbSnapshotIdentifier,
...monitoringOptions,
tags: { ...common_tags_1.commonTags, ...args.tags },
}, { parent: this, dependsOn: [this.password] });
return instance;
}
}
exports.Database = Database;