fosrl.pangolin/server/routers/traefik/getTraefikConfig.ts

116 lines
3.6 KiB
TypeScript
Raw Normal View History

2024-09-28 22:50:10 -04:00
import { Request, Response } from "express";
import db from "@server/db";
import * as schema from "@server/db/schema";
import { DynamicTraefikConfig } from "./configSchema";
import { and, like, eq } from "drizzle-orm";
2024-09-28 22:50:10 -04:00
import logger from "@server/logger";
2024-10-01 20:48:03 -04:00
import HttpCode from "@server/types/HttpCode";
2024-10-12 18:21:31 -04:00
import env from "@server/config";
import config from "@server/config";
2024-09-28 22:50:10 -04:00
export async function traefikConfigProvider(_: Request, res: Response) {
try {
const targets = await getAllTargets();
const traefikConfig = buildTraefikConfig(targets);
2024-10-01 20:48:03 -04:00
res.status(HttpCode.OK).json(traefikConfig);
2024-09-28 22:50:10 -04:00
} catch (e) {
logger.error(`Failed to build traefik config: ${e}`);
2024-10-01 20:48:03 -04:00
res.status(HttpCode.INTERNAL_SERVER_ERROR).json({
error: "Failed to build traefik config",
});
2024-09-28 22:50:10 -04:00
}
}
export function buildTraefikConfig(
targets: schema.Target[],
): DynamicTraefikConfig {
2024-09-29 14:37:26 -04:00
const middlewareName = "badger";
2024-09-28 22:50:10 -04:00
2024-10-20 15:00:19 -04:00
const http: any = {
routers: {
main: {
2024-10-20 14:15:19 -04:00
entryPoints: ["https"],
middlewares: [],
service: "service-main",
2024-10-20 15:03:44 -04:00
rule: "Host(`fossorial.io`)",
2024-10-20 15:00:19 -04:00
tls: {
certResolver: "letsencrypt",
2024-10-20 15:03:44 -04:00
domains: [
{
main: "fossorial.io",
sans: ["*.fossorial.io"],
},
],
},
},
},
services: {
"service-main": {
loadBalancer: {
servers: [
{
2024-10-20 13:28:56 -04:00
url: `http://${config.server.internal_hostname}:${config.server.external_port}`,
},
],
},
},
},
2024-09-29 14:37:26 -04:00
middlewares: {
[middlewareName]: {
plugin: {
[middlewareName]: {
2024-10-12 21:23:12 -04:00
apiBaseUrl: new URL(
"/api/v1",
`http://${config.server.internal_hostname}:${config.server.internal_port}`,
).href,
2024-10-20 15:53:58 -04:00
appBaseUrl: config.app.base_url,
2024-09-29 14:37:26 -04:00
},
},
},
},
2024-09-28 22:50:10 -04:00
};
for (const target of targets) {
const routerName = `router-${target.targetId}`;
const serviceName = `service-${target.targetId}`;
http.routers![routerName] = {
2024-10-20 16:01:52 -04:00
entryPoints: ["https"],
2024-09-29 14:37:26 -04:00
middlewares: [middlewareName],
2024-09-28 22:50:10 -04:00
service: serviceName,
rule: `Host(\`${target.resourceId}\`)`, // assuming resourceId is a valid full hostname
2024-10-20 15:55:11 -04:00
tls: {
certResolver: "letsencrypt",
domains: [
{
main: "fossorial.io",
sans: ["*.fossorial.io"],
},
],
},
2024-09-28 22:50:10 -04:00
};
http.services![serviceName] = {
2024-09-28 22:50:10 -04:00
loadBalancer: {
servers: [
{ url: `${target.method}://${target.ip}:${target.port}` },
],
},
};
}
return { http } as DynamicTraefikConfig;
}
export async function getAllTargets(): Promise<schema.Target[]> {
const all = await db
.select()
.from(schema.targets)
.where(
and(
eq(schema.targets.enabled, true),
like(schema.targets.resourceId, "%.%"),
),
); // any resourceId with a dot is a valid hostname; otherwise it's a UUID placeholder
2024-09-28 22:50:10 -04:00
return all;
}