A simple command-line tool to start NetBSD virtual machines using QEMU with sensible defaults.
at main 101 lines 2.6 kB view raw
1import { Table } from "@cliffy/table"; 2import dayjs from "dayjs"; 3import relativeTime from "dayjs/plugin/relativeTime.js"; 4import utc from "dayjs/plugin/utc.js"; 5import { Data, Effect, pipe } from "effect"; 6import { ctx } from "../context.ts"; 7import type { VirtualMachine } from "../db.ts"; 8 9dayjs.extend(relativeTime); 10dayjs.extend(utc); 11 12class DbQueryError extends Data.TaggedError("DbQueryError")<{ 13 cause?: unknown; 14}> {} 15 16const fetchVMs = (all: boolean) => 17 Effect.tryPromise({ 18 try: () => 19 ctx.db.selectFrom("virtual_machines") 20 .selectAll() 21 .where((eb) => { 22 if (all) { 23 return eb("id", "!=", ""); 24 } 25 return eb("status", "=", "RUNNING"); 26 }) 27 .execute(), 28 catch: (error) => new DbQueryError({ cause: error }), 29 }); 30 31const createTable = () => 32 Effect.succeed( 33 new Table( 34 ["NAME", "VCPU", "MEMORY", "STATUS", "PID", "BRIDGE", "PORTS", "CREATED"], 35 ), 36 ); 37 38const populateTable = (table: Table, vms: VirtualMachine[]) => 39 Effect.sync(() => { 40 for (const vm of vms) { 41 table.push([ 42 vm.name, 43 vm.cpus.toString(), 44 vm.memory, 45 formatStatus(vm), 46 vm.pid?.toString() ?? "-", 47 vm.bridge ?? "-", 48 formatPorts(vm.portForward), 49 dayjs.utc(vm.createdAt).local().fromNow(), 50 ]); 51 } 52 return table; 53 }); 54 55const displayTable = (table: Table) => 56 Effect.sync(() => { 57 console.log(table.padding(2).toString()); 58 }); 59 60const handleError = (error: DbQueryError | Error) => 61 Effect.sync(() => { 62 console.error(`Failed to fetch virtual machines: ${error}`); 63 Deno.exit(1); 64 }); 65 66const psEffect = (all: boolean) => 67 pipe( 68 Effect.all([fetchVMs(all), createTable()]), 69 Effect.flatMap(([vms, table]) => populateTable(table, vms)), 70 Effect.flatMap(displayTable), 71 Effect.catchAll(handleError), 72 ); 73 74export default async function (all: boolean) { 75 await Effect.runPromise(psEffect(all)); 76} 77 78function formatStatus(vm: VirtualMachine) { 79 switch (vm.status) { 80 case "RUNNING": 81 return `Up ${ 82 dayjs.utc(vm.updatedAt).local().fromNow().replace("ago", "") 83 }`; 84 case "STOPPED": 85 return `Exited ${dayjs.utc(vm.updatedAt).local().fromNow()}`; 86 default: 87 return vm.status; 88 } 89} 90 91function formatPorts(portForward?: string) { 92 if (!portForward) { 93 return "-"; 94 } 95 96 const mappings = portForward.split(","); 97 return mappings.map((mapping) => { 98 const [hostPort, guestPort] = mapping.split(":"); 99 return `${hostPort}->${guestPort}`; 100 }).join(", "); 101}