fix(mothership): improve cname/domains migration mangement

This commit is contained in:
Ben Allfree 2025-07-18 18:06:08 -07:00
parent a5fbcb7958
commit 8bbe307191
4 changed files with 186 additions and 61 deletions

View File

@ -26,20 +26,20 @@ const HandleInstanceCreate = (c) => {
const dao = $app.dao(); const dao = $app.dao();
const log = mkLog(`POST:instance`); const log = mkLog(`POST:instance`);
const authRecord = c.get("authRecord"); const authRecord = c.get("authRecord");
log(`***authRecord`, JSON.stringify(authRecord)); log(`authRecord`, JSON.stringify(authRecord));
if (!authRecord) throw new Error(`Expected authRecord here`); if (!authRecord) throw new Error(`Expected authRecord here`);
log(`***TOP OF POST`); log(`TOP OF POST`);
let data = new DynamicModel({ let data = new DynamicModel({
subdomain: "", subdomain: "",
version: versions[0], version: versions[0],
region: "sfo-2" region: "sfo-2"
}); });
log(`***before bind`); log(`before bind`);
c.bind(data); c.bind(data);
log(`***after bind`); log(`after bind`);
data = JSON.parse(JSON.stringify(data)); data = JSON.parse(JSON.stringify(data));
const { subdomain, version, region } = data; const { subdomain, version, region } = data;
log(`***vars`, JSON.stringify({ log(`vars`, JSON.stringify({
subdomain, subdomain,
region region
})); }));
@ -280,36 +280,65 @@ const HandleMigrateCnamesToDomains = (e) => {
return; return;
} }
log(`Found ${instancesWithCnames.length} instances with cnames`); log(`Found ${instancesWithCnames.length} instances with cnames`);
const unmigrated = instancesWithCnames.filter((instance) => { log(`Phase 1: Migrating cnames to domains collection`);
if (!instance) return false; let cnameMigrated = 0;
try { instancesWithCnames.forEach((instance) => {
const existingDomain = dao.findFirstRecordByFilter("domains", `instance = "${instance.getId()}"`);
return !existingDomain;
} catch (e$1) {
return true;
}
});
if (unmigrated.length === 0) {
log(`All cnames already migrated`);
return;
}
log(`Found ${unmigrated.length} cnames to migrate`);
let migrated = 0;
unmigrated.forEach((instance) => {
if (!instance) return; if (!instance) return;
try { try {
const domainsCollection$1 = dao.findCollectionByNameOrId("domains"); const cname = instance.getString("cname");
const domainRecord = new Record(domainsCollection$1); if (!cname) return;
domainRecord.set("instance", instance.getId()); const instanceId = instance.getId();
domainRecord.set("domain", instance.getString("cname")); let domainExists = false;
domainRecord.set("active", instance.getBool("cname_active")); try {
dao.saveRecord(domainRecord); dao.findFirstRecordByFilter("domains", `instance = "${instanceId}" && domain = "${cname}"`);
migrated++; domainExists = true;
} catch (e$1) {}
if (!domainExists) {
const domainsCollection$1 = dao.findCollectionByNameOrId("domains");
const domainRecord = new Record(domainsCollection$1);
domainRecord.set("instance", instanceId);
domainRecord.set("domain", cname);
domainRecord.set("active", instance.getBool("cname_active"));
dao.saveRecord(domainRecord);
log(`Created domain record for ${cname}`);
cnameMigrated++;
}
} catch (error$1) { } catch (error$1) {
log(`Failed to migrate cname for instance ${instance.getId()}:`, error$1); log(`Failed to migrate cname for instance ${instance.getId()}:`, error$1);
} }
}); });
log(`Successfully migrated ${migrated} cnames to domains table`); log(`Phase 1 complete: migrated ${cnameMigrated} cnames to domains collection`);
log(`Phase 2: Syncing domains collection with instances.domains arrays`);
const allDomainRecords = dao.findRecordsByFilter("domains", "1=1");
log(`Found ${allDomainRecords.length} domain records`);
let instancesUpdated = 0;
const domainsByInstance = /* @__PURE__ */ new Map();
allDomainRecords.forEach((domainRecord) => {
if (!domainRecord) return;
const instanceId = domainRecord.getString("instance");
if (!domainsByInstance.has(instanceId)) domainsByInstance.set(instanceId, []);
domainsByInstance.get(instanceId).push(domainRecord.getId());
});
log(`Updating instances.domains arrays`);
domainsByInstance.forEach((domainIds, instanceId) => {
try {
const instance = dao.findRecordById("instances", instanceId);
if (!instance) return;
const currentDomains = instance.get("domains") || [];
log(`Current domains:`, currentDomains);
const missingIds = domainIds.filter((id) => !currentDomains.includes(id));
if (missingIds.length > 0) {
const updatedDomains = [...currentDomains, ...missingIds];
instance.set("domains", updatedDomains);
dao.saveRecord(instance);
log(`Updated instance ${instanceId}: added ${missingIds.length} domain IDs to domains array`);
instancesUpdated++;
}
} catch (error$1) {
log(`Failed to update domains array for instance ${instanceId}:`, error$1);
}
});
log(`Phase 2 complete: updated domains arrays for ${instancesUpdated} instances`);
} catch (error$1) { } catch (error$1) {
log(`Error migrating cnames: ${error$1}`); log(`Error migrating cnames: ${error$1}`);
} }
@ -350,8 +379,10 @@ const HandleMigrateInstanceVersions = (e) => {
/** Migrate version numbers */ /** Migrate version numbers */
const HandleMigrateRegions = (e) => { const HandleMigrateRegions = (e) => {
const dao = $app.dao(); const dao = $app.dao();
console.log(`***Migrating regions`); const log = mkLog(`HandleMigrateRegions`);
log(`Migrating regions`);
dao.db().newQuery(`update instances set region='sfo-1' where region=''`).execute(); dao.db().newQuery(`update instances set region='sfo-1' where region=''`).execute();
log(`Migrated regions`);
}; };
//#endregion //#endregion
@ -654,7 +685,7 @@ const HandleMailSend = (c) => {
const HandleMetaUpdateAtBoot = (c) => { const HandleMetaUpdateAtBoot = (c) => {
const log = mkLog("HandleMetaUpdateAtBoot"); const log = mkLog("HandleMetaUpdateAtBoot");
log(`At top of HandleMetaUpdateAtBoot`); log(`At top of HandleMetaUpdateAtBoot`);
log(`***app URL`, process.env.APP_URL); log(`app URL`, process.env.APP_URL);
const form = new SettingsUpsertForm($app); const form = new SettingsUpsertForm($app);
form.meta = { form.meta = {
...$app.settings().meta, ...$app.settings().meta,

View File

@ -0,0 +1,18 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((db) => {
const dao = new Dao(db)
const collection = dao.findCollectionByNameOrId("jw1wz9nmkvnhcm6")
collection.listRule = "@request.auth.id=instance.uid"
collection.viewRule = "@request.auth.id=instance.uid"
return dao.saveCollection(collection)
}, (db) => {
const dao = new Dao(db)
const collection = dao.findCollectionByNameOrId("jw1wz9nmkvnhcm6")
collection.listRule = null
collection.viewRule = null
return dao.saveCollection(collection)
})

View File

@ -0,0 +1,33 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((db) => {
const dao = new Dao(db)
const collection = dao.findCollectionByNameOrId("etae8tuiaxl6xfv")
// add
collection.schema.addField(new SchemaField({
"system": false,
"id": "smblegnt",
"name": "domains",
"type": "relation",
"required": false,
"presentable": false,
"unique": false,
"options": {
"collectionId": "jw1wz9nmkvnhcm6",
"cascadeDelete": false,
"minSelect": null,
"maxSelect": null,
"displayFields": null
}
}))
return dao.saveCollection(collection)
}, (db) => {
const dao = new Dao(db)
const collection = dao.findCollectionByNameOrId("etae8tuiaxl6xfv")
// remove
collection.schema.removeField("smblegnt")
return dao.saveCollection(collection)
})

View File

@ -25,45 +25,88 @@ export const HandleMigrateCnamesToDomains = (e: core.BootstrapEvent) => {
log(`Found ${instancesWithCnames.length} instances with cnames`) log(`Found ${instancesWithCnames.length} instances with cnames`)
// Check which ones are already migrated // Phase 1: Migrate cnames to domains collection
const unmigrated = instancesWithCnames.filter((instance) => { log(`Phase 1: Migrating cnames to domains collection`)
if (!instance) return false let cnameMigrated = 0
try { instancesWithCnames.forEach((instance) => {
const existingDomain = dao.findFirstRecordByFilter('domains', `instance = "${instance.getId()}"`)
return !existingDomain
} catch (e) {
// Not found means not migrated
return true
}
})
if (unmigrated.length === 0) {
log(`All cnames already migrated`)
return
}
log(`Found ${unmigrated.length} cnames to migrate`)
// Migrate cnames to domains table
let migrated = 0
unmigrated.forEach((instance) => {
if (!instance) return if (!instance) return
try { try {
const domainsCollection = dao.findCollectionByNameOrId('domains') const cname = instance.getString('cname')
const domainRecord = new Record(domainsCollection) if (!cname) return
domainRecord.set('instance', instance.getId()) const instanceId = instance.getId()
domainRecord.set('domain', instance.getString('cname'))
domainRecord.set('active', instance.getBool('cname_active'))
dao.saveRecord(domainRecord) // Check if domain record already exists
migrated++ let domainExists = false
try {
dao.findFirstRecordByFilter('domains', `instance = "${instanceId}" && domain = "${cname}"`)
domainExists = true
} catch (e) {
// Domain record doesn't exist
}
if (!domainExists) {
const domainsCollection = dao.findCollectionByNameOrId('domains')
const domainRecord = new Record(domainsCollection)
domainRecord.set('instance', instanceId)
domainRecord.set('domain', cname)
domainRecord.set('active', instance.getBool('cname_active'))
dao.saveRecord(domainRecord)
log(`Created domain record for ${cname}`)
cnameMigrated++
}
} catch (error) { } catch (error) {
log(`Failed to migrate cname for instance ${instance.getId()}:`, error) log(`Failed to migrate cname for instance ${instance.getId()}:`, error)
} }
}) })
log(`Successfully migrated ${migrated} cnames to domains table`) log(`Phase 1 complete: migrated ${cnameMigrated} cnames to domains collection`)
// Phase 2: Sync all domain records with instances.domains arrays
log(`Phase 2: Syncing domains collection with instances.domains arrays`)
const allDomainRecords = dao.findRecordsByFilter('domains', '1=1')
log(`Found ${allDomainRecords.length} domain records`)
let instancesUpdated = 0
// Group domains by instance for efficiency
const domainsByInstance = new Map()
allDomainRecords.forEach((domainRecord) => {
if (!domainRecord) return
const instanceId = domainRecord.getString('instance')
if (!domainsByInstance.has(instanceId)) {
domainsByInstance.set(instanceId, [])
}
domainsByInstance.get(instanceId).push(domainRecord.getId())
})
// Update each instance's domains array
log(`Updating instances.domains arrays`)
domainsByInstance.forEach((domainIds, instanceId) => {
try {
const instance = dao.findRecordById('instances', instanceId)
if (!instance) return
const currentDomains = instance.get('domains') || []
log(`Current domains:`, currentDomains)
const missingIds = domainIds.filter((id: string) => !currentDomains.includes(id))
if (missingIds.length > 0) {
const updatedDomains = [...currentDomains, ...missingIds]
instance.set('domains', updatedDomains)
dao.saveRecord(instance)
log(`Updated instance ${instanceId}: added ${missingIds.length} domain IDs to domains array`)
instancesUpdated++
}
} catch (error) {
log(`Failed to update domains array for instance ${instanceId}:`, error)
}
})
log(`Phase 2 complete: updated domains arrays for ${instancesUpdated} instances`)
} catch (error) { } catch (error) {
log(`Error migrating cnames: ${error}`) log(`Error migrating cnames: ${error}`)
} }