adjustments to migration after testing

This commit is contained in:
miloschwartz 2025-02-25 22:58:52 -05:00
parent e4789c6b08
commit de70c62ea8
No known key found for this signature in database
5 changed files with 139 additions and 62 deletions

View file

@ -38,14 +38,45 @@ const configSchema = z.object({
save_logs: z.boolean(), save_logs: z.boolean(),
log_failed_attempts: z.boolean().optional() log_failed_attempts: z.boolean().optional()
}), }),
domains: z.record( domains: z
z.string(), .record(
z.object({ z.string(),
base_domain: hostnameSchema.transform((url) => url.toLowerCase()), z.object({
cert_resolver: z.string().optional(), base_domain: hostnameSchema.transform((url) =>
prefer_wildcard_cert: z.boolean().optional() url.toLowerCase()
}) ),
), cert_resolver: z.string().optional(),
prefer_wildcard_cert: z.boolean().optional()
})
)
.refine(
(domains) => {
const keys = Object.keys(domains);
if (keys.length === 0) {
return false;
}
return true;
},
{
message: "At least one domain must be defined"
}
)
.refine(
(domains) => {
const envBaseDomain = process.env.APP_BASE_DOMAIN;
if (envBaseDomain) {
return hostnameSchema.safeParse(envBaseDomain).success;
}
return true;
},
{
message: "APP_BASE_DOMAIN must be a valid hostname"
}
),
server: z.object({ server: z.object({
external_port: portSchema external_port: portSchema
.optional() .optional()
@ -169,8 +200,6 @@ export class Config {
} }
} }
public loadEnvironment() {}
public loadConfig() { public loadConfig() {
const loadConfig = (configPath: string) => { const loadConfig = (configPath: string) => {
try { try {
@ -277,6 +306,17 @@ export class Config {
: "false"; : "false";
process.env.DASHBOARD_URL = parsedConfig.data.app.dashboard_url; process.env.DASHBOARD_URL = parsedConfig.data.app.dashboard_url;
if (process.env.APP_BASE_DOMAIN) {
console.log(
`DEPRECATED! APP_BASE_DOMAIN is deprecated and will be removed in a future release. Use the domains section in the configuration file instead. See https://docs.fossorial.io/Pangolin/Configuration/config for more information.`
);
parsedConfig.data.domains.domain1 = {
base_domain: process.env.APP_BASE_DOMAIN,
cert_resolver: "letsencrypt"
};
}
this.rawConfig = parsedConfig.data; this.rawConfig = parsedConfig.data;
} }

View file

@ -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.0.0-beta.13"; export const APP_VERSION = "1.0.0-beta.15";
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);

View file

@ -51,6 +51,32 @@ export async function copyInConfig() {
} }
} }
const allOrgs = await trx.select().from(orgs);
const existingOrgDomains = await trx.select().from(orgDomains);
const existingOrgDomainSet = new Set(
existingOrgDomains.map((od) => `${od.orgId}-${od.domainId}`)
);
const newOrgDomains = [];
for (const org of allOrgs) {
for (const domain of configDomains) {
const key = `${org.orgId}-${domain.domainId}`;
if (!existingOrgDomainSet.has(key)) {
newOrgDomains.push({
orgId: org.orgId,
domainId: domain.domainId
});
}
}
}
if (newOrgDomains.length > 0) {
await trx.insert(orgDomains).values(newOrgDomains).execute();
}
});
await db.transaction(async (trx) => {
const allResources = await trx const allResources = await trx
.select() .select()
.from(resources) .from(resources)
@ -77,30 +103,6 @@ export async function copyInConfig() {
.set({ fullDomain }) .set({ fullDomain })
.where(eq(resources.resourceId, resource.resourceId)); .where(eq(resources.resourceId, resource.resourceId));
} }
const allOrgs = await trx.select().from(orgs);
const existingOrgDomains = await trx.select().from(orgDomains);
const existingOrgDomainSet = new Set(
existingOrgDomains.map((od) => `${od.orgId}-${od.domainId}`)
);
const newOrgDomains = [];
for (const org of allOrgs) {
for (const domain of configDomains) {
const key = `${org.orgId}-${domain.domainId}`;
if (!existingOrgDomainSet.has(key)) {
newOrgDomains.push({
orgId: org.orgId,
domainId: domain.domainId
});
}
}
}
if (newOrgDomains.length > 0) {
await trx.insert(orgDomains).values(newOrgDomains).execute();
}
}); });
// TODO: eventually each exit node could have a different endpoint // TODO: eventually each exit node could have a different endpoint

View file

