mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-30 04:32:53 +00:00
Add 1.18 migrations
This commit is contained in:
@@ -2,7 +2,7 @@ import path from "path";
|
|||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
// This is a placeholder value replaced by the build process
|
// This is a placeholder value replaced by the build process
|
||||||
export const APP_VERSION = "1.17.0";
|
export const APP_VERSION = "1.18.0";
|
||||||
|
|
||||||
export const __FILENAME = fileURLToPath(import.meta.url);
|
export const __FILENAME = fileURLToPath(import.meta.url);
|
||||||
export const __DIRNAME = path.dirname(__FILENAME);
|
export const __DIRNAME = path.dirname(__FILENAME);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import m13 from "./scriptsPg/1.15.3";
|
|||||||
import m14 from "./scriptsPg/1.15.4";
|
import m14 from "./scriptsPg/1.15.4";
|
||||||
import m15 from "./scriptsPg/1.16.0";
|
import m15 from "./scriptsPg/1.16.0";
|
||||||
import m16 from "./scriptsPg/1.17.0";
|
import m16 from "./scriptsPg/1.17.0";
|
||||||
|
import m17 from "./scriptsPg/1.18.0";
|
||||||
|
|
||||||
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
||||||
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
||||||
@@ -43,7 +44,8 @@ const migrations = [
|
|||||||
{ version: "1.15.3", run: m13 },
|
{ version: "1.15.3", run: m13 },
|
||||||
{ version: "1.15.4", run: m14 },
|
{ version: "1.15.4", run: m14 },
|
||||||
{ version: "1.16.0", run: m15 },
|
{ version: "1.16.0", run: m15 },
|
||||||
{ version: "1.17.0", run: m16 }
|
{ version: "1.17.0", run: m16 },
|
||||||
|
{ version: "1.18.0", run: m17 }
|
||||||
// Add new migrations here as they are created
|
// Add new migrations here as they are created
|
||||||
] as {
|
] as {
|
||||||
version: string;
|
version: string;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import m34 from "./scriptsSqlite/1.15.3";
|
|||||||
import m35 from "./scriptsSqlite/1.15.4";
|
import m35 from "./scriptsSqlite/1.15.4";
|
||||||
import m36 from "./scriptsSqlite/1.16.0";
|
import m36 from "./scriptsSqlite/1.16.0";
|
||||||
import m37 from "./scriptsSqlite/1.17.0";
|
import m37 from "./scriptsSqlite/1.17.0";
|
||||||
|
import m38 from "./scriptsSqlite/1.18.0";
|
||||||
|
|
||||||
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
||||||
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
||||||
@@ -77,7 +78,8 @@ const migrations = [
|
|||||||
{ version: "1.15.3", run: m34 },
|
{ version: "1.15.3", run: m34 },
|
||||||
{ version: "1.15.4", run: m35 },
|
{ version: "1.15.4", run: m35 },
|
||||||
{ version: "1.16.0", run: m36 },
|
{ version: "1.16.0", run: m36 },
|
||||||
{ version: "1.17.0", run: m37 }
|
{ version: "1.17.0", run: m37 },
|
||||||
|
{ version: "1.18.0", run: m38 }
|
||||||
// Add new migrations here as they are created
|
// Add new migrations here as they are created
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
|||||||
434
server/setup/scriptsPg/1.18.0.ts
Normal file
434
server/setup/scriptsPg/1.18.0.ts
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
import { db } from "@server/db/pg/driver";
|
||||||
|
import { sql } from "drizzle-orm";
|
||||||
|
|
||||||
|
const version = "1.18.0";
|
||||||
|
|
||||||
|
export default async function migration() {
|
||||||
|
console.log(`Running setup script ${version}...`);
|
||||||
|
|
||||||
|
// Query existing targetHealthCheck data with joined siteId and orgId before
|
||||||
|
// the transaction adds the new columns (which start NULL for existing rows).
|
||||||
|
// We will delete all rows and reinsert them with targetHealthCheckId = targetId
|
||||||
|
// so the two IDs form a stable 1:1 mapping.
|
||||||
|
const healthChecksQuery = await db.execute(
|
||||||
|
sql`SELECT
|
||||||
|
thc."targetHealthCheckId",
|
||||||
|
thc."targetId",
|
||||||
|
t."siteId",
|
||||||
|
s."orgId",
|
||||||
|
thc."hcEnabled",
|
||||||
|
thc."hcPath",
|
||||||
|
thc."hcScheme",
|
||||||
|
thc."hcMode",
|
||||||
|
thc."hcHostname",
|
||||||
|
thc."hcPort",
|
||||||
|
thc."hcInterval",
|
||||||
|
thc."hcUnhealthyInterval",
|
||||||
|
thc."hcTimeout",
|
||||||
|
thc."hcHeaders",
|
||||||
|
thc."hcFollowRedirects",
|
||||||
|
thc."hcMethod",
|
||||||
|
thc."hcStatus",
|
||||||
|
thc."hcHealth",
|
||||||
|
thc."hcTlsServerName"
|
||||||
|
FROM "targetHealthCheck" thc
|
||||||
|
JOIN "targets" t ON thc."targetId" = t."targetId"
|
||||||
|
JOIN "sites" s ON t."siteId" = s."siteId"`
|
||||||
|
);
|
||||||
|
const existingHealthChecks = healthChecksQuery.rows as {
|
||||||
|
targetHealthCheckId: number;
|
||||||
|
targetId: number;
|
||||||
|
siteId: number;
|
||||||
|
orgId: string;
|
||||||
|
hcEnabled: boolean;
|
||||||
|
hcPath: string | null;
|
||||||
|
hcScheme: string | null;
|
||||||
|
hcMode: string | null;
|
||||||
|
hcHostname: string | null;
|
||||||
|
hcPort: number | null;
|
||||||
|
hcInterval: number | null;
|
||||||
|
hcUnhealthyInterval: number | null;
|
||||||
|
hcTimeout: number | null;
|
||||||
|
hcHeaders: string | null;
|
||||||
|
hcFollowRedirects: boolean | null;
|
||||||
|
hcMethod: string | null;
|
||||||
|
hcStatus: number | null;
|
||||||
|
hcHealth: string | null;
|
||||||
|
hcTlsServerName: string | null;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Found ${existingHealthChecks.length} existing targetHealthCheck row(s) to migrate`
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.execute(sql`BEGIN`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "alertEmailActions" (
|
||||||
|
"emailActionId" serial PRIMARY KEY NOT NULL,
|
||||||
|
"alertRuleId" integer NOT NULL,
|
||||||
|
"enabled" boolean DEFAULT true NOT NULL,
|
||||||
|
"lastSentAt" bigint
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "alertEmailRecipients" (
|
||||||
|
"recipientId" serial PRIMARY KEY NOT NULL,
|
||||||
|
"emailActionId" integer NOT NULL,
|
||||||
|
"userId" varchar,
|
||||||
|
"roleId" integer,
|
||||||
|
"email" varchar(255)
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "alertHealthChecks" (
|
||||||
|
"alertRuleId" integer NOT NULL,
|
||||||
|
"healthCheckId" integer NOT NULL
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "alertResources" (
|
||||||
|
"alertRuleId" integer NOT NULL,
|
||||||
|
"resourceId" integer NOT NULL
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "alertRules" (
|
||||||
|
"alertRuleId" serial PRIMARY KEY NOT NULL,
|
||||||
|
"orgId" varchar(255) NOT NULL,
|
||||||
|
"name" varchar(255) NOT NULL,
|
||||||
|
"eventType" varchar(100) NOT NULL,
|
||||||
|
"enabled" boolean DEFAULT true NOT NULL,
|
||||||
|
"cooldownSeconds" integer DEFAULT 300 NOT NULL,
|
||||||
|
"allSites" boolean DEFAULT false NOT NULL,
|
||||||
|
"allHealthChecks" boolean DEFAULT false NOT NULL,
|
||||||
|
"allResources" boolean DEFAULT false NOT NULL,
|
||||||
|
"lastTriggeredAt" bigint,
|
||||||
|
"createdAt" bigint NOT NULL,
|
||||||
|
"updatedAt" bigint NOT NULL
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "alertSites" (
|
||||||
|
"alertRuleId" integer NOT NULL,
|
||||||
|
"siteId" integer NOT NULL
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "alertWebhookActions" (
|
||||||
|
"webhookActionId" serial PRIMARY KEY NOT NULL,
|
||||||
|
"alertRuleId" integer NOT NULL,
|
||||||
|
"webhookUrl" text NOT NULL,
|
||||||
|
"config" text,
|
||||||
|
"enabled" boolean DEFAULT true NOT NULL,
|
||||||
|
"lastSentAt" bigint
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "networks" (
|
||||||
|
"networkId" serial PRIMARY KEY NOT NULL,
|
||||||
|
"niceId" text,
|
||||||
|
"name" text,
|
||||||
|
"scope" varchar DEFAULT 'global' NOT NULL,
|
||||||
|
"orgId" varchar NOT NULL
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "siteNetworks" (
|
||||||
|
"siteId" integer NOT NULL,
|
||||||
|
"networkId" integer NOT NULL
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE "statusHistory" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"entityType" varchar NOT NULL,
|
||||||
|
"entityId" integer NOT NULL,
|
||||||
|
"orgId" varchar NOT NULL,
|
||||||
|
"status" varchar NOT NULL,
|
||||||
|
"timestamp" integer NOT NULL
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" DROP CONSTRAINT "siteResources_siteId_sites_siteId_fk";
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "targetHealthCheck" ALTER COLUMN "targetId" DROP NOT NULL;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "subscriptions" ADD COLUMN "expiresAt" bigint;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "subscriptions" ADD COLUMN "trial" boolean DEFAULT false;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "requestAuditLog" ADD COLUMN "siteResourceId" integer;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD COLUMN "networkId" integer;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD COLUMN "defaultNetworkId" integer;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD COLUMN "ssl" boolean DEFAULT false NOT NULL;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD COLUMN "scheme" varchar;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD COLUMN "domainId" varchar;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD COLUMN "subdomain" varchar;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD COLUMN "fullDomain" varchar;
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Add orgId and siteId as nullable first; NOT NULL constraints are applied
|
||||||
|
// after the data migration below once every row has been populated.
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "targetHealthCheck" ADD COLUMN "orgId" varchar;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "targetHealthCheck" ADD COLUMN "siteId" integer;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "targetHealthCheck" ADD COLUMN "name" varchar;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "targetHealthCheck" ADD COLUMN "hcHealthyThreshold" integer DEFAULT 1;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "targetHealthCheck" ADD COLUMN "hcUnhealthyThreshold" integer DEFAULT 1;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertEmailActions" ADD CONSTRAINT "alertEmailActions_alertRuleId_alertRules_alertRuleId_fk" FOREIGN KEY ("alertRuleId") REFERENCES "public"."alertRules"("alertRuleId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertEmailRecipients" ADD CONSTRAINT "alertEmailRecipients_emailActionId_alertEmailActions_emailActionId_fk" FOREIGN KEY ("emailActionId") REFERENCES "public"."alertEmailActions"("emailActionId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertEmailRecipients" ADD CONSTRAINT "alertEmailRecipients_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertEmailRecipients" ADD CONSTRAINT "alertEmailRecipients_roleId_roles_roleId_fk" FOREIGN KEY ("roleId") REFERENCES "public"."roles"("roleId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertHealthChecks" ADD CONSTRAINT "alertHealthChecks_alertRuleId_alertRules_alertRuleId_fk" FOREIGN KEY ("alertRuleId") REFERENCES "public"."alertRules"("alertRuleId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertHealthChecks" ADD CONSTRAINT "alertHealthChecks_healthCheckId_targetHealthCheck_targetHealthCheckId_fk" FOREIGN KEY ("healthCheckId") REFERENCES "public"."targetHealthCheck"("targetHealthCheckId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertResources" ADD CONSTRAINT "alertResources_alertRuleId_alertRules_alertRuleId_fk" FOREIGN KEY ("alertRuleId") REFERENCES "public"."alertRules"("alertRuleId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertResources" ADD CONSTRAINT "alertResources_resourceId_resources_resourceId_fk" FOREIGN KEY ("resourceId") REFERENCES "public"."resources"("resourceId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertRules" ADD CONSTRAINT "alertRules_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertSites" ADD CONSTRAINT "alertSites_alertRuleId_alertRules_alertRuleId_fk" FOREIGN KEY ("alertRuleId") REFERENCES "public"."alertRules"("alertRuleId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertSites" ADD CONSTRAINT "alertSites_siteId_sites_siteId_fk" FOREIGN KEY ("siteId") REFERENCES "public"."sites"("siteId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "alertWebhookActions" ADD CONSTRAINT "alertWebhookActions_alertRuleId_alertRules_alertRuleId_fk" FOREIGN KEY ("alertRuleId") REFERENCES "public"."alertRules"("alertRuleId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "networks" ADD CONSTRAINT "networks_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteNetworks" ADD CONSTRAINT "siteNetworks_siteId_sites_siteId_fk" FOREIGN KEY ("siteId") REFERENCES "public"."sites"("siteId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteNetworks" ADD CONSTRAINT "siteNetworks_networkId_networks_networkId_fk" FOREIGN KEY ("networkId") REFERENCES "public"."networks"("networkId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "statusHistory" ADD CONSTRAINT "statusHistory_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE INDEX "idx_statusHistory_entity" ON "statusHistory" USING btree ("entityType","entityId","timestamp");
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE INDEX "idx_statusHistory_org_timestamp" ON "statusHistory" USING btree ("orgId","timestamp");
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD CONSTRAINT "siteResources_networkId_networks_networkId_fk" FOREIGN KEY ("networkId") REFERENCES "public"."networks"("networkId") ON DELETE set null ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD CONSTRAINT "siteResources_defaultNetworkId_networks_networkId_fk" FOREIGN KEY ("defaultNetworkId") REFERENCES "public"."networks"("networkId") ON DELETE restrict ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" ADD CONSTRAINT "siteResources_domainId_domains_domainId_fk" FOREIGN KEY ("domainId") REFERENCES "public"."domains"("domainId") ON DELETE set null ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "targetHealthCheck" ADD CONSTRAINT "targetHealthCheck_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "targetHealthCheck" ADD CONSTRAINT "targetHealthCheck_siteId_sites_siteId_fk" FOREIGN KEY ("siteId") REFERENCES "public"."sites"("siteId") ON DELETE cascade ON UPDATE no action;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" DROP COLUMN "siteId";
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "siteResources" DROP COLUMN "protocol";
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`COMMIT`);
|
||||||
|
console.log("Migrated database");
|
||||||
|
} catch (e) {
|
||||||
|
await db.execute(sql`ROLLBACK`);
|
||||||
|
console.log("Unable to migrate database");
|
||||||
|
console.log(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reinsert targetHealthCheck rows with corrected IDs:
|
||||||
|
// targetHealthCheckId is set to the same integer as targetId (1:1 mapping),
|
||||||
|
// siteId and orgId are populated from the associated target and site.
|
||||||
|
//
|
||||||
|
// Because targetHealthCheckId is a serial (sequence-backed) column, inserting
|
||||||
|
// explicit values is allowed in PostgreSQL — the sequence is simply bypassed.
|
||||||
|
// After all inserts we advance the sequence to MAX(targetHealthCheckId) via
|
||||||
|
// setval() so future auto-inserts never collide with the explicit IDs we used.
|
||||||
|
if (existingHealthChecks.length > 0) {
|
||||||
|
try {
|
||||||
|
// Remove all existing rows first. The alertHealthChecks table is brand
|
||||||
|
// new in this migration so there are no FK references to worry about.
|
||||||
|
await db.execute(sql`DELETE FROM "targetHealthCheck"`);
|
||||||
|
|
||||||
|
for (const hc of existingHealthChecks) {
|
||||||
|
await db.execute(sql`
|
||||||
|
INSERT INTO "targetHealthCheck" (
|
||||||
|
"targetHealthCheckId",
|
||||||
|
"targetId",
|
||||||
|
"orgId",
|
||||||
|
"siteId",
|
||||||
|
"hcEnabled",
|
||||||
|
"hcPath",
|
||||||
|
"hcScheme",
|
||||||
|
"hcMode",
|
||||||
|
"hcHostname",
|
||||||
|
"hcPort",
|
||||||
|
"hcInterval",
|
||||||
|
"hcUnhealthyInterval",
|
||||||
|
"hcTimeout",
|
||||||
|
"hcHeaders",
|
||||||
|
"hcFollowRedirects",
|
||||||
|
"hcMethod",
|
||||||
|
"hcStatus",
|
||||||
|
"hcHealth",
|
||||||
|
"hcTlsServerName"
|
||||||
|
) VALUES (
|
||||||
|
${hc.targetId},
|
||||||
|
${hc.targetId},
|
||||||
|
${hc.orgId},
|
||||||
|
${hc.siteId},
|
||||||
|
${hc.hcEnabled},
|
||||||
|
${hc.hcPath},
|
||||||
|
${hc.hcScheme},
|
||||||
|
${hc.hcMode},
|
||||||
|
${hc.hcHostname},
|
||||||
|
${hc.hcPort},
|
||||||
|
${hc.hcInterval},
|
||||||
|
${hc.hcUnhealthyInterval},
|
||||||
|
${hc.hcTimeout},
|
||||||
|
${hc.hcHeaders},
|
||||||
|
${hc.hcFollowRedirects},
|
||||||
|
${hc.hcMethod},
|
||||||
|
${hc.hcStatus},
|
||||||
|
${hc.hcHealth},
|
||||||
|
${hc.hcTlsServerName}
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that every row has orgId and siteId populated, enforce NOT NULL.
|
||||||
|
await db.execute(
|
||||||
|
sql`ALTER TABLE "targetHealthCheck" ALTER COLUMN "orgId" SET NOT NULL`
|
||||||
|
);
|
||||||
|
await db.execute(
|
||||||
|
sql`ALTER TABLE "targetHealthCheck" ALTER COLUMN "siteId" SET NOT NULL`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Advance the sequence so the next auto-insert picks up after the
|
||||||
|
// largest ID we explicitly wrote. setval(..., max, true) means the
|
||||||
|
// next nextval() call will return max + 1.
|
||||||
|
await db.execute(sql`
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('"targetHealthCheck"', 'targetHealthCheckId'),
|
||||||
|
(SELECT MAX("targetHealthCheckId") FROM "targetHealthCheck"),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Migrated ${existingHealthChecks.length} targetHealthCheck row(s) with corrected IDs`
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
"Error while migrating targetHealthCheck rows:",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`${version} migration complete`);
|
||||||
|
}
|
||||||
403
server/setup/scriptsSqlite/1.18.0.ts
Normal file
403
server/setup/scriptsSqlite/1.18.0.ts
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
import { APP_PATH } from "@server/lib/consts";
|
||||||
|
import Database from "better-sqlite3";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
const version = "1.18.0";
|
||||||
|
|
||||||
|
export default async function migration() {
|
||||||
|
console.log(`Running setup script ${version}...`);
|
||||||
|
|
||||||
|
const location = path.join(APP_PATH, "db", "db.sqlite");
|
||||||
|
const db = new Database(location);
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.pragma("foreign_keys = OFF");
|
||||||
|
|
||||||
|
// Query existing targetHealthCheck data with joined siteId and orgId before
|
||||||
|
// the transaction drops and recreates the table
|
||||||
|
const existingHealthChecks = db
|
||||||
|
.prepare(
|
||||||
|
`SELECT
|
||||||
|
thc."targetHealthCheckId",
|
||||||
|
thc."targetId",
|
||||||
|
t."siteId",
|
||||||
|
s."orgId",
|
||||||
|
thc."hcEnabled",
|
||||||
|
thc."hcPath",
|
||||||
|
thc."hcScheme",
|
||||||
|
thc."hcMode",
|
||||||
|
thc."hcHostname",
|
||||||
|
thc."hcPort",
|
||||||
|
thc."hcInterval",
|
||||||
|
thc."hcUnhealthyInterval",
|
||||||
|
thc."hcTimeout",
|
||||||
|
thc."hcHeaders",
|
||||||
|
thc."hcFollowRedirects",
|
||||||
|
thc."hcMethod",
|
||||||
|
thc."hcStatus",
|
||||||
|
thc."hcHealth",
|
||||||
|
thc."hcTlsServerName"
|
||||||
|
FROM 'targetHealthCheck' thc
|
||||||
|
JOIN 'targets' t ON thc."targetId" = t."targetId"
|
||||||
|
JOIN 'sites' s ON t."siteId" = s."siteId"`
|
||||||
|
)
|
||||||
|
.all() as {
|
||||||
|
targetHealthCheckId: number;
|
||||||
|
targetId: number;
|
||||||
|
siteId: number;
|
||||||
|
orgId: string;
|
||||||
|
hcEnabled: number;
|
||||||
|
hcPath: string | null;
|
||||||
|
hcScheme: string | null;
|
||||||
|
hcMode: string | null;
|
||||||
|
hcHostname: string | null;
|
||||||
|
hcPort: number | null;
|
||||||
|
hcInterval: number | null;
|
||||||
|
hcUnhealthyInterval: number | null;
|
||||||
|
hcTimeout: number | null;
|
||||||
|
hcHeaders: string | null;
|
||||||
|
hcFollowRedirects: number | null;
|
||||||
|
hcMethod: string | null;
|
||||||
|
hcStatus: number | null;
|
||||||
|
hcHealth: string | null;
|
||||||
|
hcTlsServerName: string | null;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Found ${existingHealthChecks.length} existing targetHealthCheck row(s) to migrate`
|
||||||
|
);
|
||||||
|
|
||||||
|
db.transaction(() => {
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'alertEmailActions' (
|
||||||
|
'emailActionId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
'alertRuleId' integer NOT NULL,
|
||||||
|
'enabled' integer DEFAULT true NOT NULL,
|
||||||
|
'lastSentAt' integer,
|
||||||
|
FOREIGN KEY ('alertRuleId') REFERENCES 'alertRules'('alertRuleId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'alertEmailRecipients' (
|
||||||
|
'recipientId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
'emailActionId' integer NOT NULL,
|
||||||
|
'userId' text,
|
||||||
|
'roleId' integer,
|
||||||
|
'email' text,
|
||||||
|
FOREIGN KEY ('emailActionId') REFERENCES 'alertEmailActions'('emailActionId') ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY ('userId') REFERENCES 'user'('id') ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY ('roleId') REFERENCES 'roles'('roleId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'alertHealthChecks' (
|
||||||
|
'alertRuleId' integer NOT NULL,
|
||||||
|
'healthCheckId' integer NOT NULL,
|
||||||
|
FOREIGN KEY ('alertRuleId') REFERENCES 'alertRules'('alertRuleId') ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY ('healthCheckId') REFERENCES 'targetHealthCheck'('targetHealthCheckId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'alertResources' (
|
||||||
|
'alertRuleId' integer NOT NULL,
|
||||||
|
'resourceId' integer NOT NULL,
|
||||||
|
FOREIGN KEY ('alertRuleId') REFERENCES 'alertRules'('alertRuleId') ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'alertRules' (
|
||||||
|
'alertRuleId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
'orgId' text NOT NULL,
|
||||||
|
'name' text NOT NULL,
|
||||||
|
'eventType' text NOT NULL,
|
||||||
|
'enabled' integer DEFAULT true NOT NULL,
|
||||||
|
'cooldownSeconds' integer DEFAULT 300 NOT NULL,
|
||||||
|
'allSites' integer DEFAULT false NOT NULL,
|
||||||
|
'allHealthChecks' integer DEFAULT false NOT NULL,
|
||||||
|
'allResources' integer DEFAULT false NOT NULL,
|
||||||
|
'lastTriggeredAt' integer,
|
||||||
|
'createdAt' integer NOT NULL,
|
||||||
|
'updatedAt' integer NOT NULL,
|
||||||
|
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'alertSites' (
|
||||||
|
'alertRuleId' integer NOT NULL,
|
||||||
|
'siteId' integer NOT NULL,
|
||||||
|
FOREIGN KEY ('alertRuleId') REFERENCES 'alertRules'('alertRuleId') ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY ('siteId') REFERENCES 'sites'('siteId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'alertWebhookActions' (
|
||||||
|
'webhookActionId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
'alertRuleId' integer NOT NULL,
|
||||||
|
'webhookUrl' text NOT NULL,
|
||||||
|
'config' text,
|
||||||
|
'enabled' integer DEFAULT true NOT NULL,
|
||||||
|
'lastSentAt' integer,
|
||||||
|
FOREIGN KEY ('alertRuleId') REFERENCES 'alertRules'('alertRuleId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'networks' (
|
||||||
|
'networkId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
'niceId' text,
|
||||||
|
'name' text,
|
||||||
|
'scope' text DEFAULT 'global' NOT NULL,
|
||||||
|
'orgId' text NOT NULL,
|
||||||
|
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'siteNetworks' (
|
||||||
|
'siteId' integer NOT NULL,
|
||||||
|
'networkId' integer NOT NULL,
|
||||||
|
FOREIGN KEY ('siteId') REFERENCES 'sites'('siteId') ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY ('networkId') REFERENCES 'networks'('networkId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE 'statusHistory' (
|
||||||
|
'id' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
'entityType' text NOT NULL,
|
||||||
|
'entityId' integer NOT NULL,
|
||||||
|
'orgId' text NOT NULL,
|
||||||
|
'status' text NOT NULL,
|
||||||
|
'timestamp' integer NOT NULL,
|
||||||
|
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE INDEX 'idx_statusHistory_entity' ON 'statusHistory' ('entityType','entityId','timestamp');
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE INDEX 'idx_statusHistory_org_timestamp' ON 'statusHistory' ('orgId','timestamp');
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE '__new_siteResources' (
|
||||||
|
'siteResourceId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
'orgId' text NOT NULL,
|
||||||
|
'networkId' integer,
|
||||||
|
'defaultNetworkId' integer,
|
||||||
|
'niceId' text NOT NULL,
|
||||||
|
'name' text NOT NULL,
|
||||||
|
'ssl' integer DEFAULT false NOT NULL,
|
||||||
|
'mode' text NOT NULL,
|
||||||
|
'scheme' text,
|
||||||
|
'proxyPort' integer,
|
||||||
|
'destinationPort' integer,
|
||||||
|
'destination' text NOT NULL,
|
||||||
|
'enabled' integer DEFAULT true NOT NULL,
|
||||||
|
'alias' text,
|
||||||
|
'aliasAddress' text,
|
||||||
|
'tcpPortRangeString' text DEFAULT '*' NOT NULL,
|
||||||
|
'udpPortRangeString' text DEFAULT '*' NOT NULL,
|
||||||
|
'disableIcmp' integer DEFAULT false NOT NULL,
|
||||||
|
'authDaemonPort' integer DEFAULT 22123,
|
||||||
|
'authDaemonMode' text DEFAULT 'site',
|
||||||
|
'domainId' text,
|
||||||
|
'subdomain' text,
|
||||||
|
'fullDomain' text,
|
||||||
|
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY ('networkId') REFERENCES 'networks'('networkId') ON UPDATE no action ON DELETE set null,
|
||||||
|
FOREIGN KEY ('defaultNetworkId') REFERENCES 'networks'('networkId') ON UPDATE no action ON DELETE restrict,
|
||||||
|
FOREIGN KEY ('domainId') REFERENCES 'domains'('domainId') ON UPDATE no action ON DELETE set null
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
INSERT INTO '__new_siteResources'("siteResourceId", "orgId", "networkId", "defaultNetworkId", "niceId", "name", "ssl", "mode", "scheme", "proxyPort", "destinationPort", "destination", "enabled", "alias", "aliasAddress", "tcpPortRangeString", "udpPortRangeString", "disableIcmp", "authDaemonPort", "authDaemonMode", "domainId", "subdomain", "fullDomain") SELECT "siteResourceId", "orgId", "networkId", "defaultNetworkId", "niceId", "name", "ssl", "mode", "scheme", "proxyPort", "destinationPort", "destination", "enabled", "alias", "aliasAddress", "tcpPortRangeString", "udpPortRangeString", "disableIcmp", "authDaemonPort", "authDaemonMode", "domainId", "subdomain", "fullDomain" FROM 'siteResources';
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
DROP TABLE 'siteResources';
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
ALTER TABLE '__new_siteResources' RENAME TO 'siteResources';
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
CREATE TABLE '__new_targetHealthCheck' (
|
||||||
|
'targetHealthCheckId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
'targetId' integer,
|
||||||
|
'orgId' text NOT NULL,
|
||||||
|
'siteId' integer NOT NULL,
|
||||||
|
'name' text,
|
||||||
|
'hcEnabled' integer DEFAULT false NOT NULL,
|
||||||
|
'hcPath' text,
|
||||||
|
'hcScheme' text,
|
||||||
|
'hcMode' text DEFAULT 'http',
|
||||||
|
'hcHostname' text,
|
||||||
|
'hcPort' integer,
|
||||||
|
'hcInterval' integer DEFAULT 30,
|
||||||
|
'hcUnhealthyInterval' integer DEFAULT 30,
|
||||||
|
'hcTimeout' integer DEFAULT 5,
|
||||||
|
'hcHeaders' text,
|
||||||
|
'hcFollowRedirects' integer DEFAULT true,
|
||||||
|
'hcMethod' text DEFAULT 'GET',
|
||||||
|
'hcStatus' integer,
|
||||||
|
'hcHealth' text DEFAULT 'unknown',
|
||||||
|
'hcTlsServerName' text,
|
||||||
|
'hcHealthyThreshold' integer DEFAULT 1,
|
||||||
|
'hcUnhealthyThreshold' integer DEFAULT 1,
|
||||||
|
FOREIGN KEY ('targetId') REFERENCES 'targets'('targetId') ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY ('siteId') REFERENCES 'sites'('siteId') ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
// INSERT INTO '__new_targetHealthCheck'("targetHealthCheckId", "targetId", "orgId", "siteId", "name", "hcEnabled", "hcPath", "hcScheme", "hcMode", "hcHostname", "hcPort", "hcInterval", "hcUnhealthyInterval", "hcTimeout", "hcHeaders", "hcFollowRedirects", "hcMethod", "hcStatus", "hcHealth", "hcTlsServerName", "hcHealthyThreshold", "hcUnhealthyThreshold") SELECT "targetHealthCheckId", "targetId", "orgId", "siteId", "name", "hcEnabled", "hcPath", "hcScheme", "hcMode", "hcHostname", "hcPort", "hcInterval", "hcUnhealthyInterval", "hcTimeout", "hcHeaders", "hcFollowRedirects", "hcMethod", "hcStatus", "hcHealth", "hcTlsServerName", "hcHealthyThreshold", "hcUnhealthyThreshold" FROM 'targetHealthCheck';
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
DROP TABLE 'targetHealthCheck';
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
ALTER TABLE '__new_targetHealthCheck' RENAME TO 'targetHealthCheck';
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
ALTER TABLE 'subscriptions' ADD 'expiresAt' integer;
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
ALTER TABLE 'subscriptions' ADD 'trial' integer DEFAULT false;
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
ALTER TABLE 'requestAuditLog' ADD 'siteResourceId' integer;
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
ALTER TABLE 'sites' ADD 'networkId' integer REFERENCES networks(networkId);
|
||||||
|
`
|
||||||
|
).run();
|
||||||
|
})();
|
||||||
|
|
||||||
|
db.pragma("foreign_keys = ON");
|
||||||
|
|
||||||
|
// Re-insert targetHealthCheck rows with corrected IDs:
|
||||||
|
// targetHealthCheckId is set to the same integer as targetId (1:1 mapping),
|
||||||
|
// siteId and orgId are populated from the associated target and site.
|
||||||
|
//
|
||||||
|
// Because targetHealthCheckId is AUTOINCREMENT, inserting explicit values is
|
||||||
|
// allowed, but sqlite_sequence must be updated afterwards so future
|
||||||
|
// auto-increments don't reuse or collide with these IDs.
|
||||||
|
if (existingHealthChecks.length > 0) {
|
||||||
|
const insertHealthCheck = db.prepare(
|
||||||
|
`INSERT INTO 'targetHealthCheck' (
|
||||||
|
"targetHealthCheckId",
|
||||||
|
"targetId",
|
||||||
|
"orgId",
|
||||||
|
"siteId",
|
||||||
|
"hcEnabled",
|
||||||
|
"hcPath",
|
||||||
|
"hcScheme",
|
||||||
|
"hcMode",
|
||||||
|
"hcHostname",
|
||||||
|
"hcPort",
|
||||||
|
"hcInterval",
|
||||||
|
"hcUnhealthyInterval",
|
||||||
|
"hcTimeout",
|
||||||
|
"hcHeaders",
|
||||||
|
"hcFollowRedirects",
|
||||||
|
"hcMethod",
|
||||||
|
"hcStatus",
|
||||||
|
"hcHealth",
|
||||||
|
"hcTlsServerName"
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||||
|
);
|
||||||
|
|
||||||
|
const insertAll = db.transaction(() => {
|
||||||
|
for (const hc of existingHealthChecks) {
|
||||||
|
insertHealthCheck.run(
|
||||||
|
hc.targetId, // targetHealthCheckId = targetId (explicit, non-sequential is fine)
|
||||||
|
hc.targetId,
|
||||||
|
hc.orgId,
|
||||||
|
hc.siteId,
|
||||||
|
hc.hcEnabled,
|
||||||
|
hc.hcPath,
|
||||||
|
hc.hcScheme,
|
||||||
|
hc.hcMode,
|
||||||
|
hc.hcHostname,
|
||||||
|
hc.hcPort,
|
||||||
|
hc.hcInterval,
|
||||||
|
hc.hcUnhealthyInterval,
|
||||||
|
hc.hcTimeout,
|
||||||
|
hc.hcHeaders,
|
||||||
|
hc.hcFollowRedirects,
|
||||||
|
hc.hcMethod,
|
||||||
|
hc.hcStatus,
|
||||||
|
hc.hcHealth,
|
||||||
|
hc.hcTlsServerName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
insertAll();
|
||||||
|
|
||||||
|
// Ensure sqlite_sequence reflects the true max so that future
|
||||||
|
// AUTOINCREMENT inserts never reuse one of the explicitly-set IDs.
|
||||||
|
// INSERT OR IGNORE handles the case where no auto-insert has happened
|
||||||
|
// yet and the row doesn't exist in sqlite_sequence.
|
||||||
|
db.prepare(
|
||||||
|
`INSERT OR IGNORE INTO sqlite_sequence (name, seq) VALUES ('targetHealthCheck', 0)`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`UPDATE sqlite_sequence
|
||||||
|
SET seq = MAX(seq, (SELECT COALESCE(MAX("targetHealthCheckId"), 0) FROM 'targetHealthCheck'))
|
||||||
|
WHERE name = 'targetHealthCheck'`
|
||||||
|
).run();
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Migrated ${existingHealthChecks.length} targetHealthCheck row(s) with corrected IDs`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Migrated database`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Failed to migrate db:", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`${version} migration complete`);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user