getTraefikConfig.ts 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { Request, Response } from "express";
  2. import db from "@server/db";
  3. import * as schema from "@server/db/schema";
  4. import { DynamicTraefikConfig } from "./configSchema";
  5. import { and, like, eq, isNotNull } from "drizzle-orm";
  6. import logger from "@server/logger";
  7. import HttpCode from "@server/types/HttpCode";
  8. import config from "@server/config";
  9. export async function traefikConfigProvider(_: Request, res: Response) {
  10. try {
  11. const targets = await getAllTargets();
  12. const traefikConfig = buildTraefikConfig(targets);
  13. res.status(HttpCode.OK).json(traefikConfig);
  14. } catch (e) {
  15. logger.error(`Failed to build traefik config: ${e}`);
  16. res.status(HttpCode.INTERNAL_SERVER_ERROR).json({
  17. error: "Failed to build traefik config",
  18. });
  19. }
  20. }
  21. export function buildTraefikConfig(
  22. targets: schema.Target[]
  23. ): DynamicTraefikConfig {
  24. if (!targets.length) {
  25. return { http: {} } as DynamicTraefikConfig;
  26. }
  27. const middlewareName = "badger";
  28. const baseDomain = new URL(config.app.base_url).hostname;
  29. const tls = {
  30. certResolver: config.traefik.cert_resolver,
  31. // domains: [ // TODO: figure out if this is neccessary
  32. // {
  33. // main: baseDomain,
  34. // sans: ["*." + baseDomain],
  35. // },
  36. // ],
  37. };
  38. const http: any = {
  39. routers: {},
  40. services: {},
  41. middlewares: {
  42. [middlewareName]: {
  43. plugin: {
  44. [middlewareName]: {
  45. apiBaseUrl: new URL(
  46. "/api/v1",
  47. `http://${config.server.internal_hostname}:${config.server.internal_port}`
  48. ).href,
  49. appBaseUrl: config.app.base_url,
  50. },
  51. },
  52. },
  53. },
  54. };
  55. for (const target of targets) {
  56. const routerName = `router-${target.targetId}`;
  57. const serviceName = `service-${target.targetId}`;
  58. http.routers![routerName] = {
  59. entryPoints: [target.ssl ? config.traefik.https_entrypoint : config.traefik.https_entrypoint],
  60. middlewares: [middlewareName],
  61. service: serviceName,
  62. rule: `Host(\`${target.resourceId}\`)`, // assuming resourceId is a valid full hostname
  63. ...(target.ssl ? { tls } : {}),
  64. };
  65. http.services![serviceName] = {
  66. loadBalancer: {
  67. servers: [
  68. { url: `${target.method}://${target.ip}:${target.port}` },
  69. ],
  70. },
  71. };
  72. }
  73. return { http } as DynamicTraefikConfig;
  74. }
  75. export async function getAllTargets(): Promise<schema.Target[]> {
  76. const all = await db
  77. .select()
  78. .from(schema.targets)
  79. .innerJoin(schema.resources, eq(schema.targets.resourceId, schema.resources.resourceId))
  80. .where(
  81. and(
  82. eq(schema.targets.enabled, true),
  83. isNotNull(schema.resources.fullDomain)
  84. )
  85. );
  86. return all.map((row) => row.targets);
  87. }