Skip to content

Commit

Permalink
build(docker): setup healthchecks (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
derevnjuk authored Aug 17, 2021
1 parent d3028c9 commit 5314c18
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 99 deletions.
2 changes: 0 additions & 2 deletions docker-compose.local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ services:

proxy:
image: nginx:1.17.3-alpine

ports:
- 8090:80

volumes:
- ./nginx-config/local.conf:/etc/nginx/conf.d/default.conf
- ./public/build:/htdocs
Expand Down
56 changes: 44 additions & 12 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,21 @@ services:
POSTGRES_DB: bc
POSTGRES_USER: bc
POSTGRES_PASSWORD: bc
healthcheck:
interval: 10s
retries: 10
test:
[
'CMD',
'pg_isready',
'-U',
'${POSTGRES_USER}',
'-P',
'${POSTGRES_PASSWORD}',
]
timeout: 45s
volumes:
- ./pg.sql:/docker-entrypoint-initdb.d/pg.sql
- ./pg.sql:/docker-entrypoint-initdb.d/pg.sql

nodejs:
image: neuralegion/brokencrystals
Expand All @@ -21,8 +34,8 @@ services:
cpus: 3.5
logging:
options:
max-file: "5"
max-size: "10m"
max-file: '5'
max-size: '10m'
depends_on:
- db
- keycloak
Expand All @@ -31,10 +44,10 @@ services:
image: neuralegion/brokencrystals-client
restart: always
environment:
CERTBOT_EMAIL: "[email protected]"
CERTBOT_EMAIL: '[email protected]'
ports:
- "80:80"
- "443:443"
- '80:80'
- '443:443'
depends_on:
- nodejs
volumes:
Expand All @@ -46,28 +59,41 @@ services:
restart: always
logging:
options:
max-file: "5"
max-size: "10m"
max-file: '5'
max-size: '10m'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 300 --debug

keycloak-db:
image: "postgres:12.2-alpine"
image: 'postgres:12.2-alpine'
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
healthcheck:
interval: 10s
retries: 10
test:
[
'CMD',
'pg_isready',
'-U',
'${POSTGRES_USER}',
'-P',
'${POSTGRES_PASSWORD}',
]
timeout: 45s
restart: on-failure
stdin_open: true
tty: true
volumes:
- "./keycloak/db:/var/lib/postgresql/data/"
- './keycloak/db:/var/lib/postgresql/data/'

keycloak:
image: jboss/keycloak:latest
volumes:
- "./keycloak/imports/realm-export.json:/opt/jboss/keycloak/imports/realm-export.json"
- './keycloak/imports/realm-export.json:/opt/jboss/keycloak/imports/realm-export.json'
environment:
DB_VENDOR: POSTGRES
DB_ADDR: keycloak-db
Expand All @@ -79,7 +105,13 @@ services:
KEYCLOAK_PASSWORD: Pa55w0rd
KEYCLOAK_IMPORT: /opt/jboss/keycloak/imports/realm-export.json -Dkeycloak.profile.feature.upload_scripts=enabled
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:8080/auth/realms/brokencrystals/health/check/database" ]
test:
[
'CMD',
'curl',
'-f',
'http://localhost:8080/auth/realms/brokencrystals/health/check/database',
]
timeout: 10s
interval: 30s
retries: 3
Expand Down
4 changes: 2 additions & 2 deletions pg.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ create table "product" ("id" serial primary key, "created_at" timestamptz(0) not

set session_replication_role = 'origin';
--password is admin
INSERT INTO public."user" (created_at, updated_at, email, password, first_name, last_name, is_admin, photo) VALUES (now(), now(), 'admin', '$2b$10$BBJjmVNNdyEgv7pV/zQR9u/ssIuwZsdDJbowW/Dgp28uws3GmO0Ky', 'admin', 'admin', false, null);
INSERT INTO "user" (created_at, updated_at, email, password, first_name, last_name, is_admin, photo) VALUES (now(), now(), 'admin', '$2b$10$BBJjmVNNdyEgv7pV/zQR9u/ssIuwZsdDJbowW/Dgp28uws3GmO0Ky', 'admin', 'admin', false, null);

--insert default products into the table
INSERT INTO "product" ("category", "photo_url", "name", "description") VALUES ('Healing', '/api/file?path=config/products/crystals/amethyst.jpg&type=image/jpg', 'Amethyst', 'a violet variety of quartz');
Expand All @@ -19,4 +19,4 @@ INSERT INTO "product" ("category", "photo_url", "name", "description") VALUES ('
INSERT INTO "product" ("category", "photo_url", "name", "description") VALUES ('Healing', '/api/file?path=config/products/crystals/amber.jpg&type=image/jpg', 'Amber', 'fossilized tree resin');
INSERT INTO "product" ("category", "photo_url", "name", "description") VALUES ('Jewellery', '/api/file?path=config/products/crystals/emerald.jpg&type=image/jpg', 'Emerald', 'symbol of fertility and life');
INSERT INTO "product" ("category", "photo_url", "name", "description") VALUES ('Jewellery', '/api/file?path=config/products/crystals/shattuckite.jpg&type=image/jpg', 'Shattuckite', 'mistery');
INSERT INTO "product" ("category", "photo_url", "name", "description") VALUES ('Gemstones', '/api/file?path=config/products/crystals/bismuth.jpg&type=image/jpg', 'Bismuth', 'rainbow');
INSERT INTO "product" ("category", "photo_url", "name", "description") VALUES ('Gemstones', '/api/file?path=config/products/crystals/bismuth.jpg&type=image/jpg', 'Bismuth', 'rainbow');
132 changes: 65 additions & 67 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
BadRequestException,
Body,
Query,
Controller,
Get,
HttpStatus,
Expand All @@ -13,7 +12,7 @@ import {
UnauthorizedException,
UseGuards,
} from '@nestjs/common';
import { createHash } from 'crypto';
import { createHash, randomBytes } from 'crypto';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { User } from '../model/user.entity';
import { LdapQueryHandler } from '../users/ldap.query.handler';
Expand Down Expand Up @@ -42,7 +41,6 @@ import { AuthService, JwtProcessorType } from './auth.service';
import { passwordMatches } from './credentials.utils';
import { JwtType } from './jwt/jwt.type.decorator';
import { FastifyReply, FastifyRequest } from 'fastify';
import { randomBytes } from 'crypto';
import { CsrfGuard } from './csrf.guard';
import { ClientType, KeyCloakService } from '../keycloak/keycloak.service';

Expand All @@ -64,70 +62,6 @@ export class AuthController {
private readonly authService: AuthService,
) {}

private async loginOidc(req: LoginRequest): Promise<LoginData> {
try {
const {
token_type,
access_token,
} = await this.keyCloakService.generateToken({
username: req.user,
password: req.password,
});

return {
email: req.user,
ldapProfileLink: LdapQueryHandler.LDAP_SEARCH_QUERY(req.user),
token: `${token_type} ${access_token}`,
};
} catch (err) {
if (err.response.status === 401) {
throw new UnauthorizedException({
error: 'Invalid credentials',
location: __filename,
});
}

throw new InternalServerErrorException({
error: err.message,
location: __filename,
});
}
}

private async login(req: LoginRequest): Promise<LoginData> {
let user: User;

try {
user = await this.usersService.findByEmail(req.user);
} catch (err) {
throw new InternalServerErrorException({
error: err.message,
location: __filename,
});
}

if (!user || !(await passwordMatches(req.password, user.password))) {
throw new UnauthorizedException({
error: 'Invalid credentials',
location: __filename,
});
}

const token = await this.authService.createToken(
{
user: user.email,
exp: 90 + Math.floor(Date.now() / 1000),
},
JwtProcessorType.RSA,
);

return {
token,
email: user.email,
ldapProfileLink: LdapQueryHandler.LDAP_SEARCH_QUERY(user.email),
};
}

@Post('/admin/login')
@ApiResponse({
type: LoginResponse,
Expand Down Expand Up @@ -530,4 +464,68 @@ export class AuthController {
secret: 'this is our secret',
};
}

private async loginOidc(req: LoginRequest): Promise<LoginData> {
try {
const {
token_type,
access_token,
} = await this.keyCloakService.generateToken({
username: req.user,
password: req.password,
});

return {
email: req.user,
ldapProfileLink: LdapQueryHandler.LDAP_SEARCH_QUERY(req.user),
token: `${token_type} ${access_token}`,
};
} catch (err) {
if (err.response.status === 401) {
throw new UnauthorizedException({
error: 'Invalid credentials',
location: __filename,
});
}

throw new InternalServerErrorException({
error: err.message,
location: __filename,
});
}
}

private async login(req: LoginRequest): Promise<LoginData> {
let user: User;

try {
user = await this.usersService.findByEmail(req.user);
} catch (err) {
throw new InternalServerErrorException({
error: err.message,
location: __filename,
});
}

if (!user || !(await passwordMatches(req.password, user.password))) {
throw new UnauthorizedException({
error: 'Invalid credentials',
location: __filename,
});
}

const token = await this.authService.createToken(
{
user: user.email,
exp: 90 + Math.floor(Date.now() / 1000),
},
JwtProcessorType.RSA,
);

return {
token,
email: user.email,
ldapProfileLink: LdapQueryHandler.LDAP_SEARCH_QUERY(user.email),
};
}
}
13 changes: 2 additions & 11 deletions src/products/products.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import {
Body,
Controller,
Get,
Logger,
Post,
Query,
UseGuards,
} from '@nestjs/common';
import { Controller, Get, Logger, UseGuards } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { AuthGuard } from '../auth/auth.guard';
import { JwtProcessorType } from '../auth/auth.service';
import { JwtType } from '../auth/jwt/jwt.type.decorator';
import { CreateProductRequest } from './api/CreateProductRequest';
import { ProductDto } from './api/ProductDto';
import { ProductsService } from './products.service';
import { Product } from '../model/product.entity';
Expand All @@ -37,7 +28,7 @@ export class ProductsController {
async getProducts(): Promise<ProductDto[]> {
this.logger.debug('Get all products.');
const allProducts = await this.productsService.findAll();
return allProducts.map<ProductDto>((p: Product) => new ProductDto(p));
return allProducts.map((p: Product) => new ProductDto(p));
}

@Get('latest')
Expand Down
5 changes: 2 additions & 3 deletions src/products/products.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EntityManager, EntityRepository, MikroORM } from '@mikro-orm/core';
import { EntityRepository } from '@mikro-orm/core';
import { InjectRepository } from '@mikro-orm/nestjs';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import { Product } from '../model/product.entity';

@Injectable()
Expand All @@ -10,7 +10,6 @@ export class ProductsService {
constructor(
@InjectRepository(Product)
private readonly productsRepository: EntityRepository<Product>,
private readonly em: EntityManager,
) {}

async findAll(): Promise<Product[]> {
Expand Down
4 changes: 2 additions & 2 deletions src/testimonials/testimonials.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EntityManager, EntityRepository, MikroORM } from '@mikro-orm/core';
import { EntityManager, EntityRepository } from '@mikro-orm/core';
import { InjectRepository } from '@mikro-orm/nestjs';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import { Testimonial } from '../model/testimonial.entity';

@Injectable()
Expand Down

0 comments on commit 5314c18

Please sign in to comment.