mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-04 18:14:53 +02:00
sync config managed domains to db
This commit is contained in:
parent
62238948e0
commit
532d3696c2
3 changed files with 106 additions and 39 deletions
|
@ -2,21 +2,23 @@ import { InferSelectModel } from "drizzle-orm";
|
|||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
|
||||
export const domains = sqliteTable("domains", {
|
||||
domainId: integer("domainId").primaryKey({ autoIncrement: true }),
|
||||
baseDomain: text("domain").notNull().unique()
|
||||
domainId: text("domainId").primaryKey(),
|
||||
baseDomain: text("baseDomain").notNull().unique(),
|
||||
configManaged: integer("configManaged", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false)
|
||||
});
|
||||
|
||||
export const orgs = sqliteTable("orgs", {
|
||||
orgId: text("orgId").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
domain: text("domain").notNull()
|
||||
name: text("name").notNull()
|
||||
});
|
||||
|
||||
export const orgDomains = sqliteTable("orgDomains", {
|
||||
orgId: text("orgId")
|
||||
.notNull()
|
||||
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||
domainId: integer("domainId")
|
||||
domainId: text("domainId")
|
||||
.notNull()
|
||||
.references(() => domains.domainId, { onDelete: "cascade" })
|
||||
});
|
||||
|
@ -57,7 +59,7 @@ export const resources = sqliteTable("resources", {
|
|||
name: text("name").notNull(),
|
||||
subdomain: text("subdomain"),
|
||||
fullDomain: text("fullDomain"),
|
||||
domainId: integer("domainId").references(() => domains.domainId, {
|
||||
domainId: text("domainId").references(() => domains.domainId, {
|
||||
onDelete: "set null"
|
||||
}),
|
||||
ssl: integer("ssl", { mode: "boolean" }).notNull().default(false),
|
||||
|
|
|
@ -38,23 +38,12 @@ const configSchema = z.object({
|
|||
save_logs: z.boolean(),
|
||||
log_failed_attempts: z.boolean().optional()
|
||||
}),
|
||||
domains: z
|
||||
.array(
|
||||
z.object({
|
||||
base_domain: hostnameSchema.transform((url) =>
|
||||
url.toLowerCase()
|
||||
)
|
||||
})
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
const baseDomains = data.map((d) => d.base_domain);
|
||||
return new Set(baseDomains).size === baseDomains.length;
|
||||
},
|
||||
{
|
||||
message: "Base domains must be unique"
|
||||
}
|
||||
),
|
||||
domains: z.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
base_domain: hostnameSchema.transform((url) => url.toLowerCase())
|
||||
})
|
||||
),
|
||||
server: z.object({
|
||||
external_port: portSchema
|
||||
.optional()
|
||||
|
|
|
@ -1,40 +1,116 @@
|
|||
import { db } from "@server/db";
|
||||
import { exitNodes, orgs, resources } from "../db/schema";
|
||||
import { domains, exitNodes, orgDomains, orgs, resources } from "../db/schema";
|
||||
import config from "@server/lib/config";
|
||||
import { eq, ne } from "drizzle-orm";
|
||||
import logger from "@server/logger";
|
||||
|
||||
export async function copyInConfig() {
|
||||
const domain = config.getBaseDomain();
|
||||
const endpoint = config.getRawConfig().gerbil.base_endpoint;
|
||||
const listenPort = config.getRawConfig().gerbil.start_port;
|
||||
|
||||
// update the domain on all of the orgs where the domain is not equal to the new domain
|
||||
// TODO: eventually each org could have a unique domain that we do not want to overwrite, so this will be unnecessary
|
||||
await db.update(orgs).set({ domain }).where(ne(orgs.domain, domain));
|
||||
|
||||
// TODO: eventually each exit node could have a different endpoint
|
||||
await db.update(exitNodes).set({ endpoint }).where(ne(exitNodes.endpoint, endpoint));
|
||||
// TODO: eventually each exit node could have a different port
|
||||
await db.update(exitNodes).set({ listenPort }).where(ne(exitNodes.listenPort, listenPort));
|
||||
|
||||
// update all resources fullDomain to use the new domain
|
||||
await db.transaction(async (trx) => {
|
||||
const allResources = await trx.select().from(resources);
|
||||
const rawDomains = config.getRawConfig().domains;
|
||||
|
||||
const configDomains = Object.entries(rawDomains).map(
|
||||
([key, value]) => ({
|
||||
domainId: key,
|
||||
baseDomain: value.base_domain.toLowerCase()
|
||||
})
|
||||
);
|
||||
|
||||
const existingDomains = await trx
|
||||
.select()
|
||||
.from(domains)
|
||||
.where(eq(domains.configManaged, true));
|
||||
const existingDomainKeys = new Set(
|
||||
existingDomains.map((d) => d.domainId)
|
||||
);
|
||||
|
||||
const configDomainKeys = new Set(configDomains.map((d) => d.domainId));
|
||||
for (const existingDomain of existingDomains) {
|
||||
if (!configDomainKeys.has(existingDomain.domainId)) {
|
||||
await trx
|
||||
.delete(domains)
|
||||
.where(eq(domains.domainId, existingDomain.domainId))
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
for (const { domainId, baseDomain } of configDomains) {
|
||||
if (existingDomainKeys.has(domainId)) {
|
||||
await trx
|
||||
.update(domains)
|
||||
.set({ baseDomain })
|
||||
.where(eq(domains.domainId, domainId))
|
||||
.execute();
|
||||
} else {
|
||||
await trx
|
||||
.insert(domains)
|
||||
.values({ domainId, baseDomain, configManaged: true })
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
const allResources = await trx
|
||||
.select()
|
||||
.from(resources)
|
||||
.leftJoin(domains, eq(domains.domainId, resources.domainId));
|
||||
|
||||
for (const { resources: resource, domains: domain } of allResources) {
|
||||
if (!resource || !domain) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!domain.configManaged) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const resource of allResources) {
|
||||
let fullDomain = "";
|
||||
if (resource.isBaseDomain) {
|
||||
fullDomain = domain;
|
||||
fullDomain = domain.baseDomain;
|
||||
} else {
|
||||
fullDomain = `${resource.subdomain}.${domain}`;
|
||||
}
|
||||
|
||||
await trx
|
||||
.update(resources)
|
||||
.set({ fullDomain })
|
||||
.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();
|
||||
}
|
||||
});
|
||||
|
||||
logger.info(`Updated orgs with new domain (${domain})`);
|
||||
// TODO: eventually each exit node could have a different endpoint
|
||||
await db
|
||||
.update(exitNodes)
|
||||
.set({ endpoint })
|
||||
.where(ne(exitNodes.endpoint, endpoint));
|
||||
// TODO: eventually each exit node could have a different port
|
||||
await db
|
||||
.update(exitNodes)
|
||||
.set({ listenPort })
|
||||
.where(ne(exitNodes.listenPort, listenPort));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue