mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-28 13:48:13 +02:00
Fix traefik config merge
This commit is contained in:
parent
7bf98c0c40
commit
f07cd8aee3
1 changed files with 81 additions and 268 deletions
|
@ -94,94 +94,94 @@ export async function getTraefikConfig(exitNodeId: number): Promise<any> {
|
||||||
// Get all resources with related data
|
// Get all resources with related data
|
||||||
const allResources = await db.transaction(async (tx) => {
|
const allResources = await db.transaction(async (tx) => {
|
||||||
// Get resources with their targets and sites in a single optimized query
|
// Get resources with their targets and sites in a single optimized query
|
||||||
// Start from sites on this exit node, then join to targets and resources
|
// Start from sites on this exit node, then join to targets and resources
|
||||||
const resourcesWithTargetsAndSites = await tx
|
const resourcesWithTargetsAndSites = await tx
|
||||||
.select({
|
.select({
|
||||||
// Resource fields
|
// Resource fields
|
||||||
resourceId: resources.resourceId,
|
resourceId: resources.resourceId,
|
||||||
fullDomain: resources.fullDomain,
|
fullDomain: resources.fullDomain,
|
||||||
ssl: resources.ssl,
|
ssl: resources.ssl,
|
||||||
http: resources.http,
|
http: resources.http,
|
||||||
proxyPort: resources.proxyPort,
|
proxyPort: resources.proxyPort,
|
||||||
protocol: resources.protocol,
|
protocol: resources.protocol,
|
||||||
subdomain: resources.subdomain,
|
subdomain: resources.subdomain,
|
||||||
domainId: resources.domainId,
|
domainId: resources.domainId,
|
||||||
enabled: resources.enabled,
|
enabled: resources.enabled,
|
||||||
stickySession: resources.stickySession,
|
stickySession: resources.stickySession,
|
||||||
tlsServerName: resources.tlsServerName,
|
tlsServerName: resources.tlsServerName,
|
||||||
setHostHeader: resources.setHostHeader,
|
setHostHeader: resources.setHostHeader,
|
||||||
enableProxy: resources.enableProxy,
|
enableProxy: resources.enableProxy,
|
||||||
// Target fields
|
// Target fields
|
||||||
targetId: targets.targetId,
|
targetId: targets.targetId,
|
||||||
targetEnabled: targets.enabled,
|
targetEnabled: targets.enabled,
|
||||||
ip: targets.ip,
|
ip: targets.ip,
|
||||||
method: targets.method,
|
method: targets.method,
|
||||||
port: targets.port,
|
port: targets.port,
|
||||||
internalPort: targets.internalPort,
|
internalPort: targets.internalPort,
|
||||||
// Site fields
|
// Site fields
|
||||||
siteId: sites.siteId,
|
siteId: sites.siteId,
|
||||||
siteType: sites.type,
|
siteType: sites.type,
|
||||||
subnet: sites.subnet,
|
subnet: sites.subnet,
|
||||||
exitNodeId: sites.exitNodeId
|
exitNodeId: sites.exitNodeId
|
||||||
})
|
})
|
||||||
.from(sites)
|
.from(sites)
|
||||||
.innerJoin(targets, eq(targets.siteId, sites.siteId))
|
.innerJoin(targets, eq(targets.siteId, sites.siteId))
|
||||||
.innerJoin(resources, eq(resources.resourceId, targets.resourceId))
|
.innerJoin(resources, eq(resources.resourceId, targets.resourceId))
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(targets.enabled, true),
|
eq(targets.enabled, true),
|
||||||
eq(resources.enabled, true),
|
eq(resources.enabled, true),
|
||||||
or(
|
or(
|
||||||
eq(sites.exitNodeId, currentExitNodeId),
|
eq(sites.exitNodeId, currentExitNodeId),
|
||||||
isNull(sites.exitNodeId)
|
isNull(sites.exitNodeId)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
|
);
|
||||||
|
|
||||||
// Group by resource and include targets with their unique site data
|
// Group by resource and include targets with their unique site data
|
||||||
const resourcesMap = new Map();
|
const resourcesMap = new Map();
|
||||||
|
|
||||||
resourcesWithTargetsAndSites.forEach((row) => {
|
resourcesWithTargetsAndSites.forEach((row) => {
|
||||||
const resourceId = row.resourceId;
|
const resourceId = row.resourceId;
|
||||||
|
|
||||||
if (!resourcesMap.has(resourceId)) {
|
if (!resourcesMap.has(resourceId)) {
|
||||||
resourcesMap.set(resourceId, {
|
resourcesMap.set(resourceId, {
|
||||||
resourceId: row.resourceId,
|
|
||||||
fullDomain: row.fullDomain,
|
|
||||||
ssl: row.ssl,
|
|
||||||
http: row.http,
|
|
||||||
proxyPort: row.proxyPort,
|
|
||||||
protocol: row.protocol,
|
|
||||||
subdomain: row.subdomain,
|
|
||||||
domainId: row.domainId,
|
|
||||||
enabled: row.enabled,
|
|
||||||
stickySession: row.stickySession,
|
|
||||||
tlsServerName: row.tlsServerName,
|
|
||||||
setHostHeader: row.setHostHeader,
|
|
||||||
enableProxy: row.enableProxy,
|
|
||||||
targets: []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add target with its associated site data
|
|
||||||
resourcesMap.get(resourceId).targets.push({
|
|
||||||
resourceId: row.resourceId,
|
resourceId: row.resourceId,
|
||||||
targetId: row.targetId,
|
fullDomain: row.fullDomain,
|
||||||
ip: row.ip,
|
ssl: row.ssl,
|
||||||
method: row.method,
|
http: row.http,
|
||||||
port: row.port,
|
proxyPort: row.proxyPort,
|
||||||
internalPort: row.internalPort,
|
protocol: row.protocol,
|
||||||
enabled: row.targetEnabled,
|
subdomain: row.subdomain,
|
||||||
site: {
|
domainId: row.domainId,
|
||||||
siteId: row.siteId,
|
enabled: row.enabled,
|
||||||
type: row.siteType,
|
stickySession: row.stickySession,
|
||||||
subnet: row.subnet,
|
tlsServerName: row.tlsServerName,
|
||||||
exitNodeId: row.exitNodeId
|
setHostHeader: row.setHostHeader,
|
||||||
}
|
enableProxy: row.enableProxy,
|
||||||
|
targets: []
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
return Array.from(resourcesMap.values());
|
// Add target with its associated site data
|
||||||
|
resourcesMap.get(resourceId).targets.push({
|
||||||
|
resourceId: row.resourceId,
|
||||||
|
targetId: row.targetId,
|
||||||
|
ip: row.ip,
|
||||||
|
method: row.method,
|
||||||
|
port: row.port,
|
||||||
|
internalPort: row.internalPort,
|
||||||
|
enabled: row.targetEnabled,
|
||||||
|
site: {
|
||||||
|
siteId: row.siteId,
|
||||||
|
type: row.siteType,
|
||||||
|
subnet: row.subnet,
|
||||||
|
exitNodeId: row.exitNodeId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(resourcesMap.values());
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!allResources.length) {
|
if (!allResources.length) {
|
||||||
|
@ -299,194 +299,7 @@ export async function getTraefikConfig(exitNodeId: number): Promise<any> {
|
||||||
middlewares: [redirectHttpsMiddlewareName],
|
middlewares: [redirectHttpsMiddlewareName],
|
||||||
service: serviceName,
|
service: serviceName,
|
||||||
rule: `Host(\`${fullDomain}\`)`,
|
rule: `Host(\`${fullDomain}\`)`,
|
||||||
<<<<<<< HEAD
|
|
||||||
priority: 100
|
priority: 100
|
||||||
=======
|
|
||||||
priority: 100,
|
|
||||||
...(resource.ssl ? { tls } : {})
|
|
||||||
};
|
|
||||||
|
|
||||||
if (resource.ssl) {
|
|
||||||
config_output.http.routers![routerName + "-redirect"] = {
|
|
||||||
entryPoints: [
|
|
||||||
config.getRawConfig().traefik.http_entrypoint
|
|
||||||
],
|
|
||||||
middlewares: [redirectHttpsMiddlewareName],
|
|
||||||
service: serviceName,
|
|
||||||
rule: `Host(\`${fullDomain}\`)`,
|
|
||||||
priority: 100
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
config_output.http.services![serviceName] = {
|
|
||||||
loadBalancer: {
|
|
||||||
servers: targets
|
|
||||||
.filter((target: TargetWithSite) => {
|
|
||||||
if (!target.enabled) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
target.site.type === "local" ||
|
|
||||||
target.site.type === "wireguard"
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
!target.ip ||
|
|
||||||
!target.port ||
|
|
||||||
!target.method
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (target.site.type === "newt") {
|
|
||||||
if (
|
|
||||||
!target.internalPort ||
|
|
||||||
!target.method ||
|
|
||||||
!target.site.subnet
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
.map((target: TargetWithSite) => {
|
|
||||||
if (
|
|
||||||
target.site.type === "local" ||
|
|
||||||
target.site.type === "wireguard"
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
url: `${target.method}://${target.ip}:${target.port}`
|
|
||||||
};
|
|
||||||
} else if (target.site.type === "newt") {
|
|
||||||
const ip = target.site.subnet!.split("/")[0];
|
|
||||||
return {
|
|
||||||
url: `${target.method}://${ip}:${target.internalPort}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
...(resource.stickySession
|
|
||||||
? {
|
|
||||||
sticky: {
|
|
||||||
cookie: {
|
|
||||||
name: "p_sticky", // TODO: make this configurable via config.yml like other cookies
|
|
||||||
secure: resource.ssl,
|
|
||||||
httpOnly: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add the serversTransport if TLS server name is provided
|
|
||||||
if (resource.tlsServerName) {
|
|
||||||
if (!config_output.http.serversTransports) {
|
|
||||||
config_output.http.serversTransports = {};
|
|
||||||
}
|
|
||||||
config_output.http.serversTransports![transportName] = {
|
|
||||||
serverName: resource.tlsServerName,
|
|
||||||
//unfortunately the following needs to be set. traefik doesn't merge the default serverTransport settings
|
|
||||||
// if defined in the static config and here. if not set, self-signed certs won't work
|
|
||||||
insecureSkipVerify: true
|
|
||||||
};
|
|
||||||
config_output.http.services![
|
|
||||||
serviceName
|
|
||||||
].loadBalancer.serversTransport = transportName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the host header middleware
|
|
||||||
if (resource.setHostHeader) {
|
|
||||||
if (!config_output.http.middlewares) {
|
|
||||||
config_output.http.middlewares = {};
|
|
||||||
}
|
|
||||||
config_output.http.middlewares[hostHeaderMiddlewareName] = {
|
|
||||||
headers: {
|
|
||||||
customRequestHeaders: {
|
|
||||||
Host: resource.setHostHeader
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (!config_output.http.routers![routerName].middlewares) {
|
|
||||||
config_output.http.routers![routerName].middlewares =
|
|
||||||
[];
|
|
||||||
}
|
|
||||||
config_output.http.routers![routerName].middlewares = [
|
|
||||||
...config_output.http.routers![routerName].middlewares,
|
|
||||||
hostHeaderMiddlewareName
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Non-HTTP (TCP/UDP) configuration
|
|
||||||
if (!resource.enableProxy) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const protocol = resource.protocol.toLowerCase();
|
|
||||||
const port = resource.proxyPort;
|
|
||||||
|
|
||||||
if (!port) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config_output[protocol]) {
|
|
||||||
config_output[protocol] = {
|
|
||||||
routers: {},
|
|
||||||
services: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
config_output[protocol].routers[routerName] = {
|
|
||||||
entryPoints: [`${protocol}-${port}`],
|
|
||||||
service: serviceName,
|
|
||||||
...(protocol === "tcp" ? { rule: "HostSNI(`*`)" } : {})
|
|
||||||
};
|
|
||||||
|
|
||||||
config_output[protocol].services[serviceName] = {
|
|
||||||
loadBalancer: {
|
|
||||||
servers: targets
|
|
||||||
.filter((target: TargetWithSite) => {
|
|
||||||
if (!target.enabled) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
target.site.type === "local" ||
|
|
||||||
target.site.type === "wireguard"
|
|
||||||
) {
|
|
||||||
if (!target.ip || !target.port) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (target.site.type === "newt") {
|
|
||||||
if (!target.internalPort || !target.site.subnet) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
.map((target: TargetWithSite) => {
|
|
||||||
if (
|
|
||||||
target.site.type === "local" ||
|
|
||||||
target.site.type === "wireguard"
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
address: `${target.ip}:${target.port}`
|
|
||||||
};
|
|
||||||
} else if (target.site.type === "newt") {
|
|
||||||
const ip = target.site.subnet!.split("/")[0];
|
|
||||||
return {
|
|
||||||
address: `${ip}:${target.internalPort}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
...(resource.stickySession
|
|
||||||
? {
|
|
||||||
sticky: {
|
|
||||||
ipStrategy: {
|
|
||||||
depth: 0,
|
|
||||||
sourcePort: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
}
|
|
||||||
>>>>>>> dev
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue