Skip to content

Commit

Permalink
feat(domains): create traefik routers to subdomains
Browse files Browse the repository at this point in the history
  • Loading branch information
igr-santos committed Mar 31, 2022
1 parent efaed8c commit 8c239db
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Mock de certificates redis API (Padrão para todos os testes)
const mockCreateWildcard = jest.fn();
const mockCreateRouters = jest.fn();

jest.mock('../redis-db/certificates', () => ({
createWildcard: mockCreateWildcard
createWildcard: mockCreateWildcard,
createRouters: mockCreateRouters
}))

import CertificatesController from './certificates-controller';
Expand All @@ -11,28 +14,24 @@ describe('Certificates controller', () => {
const mockGraphQLClient = {
request: jest.fn()
}
const mockRedisClient = {
connect: jest.fn(),
set: jest.fn(),
quit: jest.fn()
};

beforeEach(() => {
jest.clearAllMocks();
})

describe('certificate is create', () => {
// Mock de entradas da função (Padrão para testes que criam certificado)
const dns = {
id: 4,
community_id: 1,
domain_name: 'test.org',
ns_ok: true
};
const request = {
body: {
event: {
data: {
new: {
id: 4,
community_id: 1,
domain_name: 'test.org',
ns_ok: true
}
new: dns
}
}
}
Expand All @@ -54,23 +53,42 @@ describe('Certificates controller', () => {
}

// Mock de clients externos API e Redis
mockGraphQLClient.request.mockResolvedValue({ insert_certificates_one: result });
mockGraphQLClient.request.mockResolvedValueOnce({ mobilizations: [] });
mockGraphQLClient.request.mockResolvedValueOnce({ insert_certificates_one: result });

const certificatesController = new CertificatesController(mockRedisClient, mockGraphQLClient);
const certificatesController = new CertificatesController(mockGraphQLClient);
await certificatesController.create(request, response);

expect(response.status.mock.calls[0][0]).toBe(200);
expect(mockJson.mock.calls[0][0]).toBe(result);
});

it('should create traefik routers in redis', async () => {
const certificatesController = new CertificatesController(mockRedisClient, mockGraphQLClient);
it('should create traefik router with wildcard in redis', async () => {
mockGraphQLClient.request.mockResolvedValueOnce({ mobilizations: [] });

const certificatesController = new CertificatesController(mockGraphQLClient);
await certificatesController.create(request, response);

const tRouterName = `${request.body.event.data.new.id}-${request.body.event.data.new.domain_name.replace('.', '-')}`;

expect(mockCreateWildcard.mock.calls[0]).toEqual([tRouterName, request.body.event.data.new.domain_name])
});

it('should create traefik routers for subdomains in redis', async () => {
const mobilizations = [
{ id: 1, community_id: 2, custom_domain: `www.campaign0.${dns.domain_name}` },
{ id: 2, community_id: 2, custom_domain: `www.campaign1.${dns.domain_name}` }
]

mockGraphQLClient.request.mockResolvedValue({ mobilizations });

const certificatesController = new CertificatesController(mockGraphQLClient);
await certificatesController.create(request, response);
const routerName = `${request.body.event.data.new.id}-${request.body.event.data.new.domain_name.replace('.', '-')}-www`;

expect(mockCreateRouters.mock.calls[0])
.toEqual([routerName, mobilizations.map(m => m.custom_domain)])
});
});

describe('certificate is not create', () => {
Expand All @@ -97,7 +115,7 @@ describe('Certificates controller', () => {
}

it('should return 400 when dns is not ok', async () => {
const certificatesController = new CertificatesController(mockRedisClient, mockGraphQLClient);
const certificatesController = new CertificatesController(mockGraphQLClient);
await certificatesController.create(request, response);

expect(response.status.mock.calls[0][0]).toEqual(402);
Expand Down
49 changes: 35 additions & 14 deletions packages/domains-api/src/controllers/certificates-controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import logger from '../config/logger';
import { gql } from '../graphql-api/client';
import { createWildcard } from '../redis-db/certificates';
import { createRouters, createWildcard } from '../redis-db/certificates';
import { validationResult, check } from 'express-validator';
import sslChecker from "ssl-checker";

Expand Down Expand Up @@ -31,6 +31,12 @@ export interface DNSHostedZone {
ns_ok?: boolean;
}

export interface Mobilization {
id: number;
custom_domain: string;
community_id: number;
}

const insert_certificate = gql`mutation ($input: certificates_insert_input!) {
insert_certificates_one(object:$input) {
id
Expand All @@ -56,20 +62,20 @@ mutation ($id: Int!, $ssl_checker_response: jsonb) {
}
`;

`
query {
mobilizations (where:{custom_domain:{_ilike:"%minhasampa.org.br"}}) {
id, custom_domain
export const fetch_mobilizations_by_domain = gql`
query ($domainName: String) {
mobilizations (where:{ custom_domain:{ _ilike: $domainName } }) {
id
custom_domain
community_id
}
}
}
`
`;

class CertificatesController {
private redisClient: any
private graphqlClient: any

constructor(redisClient, graphqlClient) {
this.redisClient = redisClient;
constructor(graphqlClient) {
this.graphqlClient = graphqlClient;
}

Expand All @@ -80,10 +86,13 @@ class CertificatesController {
return res.status(400).json({ errors: errors.array() });
}

if (req.body.event.data.new.ns_ok) {
const dns_hosted_zone = req.body.event.data.new;

if (dns_hosted_zone.ns_ok) {
try {
await this.insertCertificateRedis(req.body.event.data.new);
res.status(200).json(await this.insertCertificateGraphql(req.body.event.data.new));
const domains: string[] = await this.fetchCustomDomains(dns_hosted_zone.domain_name);
await this.insertCertificateRedis(dns_hosted_zone, domains);
res.status(200).json(await this.insertCertificateGraphql(dns_hosted_zone));
} catch (e: any) {
logger.info(e)
res.status(500).json({ ok: false, ...e });
Expand All @@ -93,12 +102,13 @@ class CertificatesController {
}
}

private insertCertificateRedis = async (input: DNSHostedZone) => {
private insertCertificateRedis = async (input: DNSHostedZone, domains: string[]) => {
const { domain_name, id: dns_hosted_zone_id } = input;
const tRouterName = `${dns_hosted_zone_id}-${domain_name.replace('.', '-')}`
logger.info(`In controller - createCertificate ${tRouterName}`);

await createWildcard(tRouterName, domain_name);
await createRouters(`${tRouterName}-www`, domains);
}

private insertCertificateGraphql = async (input: any): Promise<CertificateTLS> => {
Expand All @@ -124,6 +134,17 @@ class CertificatesController {
return data.update_certificates_by_pk;
}

private fetchCustomDomains = async (domain: string): Promise<string[]> => {
const data: { mobilizations: Mobilization[] } = await this.graphqlClient.request({
document: fetch_mobilizations_by_domain,
variables: { domain: `%${domain}%` }
});

logger.child({ data }).info('fetch_mobilizations_by_domain');

return data.mobilizations.map((mob) => mob.custom_domain);
}

check = async (req: Request<CertificateTLS>, res) => {
/**
* Esse evento deve ser chamado sempre que criar um novo certificado
Expand Down
4 changes: 2 additions & 2 deletions packages/domains-api/src/routes/events-route.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// import dependencies and initialize the express router
import express from 'express';
import CertificatesController from '../controllers/certificates-controller';
import redisClient from '../redis-db/client'
// import redisClient from '../redis-db/client'
import { client } from '../graphql-api/client';

const router = express.Router();

const certificatesController = new CertificatesController(redisClient, client);
const certificatesController = new CertificatesController(client);

// define routes
router.post('/create-certificate', certificatesController.create);
Expand Down

0 comments on commit 8c239db

Please sign in to comment.