mirror of
https://github.com/fosrl/pangolin.git
synced 2026-06-03 14:30:57 +00:00
Working on newt compat
This commit is contained in:
@@ -21,6 +21,7 @@ import {
|
|||||||
generateSubnetProxyTargetV2,
|
generateSubnetProxyTargetV2,
|
||||||
SubnetProxyTargetV2
|
SubnetProxyTargetV2
|
||||||
} from "@server/lib/ip";
|
} from "@server/lib/ip";
|
||||||
|
import { supportsTargetHealthChecksV2 } from "./targets";
|
||||||
|
|
||||||
export async function buildClientConfigurationForNewtClient(
|
export async function buildClientConfigurationForNewtClient(
|
||||||
site: Site,
|
site: Site,
|
||||||
@@ -86,7 +87,8 @@ export async function buildClientConfigurationForNewtClient(
|
|||||||
// )
|
// )
|
||||||
// );
|
// );
|
||||||
|
|
||||||
if (!client.clientSitesAssociationsCache.isJitMode) { // if we are adding sites through jit then dont add the site to the olm
|
if (!client.clientSitesAssociationsCache.isJitMode) {
|
||||||
|
// if we are adding sites through jit then dont add the site to the olm
|
||||||
// update the peer info on the olm
|
// update the peer info on the olm
|
||||||
// if the peer has not been added yet this will be a no-op
|
// if the peer has not been added yet this will be a no-op
|
||||||
await updatePeer(client.clients.clientId, {
|
await updatePeer(client.clients.clientId, {
|
||||||
@@ -189,7 +191,10 @@ export async function buildClientConfigurationForNewtClient(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function buildTargetConfigurationForNewtClient(siteId: number) {
|
export async function buildTargetConfigurationForNewtClient(
|
||||||
|
siteId: number,
|
||||||
|
version?: string | null
|
||||||
|
) {
|
||||||
// Get all enabled targets with their resource protocol information
|
// Get all enabled targets with their resource protocol information
|
||||||
const allTargets = await db
|
const allTargets = await db
|
||||||
.select({
|
.select({
|
||||||
@@ -201,7 +206,7 @@ export async function buildTargetConfigurationForNewtClient(siteId: number) {
|
|||||||
internalPort: targets.internalPort,
|
internalPort: targets.internalPort,
|
||||||
enabled: targets.enabled,
|
enabled: targets.enabled,
|
||||||
protocol: resources.protocol,
|
protocol: resources.protocol,
|
||||||
hcId: targetHealthCheck.targetHealthCheckId,
|
targetHealthCheckId: targetHealthCheck.targetHealthCheckId,
|
||||||
hcEnabled: targetHealthCheck.hcEnabled,
|
hcEnabled: targetHealthCheck.hcEnabled,
|
||||||
hcPath: targetHealthCheck.hcPath,
|
hcPath: targetHealthCheck.hcPath,
|
||||||
hcScheme: targetHealthCheck.hcScheme,
|
hcScheme: targetHealthCheck.hcScheme,
|
||||||
@@ -273,8 +278,9 @@ export async function buildTargetConfigurationForNewtClient(siteId: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: target.targetId,
|
id: supportsTargetHealthChecksV2(version)
|
||||||
hcId: target.hcId,
|
? target.targetId
|
||||||
|
: target.targetHealthCheckId,
|
||||||
hcEnabled: target.hcEnabled,
|
hcEnabled: target.hcEnabled,
|
||||||
hcPath: target.hcPath,
|
hcPath: target.hcPath,
|
||||||
hcScheme: target.hcScheme,
|
hcScheme: target.hcScheme,
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ export const handleNewtRegisterMessage: MessageHandler = async (context) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { tcpTargets, udpTargets, validHealthCheckTargets } =
|
const { tcpTargets, udpTargets, validHealthCheckTargets } =
|
||||||
await buildTargetConfigurationForNewtClient(siteId);
|
await buildTargetConfigurationForNewtClient(siteId, newtVersion);
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Sending health check targets to newt ${newt.newtId}: ${JSON.stringify(validHealthCheckTargets)}`
|
`Sending health check targets to newt ${newt.newtId}: ${JSON.stringify(validHealthCheckTargets)}`
|
||||||
|
|||||||
@@ -2,6 +2,13 @@ import { Target, TargetHealthCheck } from "@server/db";
|
|||||||
import { sendToClient } from "#dynamic/routers/ws";
|
import { sendToClient } from "#dynamic/routers/ws";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { canCompress } from "@server/lib/clientVersionChecks";
|
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(
|
export async function addTargets(
|
||||||
newtId: string,
|
newtId: string,
|
||||||
@@ -83,8 +90,7 @@ export async function addTargets(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: target.targetId,
|
id: supportsTargetHealthChecksV2(version) ? target.targetId : hc.targetHealthCheckId,
|
||||||
hcId: hc.targetHealthCheckId,
|
|
||||||
hcEnabled: hc.hcEnabled,
|
hcEnabled: hc.hcEnabled,
|
||||||
hcPath: hc.hcPath,
|
hcPath: hc.hcPath,
|
||||||
hcScheme: hc.hcScheme,
|
hcScheme: hc.hcScheme,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
fireHealthCheckHealthyAlert,
|
fireHealthCheckHealthyAlert,
|
||||||
fireHealthCheckNotHealthyAlert
|
fireHealthCheckNotHealthyAlert
|
||||||
} from "#dynamic/lib/alerts";
|
} from "#dynamic/lib/alerts";
|
||||||
|
import { supportsTargetHealthChecksV2 } from "@server/routers/newt/targets";
|
||||||
|
|
||||||
interface TargetHealthStatus {
|
interface TargetHealthStatus {
|
||||||
status: string;
|
status: string;
|
||||||
@@ -73,6 +74,8 @@ export const handleHealthcheckStatusMessage: MessageHandler = async (
|
|||||||
let successCount = 0;
|
let successCount = 0;
|
||||||
let errorCount = 0;
|
let errorCount = 0;
|
||||||
|
|
||||||
|
const isV2 = supportsTargetHealthChecksV2(newt.version);
|
||||||
|
|
||||||
// Process each target status update
|
// Process each target status update
|
||||||
for (const [targetId, healthStatus] of Object.entries(data.targets)) {
|
for (const [targetId, healthStatus] of Object.entries(data.targets)) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
@@ -88,34 +91,78 @@ export const handleHealthcheckStatusMessage: MessageHandler = async (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [targetCheck] = await db
|
let targetCheck: {
|
||||||
.select({
|
targetId: number;
|
||||||
targetId: targets.targetId,
|
siteId: number | null;
|
||||||
siteId: targets.siteId,
|
orgId: string | null;
|
||||||
orgId: targetHealthCheck.orgId,
|
targetHealthCheckId: number;
|
||||||
targetHealthCheckId: targetHealthCheck.targetHealthCheckId,
|
resourceOrgId: string | null;
|
||||||
resourceOrgId: resources.orgId,
|
resourceId: number | null;
|
||||||
resourceId: resources.resourceId,
|
name: string | null;
|
||||||
name: targetHealthCheck.name,
|
hcStatus: string | null;
|
||||||
hcStatus: targetHealthCheck.hcHealth
|
} | undefined;
|
||||||
})
|
|
||||||
.from(targets)
|
if (isV2) {
|
||||||
.innerJoin(
|
// New newt (>= 1.12.0): the key is the targetId
|
||||||
resources,
|
[targetCheck] = await db
|
||||||
eq(targets.resourceId, resources.resourceId)
|
.select({
|
||||||
)
|
targetId: targets.targetId,
|
||||||
.innerJoin(sites, eq(targets.siteId, sites.siteId))
|
siteId: targets.siteId,
|
||||||
.innerJoin(
|
orgId: targetHealthCheck.orgId,
|
||||||
targetHealthCheck,
|
targetHealthCheckId: targetHealthCheck.targetHealthCheckId,
|
||||||
eq(targets.targetId, targetHealthCheck.targetId)
|
resourceOrgId: resources.orgId,
|
||||||
)
|
resourceId: resources.resourceId,
|
||||||
.where(
|
name: targetHealthCheck.name,
|
||||||
and(
|
hcStatus: targetHealthCheck.hcHealth
|
||||||
eq(targets.targetId, targetIdNum),
|
})
|
||||||
eq(sites.siteId, newt.siteId)
|
.from(targets)
|
||||||
|
.innerJoin(
|
||||||
|
resources,
|
||||||
|
eq(targets.resourceId, resources.resourceId)
|
||||||
)
|
)
|
||||||
)
|
.innerJoin(sites, eq(targets.siteId, sites.siteId))
|
||||||
.limit(1);
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
if (!targetCheck) {
|
if (!targetCheck) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
@@ -142,7 +189,7 @@ export const handleHealthcheckStatusMessage: MessageHandler = async (
|
|||||||
| "healthy"
|
| "healthy"
|
||||||
| "unhealthy"
|
| "unhealthy"
|
||||||
})
|
})
|
||||||
.where(eq(targetHealthCheck.targetId, targetIdNum));
|
.where(eq(targetHealthCheck.targetId, targetCheck.targetId));
|
||||||
|
|
||||||
// Log the state change to status history
|
// Log the state change to status history
|
||||||
await db.insert(statusHistory).values({
|
await db.insert(statusHistory).values({
|
||||||
@@ -170,7 +217,7 @@ export const handleHealthcheckStatusMessage: MessageHandler = async (
|
|||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(targets.resourceId, targetCheck.resourceId),
|
eq(targets.resourceId, targetCheck.resourceId),
|
||||||
eq(targets.targetId, targetIdNum) // only check the other targets, not the one we just updated
|
eq(targets.targetId, targetCheck.targetId) // only check the other targets, not the one we just updated
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import { orgQueries } from "@app/lib/queries";
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { ChevronsUpDown, Plus, Trash2 } from "lucide-react";
|
import { ChevronsUpDown, Plus, Trash2 } from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import type { Control, UseFormReturn } from "react-hook-form";
|
import type { Control, UseFormReturn } from "react-hook-form";
|
||||||
import { useFormContext, useWatch } from "react-hook-form";
|
import { useFormContext, useWatch } from "react-hook-form";
|
||||||
import { useDebounce } from "use-debounce";
|
import { useDebounce } from "use-debounce";
|
||||||
@@ -484,8 +484,8 @@ function NotifyActionFields({
|
|||||||
number | null
|
number | null
|
||||||
>(null);
|
>(null);
|
||||||
|
|
||||||
const { data: orgUsers = [] } = useQuery(orgQueries.users({ orgId }));
|
const { data: orgUsers = [], isLoading: isLoadingUsers } = useQuery(orgQueries.users({ orgId }));
|
||||||
const { data: orgRoles = [] } = useQuery(orgQueries.roles({ orgId }));
|
const { data: orgRoles = [], isLoading: isLoadingRoles } = useQuery(orgQueries.roles({ orgId }));
|
||||||
|
|
||||||
const allUsers = useMemo(
|
const allUsers = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -508,6 +508,50 @@ function NotifyActionFields({
|
|||||||
[orgRoles]
|
[orgRoles]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasResolvedTagsRef = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isLoadingUsers || isLoadingRoles) return;
|
||||||
|
if (hasResolvedTagsRef.current) return;
|
||||||
|
|
||||||
|
const currentUserTags = form.getValues(
|
||||||
|
`actions.${index}.userTags`
|
||||||
|
) as Tag[];
|
||||||
|
const currentRoleTags = form.getValues(
|
||||||
|
`actions.${index}.roleTags`
|
||||||
|
) as Tag[];
|
||||||
|
|
||||||
|
const resolvedUserTags = currentUserTags.map((tag) => {
|
||||||
|
const match = allUsers.find((u) => u.id === tag.id);
|
||||||
|
return match ? { id: tag.id, text: match.text } : tag;
|
||||||
|
});
|
||||||
|
|
||||||
|
const resolvedRoleTags = currentRoleTags.map((tag) => {
|
||||||
|
const match = allRoles.find((r) => r.id === tag.id);
|
||||||
|
return match ? { id: tag.id, text: match.text } : tag;
|
||||||
|
});
|
||||||
|
|
||||||
|
const userTagsNeedUpdate = resolvedUserTags.some(
|
||||||
|
(t, i) => t.text !== currentUserTags[i]?.text
|
||||||
|
);
|
||||||
|
const roleTagsNeedUpdate = resolvedRoleTags.some(
|
||||||
|
(t, i) => t.text !== currentRoleTags[i]?.text
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userTagsNeedUpdate) {
|
||||||
|
form.setValue(`actions.${index}.userTags`, resolvedUserTags, {
|
||||||
|
shouldDirty: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (roleTagsNeedUpdate) {
|
||||||
|
form.setValue(`actions.${index}.roleTags`, resolvedRoleTags, {
|
||||||
|
shouldDirty: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
hasResolvedTagsRef.current = true;
|
||||||
|
}, [isLoadingUsers, isLoadingRoles, allUsers, allRoles]);
|
||||||
|
|
||||||
const userTags = (useWatch({ control, name: `actions.${index}.userTags` }) ?? []) as Tag[];
|
const userTags = (useWatch({ control, name: `actions.${index}.userTags` }) ?? []) as Tag[];
|
||||||
const roleTags = (useWatch({ control, name: `actions.${index}.roleTags` }) ?? []) as Tag[];
|
const roleTags = (useWatch({ control, name: `actions.${index}.roleTags` }) ?? []) as Tag[];
|
||||||
const emailTags = (useWatch({ control, name: `actions.${index}.emailTags` }) ?? []) as Tag[];
|
const emailTags = (useWatch({ control, name: `actions.${index}.emailTags` }) ?? []) as Tag[];
|
||||||
|
|||||||
Reference in New Issue
Block a user