Skip to content

Commit 08b7cde

Browse files
authored
Add DatabaseReplica component (#17)
* Add replicateSourceDb param to database constructor for DB replica instances * Do not set KMS and password since those are inherited from primary DB * Add DatabaseReplica component * Clean up * Update README * Update README
1 parent 145a46d commit 08b7cde

File tree

3 files changed

+173
-6
lines changed

3 files changed

+173
-6
lines changed

README.md

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ $ pulumi up
5858

5959
1. [Project](#project)
6060
2. [Database](#database)
61-
3. [Redis](#redis)
62-
4. [StaticSite](#static-site)
63-
5. [WebServer](#web-server)
64-
6. [Nuxt SSR](#nuxt-ssr-preset)
65-
7. [Mongo](#mongo)
66-
8. [EcsService](#ecs-service)
61+
3. [Database Replica](#database-replica)
62+
4. [Redis](#redis)
63+
5. [StaticSite](#static-site)
64+
6. [WebServer](#web-server)
65+
7. [Nuxt SSR](#nuxt-ssr-preset)
66+
8. [Mongo](#mongo)
67+
9. [EcsService](#ecs-service)
6768

6869
### Project
6970

@@ -380,6 +381,45 @@ If the password is not specified it will be autogenerated.
380381
The database password is stored as a secret inside AWS Secret Manager.
381382
The secret will be available on the `Database` resource as `password.secret`.
382383

384+
### Database Replica
385+
386+
AWS RDS Postgres instance.
387+
388+
Features:
389+
390+
- enabled encryption with a symmetric encryption key
391+
- deployed inside an isolated subnet
392+
393+
<br>
394+
395+
```ts
396+
new DatabaseReplica(name: string, args: DatabaseReplicaArgs, opts?: pulumi.CustomResourceOptions);
397+
```
398+
399+
| Argument | Description |
400+
| :------- | :--------------------------------------------: |
401+
| name \* | The unique name of the resource. |
402+
| args \* | The arguments to resource properties. |
403+
| opts | Bag of options to control resource's behavior. |
404+
405+
```ts
406+
type DatabaseReplicaArgs = {
407+
replicateSourceDb: pulumi.Input<string>;
408+
dbSubnetGroupName: pulumi.Input<string>;
409+
dbSecurityGroupId: pulumi.Input<string>;
410+
monitoringRole?: aws.iam.Role;
411+
multiAz?: pulumi.Input<boolean>;
412+
applyImmediately?: pulumi.Input<boolean>;
413+
allocatedStorage?: pulumi.Input<number>;
414+
maxAllocatedStorage?: pulumi.Input<number>;
415+
instanceClass?: pulumi.Input<string>;
416+
tags?: pulumi.Input<{
417+
[key: string]: pulumi.Input<string>;
418+
}>;
419+
};
420+
```
421+
Database replica requires primary DB instance to exist.
422+
383423
### Redis
384424

385425
[Upstash](https://upstash.com) Redis instance.

src/components/database-replica.ts

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import * as aws from '@pulumi/aws';
2+
import * as pulumi from '@pulumi/pulumi';
3+
import { commonTags } from '../constants';
4+
5+
export type DatabaseReplicaArgs = {
6+
/**
7+
* ARN of the primary DB that we want to replicate.
8+
*/
9+
replicateSourceDb: pulumi.Input<string>;
10+
/**
11+
* DB subnet group name. Should be the same as primary instance.
12+
* * If primary DB is instance of studion:Database, it can be accessed as
13+
* `db.dbSubnetGroup.name`.
14+
*/
15+
dbSubnetGroupName: pulumi.Input<string>;
16+
/**
17+
* DB security group ID. Should be the same as primary instance.
18+
* If primary DB is instance of studion:Database, it can be accessed as
19+
* `db.dbSecurityGroup.id`.
20+
*/
21+
dbSecurityGroupId: pulumi.Input<string>;
22+
/**
23+
* IAM Monitoring role. Should be the same as primary instance.
24+
*/
25+
monitoringRole?: aws.iam.Role;
26+
/**
27+
* Specifies if the RDS instance is multi-AZ. Defaults to false.
28+
*/
29+
multiAz?: pulumi.Input<boolean>;
30+
/**
31+
* Specifies whether any database modifications are applied immediately,
32+
* or during the next maintenance window. Default is false.
33+
*/
34+
applyImmediately?: pulumi.Input<boolean>;
35+
/**
36+
* The allocated storage in gibibytes. Defaults to 20GB.
37+
*/
38+
allocatedStorage?: pulumi.Input<number>;
39+
/**
40+
* The upper limit to which Amazon RDS can automatically scale
41+
* the storage of the DB instance. Defaults to 100GB.
42+
*/
43+
maxAllocatedStorage?: pulumi.Input<number>;
44+
/**
45+
* The instance type of the RDS instance. Defaults to 'db.t4g.micro'.
46+
*/
47+
instanceClass?: pulumi.Input<string>;
48+
/**
49+
* A map of tags to assign to the resource.
50+
*/
51+
tags?: pulumi.Input<{
52+
[key: string]: pulumi.Input<string>;
53+
}>;
54+
};
55+
56+
const defaults = {
57+
multiAz: false,
58+
applyImmediately: false,
59+
skipFinalSnapshot: false,
60+
allocatedStorage: 20,
61+
maxAllocatedStorage: 100,
62+
instanceClass: 'db.t4g.micro',
63+
enableMonitoring: false,
64+
};
65+
66+
export class DatabaseReplica extends pulumi.ComponentResource {
67+
name: string;
68+
instance: aws.rds.Instance;
69+
monitoringRole?: aws.iam.Role;
70+
71+
constructor(
72+
name: string,
73+
args: DatabaseReplicaArgs,
74+
opts: pulumi.ComponentResourceOptions = {},
75+
) {
76+
super('studion:DatabaseReplica', name, {}, opts);
77+
78+
this.name = name;
79+
80+
const argsWithDefaults = Object.assign({}, defaults, args);
81+
this.monitoringRole = argsWithDefaults.monitoringRole;
82+
this.instance = this.createDatabaseInstance(args);
83+
84+
this.registerOutputs();
85+
}
86+
87+
private createDatabaseInstance(args: DatabaseReplicaArgs) {
88+
const argsWithDefaults = Object.assign({}, defaults, args);
89+
const stack = pulumi.getStack();
90+
91+
const monitoringOptions =
92+
argsWithDefaults.enableMonitoring && this.monitoringRole
93+
? {
94+
monitoringInterval: 60,
95+
monitoringRoleArn: this.monitoringRole.arn,
96+
performanceInsightsEnabled: true,
97+
performanceInsightsRetentionPeriod: 7,
98+
}
99+
: {};
100+
101+
const instance = new aws.rds.Instance(
102+
`${this.name}-rds`,
103+
{
104+
identifierPrefix: `${this.name}-`,
105+
engine: 'postgres',
106+
engineVersion: '15.5',
107+
allocatedStorage: argsWithDefaults.allocatedStorage,
108+
maxAllocatedStorage: argsWithDefaults.maxAllocatedStorage,
109+
instanceClass: argsWithDefaults.instanceClass,
110+
dbSubnetGroupName: argsWithDefaults.dbSubnetGroupName,
111+
vpcSecurityGroupIds: [argsWithDefaults.dbSecurityGroupId],
112+
storageEncrypted: true,
113+
multiAz: argsWithDefaults.multiAz,
114+
publiclyAccessible: false,
115+
applyImmediately: argsWithDefaults.applyImmediately,
116+
autoMinorVersionUpgrade: true,
117+
maintenanceWindow: 'Mon:07:00-Mon:07:30',
118+
replicateSourceDb: argsWithDefaults.replicateSourceDb,
119+
...monitoringOptions,
120+
tags: { ...commonTags, ...argsWithDefaults.tags },
121+
},
122+
{ parent: this }
123+
);
124+
return instance;
125+
}
126+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './components/web-server';
22
export * from './components/mongo';
33
export * from './components/static-site';
44
export * from './components/database';
5+
export * from './components/database-replica';
56
export * from './components/redis';
67
export * from './components/project';
78
export * from './components/ec2-ssm-connect';

0 commit comments

Comments
 (0)