Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ $ pulumi up

1. [Project](#project)
2. [Database](#database)
3. [Redis](#redis)
4. [StaticSite](#static-site)
5. [WebServer](#web-server)
6. [Nuxt SSR](#nuxt-ssr-preset)
7. [Mongo](#mongo)
8. [EcsService](#ecs-service)
3. [Database Replica](#database-replica)
4. [Redis](#redis)
5. [StaticSite](#static-site)
6. [WebServer](#web-server)
7. [Nuxt SSR](#nuxt-ssr-preset)
8. [Mongo](#mongo)
9. [EcsService](#ecs-service)

### Project

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

### Database Replica

AWS RDS Postgres instance.

Features:

- enabled encryption with a symmetric encryption key
- deployed inside an isolated subnet

<br>

```ts
new DatabaseReplica(name: string, args: DatabaseReplicaArgs, opts?: pulumi.CustomResourceOptions);
```

| Argument | Description |
| :------- | :--------------------------------------------: |
| name \* | The unique name of the resource. |
| args \* | The arguments to resource properties. |
| opts | Bag of options to control resource's behavior. |

```ts
type DatabaseReplicaArgs = {
replicateSourceDb: pulumi.Input<string>;
dbSubnetGroupName: pulumi.Input<string>;
dbSecurityGroupId: pulumi.Input<string>;
monitoringRole?: aws.iam.Role;
multiAz?: pulumi.Input<boolean>;
applyImmediately?: pulumi.Input<boolean>;
allocatedStorage?: pulumi.Input<number>;
maxAllocatedStorage?: pulumi.Input<number>;
instanceClass?: pulumi.Input<string>;
tags?: pulumi.Input<{
[key: string]: pulumi.Input<string>;
}>;
};
```
Database replica requires primary DB instance to exist.

### Redis

[Upstash](https://upstash.com) Redis instance.
Expand Down
126 changes: 126 additions & 0 deletions src/components/database-replica.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import * as aws from '@pulumi/aws';
import * as pulumi from '@pulumi/pulumi';
import { commonTags } from '../constants';

export type DatabaseReplicaArgs = {
/**
* ARN of the primary DB that we want to replicate.
*/
replicateSourceDb: pulumi.Input<string>;
/**
* DB subnet group name. Should be the same as primary instance.
* * If primary DB is instance of studion:Database, it can be accessed as
* `db.dbSubnetGroup.name`.
*/
dbSubnetGroupName: pulumi.Input<string>;
/**
* DB security group ID. Should be the same as primary instance.
* If primary DB is instance of studion:Database, it can be accessed as
* `db.dbSecurityGroup.id`.
*/
dbSecurityGroupId: pulumi.Input<string>;
/**
* IAM Monitoring role. Should be the same as primary instance.
*/
monitoringRole?: aws.iam.Role;
/**
* Specifies if the RDS instance is multi-AZ. Defaults to false.
*/
multiAz?: pulumi.Input<boolean>;
/**
* Specifies whether any database modifications are applied immediately,
* or during the next maintenance window. Default is false.
*/
applyImmediately?: pulumi.Input<boolean>;
/**
* The allocated storage in gibibytes. Defaults to 20GB.
*/
allocatedStorage?: pulumi.Input<number>;
/**
* The upper limit to which Amazon RDS can automatically scale
* the storage of the DB instance. Defaults to 100GB.
*/
maxAllocatedStorage?: pulumi.Input<number>;
/**
* The instance type of the RDS instance. Defaults to 'db.t4g.micro'.
*/
instanceClass?: pulumi.Input<string>;
/**
* A map of tags to assign to the resource.
*/
tags?: pulumi.Input<{
[key: string]: pulumi.Input<string>;
}>;
};

const defaults = {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ikovac should I put defaults from this and the Database component to constants file and reuse or do we want to have them separate? I just noticed we have skipFinalSnapshot here which does not apply to replica.

Also, based on our offline talk, replicas can have multiAz too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can keep them separate

multiAz: false,
applyImmediately: false,
skipFinalSnapshot: false,
allocatedStorage: 20,
maxAllocatedStorage: 100,
instanceClass: 'db.t4g.micro',
enableMonitoring: false,
};

export class DatabaseReplica extends pulumi.ComponentResource {
name: string;
instance: aws.rds.Instance;
monitoringRole?: aws.iam.Role;

constructor(
name: string,
args: DatabaseReplicaArgs,
opts: pulumi.ComponentResourceOptions = {},
) {
super('studion:DatabaseReplica', name, {}, opts);

this.name = name;

const argsWithDefaults = Object.assign({}, defaults, args);
this.monitoringRole = argsWithDefaults.monitoringRole;
this.instance = this.createDatabaseInstance(args);

this.registerOutputs();
}

private createDatabaseInstance(args: DatabaseReplicaArgs) {
const argsWithDefaults = Object.assign({}, defaults, args);
const stack = pulumi.getStack();

const monitoringOptions =
argsWithDefaults.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: '15.5',
allocatedStorage: argsWithDefaults.allocatedStorage,
maxAllocatedStorage: argsWithDefaults.maxAllocatedStorage,
instanceClass: argsWithDefaults.instanceClass,
dbSubnetGroupName: argsWithDefaults.dbSubnetGroupName,
vpcSecurityGroupIds: [argsWithDefaults.dbSecurityGroupId],
storageEncrypted: true,
multiAz: argsWithDefaults.multiAz,
publiclyAccessible: false,
applyImmediately: argsWithDefaults.applyImmediately,
autoMinorVersionUpgrade: true,
maintenanceWindow: 'Mon:07:00-Mon:07:30',
replicateSourceDb: argsWithDefaults.replicateSourceDb,
...monitoringOptions,
tags: { ...commonTags, ...argsWithDefaults.tags },
},
{ parent: this }
);
return instance;
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './components/web-server';
export * from './components/mongo';
export * from './components/static-site';
export * from './components/database';
export * from './components/database-replica';
export * from './components/redis';
export * from './components/project';
export * from './components/ec2-ssm-connect';
Expand Down