A simple command-line tool to start NetBSD virtual machines using QEMU with sensible defaults.
at main 299 lines 9.6 kB view raw
1import { 2 type Kysely, 3 type Migration, 4 type MigrationProvider, 5 Migrator, 6 sql, 7} from "kysely"; 8import type { Database } from "./db.ts"; 9 10const migrations: Record<string, Migration> = {}; 11 12const migrationProvider: MigrationProvider = { 13 // deno-lint-ignore require-await 14 async getMigrations() { 15 return migrations; 16 }, 17}; 18 19migrations["001"] = { 20 async up(db: Kysely<unknown>): Promise<void> { 21 await db.schema 22 .createTable("virtual_machines") 23 .addColumn("id", "varchar", (col) => col.primaryKey()) 24 .addColumn("name", "varchar", (col) => col.notNull().unique()) 25 .addColumn("bridge", "varchar") 26 .addColumn("macAddress", "varchar", (col) => col.notNull().unique()) 27 .addColumn("memory", "varchar", (col) => col.notNull()) 28 .addColumn("cpus", "integer", (col) => col.notNull()) 29 .addColumn("cpu", "varchar", (col) => col.notNull()) 30 .addColumn("diskSize", "varchar", (col) => col.notNull()) 31 .addColumn("drivePath", "varchar") 32 .addColumn("version", "varchar", (col) => col.notNull()) 33 .addColumn("diskFormat", "varchar") 34 .addColumn("isoPath", "varchar") 35 .addColumn("status", "varchar", (col) => col.notNull()) 36 .addColumn("pid", "integer") 37 .addColumn( 38 "createdAt", 39 "varchar", 40 (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), 41 ) 42 .addColumn( 43 "updatedAt", 44 "varchar", 45 (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), 46 ) 47 .execute(); 48 }, 49 50 async down(db: Kysely<unknown>): Promise<void> { 51 await db.schema.dropTable("virtual_machines").execute(); 52 }, 53}; 54 55migrations["002"] = { 56 async up(db: Kysely<unknown>): Promise<void> { 57 await db.schema 58 .alterTable("virtual_machines") 59 .addColumn("portForward", "varchar") 60 .execute(); 61 }, 62 63 async down(db: Kysely<unknown>): Promise<void> { 64 await db.schema 65 .alterTable("virtual_machines") 66 .dropColumn("portForward") 67 .execute(); 68 }, 69}; 70 71migrations["003"] = { 72 async up(db: Kysely<unknown>): Promise<void> { 73 await db.schema 74 .createTable("images") 75 .addColumn("id", "varchar", (col) => col.primaryKey()) 76 .addColumn("repository", "varchar", (col) => col.notNull()) 77 .addColumn("tag", "varchar", (col) => col.notNull()) 78 .addColumn("size", "integer", (col) => col.notNull()) 79 .addColumn("path", "varchar", (col) => col.notNull()) 80 .addColumn("createdAt", "varchar", (col) => col.notNull()) 81 .execute(); 82 }, 83 84 async down(db: Kysely<unknown>): Promise<void> { 85 await db.schema.dropTable("images").execute(); 86 }, 87}; 88 89migrations["004"] = { 90 async up(db: Kysely<unknown>): Promise<void> { 91 await db.schema 92 .alterTable("images") 93 .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) 94 .execute(); 95 }, 96 97 async down(db: Kysely<unknown>): Promise<void> { 98 await db.schema 99 .alterTable("images") 100 .dropColumn("format") 101 .execute(); 102 }, 103}; 104 105migrations["005"] = { 106 async up(db: Kysely<unknown>): Promise<void> { 107 await db.schema 108 .createTable("images_new") 109 .addColumn("id", "varchar", (col) => col.primaryKey()) 110 .addColumn("repository", "varchar", (col) => col.notNull()) 111 .addColumn("tag", "varchar", (col) => col.notNull()) 112 .addColumn("size", "integer", (col) => col.notNull()) 113 .addColumn("path", "varchar", (col) => col.notNull()) 114 .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) 115 .addColumn("createdAt", "varchar", (col) => col.notNull()) 116 .addUniqueConstraint("images_repository_tag_unique", [ 117 "repository", 118 "tag", 119 ]) 120 .execute(); 121 122 await sql` 123 INSERT INTO images_new (id, repository, tag, size, path, format, createdAt) 124 SELECT id, repository, tag, size, path, format, createdAt FROM images 125 `.execute(db); 126 127 await db.schema.dropTable("images").execute(); 128 await sql`ALTER TABLE images_new RENAME TO images`.execute(db); 129 }, 130 131 async down(db: Kysely<unknown>): Promise<void> { 132 await db.schema 133 .createTable("images_old") 134 .addColumn("id", "varchar", (col) => col.primaryKey()) 135 .addColumn("repository", "varchar", (col) => col.notNull()) 136 .addColumn("tag", "varchar", (col) => col.notNull()) 137 .addColumn("size", "integer", (col) => col.notNull()) 138 .addColumn("path", "varchar", (col) => col.notNull()) 139 .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) 140 .addColumn("createdAt", "varchar", (col) => col.notNull()) 141 .execute(); 142 143 await sql` 144 INSERT INTO images_old (id, repository, tag, size, path, format, createdAt) 145 SELECT id, repository, tag, size, path, format, createdAt FROM images 146 `.execute(db); 147 148 await db.schema.dropTable("images").execute(); 149 await sql`ALTER TABLE images_old RENAME TO images`.execute(db); 150 }, 151}; 152 153migrations["006"] = { 154 async up(db: Kysely<unknown>): Promise<void> { 155 await db.schema 156 .createTable("images_new") 157 .addColumn("id", "varchar", (col) => col.primaryKey()) 158 .addColumn("repository", "varchar", (col) => col.notNull()) 159 .addColumn("tag", "varchar", (col) => col.notNull()) 160 .addColumn("size", "integer", (col) => col.notNull()) 161 .addColumn("path", "varchar", (col) => col.notNull()) 162 .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) 163 .addColumn( 164 "createdAt", 165 "varchar", 166 (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), 167 ) 168 .addUniqueConstraint("images_repository_tag_unique", [ 169 "repository", 170 "tag", 171 ]) 172 .execute(); 173 174 await sql` 175 INSERT INTO images_new (id, repository, tag, size, path, format, createdAt) 176 SELECT id, repository, tag, size, path, format, createdAt FROM images 177 `.execute(db); 178 179 await db.schema.dropTable("images").execute(); 180 await sql`ALTER TABLE images_new RENAME TO images`.execute(db); 181 }, 182 183 async down(db: Kysely<unknown>): Promise<void> { 184 await db.schema 185 .createTable("images_old") 186 .addColumn("id", "varchar", (col) => col.primaryKey()) 187 .addColumn("repository", "varchar", (col) => col.notNull()) 188 .addColumn("tag", "varchar", (col) => col.notNull()) 189 .addColumn("size", "integer", (col) => col.notNull()) 190 .addColumn("path", "varchar", (col) => col.notNull()) 191 .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) 192 .addColumn("createdAt", "varchar", (col) => col.notNull()) 193 .addUniqueConstraint("images_repository_tag_unique", [ 194 "repository", 195 "tag", 196 ]) 197 .execute(); 198 199 await sql` 200 INSERT INTO images_old (id, repository, tag, size, path, format, createdAt) 201 SELECT id, repository, tag, size, path, format, createdAt FROM images 202 `.execute(db); 203 }, 204}; 205 206migrations["007"] = { 207 async up(db: Kysely<unknown>): Promise<void> { 208 await db.schema 209 .alterTable("images") 210 .addColumn("digest", "varchar") 211 .execute(); 212 }, 213 async down(db: Kysely<unknown>): Promise<void> { 214 await db.schema 215 .alterTable("images") 216 .dropColumn("digest") 217 .execute(); 218 }, 219}; 220 221migrations["008"] = { 222 async up(db: Kysely<unknown>): Promise<void> { 223 await db.schema 224 .createTable("volumes") 225 .addColumn("id", "varchar", (col) => col.primaryKey()) 226 .addColumn("name", "varchar", (col) => col.notNull().unique()) 227 .addColumn( 228 "baseImageId", 229 "varchar", 230 (col) => col.notNull().references("images.id").onDelete("cascade"), 231 ) 232 .addColumn("path", "varchar", (col) => col.notNull()) 233 .addColumn( 234 "createdAt", 235 "varchar", 236 (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), 237 ) 238 .execute(); 239 }, 240 241 async down(db: Kysely<unknown>): Promise<void> { 242 await db.schema.dropTable("volumes").execute(); 243 }, 244}; 245 246migrations["009"] = { 247 async up(db: Kysely<unknown>): Promise<void> { 248 await db.schema 249 .createTable("volumes_new") 250 .addColumn("id", "varchar", (col) => col.primaryKey()) 251 .addColumn("name", "varchar", (col) => col.notNull().unique()) 252 .addColumn( 253 "baseImageId", 254 "varchar", 255 (col) => col.notNull().references("images.id").onDelete("cascade"), 256 ) 257 .addColumn("path", "varchar", (col) => col.notNull()) 258 .addColumn( 259 "createdAt", 260 "varchar", 261 (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), 262 ) 263 .execute(); 264 265 await sql` 266 INSERT INTO volumes_new (id, name, baseImageId, path, createdAt) 267 SELECT id, name, baseImageId, path, createdAt FROM volumes 268 `.execute(db); 269 270 await db.schema.dropTable("volumes").execute(); 271 await sql`ALTER TABLE volumes_new RENAME TO volumes`.execute(db); 272 }, 273 274 async down(db: Kysely<unknown>): Promise<void> { 275 await db.schema.dropTable("volumes").execute(); 276 }, 277}; 278 279migrations["010"] = { 280 async up(db: Kysely<unknown>): Promise<void> { 281 await db.schema 282 .alterTable("virtual_machines") 283 .addColumn("volume", "varchar") 284 .execute(); 285 }, 286 287 async down(db: Kysely<unknown>): Promise<void> { 288 await db.schema 289 .alterTable("virtual_machines") 290 .dropColumn("volume") 291 .execute(); 292 }, 293}; 294 295export const migrateToLatest = async (db: Database): Promise<void> => { 296 const migrator = new Migrator({ db, provider: migrationProvider }); 297 const { error } = await migrator.migrateToLatest(); 298 if (error) throw error; 299};