From b1293e6f563033f039b85a6c6590441cbc06346f Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 21 Apr 2026 14:12:05 -0700 Subject: [PATCH 1/4] Add siteId to api --- server/db/pg/schema/schema.ts | 3 +++ server/db/sqlite/schema/schema.ts | 3 +++ server/private/routers/healthChecks/createHealthCheck.ts | 3 +++ server/private/routers/healthChecks/getStatusHistory.ts | 2 +- server/private/routers/healthChecks/listHealthChecks.ts | 9 ++++++++- server/private/routers/healthChecks/updateHealthCheck.ts | 5 +++++ server/routers/target/createTarget.ts | 1 + server/routers/target/updateTarget.ts | 1 + 8 files changed, 25 insertions(+), 2 deletions(-) diff --git a/server/db/pg/schema/schema.ts b/server/db/pg/schema/schema.ts index f064ed906..b61cfcf19 100644 --- a/server/db/pg/schema/schema.ts +++ b/server/db/pg/schema/schema.ts @@ -194,6 +194,9 @@ export const targetHealthCheck = pgTable("targetHealthCheck", { onDelete: "cascade" }) .notNull(), + siteId: integer("siteId").references(() => sites.siteId, { + onDelete: "cascade" + }).notNull(), name: varchar("name"), hcEnabled: boolean("hcEnabled").notNull().default(false), hcPath: varchar("hcPath"), diff --git a/server/db/sqlite/schema/schema.ts b/server/db/sqlite/schema/schema.ts index 00994fa2a..c5600b756 100644 --- a/server/db/sqlite/schema/schema.ts +++ b/server/db/sqlite/schema/schema.ts @@ -217,6 +217,9 @@ export const targetHealthCheck = sqliteTable("targetHealthCheck", { onDelete: "cascade" }) .notNull(), + siteId: integer("siteId").references(() => sites.siteId, { + onDelete: "cascade" + }).notNull(), name: text("name"), hcEnabled: integer("hcEnabled", { mode: "boolean" }) .notNull() diff --git a/server/private/routers/healthChecks/createHealthCheck.ts b/server/private/routers/healthChecks/createHealthCheck.ts index 2a6028ea8..90993015d 100644 --- a/server/private/routers/healthChecks/createHealthCheck.ts +++ b/server/private/routers/healthChecks/createHealthCheck.ts @@ -27,6 +27,7 @@ const paramsSchema = z.strictObject({ const bodySchema = z.strictObject({ name: z.string().nonempty(), + siteId: z.number().int().positive(), hcEnabled: z.boolean().default(false), hcMode: z.string().default("http"), hcHostname: z.string().optional(), @@ -97,6 +98,7 @@ export async function createHealthCheck( const { name, + siteId, hcEnabled, hcMode, hcHostname, @@ -120,6 +122,7 @@ export async function createHealthCheck( .values({ targetId: null, orgId, + siteId, name, hcEnabled, hcMode, diff --git a/server/private/routers/healthChecks/getStatusHistory.ts b/server/private/routers/healthChecks/getStatusHistory.ts index f010c8ed7..5b1ddcfb0 100644 --- a/server/private/routers/healthChecks/getStatusHistory.ts +++ b/server/private/routers/healthChecks/getStatusHistory.ts @@ -43,7 +43,7 @@ export async function getHealthCheckStatusHistory( } const entityType = "healthCheck"; - const entityId = parsedParams.data.healthCheckId + const entityId = parsedParams.data.healthCheckId; const { days } = parsedQuery.data; const nowSec = Math.floor(Date.now() / 1000); diff --git a/server/private/routers/healthChecks/listHealthChecks.ts b/server/private/routers/healthChecks/listHealthChecks.ts index e266441b2..e156573e4 100644 --- a/server/private/routers/healthChecks/listHealthChecks.ts +++ b/server/private/routers/healthChecks/listHealthChecks.ts @@ -11,7 +11,7 @@ * This file is not licensed under the AGPLv3. */ -import { db, targetHealthCheck, targets, resources } from "@server/db"; +import { db, targetHealthCheck, targets, resources, sites } from "@server/db"; import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; @@ -97,6 +97,9 @@ export async function listHealthChecks( .select({ targetHealthCheckId: targetHealthCheck.targetHealthCheckId, name: targetHealthCheck.name, + siteId: targetHealthCheck.siteId, + siteName: sites.name, + siteNiceId: sites.niceId, hcEnabled: targetHealthCheck.hcEnabled, hcHealth: targetHealthCheck.hcHealth, hcMode: targetHealthCheck.hcMode, @@ -121,6 +124,7 @@ export async function listHealthChecks( .from(targetHealthCheck) .leftJoin(targets, eq(targetHealthCheck.targetId, targets.targetId)) .leftJoin(resources, eq(targets.resourceId, resources.resourceId)) + .leftJoin(sites, eq(targetHealthCheck.siteId, sites.siteId)) .where(whereClause) .orderBy(sql`${targetHealthCheck.targetHealthCheckId} DESC`) .limit(limit) @@ -136,6 +140,9 @@ export async function listHealthChecks( healthChecks: list.map((row) => ({ targetHealthCheckId: row.targetHealthCheckId, name: row.name ?? "", + siteId: row.siteId ?? null, + siteName: row.siteName ?? null, + siteNiceId: row.siteNiceId ?? null, hcEnabled: row.hcEnabled, hcHealth: (row.hcHealth ?? "unknown") as | "unknown" diff --git a/server/private/routers/healthChecks/updateHealthCheck.ts b/server/private/routers/healthChecks/updateHealthCheck.ts index c5a0759b7..e64ea220e 100644 --- a/server/private/routers/healthChecks/updateHealthCheck.ts +++ b/server/private/routers/healthChecks/updateHealthCheck.ts @@ -34,6 +34,7 @@ const paramsSchema = z const bodySchema = z.strictObject({ name: z.string().nonempty().optional(), + siteId: z.number().int().positive().optional(), hcEnabled: z.boolean().optional(), hcMode: z.string().optional(), hcHostname: z.string().optional(), @@ -55,6 +56,7 @@ const bodySchema = z.strictObject({ export type UpdateHealthCheckResponse = { targetHealthCheckId: number; name: string | null; + siteId: number | null; hcEnabled: boolean; hcHealth: string | null; hcMode: string | null; @@ -145,6 +147,7 @@ export async function updateHealthCheck( const { name, + siteId, hcEnabled, hcMode, hcHostname, @@ -166,6 +169,7 @@ export async function updateHealthCheck( const updateData: Record = {}; if (name !== undefined) updateData.name = name; + if (siteId !== undefined) updateData.siteId = siteId; if (hcEnabled !== undefined) updateData.hcEnabled = hcEnabled; if (hcMode !== undefined) updateData.hcMode = hcMode; if (hcHostname !== undefined) updateData.hcHostname = hcHostname; @@ -206,6 +210,7 @@ export async function updateHealthCheck( return response(res, { data: { targetHealthCheckId: updated.targetHealthCheckId, + siteId: updated.siteId ?? null, name: updated.name ?? null, hcEnabled: updated.hcEnabled, hcHealth: updated.hcHealth ?? null, diff --git a/server/routers/target/createTarget.ts b/server/routers/target/createTarget.ts index 7d4a724ea..ea7512b9c 100644 --- a/server/routers/target/createTarget.ts +++ b/server/routers/target/createTarget.ts @@ -230,6 +230,7 @@ export async function createTarget( .values({ orgId: resource.orgId, targetId: newTarget[0].targetId, + siteId: targetData.siteId, name: `Resource ${resource.name} - ${targetData.ip}:${targetData.port}`, hcEnabled: targetData.hcEnabled ?? false, hcPath: targetData.hcPath ?? null, diff --git a/server/routers/target/updateTarget.ts b/server/routers/target/updateTarget.ts index e42ce98a1..52759bfc8 100644 --- a/server/routers/target/updateTarget.ts +++ b/server/routers/target/updateTarget.ts @@ -228,6 +228,7 @@ export async function updateTarget( const [updatedHc] = await db .update(targetHealthCheck) .set({ + siteId: parsedBody.data.siteId, hcEnabled: parsedBody.data.hcEnabled || false, hcPath: parsedBody.data.hcPath, hcScheme: parsedBody.data.hcScheme, From 7b3c10c7b0fda522b46699f176d9dc7185f46645 Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 21 Apr 2026 14:21:58 -0700 Subject: [PATCH 2/4] Handle crud to newt with new hcs --- .../routers/healthChecks/createHealthCheck.ts | 29 +++++- .../routers/healthChecks/deleteHealthCheck.ts | 18 +++- .../routers/healthChecks/updateHealthCheck.ts | 24 +++-- server/routers/newt/buildConfiguration.ts | 25 +++-- server/routers/newt/targets.ts | 98 ++++++++++++++++++- 5 files changed, 172 insertions(+), 22 deletions(-) diff --git a/server/private/routers/healthChecks/createHealthCheck.ts b/server/private/routers/healthChecks/createHealthCheck.ts index 90993015d..ff5495e55 100644 --- a/server/private/routers/healthChecks/createHealthCheck.ts +++ b/server/private/routers/healthChecks/createHealthCheck.ts @@ -13,13 +13,15 @@ import { Request, Response, NextFunction } from "express"; 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 HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; import logger from "@server/logger"; import { fromError } from "zod-validation-error"; import { OpenAPITags, registry } from "@server/openApi"; +import { addStandaloneHealthCheck } from "@server/routers/newt/targets"; const paramsSchema = z.strictObject({ orgId: z.string().nonempty() @@ -143,6 +145,31 @@ export async function createHealthCheck( }) .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(res, { data: { targetHealthCheckId: record.targetHealthCheckId diff --git a/server/private/routers/healthChecks/deleteHealthCheck.ts b/server/private/routers/healthChecks/deleteHealthCheck.ts index b65e4a701..530653aab 100644 --- a/server/private/routers/healthChecks/deleteHealthCheck.ts +++ b/server/private/routers/healthChecks/deleteHealthCheck.ts @@ -13,7 +13,7 @@ import { Request, Response, NextFunction } from "express"; 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 HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; @@ -21,6 +21,7 @@ import logger from "@server/logger"; import { fromError } from "zod-validation-error"; import { OpenAPITags, registry } from "@server/openApi"; import { and, eq, isNull } from "drizzle-orm"; +import { removeStandaloneHealthCheck } from "@server/routers/newt/targets"; const paramsSchema = z .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(res, { data: null, success: true, diff --git a/server/private/routers/healthChecks/updateHealthCheck.ts b/server/private/routers/healthChecks/updateHealthCheck.ts index e64ea220e..713bf1e03 100644 --- a/server/private/routers/healthChecks/updateHealthCheck.ts +++ b/server/private/routers/healthChecks/updateHealthCheck.ts @@ -13,7 +13,7 @@ import { Request, Response, NextFunction } from "express"; 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 HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; @@ -21,6 +21,7 @@ import logger from "@server/logger"; import { fromError } from "zod-validation-error"; import { OpenAPITags, registry } from "@server/openApi"; import { and, eq, isNull } from "drizzle-orm"; +import { addStandaloneHealthCheck } from "@server/routers/newt/targets"; const paramsSchema = z .object({ @@ -127,10 +128,7 @@ export async function updateHealthCheck( .from(targetHealthCheck) .where( and( - eq( - targetHealthCheck.targetHealthCheckId, - healthCheckId - ), + eq(targetHealthCheck.targetHealthCheckId, healthCheckId), eq(targetHealthCheck.orgId, orgId), isNull(targetHealthCheck.targetId) ) @@ -197,16 +195,24 @@ export async function updateHealthCheck( .set(updateData) .where( and( - eq( - targetHealthCheck.targetHealthCheckId, - healthCheckId - ), + eq(targetHealthCheck.targetHealthCheckId, healthCheckId), eq(targetHealthCheck.orgId, orgId), isNull(targetHealthCheck.targetId) ) ) .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(res, { data: { targetHealthCheckId: updated.targetHealthCheckId, diff --git a/server/routers/newt/buildConfiguration.ts b/server/routers/newt/buildConfiguration.ts index cca69dd61..20f4bd95d 100644 --- a/server/routers/newt/buildConfiguration.ts +++ b/server/routers/newt/buildConfiguration.ts @@ -205,7 +205,14 @@ export async function buildTargetConfigurationForNewtClient( port: targets.port, internalPort: targets.internalPort, 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, hcEnabled: targetHealthCheck.hcEnabled, hcPath: targetHealthCheck.hcPath, @@ -224,13 +231,13 @@ export async function buildTargetConfigurationForNewtClient( hcHealthyThreshold: targetHealthCheck.hcHealthyThreshold, hcUnhealthyThreshold: targetHealthCheck.hcUnhealthyThreshold }) - .from(targets) - .innerJoin(resources, eq(targets.resourceId, resources.resourceId)) - .leftJoin( - targetHealthCheck, - eq(targets.targetId, targetHealthCheck.targetId) - ) - .where(and(eq(targets.siteId, siteId), eq(targets.enabled, true))); + .from(targetHealthCheck) + .where( + and( + eq(targetHealthCheck.siteId, siteId), + eq(targetHealthCheck.hcEnabled, true) + ) + ); const { tcpTargets, udpTargets } = allTargets.reduce( (acc, target) => { @@ -254,7 +261,7 @@ export async function buildTargetConfigurationForNewtClient( { tcpTargets: [] as string[], udpTargets: [] as string[] } ); - const healthCheckTargets = allTargets.map((target) => { + const healthCheckTargets = allHealthChecks.map((target) => { // make sure the stuff is defined const isTCP = target.hcMode?.toLowerCase() === "tcp"; if (!target.hcHostname || !target.hcPort || !target.hcInterval) { diff --git a/server/routers/newt/targets.ts b/server/routers/newt/targets.ts index a28ef4f91..c7253060f 100644 --- a/server/routers/newt/targets.ts +++ b/server/routers/newt/targets.ts @@ -7,7 +7,9 @@ import semver from "semver"; const NEWT_V2_TARGET_HEALTH_CHECK_VERSION = ">=1.12.0"; 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( @@ -90,7 +92,9 @@ export async function addTargets( } return { - id: supportsTargetHealthChecksV2(version) ? target.targetId : hc.targetHealthCheckId, + id: supportsTargetHealthChecksV2(version) + ? target.targetId + : hc.targetHealthCheckId, hcEnabled: hc.hcEnabled, hcPath: hc.hcPath, 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( newtId: string, targets: Target[], From dc299a740b9ff383444b5a135271629b198277ca Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 21 Apr 2026 14:34:28 -0700 Subject: [PATCH 3/4] Add the site to the ui and allow picking --- server/routers/healthChecks/types.ts | 3 ++ src/components/HealthCheckCredenza.tsx | 52 ++++++++++++++++++++++++++ src/components/HealthChecksTable.tsx | 21 +++++++++++ src/lib/queries.ts | 3 ++ 4 files changed, 79 insertions(+) diff --git a/server/routers/healthChecks/types.ts b/server/routers/healthChecks/types.ts index d8395c593..0def60833 100644 --- a/server/routers/healthChecks/types.ts +++ b/server/routers/healthChecks/types.ts @@ -2,6 +2,9 @@ export type ListHealthChecksResponse = { healthChecks: { targetHealthCheckId: number; name: string; + siteId: number | null; + siteName: string | null; + siteNiceId: string | null; hcEnabled: boolean; hcHealth: "unknown" | "healthy" | "unhealthy"; hcMode: string | null; diff --git a/src/components/HealthCheckCredenza.tsx b/src/components/HealthCheckCredenza.tsx index f29fccccd..671a16e7d 100644 --- a/src/components/HealthCheckCredenza.tsx +++ b/src/components/HealthCheckCredenza.tsx @@ -41,6 +41,11 @@ import { createApiClient, formatAxiosError } from "@app/lib/api"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { useTranslations } from "next-intl"; import { ContactSalesBanner } from "@app/components/ContactSalesBanner"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; +import { SitesSelector } from "@app/components/site-selector"; +import type { Selectedsite } from "@app/components/site-selector"; +import { CaretSortIcon } from "@radix-ui/react-icons"; +import { cn } from "@app/lib/cn"; export type HealthCheckConfig = { hcEnabled: boolean; @@ -84,6 +89,9 @@ export type HealthCheckRow = { resourceId: number | null; resourceName: string | null; resourceNiceId: string | null; + siteId: number | null; + siteName: string | null; + siteNiceId: string | null; }; export type HealthCheckCredenzaProps = @@ -132,6 +140,7 @@ export function HealthCheckCredenza(props: HealthCheckCredenzaProps) { const t = useTranslations(); const api = createApiClient(useEnvContext()); const [loading, setLoading] = useState(false); + const [selectedSite, setSelectedSite] = useState(null); const healthCheckSchema = z .object({ @@ -280,8 +289,14 @@ export function HealthCheckCredenza(props: HealthCheckCredenzaProps) { hcStatus: initialValues.hcStatus ?? null, hcHeaders: parsedHeaders }); + if (initialValues.siteId && initialValues.siteName) { + setSelectedSite({ siteId: initialValues.siteId, name: initialValues.siteName, type: "" }); + } else { + setSelectedSite(null); + } } else { form.reset(DEFAULT_VALUES); + setSelectedSite(null); } } }, [open]); @@ -331,6 +346,7 @@ export function HealthCheckCredenza(props: HealthCheckCredenzaProps) { try { const payload = { name: (values as any).name, + siteId: selectedSite?.siteId, hcEnabled: values.hcEnabled, hcMode: values.hcMode, hcScheme: values.hcScheme, @@ -439,6 +455,42 @@ export function HealthCheckCredenza(props: HealthCheckCredenzaProps) { /> )} + {/* Site picker (submit mode only) */} + {mode === "submit" && ( +
+ + {t("site")} + + + + + + { + setSelectedSite(site); + }} + /> + + + +
+ )} +
( + Site + ), + cell: ({ row }) => { + const r = row.original; + if (!r.siteId || !r.siteName || !r.siteNiceId) { + return -; + } + return ( + + + + ); + } + }, { id: "health", friendlyName: t("standaloneHcColumnHealth"), diff --git a/src/lib/queries.ts b/src/lib/queries.ts index 29bca39ce..1e7074e3a 100644 --- a/src/lib/queries.ts +++ b/src/lib/queries.ts @@ -335,6 +335,9 @@ export const orgQueries = { healthChecks: { targetHealthCheckId: number; name: string; + siteId: number | null; + siteName: string | null; + siteNiceId: string | null; hcEnabled: boolean; hcHealth: "unknown" | "healthy" | "unhealthy"; hcMode: string | null; From ff1ca7eafb08f193933ad67b740ca4b1dbe6ed48 Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 21 Apr 2026 14:56:25 -0700 Subject: [PATCH 4/4] Just use the targetHealthCheckId as the id --- server/lib/blueprints/proxyResources.ts | 1 + server/routers/newt/buildConfiguration.ts | 12 +-- server/routers/newt/targets.ts | 13 +-- .../target/handleHealthcheckStatusMessage.ts | 101 +++++------------- 4 files changed, 31 insertions(+), 96 deletions(-) diff --git a/server/lib/blueprints/proxyResources.ts b/server/lib/blueprints/proxyResources.ts index 237238910..175c8c79f 100644 --- a/server/lib/blueprints/proxyResources.ts +++ b/server/lib/blueprints/proxyResources.ts @@ -141,6 +141,7 @@ export async function updateProxyResources( .insert(targetHealthCheck) .values({ name: `${targetData.hostname}:${targetData.port}`, + siteId: site.siteId, targetId: newTarget.targetId, orgId: orgId, hcEnabled: healthcheckData?.enabled || false, diff --git a/server/routers/newt/buildConfiguration.ts b/server/routers/newt/buildConfiguration.ts index 20f4bd95d..f87d38450 100644 --- a/server/routers/newt/buildConfiguration.ts +++ b/server/routers/newt/buildConfiguration.ts @@ -21,7 +21,6 @@ import { generateSubnetProxyTargetV2, SubnetProxyTargetV2 } from "@server/lib/ip"; -import { supportsTargetHealthChecksV2 } from "./targets"; export async function buildClientConfigurationForNewtClient( site: Site, @@ -232,12 +231,7 @@ export async function buildTargetConfigurationForNewtClient( hcUnhealthyThreshold: targetHealthCheck.hcUnhealthyThreshold }) .from(targetHealthCheck) - .where( - and( - eq(targetHealthCheck.siteId, siteId), - eq(targetHealthCheck.hcEnabled, true) - ) - ); + .where(eq(targetHealthCheck.siteId, siteId)); const { tcpTargets, udpTargets } = allTargets.reduce( (acc, target) => { @@ -285,9 +279,7 @@ export async function buildTargetConfigurationForNewtClient( } return { - id: supportsTargetHealthChecksV2(version) - ? target.targetId - : target.targetHealthCheckId, + id: target.targetHealthCheckId, hcEnabled: target.hcEnabled, hcPath: target.hcPath, hcScheme: target.hcScheme, diff --git a/server/routers/newt/targets.ts b/server/routers/newt/targets.ts index c7253060f..25b520854 100644 --- a/server/routers/newt/targets.ts +++ b/server/routers/newt/targets.ts @@ -2,15 +2,6 @@ import { Target, TargetHealthCheck } from "@server/db"; import { sendToClient } from "#dynamic/routers/ws"; import logger from "@server/logger"; import { canCompress } from "@server/lib/clientVersionChecks"; -import semver from "semver"; - -const NEWT_V2_TARGET_HEALTH_CHECK_VERSION = ">=1.12.0"; - -export function supportsTargetHealthChecksV2(version?: string | null) { - return version - ? semver.satisfies(version, NEWT_V2_TARGET_HEALTH_CHECK_VERSION) - : false; -} export async function addTargets( newtId: string, @@ -92,9 +83,7 @@ export async function addTargets( } return { - id: supportsTargetHealthChecksV2(version) - ? target.targetId - : hc.targetHealthCheckId, + id: hc.targetHealthCheckId, hcEnabled: hc.hcEnabled, hcPath: hc.hcPath, hcScheme: hc.hcScheme, diff --git a/server/routers/target/handleHealthcheckStatusMessage.ts b/server/routers/target/handleHealthcheckStatusMessage.ts index b35ab8ed2..55834d926 100644 --- a/server/routers/target/handleHealthcheckStatusMessage.ts +++ b/server/routers/target/handleHealthcheckStatusMessage.ts @@ -14,7 +14,6 @@ import { fireHealthCheckHealthyAlert, fireHealthCheckNotHealthyAlert } from "#dynamic/lib/alerts"; -import { supportsTargetHealthChecksV2 } from "@server/routers/newt/targets"; interface TargetHealthStatus { status: string; @@ -74,8 +73,6 @@ export const handleHealthcheckStatusMessage: MessageHandler = async ( let successCount = 0; let errorCount = 0; - const isV2 = supportsTargetHealthChecksV2(newt.version); - // Process each target status update for (const [targetId, healthStatus] of Object.entries(data.targets)) { logger.debug( @@ -91,78 +88,34 @@ export const handleHealthcheckStatusMessage: MessageHandler = async ( continue; } - let targetCheck: { - targetId: number; - siteId: number | null; - orgId: string | null; - targetHealthCheckId: number; - resourceOrgId: string | null; - resourceId: number | null; - name: string | null; - hcStatus: string | null; - } | undefined; - - if (isV2) { - // New newt (>= 1.12.0): the key is the targetId - [targetCheck] = await db - .select({ - targetId: targets.targetId, - siteId: targets.siteId, - orgId: targetHealthCheck.orgId, - targetHealthCheckId: targetHealthCheck.targetHealthCheckId, - resourceOrgId: resources.orgId, - resourceId: resources.resourceId, - name: targetHealthCheck.name, - hcStatus: targetHealthCheck.hcHealth - }) - .from(targets) - .innerJoin( - resources, - eq(targets.resourceId, resources.resourceId) + const [targetCheck] = await db + .select({ + targetId: targets.targetId, + siteId: targets.siteId, + orgId: targetHealthCheck.orgId, + targetHealthCheckId: targetHealthCheck.targetHealthCheckId, + resourceOrgId: resources.orgId, + resourceId: resources.resourceId, + name: targetHealthCheck.name, + hcStatus: targetHealthCheck.hcHealth + }) + .from(targetHealthCheck) + .innerJoin( + targets, + eq(targetHealthCheck.targetId, targets.targetId) + ) + .innerJoin( + resources, + eq(targets.resourceId, resources.resourceId) + ) + .innerJoin(sites, eq(targets.siteId, sites.siteId)) + .where( + and( + eq(targetHealthCheck.targetHealthCheckId, targetIdNum), + eq(sites.siteId, newt.siteId) ) - .innerJoin(sites, eq(targets.siteId, sites.siteId)) - .innerJoin( - targetHealthCheck, - eq(targets.targetId, targetHealthCheck.targetId) - ) - .where( - and( - eq(targets.targetId, targetIdNum), - eq(sites.siteId, newt.siteId) - ) - ) - .limit(1); - } else { - // Old newt (< 1.12.0): the key is the targetHealthCheckId - [targetCheck] = await db - .select({ - targetId: targets.targetId, - siteId: targets.siteId, - orgId: targetHealthCheck.orgId, - targetHealthCheckId: targetHealthCheck.targetHealthCheckId, - resourceOrgId: resources.orgId, - resourceId: resources.resourceId, - name: targetHealthCheck.name, - hcStatus: targetHealthCheck.hcHealth - }) - .from(targetHealthCheck) - .innerJoin( - targets, - eq(targetHealthCheck.targetId, targets.targetId) - ) - .innerJoin( - resources, - eq(targets.resourceId, resources.resourceId) - ) - .innerJoin(sites, eq(targets.siteId, sites.siteId)) - .where( - and( - eq(targetHealthCheck.targetHealthCheckId, targetIdNum), - eq(sites.siteId, newt.siteId) - ) - ) - .limit(1); - } + ) + .limit(1); if (!targetCheck) { logger.warn(