mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-25 10:12:35 +00:00
Handle crud to newt with new hcs
This commit is contained in:
@@ -13,13 +13,15 @@
|
|||||||
|
|
||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, targetHealthCheck } from "@server/db";
|
import { db, targetHealthCheck, newts, sites } from "@server/db";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import { addStandaloneHealthCheck } from "@server/routers/newt/targets";
|
||||||
|
|
||||||
const paramsSchema = z.strictObject({
|
const paramsSchema = z.strictObject({
|
||||||
orgId: z.string().nonempty()
|
orgId: z.string().nonempty()
|
||||||
@@ -143,6 +145,31 @@ export async function createHealthCheck(
|
|||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
// Push health check to newt if the site is a newt site
|
||||||
|
if (siteId) {
|
||||||
|
const [site] = await db
|
||||||
|
.select()
|
||||||
|
.from(sites)
|
||||||
|
.where(eq(sites.siteId, siteId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (site && site.type === "newt") {
|
||||||
|
const [newt] = await db
|
||||||
|
.select()
|
||||||
|
.from(newts)
|
||||||
|
.where(eq(newts.siteId, site.siteId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (newt) {
|
||||||
|
await addStandaloneHealthCheck(
|
||||||
|
newt.newtId,
|
||||||
|
record,
|
||||||
|
newt.version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return response<CreateHealthCheckResponse>(res, {
|
return response<CreateHealthCheckResponse>(res, {
|
||||||
data: {
|
data: {
|
||||||
targetHealthCheckId: record.targetHealthCheckId
|
targetHealthCheckId: record.targetHealthCheckId
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, targetHealthCheck } from "@server/db";
|
import { db, targetHealthCheck, newts, sites } from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -21,6 +21,7 @@ import logger from "@server/logger";
|
|||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
import { and, eq, isNull } from "drizzle-orm";
|
import { and, eq, isNull } from "drizzle-orm";
|
||||||
|
import { removeStandaloneHealthCheck } from "@server/routers/newt/targets";
|
||||||
|
|
||||||
const paramsSchema = z
|
const paramsSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -91,6 +92,21 @@ export async function deleteHealthCheck(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Remove health check from newt if the site is a newt site
|
||||||
|
const [newt] = await db
|
||||||
|
.select()
|
||||||
|
.from(newts)
|
||||||
|
.where(eq(newts.siteId, existing.siteId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (newt) {
|
||||||
|
await removeStandaloneHealthCheck(
|
||||||
|
newt.newtId,
|
||||||
|
healthCheckId,
|
||||||
|
newt.version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return response<null>(res, {
|
return response<null>(res, {
|
||||||
data: null,
|
data: null,
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, targetHealthCheck } from "@server/db";
|
import { db, targetHealthCheck, newts, sites } from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -21,6 +21,7 @@ import logger from "@server/logger";
|
|||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
import { and, eq, isNull } from "drizzle-orm";
|
import { and, eq, isNull } from "drizzle-orm";
|
||||||
|
import { addStandaloneHealthCheck } from "@server/routers/newt/targets";
|
||||||
|
|
||||||
const paramsSchema = z
|
const paramsSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -127,10 +128,7 @@ export async function updateHealthCheck(
|
|||||||
.from(targetHealthCheck)
|
.from(targetHealthCheck)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(
|
eq(targetHealthCheck.targetHealthCheckId, healthCheckId),
|
||||||
targetHealthCheck.targetHealthCheckId,
|
|
||||||
healthCheckId
|
|
||||||
),
|
|
||||||
eq(targetHealthCheck.orgId, orgId),
|
eq(targetHealthCheck.orgId, orgId),
|
||||||
isNull(targetHealthCheck.targetId)
|
isNull(targetHealthCheck.targetId)
|
||||||
)
|
)
|
||||||
@@ -197,16 +195,24 @@ export async function updateHealthCheck(
|
|||||||
.set(updateData)
|
.set(updateData)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(
|
eq(targetHealthCheck.targetHealthCheckId, healthCheckId),
|
||||||
targetHealthCheck.targetHealthCheckId,
|
|
||||||
healthCheckId
|
|
||||||
),
|
|
||||||
eq(targetHealthCheck.orgId, orgId),
|
eq(targetHealthCheck.orgId, orgId),
|
||||||
isNull(targetHealthCheck.targetId)
|
isNull(targetHealthCheck.targetId)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
// Push updated health check to newt if the site is a newt site
|
||||||
|
const [newt] = await db
|
||||||
|
.select()
|
||||||
|
.from(newts)
|
||||||
|
.where(eq(newts.siteId, updated.siteId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (newt) {
|
||||||
|
await addStandaloneHealthCheck(newt.newtId, updated, newt.version);
|
||||||
|
}
|
||||||
|
|
||||||
return response<UpdateHealthCheckResponse>(res, {
|
return response<UpdateHealthCheckResponse>(res, {
|
||||||
data: {
|
data: {
|
||||||
targetHealthCheckId: updated.targetHealthCheckId,
|
targetHealthCheckId: updated.targetHealthCheckId,
|
||||||
|
|||||||
@@ -205,7 +205,14 @@ export async function buildTargetConfigurationForNewtClient(
|
|||||||
port: targets.port,
|
port: targets.port,
|
||||||
internalPort: targets.internalPort,
|
internalPort: targets.internalPort,
|
||||||
enabled: targets.enabled,
|
enabled: targets.enabled,
|
||||||
protocol: resources.protocol,
|
protocol: resources.protocol
|
||||||
|
})
|
||||||
|
.from(targets)
|
||||||
|
.innerJoin(resources, eq(targets.resourceId, resources.resourceId))
|
||||||
|
.where(and(eq(targets.siteId, siteId), eq(targets.enabled, true)));
|
||||||
|
|
||||||
|
const allHealthChecks = await db
|
||||||
|
.select({
|
||||||
targetHealthCheckId: targetHealthCheck.targetHealthCheckId,
|
targetHealthCheckId: targetHealthCheck.targetHealthCheckId,
|
||||||
hcEnabled: targetHealthCheck.hcEnabled,
|
hcEnabled: targetHealthCheck.hcEnabled,
|
||||||
hcPath: targetHealthCheck.hcPath,
|
hcPath: targetHealthCheck.hcPath,
|
||||||
@@ -224,13 +231,13 @@ export async function buildTargetConfigurationForNewtClient(
|
|||||||
hcHealthyThreshold: targetHealthCheck.hcHealthyThreshold,
|
hcHealthyThreshold: targetHealthCheck.hcHealthyThreshold,
|
||||||
hcUnhealthyThreshold: targetHealthCheck.hcUnhealthyThreshold
|
hcUnhealthyThreshold: targetHealthCheck.hcUnhealthyThreshold
|
||||||
})
|
})
|
||||||
.from(targets)
|
.from(targetHealthCheck)
|
||||||
.innerJoin(resources, eq(targets.resourceId, resources.resourceId))
|
.where(
|
||||||
.leftJoin(
|
and(
|
||||||
targetHealthCheck,
|
eq(targetHealthCheck.siteId, siteId),
|
||||||
eq(targets.targetId, targetHealthCheck.targetId)
|
eq(targetHealthCheck.hcEnabled, true)
|
||||||
)
|
)
|
||||||
.where(and(eq(targets.siteId, siteId), eq(targets.enabled, true)));
|
);
|
||||||
|
|
||||||
const { tcpTargets, udpTargets } = allTargets.reduce(
|
const { tcpTargets, udpTargets } = allTargets.reduce(
|
||||||
(acc, target) => {
|
(acc, target) => {
|
||||||
@@ -254,7 +261,7 @@ export async function buildTargetConfigurationForNewtClient(
|
|||||||
{ tcpTargets: [] as string[], udpTargets: [] as string[] }
|
{ tcpTargets: [] as string[], udpTargets: [] as string[] }
|
||||||
);
|
);
|
||||||
|
|
||||||
const healthCheckTargets = allTargets.map((target) => {
|
const healthCheckTargets = allHealthChecks.map((target) => {
|
||||||
// make sure the stuff is defined
|
// make sure the stuff is defined
|
||||||
const isTCP = target.hcMode?.toLowerCase() === "tcp";
|
const isTCP = target.hcMode?.toLowerCase() === "tcp";
|
||||||
if (!target.hcHostname || !target.hcPort || !target.hcInterval) {
|
if (!target.hcHostname || !target.hcPort || !target.hcInterval) {
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import semver from "semver";
|
|||||||
const NEWT_V2_TARGET_HEALTH_CHECK_VERSION = ">=1.12.0";
|
const NEWT_V2_TARGET_HEALTH_CHECK_VERSION = ">=1.12.0";
|
||||||
|
|
||||||
export function supportsTargetHealthChecksV2(version?: string | null) {
|
export function supportsTargetHealthChecksV2(version?: string | null) {
|
||||||
return version ? semver.satisfies(version, NEWT_V2_TARGET_HEALTH_CHECK_VERSION) : false;
|
return version
|
||||||
|
? semver.satisfies(version, NEWT_V2_TARGET_HEALTH_CHECK_VERSION)
|
||||||
|
: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addTargets(
|
export async function addTargets(
|
||||||
@@ -90,7 +92,9 @@ export async function addTargets(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: supportsTargetHealthChecksV2(version) ? target.targetId : hc.targetHealthCheckId,
|
id: supportsTargetHealthChecksV2(version)
|
||||||
|
? target.targetId
|
||||||
|
: hc.targetHealthCheckId,
|
||||||
hcEnabled: hc.hcEnabled,
|
hcEnabled: hc.hcEnabled,
|
||||||
hcPath: hc.hcPath,
|
hcPath: hc.hcPath,
|
||||||
hcScheme: hc.hcScheme,
|
hcScheme: hc.hcScheme,
|
||||||
@@ -127,6 +131,96 @@ export async function addTargets(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function addStandaloneHealthCheck(
|
||||||
|
newtId: string,
|
||||||
|
healthCheck: TargetHealthCheck,
|
||||||
|
version?: string | null
|
||||||
|
) {
|
||||||
|
const isTCP = healthCheck.hcMode?.toLowerCase() === "tcp";
|
||||||
|
if (
|
||||||
|
!healthCheck.hcHostname ||
|
||||||
|
!healthCheck.hcPort ||
|
||||||
|
!healthCheck.hcInterval
|
||||||
|
) {
|
||||||
|
logger.debug(
|
||||||
|
`Skipping standalone health check ${healthCheck.targetHealthCheckId} due to missing fields`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isTCP && (!healthCheck.hcPath || !healthCheck.hcMethod)) {
|
||||||
|
logger.debug(
|
||||||
|
`Skipping standalone health check ${healthCheck.targetHealthCheckId} due to missing HTTP health check fields`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hcHeadersParse = healthCheck.hcHeaders
|
||||||
|
? JSON.parse(healthCheck.hcHeaders)
|
||||||
|
: null;
|
||||||
|
const hcHeadersSend: { [key: string]: string } = {};
|
||||||
|
if (hcHeadersParse) {
|
||||||
|
hcHeadersParse.forEach((header: { name: string; value: string }) => {
|
||||||
|
hcHeadersSend[header.name] = header.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let hcStatus: number | undefined = undefined;
|
||||||
|
if (healthCheck.hcStatus) {
|
||||||
|
const parsedStatus = parseInt(healthCheck.hcStatus.toString());
|
||||||
|
if (!isNaN(parsedStatus)) {
|
||||||
|
hcStatus = parsedStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await sendToClient(
|
||||||
|
newtId,
|
||||||
|
{
|
||||||
|
type: `newt/healthcheck/add`,
|
||||||
|
data: {
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
id: healthCheck.targetHealthCheckId,
|
||||||
|
hcEnabled: healthCheck.hcEnabled,
|
||||||
|
hcPath: healthCheck.hcPath,
|
||||||
|
hcScheme: healthCheck.hcScheme,
|
||||||
|
hcMode: healthCheck.hcMode,
|
||||||
|
hcHostname: healthCheck.hcHostname,
|
||||||
|
hcPort: healthCheck.hcPort,
|
||||||
|
hcInterval: healthCheck.hcInterval,
|
||||||
|
hcUnhealthyInterval: healthCheck.hcUnhealthyInterval,
|
||||||
|
hcTimeout: healthCheck.hcTimeout,
|
||||||
|
hcHeaders: hcHeadersSend,
|
||||||
|
hcFollowRedirects: healthCheck.hcFollowRedirects,
|
||||||
|
hcMethod: healthCheck.hcMethod,
|
||||||
|
hcStatus: hcStatus,
|
||||||
|
hcTlsServerName: healthCheck.hcTlsServerName,
|
||||||
|
hcHealthyThreshold: healthCheck.hcHealthyThreshold,
|
||||||
|
hcUnhealthyThreshold: healthCheck.hcUnhealthyThreshold
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ incrementConfigVersion: true, compress: canCompress(version, "newt") }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function removeStandaloneHealthCheck(
|
||||||
|
newtId: string,
|
||||||
|
healthCheckId: number,
|
||||||
|
version?: string | null
|
||||||
|
) {
|
||||||
|
await sendToClient(
|
||||||
|
newtId,
|
||||||
|
{
|
||||||
|
type: `newt/healthcheck/remove`,
|
||||||
|
data: {
|
||||||
|
ids: [healthCheckId]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ incrementConfigVersion: true, compress: canCompress(version, "newt") }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function removeTargets(
|
export async function removeTargets(
|
||||||
newtId: string,
|
newtId: string,
|
||||||
targets: Target[],
|
targets: Target[],
|
||||||
|
|||||||
Reference in New Issue
Block a user