mirror of
https://github.com/outbackdingo/pangolin.git
synced 2026-01-27 10:20:03 +00:00
Fix various bugs
This commit is contained in:
@@ -20,7 +20,7 @@ services:
|
||||
pangolin:
|
||||
condition: service_healthy
|
||||
command:
|
||||
- --reachableAt=http://gerbil:3003
|
||||
- --reachableAt=http://gerbil:3004
|
||||
- --generateAndSaveKeyTo=/var/config/key
|
||||
- --remoteConfig=http://pangolin:3001/api/v1/
|
||||
volumes:
|
||||
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
pangolin:
|
||||
condition: service_healthy
|
||||
command:
|
||||
- --reachableAt=http://gerbil:3003
|
||||
- --reachableAt=http://gerbil:3004
|
||||
- --generateAndSaveKeyTo=/var/config/key
|
||||
- --remoteConfig=http://pangolin:3001/api/v1/
|
||||
volumes:
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import { db, targetHealthCheck } from "@server/db";
|
||||
import { and, eq, inArray, or, isNull, ne, isNotNull, desc } from "drizzle-orm";
|
||||
import {
|
||||
and,
|
||||
eq,
|
||||
inArray,
|
||||
or,
|
||||
isNull,
|
||||
ne,
|
||||
isNotNull,
|
||||
desc,
|
||||
sql
|
||||
} from "drizzle-orm";
|
||||
import logger from "@server/logger";
|
||||
import config from "@server/lib/config";
|
||||
import { resources, sites, Target, targets } from "@server/db";
|
||||
@@ -78,7 +88,13 @@ export async function getTraefikConfig(
|
||||
and(
|
||||
eq(targets.enabled, true),
|
||||
eq(resources.enabled, true),
|
||||
or(eq(sites.exitNodeId, exitNodeId), isNull(sites.exitNodeId)),
|
||||
or(
|
||||
eq(sites.exitNodeId, exitNodeId),
|
||||
and(
|
||||
isNull(sites.exitNodeId),
|
||||
sql`(${siteTypes.includes("local") ? 1 : 0} = 1)` // only allow local sites if "local" is in siteTypes
|
||||
)
|
||||
),
|
||||
or(
|
||||
ne(targetHealthCheck.hcHealth, "unhealthy"), // Exclude unhealthy targets
|
||||
isNull(targetHealthCheck.hcHealth) // Include targets with no health check record
|
||||
|
||||
@@ -19,7 +19,17 @@ import {
|
||||
loginPage,
|
||||
targetHealthCheck
|
||||
} from "@server/db";
|
||||
import { and, eq, inArray, or, isNull, ne, isNotNull, desc } from "drizzle-orm";
|
||||
import {
|
||||
and,
|
||||
eq,
|
||||
inArray,
|
||||
or,
|
||||
isNull,
|
||||
ne,
|
||||
isNotNull,
|
||||
desc,
|
||||
sql
|
||||
} from "drizzle-orm";
|
||||
import logger from "@server/logger";
|
||||
import config from "@server/lib/config";
|
||||
import { orgs, resources, sites, Target, targets } from "@server/db";
|
||||
@@ -110,15 +120,19 @@ export async function getTraefikConfig(
|
||||
and(
|
||||
eq(targets.enabled, true),
|
||||
eq(resources.enabled, true),
|
||||
// or(
|
||||
eq(sites.exitNodeId, exitNodeId),
|
||||
// isNull(sites.exitNodeId)
|
||||
// ),
|
||||
or(
|
||||
eq(sites.exitNodeId, exitNodeId),
|
||||
and(
|
||||
isNull(sites.exitNodeId),
|
||||
sql`(${siteTypes.includes("local") ? 1 : 0} = 1)` // only allow local sites if "local" is in siteTypes
|
||||
)
|
||||
),
|
||||
or(
|
||||
ne(targetHealthCheck.hcHealth, "unhealthy"), // Exclude unhealthy targets
|
||||
isNull(targetHealthCheck.hcHealth) // Include targets with no health check record
|
||||
),
|
||||
inArray(sites.type, siteTypes),
|
||||
// lets rewrite this using sql
|
||||
config.getRawConfig().traefik.allow_raw_resources
|
||||
? isNotNull(resources.http) // ignore the http check if allow_raw_resources is true
|
||||
: eq(resources.http, true)
|
||||
|
||||
@@ -61,7 +61,14 @@ export async function createExitNode(
|
||||
`Created new exit node ${exitNode.name} with address ${exitNode.address} and port ${exitNode.listenPort}`
|
||||
);
|
||||
} else {
|
||||
exitNode = exitNodeQuery;
|
||||
// update the reachable at
|
||||
[exitNode] = await db
|
||||
.update(exitNodes)
|
||||
.set({
|
||||
reachableAt
|
||||
})
|
||||
.where(eq(exitNodes.exitNodeId, exitNodeQuery.exitNodeId))
|
||||
.returning();
|
||||
}
|
||||
|
||||
return exitNode;
|
||||
|
||||
@@ -46,14 +46,23 @@ const createTargetSchema = z
|
||||
.optional()
|
||||
.nullable(),
|
||||
hcTimeout: z.number().int().positive().min(1).optional().nullable(),
|
||||
hcHeaders: z.array(z.object({ name: z.string(), value: z.string() })).nullable().optional(),
|
||||
hcHeaders: z
|
||||
.array(z.object({ name: z.string(), value: z.string() }))
|
||||
.nullable()
|
||||
.optional(),
|
||||
hcFollowRedirects: z.boolean().optional().nullable(),
|
||||
hcMethod: z.string().min(1).optional().nullable(),
|
||||
hcStatus: z.number().int().optional().nullable(),
|
||||
path: z.string().optional().nullable(),
|
||||
pathMatchType: z.enum(["exact", "prefix", "regex"]).optional().nullable(),
|
||||
pathMatchType: z
|
||||
.enum(["exact", "prefix", "regex"])
|
||||
.optional()
|
||||
.nullable(),
|
||||
rewritePath: z.string().optional().nullable(),
|
||||
rewritePathType: z.enum(["exact", "prefix", "regex", "stripPrefix"]).optional().nullable(),
|
||||
rewritePathType: z
|
||||
.enum(["exact", "prefix", "regex", "stripPrefix"])
|
||||
.optional()
|
||||
.nullable(),
|
||||
priority: z.number().int().min(1).max(1000)
|
||||
})
|
||||
.strict();
|
||||
@@ -164,6 +173,7 @@ export async function createTarget(
|
||||
|
||||
let newTarget: Target[] = [];
|
||||
let healthCheck: TargetHealthCheck[] = [];
|
||||
let targetIps: string[] = [];
|
||||
if (site.type == "local") {
|
||||
newTarget = await db
|
||||
.insert(targets)
|
||||
@@ -186,7 +196,7 @@ export async function createTarget(
|
||||
);
|
||||
}
|
||||
|
||||
const { internalPort, targetIps } = await pickPort(
|
||||
const { internalPort, targetIps: newTargetIps } = await pickPort(
|
||||
site.siteId!,
|
||||
db
|
||||
);
|
||||
@@ -218,57 +228,59 @@ export async function createTarget(
|
||||
})
|
||||
.returning();
|
||||
|
||||
let hcHeaders = null;
|
||||
if (targetData.hcHeaders) {
|
||||
hcHeaders = JSON.stringify(targetData.hcHeaders);
|
||||
}
|
||||
|
||||
healthCheck = await db
|
||||
.insert(targetHealthCheck)
|
||||
.values({
|
||||
targetId: newTarget[0].targetId,
|
||||
hcEnabled: targetData.hcEnabled ?? false,
|
||||
hcPath: targetData.hcPath ?? null,
|
||||
hcScheme: targetData.hcScheme ?? null,
|
||||
hcMode: targetData.hcMode ?? null,
|
||||
hcHostname: targetData.hcHostname ?? null,
|
||||
hcPort: targetData.hcPort ?? null,
|
||||
hcInterval: targetData.hcInterval ?? null,
|
||||
hcUnhealthyInterval: targetData.hcUnhealthyInterval ?? null,
|
||||
hcTimeout: targetData.hcTimeout ?? null,
|
||||
hcHeaders: hcHeaders,
|
||||
hcFollowRedirects: targetData.hcFollowRedirects ?? null,
|
||||
hcMethod: targetData.hcMethod ?? null,
|
||||
hcStatus: targetData.hcStatus ?? null,
|
||||
hcHealth: "unknown"
|
||||
})
|
||||
.returning();
|
||||
|
||||
// add the new target to the targetIps array
|
||||
targetIps.push(`${targetData.ip}/32`);
|
||||
newTargetIps.push(`${targetData.ip}/32`);
|
||||
|
||||
if (site.pubKey) {
|
||||
if (site.type == "wireguard") {
|
||||
await addPeer(site.exitNodeId!, {
|
||||
publicKey: site.pubKey,
|
||||
allowedIps: targetIps.flat()
|
||||
});
|
||||
} else if (site.type == "newt") {
|
||||
// get the newt on the site by querying the newt table for siteId
|
||||
const [newt] = await db
|
||||
.select()
|
||||
.from(newts)
|
||||
.where(eq(newts.siteId, site.siteId))
|
||||
.limit(1);
|
||||
targetIps = newTargetIps;
|
||||
}
|
||||
|
||||
await addTargets(
|
||||
newt.newtId,
|
||||
newTarget,
|
||||
healthCheck,
|
||||
resource.protocol,
|
||||
resource.proxyPort
|
||||
);
|
||||
}
|
||||
let hcHeaders = null;
|
||||
if (targetData.hcHeaders) {
|
||||
hcHeaders = JSON.stringify(targetData.hcHeaders);
|
||||
}
|
||||
|
||||
healthCheck = await db
|
||||
.insert(targetHealthCheck)
|
||||
.values({
|
||||
targetId: newTarget[0].targetId,
|
||||
hcEnabled: targetData.hcEnabled ?? false,
|
||||
hcPath: targetData.hcPath ?? null,
|
||||
hcScheme: targetData.hcScheme ?? null,
|
||||
hcMode: targetData.hcMode ?? null,
|
||||
hcHostname: targetData.hcHostname ?? null,
|
||||
hcPort: targetData.hcPort ?? null,
|
||||
hcInterval: targetData.hcInterval ?? null,
|
||||
hcUnhealthyInterval: targetData.hcUnhealthyInterval ?? null,
|
||||
hcTimeout: targetData.hcTimeout ?? null,
|
||||
hcHeaders: hcHeaders,
|
||||
hcFollowRedirects: targetData.hcFollowRedirects ?? null,
|
||||
hcMethod: targetData.hcMethod ?? null,
|
||||
hcStatus: targetData.hcStatus ?? null,
|
||||
hcHealth: "unknown"
|
||||
})
|
||||
.returning();
|
||||
|
||||
if (site.pubKey) {
|
||||
if (site.type == "wireguard") {
|
||||
await addPeer(site.exitNodeId!, {
|
||||
publicKey: site.pubKey,
|
||||
allowedIps: targetIps.flat()
|
||||
});
|
||||
} else if (site.type == "newt") {
|
||||
// get the newt on the site by querying the newt table for siteId
|
||||
const [newt] = await db
|
||||
.select()
|
||||
.from(newts)
|
||||
.where(eq(newts.siteId, site.siteId))
|
||||
.limit(1);
|
||||
|
||||
await addTargets(
|
||||
newt.newtId,
|
||||
newTarget,
|
||||
healthCheck,
|
||||
resource.protocol,
|
||||
resource.proxyPort
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -666,7 +666,7 @@ export default function ReverseProxyTargets(props: {
|
||||
...target,
|
||||
...data,
|
||||
updated: true,
|
||||
// siteType: site?.type || null
|
||||
siteType: site ? site.type : target.siteType
|
||||
}
|
||||
: target
|
||||
)
|
||||
|
||||
@@ -375,8 +375,8 @@ export default function Page() {
|
||||
// Helper function to check if all targets have required fields using schema validation
|
||||
const areAllTargetsValid = () => {
|
||||
if (targets.length === 0) return true; // No targets is valid
|
||||
|
||||
return targets.every(target => {
|
||||
|
||||
return targets.every((target) => {
|
||||
try {
|
||||
addTargetSchema.parse({
|
||||
ip: target.ip,
|
||||
@@ -518,8 +518,8 @@ export default function Page() {
|
||||
? {
|
||||
...target,
|
||||
...data,
|
||||
updated: true
|
||||
// siteType: site?.type || null
|
||||
updated: true,
|
||||
siteType: site ? site.type : target.siteType
|
||||
}
|
||||
: target
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user