mirror of
https://github.com/fosrl/pangolin.git
synced 2025-07-22 19:55:37 +02:00
adjustments to migration after testing
This commit is contained in:
parent
e4789c6b08
commit
de70c62ea8
5 changed files with 139 additions and 62 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue