68 lines
4.3 KiB
TypeScript
68 lines
4.3 KiB
TypeScript
import type Database from 'better-sqlite3';
|
|
|
|
export function migrateNativeInstances(handle: Database.Database): void {
|
|
migrateUnplacedCreationPort(handle);
|
|
handle.exec(`
|
|
CREATE TABLE IF NOT EXISTS native_creation_intents (
|
|
deployment_id TEXT PRIMARY KEY REFERENCES server_deployments(id) ON DELETE CASCADE,
|
|
selection TEXT NOT NULL
|
|
);
|
|
CREATE TABLE IF NOT EXISTS native_instances (
|
|
id TEXT PRIMARY KEY, server TEXT NOT NULL, host_id TEXT NOT NULL,
|
|
generation INTEGER NOT NULL DEFAULT 1, library_id TEXT NOT NULL,
|
|
image TEXT NOT NULL, bind_address TEXT NOT NULL DEFAULT '0.0.0.0',
|
|
port INTEGER NOT NULL, public_address TEXT, public_port INTEGER,
|
|
created_at TEXT NOT NULL, retired_at TEXT
|
|
);
|
|
CREATE INDEX IF NOT EXISTS native_instance_host ON native_instances(host_id) WHERE retired_at IS NULL;
|
|
CREATE UNIQUE INDEX IF NOT EXISTS native_instance_live_name ON native_instances(server) WHERE retired_at IS NULL;
|
|
CREATE TABLE IF NOT EXISTS native_provisioning (
|
|
deployment_id TEXT PRIMARY KEY REFERENCES server_deployments(id),
|
|
instance_id TEXT NOT NULL REFERENCES native_instances(id), generation INTEGER NOT NULL,
|
|
stage_operation_id TEXT, operation_id TEXT, files_json TEXT,
|
|
applied_at TEXT, verified_at TEXT
|
|
);
|
|
CREATE INDEX IF NOT EXISTS native_provisioning_instance ON native_provisioning(instance_id);
|
|
CREATE TABLE IF NOT EXISTS provisioning_safety_overrides (
|
|
deployment_id TEXT PRIMARY KEY REFERENCES server_deployments(id) ON DELETE CASCADE,
|
|
actor_id TEXT NOT NULL, actor_name TEXT NOT NULL, confirmed_at TEXT NOT NULL
|
|
);
|
|
CREATE TABLE IF NOT EXISTS ec_host_migrations (
|
|
deployment_id TEXT PRIMARY KEY REFERENCES server_deployments(id),
|
|
source_host_id TEXT NOT NULL, instance_id TEXT NOT NULL REFERENCES native_instances(id),
|
|
target_host_id TEXT, target_port INTEGER, target_bind TEXT,
|
|
remove_operation_id TEXT, removed_at TEXT
|
|
);
|
|
CREATE INDEX IF NOT EXISTS ec_host_migrations_source ON ec_host_migrations(source_host_id);
|
|
CREATE INDEX IF NOT EXISTS ec_host_migrations_target ON ec_host_migrations(target_host_id);
|
|
CREATE TABLE IF NOT EXISTS native_creation_cancellations (
|
|
creation_id TEXT PRIMARY KEY REFERENCES server_deployments(id),
|
|
cleanup_id TEXT NOT NULL UNIQUE REFERENCES server_deployments(id)
|
|
);
|
|
`);
|
|
}
|
|
|
|
/** Accepted native creations receive their host port only when provisioning places them. */
|
|
function migrateUnplacedCreationPort(handle: Database.Database): void {
|
|
const columns = handle.prepare('PRAGMA table_info(server_creation_jobs)').all() as { name: string; notnull: number }[];
|
|
if (!columns.find(column => column.name === 'port')?.notnull) return;
|
|
const { sql } = handle.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='server_creation_jobs'").get() as { sql: string };
|
|
const replacement = sql.replace(/\bport\s+INTEGER\s+NOT\s+NULL\b/i, 'port INTEGER');
|
|
if (replacement === sql) throw new Error('Could not migrate unplaced creation ports.');
|
|
const dependent = handle.prepare("SELECT sql FROM sqlite_master WHERE tbl_name='server_creation_jobs' AND type IN ('index','trigger') AND sql IS NOT NULL")
|
|
.all() as { sql: string }[];
|
|
const foreignKeys = handle.pragma('foreign_keys', { simple: true });
|
|
handle.pragma('foreign_keys = OFF');
|
|
try {
|
|
handle.transaction(() => {
|
|
handle.exec(replacement.replace('server_creation_jobs', 'server_creation_jobs_unplaced'));
|
|
const names = columns.map(column => `"${column.name.replaceAll('"', '""')}"`).join(', ');
|
|
handle.exec(`INSERT INTO server_creation_jobs_unplaced(rowid,${names}) SELECT rowid,${names} FROM server_creation_jobs;
|
|
DROP TABLE server_creation_jobs;
|
|
ALTER TABLE server_creation_jobs_unplaced RENAME TO server_creation_jobs;`);
|
|
for (const object of dependent) handle.exec(object.sql);
|
|
if ((handle.pragma('foreign_key_check') as unknown[]).length) throw new Error('Unplaced creation migration found broken references.');
|
|
})();
|
|
} finally { handle.pragma(`foreign_keys = ${foreignKeys ? 'ON' : 'OFF'}`); }
|
|
}
|