mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-27 03:02:30 +00:00
Add logging when manually changing the hc status
This commit is contained in:
@@ -3196,5 +3196,6 @@
|
|||||||
"alertLabel": "Alert",
|
"alertLabel": "Alert",
|
||||||
"domainPickerWildcardSubdomainNotAllowed": "Wildcard subdomains are not allowed.",
|
"domainPickerWildcardSubdomainNotAllowed": "Wildcard subdomains are not allowed.",
|
||||||
"domainPickerWildcardCertWarning": "Wildcard certificates must be configured separately in Traefik.",
|
"domainPickerWildcardCertWarning": "Wildcard certificates must be configured separately in Traefik.",
|
||||||
"domainPickerWildcardCertWarningLink": "Learn more"
|
"domainPickerWildcardCertWarningLink": "Learn more",
|
||||||
|
"health": "Health"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ export async function updateProxyResources(
|
|||||||
newHealthcheck.name,
|
newHealthcheck.name,
|
||||||
newHealthcheck.targetId,
|
newHealthcheck.targetId,
|
||||||
undefined,
|
undefined,
|
||||||
|
true,
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -581,6 +582,7 @@ export async function updateProxyResources(
|
|||||||
newHealthcheck.name,
|
newHealthcheck.name,
|
||||||
newHealthcheck.targetId,
|
newHealthcheck.targetId,
|
||||||
undefined,
|
undefined,
|
||||||
|
true,
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ export async function fireHealthCheckHealthyAlert(
|
|||||||
healthCheckName?: string | null,
|
healthCheckName?: string | null,
|
||||||
healthCheckTargetId?: number | null,
|
healthCheckTargetId?: number | null,
|
||||||
extra?: Record<string, unknown>,
|
extra?: Record<string, unknown>,
|
||||||
trx: Transaction | typeof db = db
|
send: boolean = true,
|
||||||
|
trx: Transaction | typeof db = db,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await trx.insert(statusHistory).values({
|
await trx.insert(statusHistory).values({
|
||||||
@@ -63,6 +64,10 @@ export async function fireHealthCheckHealthyAlert(
|
|||||||
|
|
||||||
await handleResource(orgId, healthCheckTargetId, trx);
|
await handleResource(orgId, healthCheckTargetId, trx);
|
||||||
|
|
||||||
|
if (!send) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await processAlerts({
|
await processAlerts({
|
||||||
eventType: "health_check_healthy",
|
eventType: "health_check_healthy",
|
||||||
orgId,
|
orgId,
|
||||||
@@ -108,6 +113,7 @@ export async function fireHealthCheckUnhealthyAlert(
|
|||||||
healthCheckName?: string | null,
|
healthCheckName?: string | null,
|
||||||
healthCheckTargetId?: number | null,
|
healthCheckTargetId?: number | null,
|
||||||
extra?: Record<string, unknown>,
|
extra?: Record<string, unknown>,
|
||||||
|
send: boolean = true,
|
||||||
trx: Transaction | typeof db = db
|
trx: Transaction | typeof db = db
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@@ -121,6 +127,10 @@ export async function fireHealthCheckUnhealthyAlert(
|
|||||||
|
|
||||||
await handleResource(orgId, healthCheckTargetId, trx);
|
await handleResource(orgId, healthCheckTargetId, trx);
|
||||||
|
|
||||||
|
if (!send) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await processAlerts({
|
await processAlerts({
|
||||||
eventType: "health_check_unhealthy",
|
eventType: "health_check_unhealthy",
|
||||||
orgId,
|
orgId,
|
||||||
@@ -155,6 +165,7 @@ export async function fireHealthCheckUnknownAlert(
|
|||||||
healthCheckName?: string | null,
|
healthCheckName?: string | null,
|
||||||
healthCheckTargetId?: number | null,
|
healthCheckTargetId?: number | null,
|
||||||
extra?: Record<string, unknown>,
|
extra?: Record<string, unknown>,
|
||||||
|
send: boolean = true,
|
||||||
trx: Transaction | typeof db = db
|
trx: Transaction | typeof db = db
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@@ -167,6 +178,10 @@ export async function fireHealthCheckUnknownAlert(
|
|||||||
});
|
});
|
||||||
|
|
||||||
await handleResource(orgId, healthCheckTargetId, trx);
|
await handleResource(orgId, healthCheckTargetId, trx);
|
||||||
|
|
||||||
|
if (!send) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`fireHealthCheckUnknownAlert: unexpected error for healthCheckId ${healthCheckId}`,
|
`fireHealthCheckUnknownAlert: unexpected error for healthCheckId ${healthCheckId}`,
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ export async function fireSiteOfflineAlert(
|
|||||||
healthCheck.name,
|
healthCheck.name,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
|
true,
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { targetHealthCheck, statusHistory } from "@server/db";
|
import { targetHealthCheck } 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";
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { resources, statusHistory } from "@server/db";
|
import { resources } 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";
|
||||||
@@ -24,7 +24,6 @@ import { eq, and } from "drizzle-orm";
|
|||||||
import {
|
import {
|
||||||
fireResourceHealthyAlert,
|
fireResourceHealthyAlert,
|
||||||
fireResourceUnhealthyAlert,
|
fireResourceUnhealthyAlert,
|
||||||
fireResourceToggleAlert,
|
|
||||||
fireResourceDegradedAlert
|
fireResourceDegradedAlert
|
||||||
} from "#private/lib/alerts/events/resourceEvents";
|
} from "#private/lib/alerts/events/resourceEvents";
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { sites, statusHistory } from "@server/db";
|
import { 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";
|
||||||
|
|||||||
@@ -22,6 +22,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 { addStandaloneHealthCheck } from "@server/routers/newt/targets";
|
import { addStandaloneHealthCheck } from "@server/routers/newt/targets";
|
||||||
|
import { fireHealthCheckUnhealthyAlert } from "#private/lib/alerts";
|
||||||
|
|
||||||
const paramsSchema = z.strictObject({
|
const paramsSchema = z.strictObject({
|
||||||
orgId: z.string().nonempty()
|
orgId: z.string().nonempty()
|
||||||
@@ -146,6 +147,15 @@ export async function createHealthCheck(
|
|||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
await fireHealthCheckUnhealthyAlert(
|
||||||
|
record.orgId,
|
||||||
|
record.targetHealthCheckId,
|
||||||
|
record.name || "",
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
|
);
|
||||||
|
|
||||||
// Push health check to newt if the site is a newt site
|
// Push health check to newt if the site is a newt site
|
||||||
if (siteId) {
|
if (siteId) {
|
||||||
const [site] = await db
|
const [site] = await db
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ 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";
|
import { addStandaloneHealthCheck } from "@server/routers/newt/targets";
|
||||||
|
import { fireHealthCheckUnhealthyAlert, fireHealthCheckUnknownAlert, fireHealthCheckHealthyAlert } from "#private/lib/alerts";
|
||||||
|
|
||||||
const paramsSchema = z
|
const paramsSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -233,6 +234,37 @@ export async function updateHealthCheck(
|
|||||||
)
|
)
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
if (updated.hcHealth === "unhealthy" && existingHealthCheck.hcHealth !== "unhealthy") {
|
||||||
|
await fireHealthCheckUnhealthyAlert(
|
||||||
|
updated.orgId,
|
||||||
|
updated.targetHealthCheckId,
|
||||||
|
updated.name || "",
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
|
);
|
||||||
|
} else if (updated.hcHealth === "unknown" && existingHealthCheck.hcHealth !== "unknown") {
|
||||||
|
// if the health is unknown, we want to fire an alert to notify users to enable health checks
|
||||||
|
await fireHealthCheckUnknownAlert(
|
||||||
|
updated.orgId,
|
||||||
|
updated.targetHealthCheckId,
|
||||||
|
updated.name,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
|
);
|
||||||
|
} else if (updated.hcHealth === "healthy" && existingHealthCheck.hcHealth !== "healthy") {
|
||||||
|
await fireHealthCheckHealthyAlert(
|
||||||
|
updated.orgId,
|
||||||
|
updated.targetHealthCheckId,
|
||||||
|
updated.name,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Push updated health check to newt if the site is a newt site
|
// Push updated health check to newt if the site is a newt site
|
||||||
const [newt] = await db
|
const [newt] = await db
|
||||||
.select()
|
.select()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fireSiteOfflineAlert } from "@server/lib/alerts";
|
import { fireSiteOfflineAlert } from "#dynamic/lib/alerts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles disconnecting messages from sites to show disconnected in the ui
|
* Handles disconnecting messages from sites to show disconnected in the ui
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
newts,
|
newts,
|
||||||
sites,
|
sites
|
||||||
targetHealthCheck,
|
|
||||||
targets,
|
|
||||||
statusHistory
|
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import { hasActiveConnections } from "#dynamic/routers/ws";
|
import { hasActiveConnections } from "#dynamic/routers/ws";
|
||||||
import { eq, lt, isNull, and, or, ne, not, inArray } from "drizzle-orm";
|
import { eq, lt, isNull, and, or, ne, not, inArray } from "drizzle-orm";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db, statusHistory } from "@server/db";
|
||||||
import {
|
import {
|
||||||
siteProvisioningKeys,
|
siteProvisioningKeys,
|
||||||
siteProvisioningKeyOrg,
|
siteProvisioningKeyOrg,
|
||||||
@@ -223,6 +223,14 @@ export async function registerNewt(
|
|||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
await trx.insert(statusHistory).values({
|
||||||
|
entityType: "site",
|
||||||
|
entityId: newSite.siteId,
|
||||||
|
orgId: orgId,
|
||||||
|
status: "offline",
|
||||||
|
timestamp: Math.floor(Date.now() / 1000)
|
||||||
|
});
|
||||||
|
|
||||||
newSiteId = newSite.siteId;
|
newSiteId = newSite.siteId;
|
||||||
|
|
||||||
// Grant admin role access to the new site
|
// Grant admin role access to the new site
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { clients, db, exitNodes } from "@server/db";
|
import { clients, db, exitNodes, statusHistory } from "@server/db";
|
||||||
import { roles, userSites, sites, roleSites, Site, orgs } from "@server/db";
|
import { roles, userSites, sites, roleSites, Site, orgs } 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";
|
||||||
@@ -321,12 +321,7 @@ export async function createSite(
|
|||||||
const existingSite = await db
|
const existingSite = await db
|
||||||
.select()
|
.select()
|
||||||
.from(sites)
|
.from(sites)
|
||||||
.where(
|
.where(and(eq(sites.niceId, niceId), eq(sites.orgId, orgId)))
|
||||||
and(
|
|
||||||
eq(sites.niceId, niceId),
|
|
||||||
eq(sites.orgId, orgId)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (existingSite.length > 0) {
|
if (existingSite.length > 0) {
|
||||||
@@ -344,7 +339,8 @@ export async function createSite(
|
|||||||
if (type == "newt") {
|
if (type == "newt") {
|
||||||
[newSite] = await trx
|
[newSite] = await trx
|
||||||
.insert(sites)
|
.insert(sites)
|
||||||
.values({ // NOTE: NO SUBNET OR EXIT NODE ID PASSED IN HERE BECAUSE ITS NOW CHOSEN ON CONNECT
|
.values({
|
||||||
|
// NOTE: NO SUBNET OR EXIT NODE ID PASSED IN HERE BECAUSE ITS NOW CHOSEN ON CONNECT
|
||||||
orgId,
|
orgId,
|
||||||
name,
|
name,
|
||||||
niceId: updatedNiceId!,
|
niceId: updatedNiceId!,
|
||||||
@@ -354,6 +350,14 @@ export async function createSite(
|
|||||||
status: "approved"
|
status: "approved"
|
||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
await trx.insert(statusHistory).values({
|
||||||
|
entityType: "site",
|
||||||
|
entityId: newSite.siteId,
|
||||||
|
orgId: orgId,
|
||||||
|
status: "offline",
|
||||||
|
timestamp: Math.floor(Date.now() / 1000)
|
||||||
|
});
|
||||||
} else if (type == "wireguard") {
|
} else if (type == "wireguard") {
|
||||||
// we are creating a site with an exit node (tunneled)
|
// we are creating a site with an exit node (tunneled)
|
||||||
if (!subnet) {
|
if (!subnet) {
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, TargetHealthCheck, targetHealthCheck } from "@server/db";
|
import {
|
||||||
|
db,
|
||||||
|
statusHistory,
|
||||||
|
TargetHealthCheck,
|
||||||
|
targetHealthCheck
|
||||||
|
} from "@server/db";
|
||||||
import { newts, resources, sites, Target, targets } from "@server/db";
|
import { newts, resources, sites, Target, targets } 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";
|
||||||
@@ -14,6 +19,7 @@ import { eq } from "drizzle-orm";
|
|||||||
import { pickPort } from "./helpers";
|
import { pickPort } from "./helpers";
|
||||||
import { isTargetValid } from "@server/lib/validators";
|
import { isTargetValid } from "@server/lib/validators";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import { fireHealthCheckHealthyAlert, fireHealthCheckUnhealthyAlert, fireHealthCheckUnknownAlert } from "#dynamic/lib/alerts";
|
||||||
|
|
||||||
const createTargetParamsSchema = z.strictObject({
|
const createTargetParamsSchema = z.strictObject({
|
||||||
resourceId: z.string().transform(Number).pipe(z.int().positive())
|
resourceId: z.string().transform(Number).pipe(z.int().positive())
|
||||||
@@ -252,6 +258,36 @@ export async function createTarget(
|
|||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
if (healthCheck[0].hcHealth === "unhealthy") {
|
||||||
|
await fireHealthCheckUnhealthyAlert(
|
||||||
|
healthCheck[0].orgId,
|
||||||
|
healthCheck[0].targetHealthCheckId,
|
||||||
|
healthCheck[0].name,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
|
);
|
||||||
|
} else if (healthCheck[0].hcHealth === "unknown") {
|
||||||
|
// if the health is unknown, we want to fire an alert to notify users to enable health checks
|
||||||
|
await fireHealthCheckUnknownAlert(
|
||||||
|
healthCheck[0].orgId,
|
||||||
|
healthCheck[0].targetHealthCheckId,
|
||||||
|
healthCheck[0].name,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
|
);
|
||||||
|
} else if (healthCheck[0].hcHealth === "healthy") {
|
||||||
|
await fireHealthCheckHealthyAlert(
|
||||||
|
healthCheck[0].orgId,
|
||||||
|
healthCheck[0].targetHealthCheckId,
|
||||||
|
healthCheck[0].name,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (site.pubKey) {
|
if (site.pubKey) {
|
||||||
if (site.type == "wireguard") {
|
if (site.type == "wireguard") {
|
||||||
await addPeer(site.exitNodeId!, {
|
await addPeer(site.exitNodeId!, {
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
targets,
|
targetHealthCheck
|
||||||
resources,
|
|
||||||
sites,
|
|
||||||
targetHealthCheck,
|
|
||||||
statusHistory
|
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import { MessageHandler } from "@server/routers/ws";
|
import { MessageHandler } from "@server/routers/ws";
|
||||||
import { Newt } from "@server/db";
|
import { Newt } from "@server/db";
|
||||||
@@ -142,6 +138,7 @@ export const handleHealthcheckStatusMessage: MessageHandler = async (
|
|||||||
targetCheck.name ?? undefined,
|
targetCheck.name ?? undefined,
|
||||||
targetCheck.targetId,
|
targetCheck.targetId,
|
||||||
undefined,
|
undefined,
|
||||||
|
true,
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
} else if (healthStatus.status === "healthy") {
|
} else if (healthStatus.status === "healthy") {
|
||||||
@@ -151,6 +148,7 @@ export const handleHealthcheckStatusMessage: MessageHandler = async (
|
|||||||
targetCheck.name ?? undefined,
|
targetCheck.name ?? undefined,
|
||||||
targetCheck.targetId,
|
targetCheck.targetId,
|
||||||
undefined,
|
undefined,
|
||||||
|
true,
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ import logger from "@server/logger";
|
|||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { addPeer } from "../gerbil/peers";
|
import { addPeer } from "../gerbil/peers";
|
||||||
import { addTargets } from "../newt/targets";
|
import { addTargets } from "../newt/targets";
|
||||||
import { fireHealthCheckUnknownAlert } from "#dynamic/lib/alerts";
|
import { fireHealthCheckHealthyAlert, fireHealthCheckUnknownAlert } from "#dynamic/lib/alerts";
|
||||||
import { pickPort } from "./helpers";
|
import { pickPort } from "./helpers";
|
||||||
import { isTargetValid } from "@server/lib/validators";
|
import { isTargetValid } from "@server/lib/validators";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import { fireHealthCheckUnhealthyAlert } from "@server/lib/alerts";
|
||||||
|
|
||||||
|
|
||||||
const updateTargetParamsSchema = z.strictObject({
|
const updateTargetParamsSchema = z.strictObject({
|
||||||
@@ -256,12 +257,33 @@ export async function updateTarget(
|
|||||||
.where(eq(targetHealthCheck.targetId, targetId))
|
.where(eq(targetHealthCheck.targetId, targetId))
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
if (isDisablingHc) {
|
if (updatedHc.hcHealth === "unhealthy" && existingHc.hcHealth !== "unhealthy") {
|
||||||
|
await fireHealthCheckUnhealthyAlert(
|
||||||
|
updatedHc.orgId,
|
||||||
|
updatedHc.targetHealthCheckId,
|
||||||
|
updatedHc.name || "",
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
|
);
|
||||||
|
} else if (updatedHc.hcHealth === "unknown" && existingHc.hcHealth !== "unknown") {
|
||||||
|
// if the health is unknown, we want to fire an alert to notify users to enable health checks
|
||||||
await fireHealthCheckUnknownAlert(
|
await fireHealthCheckUnknownAlert(
|
||||||
resource.orgId,
|
updatedHc.orgId,
|
||||||
existingHc.targetHealthCheckId,
|
updatedHc.targetHealthCheckId,
|
||||||
existingHc.name,
|
updatedHc.name,
|
||||||
updatedHc.targetId
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
|
);
|
||||||
|
} else if (updatedHc.hcHealth === "healthy" && existingHc.hcHealth !== "healthy") {
|
||||||
|
await fireHealthCheckHealthyAlert(
|
||||||
|
updatedHc.orgId,
|
||||||
|
updatedHc.targetHealthCheckId,
|
||||||
|
updatedHc.name,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false // dont send the alert because we just want to create the alert, not notify users yet
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ export default async function AlertingHealthChecksPage(
|
|||||||
fullDomain: string | null;
|
fullDomain: string | null;
|
||||||
niceId: string;
|
niceId: string;
|
||||||
ssl: boolean;
|
ssl: boolean;
|
||||||
|
wildcard: boolean;
|
||||||
} | null = null;
|
} | null = null;
|
||||||
if (resourceIdParam) {
|
if (resourceIdParam) {
|
||||||
try {
|
try {
|
||||||
@@ -165,7 +166,8 @@ export default async function AlertingHealthChecksPage(
|
|||||||
resourceId: r.resourceId,
|
resourceId: r.resourceId,
|
||||||
fullDomain: r.fullDomain,
|
fullDomain: r.fullDomain,
|
||||||
niceId: r.niceId,
|
niceId: r.niceId,
|
||||||
ssl: r.ssl
|
ssl: r.ssl,
|
||||||
|
wildcard: r.wildcard
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -557,6 +557,7 @@ export default function DomainPicker({
|
|||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
<PaidFeaturesAlert
|
<PaidFeaturesAlert
|
||||||
|
showBookADemo={false}
|
||||||
tiers={
|
tiers={
|
||||||
tierMatrix[
|
tierMatrix[
|
||||||
TierFeature.WildcardSubdomain
|
TierFeature.WildcardSubdomain
|
||||||
|
|||||||
@@ -151,7 +151,8 @@ export default function HealthChecksTable({
|
|||||||
resourceId: resourceIdNum,
|
resourceId: resourceIdNum,
|
||||||
fullDomain: null,
|
fullDomain: null,
|
||||||
niceId: "",
|
niceId: "",
|
||||||
ssl: false
|
ssl: false,
|
||||||
|
wildcard: false
|
||||||
};
|
};
|
||||||
}, [initialFilterResource, resourceIdQ, resourceIdNum, t]);
|
}, [initialFilterResource, resourceIdQ, resourceIdNum, t]);
|
||||||
|
|
||||||
|
|||||||
@@ -114,9 +114,10 @@ function getDocsLinkRenderer(href: string) {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
tiers: Tier[];
|
tiers: Tier[];
|
||||||
|
showBookADemo?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function PaidFeaturesAlert({ tiers }: Props) {
|
export function PaidFeaturesAlert({ tiers, showBookADemo = true }: Props) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const orgId = params?.orgId as string | undefined;
|
const orgId = params?.orgId as string | undefined;
|
||||||
@@ -134,7 +135,9 @@ export function PaidFeaturesAlert({ tiers }: Props) {
|
|||||||
const tierLinkRenderer = getTierLinkRenderer(billingHref);
|
const tierLinkRenderer = getTierLinkRenderer(billingHref);
|
||||||
const pangolinCloudLinkRenderer = getPangolinCloudLinkRenderer();
|
const pangolinCloudLinkRenderer = getPangolinCloudLinkRenderer();
|
||||||
const enterpriseDocsLinkRenderer = getDocsLinkRenderer(ENTERPRISE_DOCS_URL);
|
const enterpriseDocsLinkRenderer = getDocsLinkRenderer(ENTERPRISE_DOCS_URL);
|
||||||
const bookADemoLinkRenderer = getBookADemoLinkRenderer();
|
const bookADemoLinkRenderer = showBookADemo
|
||||||
|
? getBookADemoLinkRenderer()
|
||||||
|
: () => null;
|
||||||
|
|
||||||
if (env.flags.disableEnterpriseFeatures) {
|
if (env.flags.disableEnterpriseFeatures) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -63,13 +63,6 @@ import { useDebouncedCallback } from "use-debounce";
|
|||||||
import z from "zod";
|
import z from "zod";
|
||||||
import { ColumnFilterButton } from "./ColumnFilterButton";
|
import { ColumnFilterButton } from "./ColumnFilterButton";
|
||||||
import { ControlledDataTable } from "./ui/controlled-data-table";
|
import { ControlledDataTable } from "./ui/controlled-data-table";
|
||||||
import {
|
|
||||||
Tooltip,
|
|
||||||
TooltipContent,
|
|
||||||
TooltipProvider,
|
|
||||||
TooltipTrigger
|
|
||||||
} from "@app/components/ui/tooltip";
|
|
||||||
import type { StatusHistoryResponse } from "@server/lib/statusHistory";
|
|
||||||
import UptimeMiniBar from "./UptimeMiniBar";
|
import UptimeMiniBar from "./UptimeMiniBar";
|
||||||
|
|
||||||
export type TargetHealth = {
|
export type TargetHealth = {
|
||||||
@@ -466,7 +459,7 @@ export default function ProxyResourcesTable({
|
|||||||
{
|
{
|
||||||
id: "status",
|
id: "status",
|
||||||
accessorKey: "status",
|
accessorKey: "status",
|
||||||
friendlyName: t("status"),
|
friendlyName: t("health"),
|
||||||
header: () => (
|
header: () => (
|
||||||
<ColumnFilterButton
|
<ColumnFilterButton
|
||||||
options={[
|
options={[
|
||||||
@@ -489,7 +482,7 @@ export default function ProxyResourcesTable({
|
|||||||
}
|
}
|
||||||
searchPlaceholder={t("searchPlaceholder")}
|
searchPlaceholder={t("searchPlaceholder")}
|
||||||
emptyMessage={t("emptySearchOptions")}
|
emptyMessage={t("emptySearchOptions")}
|
||||||
label={t("status")}
|
label={t("health")}
|
||||||
className="p-3"
|
className="p-3"
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user