From 8c239db1230690e149c4ac1912f8fe7c3a441e6b Mon Sep 17 00:00:00 2001 From: Igor Santos Date: Thu, 31 Mar 2022 10:30:04 -0300 Subject: [PATCH] feat(domains): create traefik routers to subdomains --- .../certificates-controller.spec.ts | 52 +++++++++++++------ .../controllers/certificates-controller.ts | 49 ++++++++++++----- .../domains-api/src/routes/events-route.ts | 4 +- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/packages/domains-api/src/controllers/certificates-controller.spec.ts b/packages/domains-api/src/controllers/certificates-controller.spec.ts index 2e9cc9a..215d15c 100644 --- a/packages/domains-api/src/controllers/certificates-controller.spec.ts +++ b/packages/domains-api/src/controllers/certificates-controller.spec.ts @@ -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'; @@ -11,11 +14,6 @@ describe('Certificates controller', () => { const mockGraphQLClient = { request: jest.fn() } - const mockRedisClient = { - connect: jest.fn(), - set: jest.fn(), - quit: jest.fn() - }; beforeEach(() => { jest.clearAllMocks(); @@ -23,16 +21,17 @@ describe('Certificates controller', () => { 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 } } } @@ -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', () => { @@ -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); diff --git a/packages/domains-api/src/controllers/certificates-controller.ts b/packages/domains-api/src/controllers/certificates-controller.ts index 0c08dc0..bbdea99 100644 --- a/packages/domains-api/src/controllers/certificates-controller.ts +++ b/packages/domains-api/src/controllers/certificates-controller.ts @@ -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"; @@ -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 @@ -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; } @@ -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 }); @@ -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 => { @@ -124,6 +134,17 @@ class CertificatesController { return data.update_certificates_by_pk; } + private fetchCustomDomains = async (domain: string): Promise => { + 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, res) => { /** * Esse evento deve ser chamado sempre que criar um novo certificado diff --git a/packages/domains-api/src/routes/events-route.ts b/packages/domains-api/src/routes/events-route.ts index 576c8ad..e57508c 100644 --- a/packages/domains-api/src/routes/events-route.ts +++ b/packages/domains-api/src/routes/events-route.ts @@ -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);