Skip to content

Fetch VPC & Subnet information from AWS (using NestJS CQRS pattern)

Notifications You must be signed in to change notification settings

jaehong21/carrot-aws

Repository files navigation

Table of Contents

Preparation
Running the app
Documentation
Description
Contact

Introduction

NestJS is a progressive Node.js Framework
carrot-aws provides you simple VPC and Subnet information on AWS

Preparation

docker-compose.yaml

  1. Fill AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY for the AWS account you want to access
  2. Check port 3000 and 5432 is empty on your environment
  3. You can set your own POSTGRES_USER and POSTGRES_PASSWORD
  4. You can uncomment volumes to save further information on docker volumes
version: "3"

services:
  carrot-aws:
    depends_on:
      - postgres
    build:
      context: .
      dockerfile: ./Dockerfile
    container_name: carrot-aws
    ports:
      - "3000:3000"
    links:
      - postgres:postgres
    environment:
      AWS_ACCESS_KEY_ID: xxx
      AWS_SECRET_ACCESS_KEY: xxx
      POSTGRES_HOST: postgres
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password

  postgres:
    image: postgres
    restart: unless-stopped
    container_name: postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
#   volumes:
#     - ./postgresql/:/var/lib/postgresql/data

Running the app

with docker

Make sure there is no existing postgres image. Already existing postgres image can cause error because different credentials with given values in docker-compose.yaml

# (Optional) prune existing docker images before running the app 
$ docker-compose down --rmi all

# docker run (foreground)
$ docker-compose up

# docker run (background)
$ docker-compose up -d 

without docker

# npm i -g @nestjs/cli

# development
$ nest start --watch

# production
$ yarn start:prod

Postgresql with database name 'postgres' needed and
.env file is needed with values below

AWS_ACCESS_KEY_ID=xxx
AWS_SECRET_ACCESS_KEY=xxx
POSTGRES_HOST=xxx
POSTGRES_USER=xxx
POSTGRES_PASSWORD=xxx

Documentation

GET /

# Simple Health Check API returns "OK"
$ curl --request GET 'localhost:3000'

GET /region

# Get list of valid AWS regions
$ curl --request GET 'localhost:3000/region'

GET /vpc

# Get VPC information from all region
$ curl --request GET 'localhost:3000/vpc'

GET /vpc/{region}

# Get VPC information for given AWS region
$ curl --request GET 'localhost:3000/vpc/ap-northeast-2'

GET /subnet

# Get Subnet information from all region
$ curl --request GET 'localhost:3000/subnet'

GET /subnet/{region}

# Get Subnet information for given AWS region
$ curl --request GET 'localhost:3000/subnet/ap-northeast-2'

POST /vpc/{region}

# Update VPC information for given AWS region
$ curl --request POST 'localhost:3000/vpc/ap-northeast-2'

POST /subnet/{region}

# Update Subnet information for given AWS region
$ curl --request POST 'localhost:3000/subnet/ap-northeast-2'

Description

├── adapter
│   ├── controller
│   └── database
├── app.module.ts
├── config
├── cron
├── entity
├── main.ts
├── mapper
├── model
└── usecase
    ├── command
    ├── command-handler
    ├── query
    └── query-handler

Adapter

├── adapter
    ├── controller
    └── database
  // vpc.controller.ts

  @Post('/:region')
  async saveVpc(@Param() awsRegionDto: AwsRegionDto): Promise<ResponseDto> {
    const vpcCommand = new VpcCommand({ region: awsRegionDto.region });
    await this.commandBus.execute(vpcCommand);
    return {
      status: 201,
      message: 'VPC List Saved Success',
      data: {},
    };
  }

Adapter contains implementation of controller and repository Which can be easily convertible to other controllers and repositories. (Port & Adapter is still working on)

Usecase (Query & Command)

// Command
type VpcCommandDto = {
  region: AwsRegion;
};
export class VpcCommand implements ICommand {
  constructor(readonly vpcCommandDto: VpcCommandDto) {}
}

// CommandHandler
@Injectable()
@CommandHandler(VpcCommand)
export class VpcCommandHandler
  implements ICommandHandler<VpcCommand, boolean>, OnModuleInit
{
  
  // ...

  async execute(command: VpcCommand): Promise<boolean> {
    const ec2 = new AWS.EC2({
      region: command.vpcCommandDto.region,
    });
    return new Promise<boolean>((resolve, reject) => {
      // ...
    });
  }
}

Usecase is based on CQRS pattern which is composed with command and query. Supported by @nestjs/cqrs package, it broadcasts Command/Query/Event

Model

export class VpcModel implements VpcType, IModel {
  constructor(properties: VpcType) {
    Object.assign(this, properties);
  }

  VpcId: string;
  CidrBlock: string;
  DhcpOptionsId: string;
  
  // ...
  
  properties() {
    return {
      vpcId: this.VpcId,
      // ...
    };
  }
}

Model is similar to the concept of Domain. Which is the key and the base of the program.

Entity

@Entity('vpc_tb')
export class VpcEntity implements IEntity {
  @PrimaryColumn({ name: 'vpc_id' })
  vpcId: string;
  
  // ...
  
  @Column({ name: 'update_time', type: 'bigint' })
  updateTime?: number;
}

Implementation of Entity in Postgresql database. There are specific database configuration on config folder.

Mapper

export abstract class IMapper<T, E> {
  abstract createEntity(T: IModel): E;
  abstract createModel(E: IEntity): T;
}

Mapper that converts between Model(Domain) and Entity

Cron

@Cron(CronExpression.EVERY_5_MINUTES)
  async handleCron() {
    this.logger.debug('Executing cron expression');
    Object.values(AwsRegion).map(async (region) => {
      await this.commandBus.execute(
        new VpcCommand({ region: <AwsRegion>region }),
      );
      await this.commandBus.execute(
        new SubnetCommand({ region: <AwsRegion>region }),
      );
    });
  }

Guarantees update VPC & Subnet information for every 5 minutes

Contact

References

Nest is MIT licensed.
https://github.com/chungjung-d/create-nestjs-hexagonal
https://learn.microsoft.com/en-us/azure/architecture/patterns/event-sourcing
https://learn.microsoft.com/ko-kr/azure/architecture/patterns/cqrs

About

Fetch VPC & Subnet information from AWS (using NestJS CQRS pattern)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published