@ -15,6 +15,7 @@ import m6 from "./scripts/1.0.0-beta9";
import m7 from "./scripts/1.0.0-beta10"; import m7 from "./scripts/1.0.0-beta10";
import m8 from "./scripts/1.0.0-beta12"; import m8 from "./scripts/1.0.0-beta12";
import m13 from "./scripts/1.0.0-beta13"; import m13 from "./scripts/1.0.0-beta13";
import m15 from "./scripts/1.0.0-beta15";
// 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
@ -29,7 +30,8 @@ const migrations = [
{ version: "1.0.0-beta.9", run: m6 }, { version: "1.0.0-beta.9", run: m6 },
{ version: "1.0.0-beta.10", run: m7 }, { version: "1.0.0-beta.10", run: m7 },
{ version: "1.0.0-beta.12", run: m8 }, { version: "1.0.0-beta.12", run: m8 },
{ version: "1.0.0-beta.13", run: m13 } { version: "1.0.0-beta.13", run: m13 },
{ version: "1.0.0-beta.15", run: m15 }
// Add new migrations here as they are created // Add new migrations here as they are created
] as const; ] as const;

View file

@ -3,38 +3,14 @@ import { configFilePath1, configFilePath2 } from "@server/lib/consts";
import fs from "fs"; import fs from "fs";
import yaml from "js-yaml"; import yaml from "js-yaml";
import { sql } from "drizzle-orm"; import { sql } from "drizzle-orm";
import { domains, orgDomains, resources } from "@server/db/schema";
const version = "1.0.0-beta.15"; const version = "1.0.0-beta.15";
export default async function migration() { export default async function migration() {
console.log(`Running setup script ${version}...`); console.log(`Running setup script ${version}...`);
try { let domain = "";
db.transaction((trx) => {
trx.run(sql`CREATE TABLE 'domains' (
'domainId' text PRIMARY KEY NOT NULL,
'baseDomain' text NOT NULL,
'configManaged' integer DEFAULT false NOT NULL
);`);
trx.run(sql`CREATE TABLE 'orgDomains' (
'orgId' text NOT NULL,
'domainId' text NOT NULL,
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('domainId') REFERENCES 'domains'('domainId') ON UPDATE no action ON DELETE cascade
);`);
trx.run(
sql`ALTER TABLE 'resources' ADD 'domainId' text REFERENCES domains(domainId);`
);
trx.run(sql`ALTER TABLE 'orgs' DROP COLUMN 'domain';`);
});
console.log(`Migrated database schema`);
} catch (e) {
console.log("Unable to migrate database schema");
throw e;
}
try { try {
// Determine which config file exists // Determine which config file exists
@ -84,11 +60,68 @@ export default async function migration() {
const updatedYaml = yaml.dump(rawConfig); const updatedYaml = yaml.dump(rawConfig);
fs.writeFileSync(filePath, updatedYaml, "utf8"); fs.writeFileSync(filePath, updatedYaml, "utf8");
domain = baseDomain;
console.log(`Moved base_domain to new domains section`); console.log(`Moved base_domain to new domains section`);
} catch (e) { } catch (e) {
console.log( console.log(
`Unable to migrate config file and move base_domain to domains. Error: ${e}` `Unable to migrate config file and move base_domain to domains. Error: ${e}`
); );
throw e;
}
try {
db.transaction((trx) => {
trx.run(sql`CREATE TABLE 'domains' (
'domainId' text PRIMARY KEY NOT NULL,
'baseDomain' text NOT NULL,
'configManaged' integer DEFAULT false NOT NULL
);`);
trx.run(sql`CREATE TABLE 'orgDomains' (
'orgId' text NOT NULL,
'domainId' text NOT NULL,
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('domainId') REFERENCES 'domains'('domainId') ON UPDATE no action ON DELETE cascade
);`);
trx.run(
sql`ALTER TABLE 'resources' ADD 'domainId' text REFERENCES domains(domainId);`
);
trx.run(sql`ALTER TABLE 'orgs' DROP COLUMN 'domain';`);
});
console.log(`Migrated database schema`);
} catch (e) {
console.log("Unable to migrate database schema");
throw e;
}
try {
await db.transaction(async (trx) => {
await trx
.insert(domains)
.values({
domainId: "domain1",
baseDomain: domain,
configManaged: true
})
.execute();
await trx.update(resources).set({ domainId: "domain1" });
const existingOrgDomains = await trx.select().from(orgDomains);
for (const orgDomain of existingOrgDomains) {
await trx
.insert(orgDomains)
.values({ orgId: orgDomain.orgId, domainId: "domain1" })
.execute();
}
});
console.log(`Updated resources table with new domainId`);
} catch (e) {
console.log(
`Unable to update resources table with new domainId. Error: ${e}`
);
return; return;
} }