mirror of
https://github.com/fosrl/pangolin.git
synced 2026-03-04 01:36:39 +00:00
Chungus
This commit is contained in:
@@ -69,9 +69,16 @@ export async function applyBlueprint(
|
||||
`Updating target ${target.targetId} on site ${site.sites.siteId}`
|
||||
);
|
||||
|
||||
// see if you can find a matching target health check from the healthchecksToUpdate array
|
||||
const matchingHealthcheck =
|
||||
result.healthchecksToUpdate.find(
|
||||
(hc) => hc.targetId === target.targetId
|
||||
);
|
||||
|
||||
await addProxyTargets(
|
||||
site.newt.newtId,
|
||||
[target],
|
||||
matchingHealthcheck ? [matchingHealthcheck] : [],
|
||||
result.proxyResource.protocol,
|
||||
result.proxyResource.proxyPort
|
||||
);
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
roleResources,
|
||||
roles,
|
||||
Target,
|
||||
TargetHealthCheck,
|
||||
targetHealthCheck,
|
||||
Transaction,
|
||||
userOrgs,
|
||||
userResources,
|
||||
@@ -22,6 +24,7 @@ import {
|
||||
TargetData
|
||||
} from "./types";
|
||||
import logger from "@server/logger";
|
||||
import { createCertificate } from "@server/routers/private/certificates/createCertificate";
|
||||
import { pickPort } from "@server/routers/target/helpers";
|
||||
import { resourcePassword } from "@server/db";
|
||||
import { hashPassword } from "@server/auth/password";
|
||||
@@ -30,6 +33,7 @@ import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
|
||||
export type ProxyResourcesResults = {
|
||||
proxyResource: Resource;
|
||||
targetsToUpdate: Target[];
|
||||
healthchecksToUpdate: TargetHealthCheck[];
|
||||
}[];
|
||||
|
||||
export async function updateProxyResources(
|
||||
@@ -43,7 +47,8 @@ export async function updateProxyResources(
|
||||
for (const [resourceNiceId, resourceData] of Object.entries(
|
||||
config["proxy-resources"]
|
||||
)) {
|
||||
const targetsToUpdate: Target[] = [];
|
||||
let targetsToUpdate: Target[] = [];
|
||||
let healthchecksToUpdate: TargetHealthCheck[] = [];
|
||||
let resource: Resource;
|
||||
|
||||
async function createTarget( // reusable function to create a target
|
||||
@@ -114,6 +119,33 @@ export async function updateProxyResources(
|
||||
.returning();
|
||||
|
||||
targetsToUpdate.push(newTarget);
|
||||
|
||||
const healthcheckData = targetData.healthcheck;
|
||||
|
||||
const hcHeaders = healthcheckData?.headers ? JSON.stringify(healthcheckData.headers) : null;
|
||||
|
||||
const [newHealthcheck] = await trx
|
||||
.insert(targetHealthCheck)
|
||||
.values({
|
||||
targetId: newTarget.targetId,
|
||||
hcEnabled: healthcheckData?.enabled || false,
|
||||
hcPath: healthcheckData?.path,
|
||||
hcScheme: healthcheckData?.scheme,
|
||||
hcMode: healthcheckData?.mode,
|
||||
hcHostname: healthcheckData?.hostname,
|
||||
hcPort: healthcheckData?.port,
|
||||
hcInterval: healthcheckData?.interval,
|
||||
hcUnhealthyInterval: healthcheckData?.unhealthyInterval,
|
||||
hcTimeout: healthcheckData?.timeout,
|
||||
hcHeaders: hcHeaders,
|
||||
hcFollowRedirects: healthcheckData?.followRedirects,
|
||||
hcMethod: healthcheckData?.method,
|
||||
hcStatus: healthcheckData?.status,
|
||||
hcHealth: "unknown"
|
||||
})
|
||||
.returning();
|
||||
|
||||
healthchecksToUpdate.push(newHealthcheck);
|
||||
}
|
||||
|
||||
// Find existing resource by niceId and orgId
|
||||
@@ -360,6 +392,64 @@ export async function updateProxyResources(
|
||||
|
||||
targetsToUpdate.push(finalUpdatedTarget);
|
||||
}
|
||||
|
||||
const healthcheckData = targetData.healthcheck;
|
||||
|
||||
const [oldHealthcheck] = await trx
|
||||
.select()
|
||||
.from(targetHealthCheck)
|
||||
.where(
|
||||
eq(
|
||||
targetHealthCheck.targetId,
|
||||
existingTarget.targetId
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
const hcHeaders = healthcheckData?.headers ? JSON.stringify(healthcheckData.headers) : null;
|
||||
|
||||
const [newHealthcheck] = await trx
|
||||
.update(targetHealthCheck)
|
||||
.set({
|
||||
hcEnabled: healthcheckData?.enabled || false,
|
||||
hcPath: healthcheckData?.path,
|
||||
hcScheme: healthcheckData?.scheme,
|
||||
hcMode: healthcheckData?.mode,
|
||||
hcHostname: healthcheckData?.hostname,
|
||||
hcPort: healthcheckData?.port,
|
||||
hcInterval: healthcheckData?.interval,
|
||||
hcUnhealthyInterval:
|
||||
healthcheckData?.unhealthyInterval,
|
||||
hcTimeout: healthcheckData?.timeout,
|
||||
hcHeaders: hcHeaders,
|
||||
hcFollowRedirects: healthcheckData?.followRedirects,
|
||||
hcMethod: healthcheckData?.method,
|
||||
hcStatus: healthcheckData?.status
|
||||
})
|
||||
.where(
|
||||
eq(
|
||||
targetHealthCheck.targetId,
|
||||
existingTarget.targetId
|
||||
)
|
||||
)
|
||||
.returning();
|
||||
|
||||
if (
|
||||
checkIfHealthcheckChanged(
|
||||
oldHealthcheck,
|
||||
newHealthcheck
|
||||
)
|
||||
) {
|
||||
healthchecksToUpdate.push(newHealthcheck);
|
||||
// if the target is not already in the targetsToUpdate array, add it
|
||||
if (
|
||||
!targetsToUpdate.find(
|
||||
(t) => t.targetId === updatedTarget.targetId
|
||||
)
|
||||
) {
|
||||
targetsToUpdate.push(updatedTarget);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await createTarget(existingResource.resourceId, targetData);
|
||||
}
|
||||
@@ -573,7 +663,8 @@ export async function updateProxyResources(
|
||||
|
||||
results.push({
|
||||
proxyResource: resource,
|
||||
targetsToUpdate
|
||||
targetsToUpdate,
|
||||
healthchecksToUpdate
|
||||
});
|
||||
}
|
||||
|
||||
@@ -783,6 +874,36 @@ async function syncWhitelistUsers(
|
||||
}
|
||||
}
|
||||
|
||||
function checkIfHealthcheckChanged(
|
||||
existing: TargetHealthCheck | undefined,
|
||||
incoming: TargetHealthCheck | undefined
|
||||
) {
|
||||
if (!existing && incoming) return true;
|
||||
if (existing && !incoming) return true;
|
||||
if (!existing || !incoming) return false;
|
||||
|
||||
if (existing.hcEnabled !== incoming.hcEnabled) return true;
|
||||
if (existing.hcPath !== incoming.hcPath) return true;
|
||||
if (existing.hcScheme !== incoming.hcScheme) return true;
|
||||
if (existing.hcMode !== incoming.hcMode) return true;
|
||||
if (existing.hcHostname !== incoming.hcHostname) return true;
|
||||
if (existing.hcPort !== incoming.hcPort) return true;
|
||||
if (existing.hcInterval !== incoming.hcInterval) return true;
|
||||
if (existing.hcUnhealthyInterval !== incoming.hcUnhealthyInterval)
|
||||
return true;
|
||||
if (existing.hcTimeout !== incoming.hcTimeout) return true;
|
||||
if (existing.hcFollowRedirects !== incoming.hcFollowRedirects) return true;
|
||||
if (existing.hcMethod !== incoming.hcMethod) return true;
|
||||
if (existing.hcStatus !== incoming.hcStatus) return true;
|
||||
if (
|
||||
JSON.stringify(existing.hcHeaders) !==
|
||||
JSON.stringify(incoming.hcHeaders)
|
||||
)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkIfTargetChanged(
|
||||
existing: Target | undefined,
|
||||
incoming: Target | undefined
|
||||
@@ -832,6 +953,8 @@ async function getDomain(
|
||||
);
|
||||
}
|
||||
|
||||
await createCertificate(domain.domainId, fullDomain, trx);
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,22 @@ export const SiteSchema = z.object({
|
||||
"docker-socket-enabled": z.boolean().optional().default(true)
|
||||
});
|
||||
|
||||
export const TargetHealthCheckSchema = z.object({
|
||||
hostname: z.string(),
|
||||
port: z.number().int().min(1).max(65535),
|
||||
enabled: z.boolean().optional().default(true),
|
||||
path: z.string().optional(),
|
||||
scheme: z.string().optional(),
|
||||
mode: z.string().default("http"),
|
||||
interval: z.number().int().default(30),
|
||||
unhealthyInterval: z.number().int().default(30),
|
||||
timeout: z.number().int().default(5),
|
||||
headers: z.array(z.object({ name: z.string(), value: z.string() })).nullable().optional().default(null),
|
||||
followRedirects: z.boolean().default(true),
|
||||
method: z.string().default("GET"),
|
||||
status: z.number().int().optional()
|
||||
});
|
||||
|
||||
// Schema for individual target within a resource
|
||||
export const TargetSchema = z.object({
|
||||
site: z.string().optional(),
|
||||
@@ -15,6 +31,7 @@ export const TargetSchema = z.object({
|
||||
"internal-port": z.number().int().min(1).max(65535).optional(),
|
||||
path: z.string().optional(),
|
||||
"path-match": z.enum(["exact", "prefix", "regex"]).optional().nullable(),
|
||||
healthcheck: TargetHealthCheckSchema.optional(),
|
||||
rewritePath: z.string().optional(),
|
||||
"rewrite-match": z.enum(["exact", "prefix", "regex", "stripPrefix"]).optional().nullable()
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user