A simple CLI tool to spin up OpenBSD virtual machines using QEMU with minimal fuss.

Enhance VM start command with additional options for CPU, memory, disk format, and networking; integrate flag parsing for improved configuration

+60 -3
+1
deno.json
··· 8 8 }, 9 9 "imports": { 10 10 "@cliffy/command": "jsr:@cliffy/command@^1.0.0-rc.8", 11 + "@cliffy/flags": "jsr:@cliffy/flags@^1.0.0-rc.8", 11 12 "@cliffy/table": "jsr:@cliffy/table@^1.0.0-rc.8", 12 13 "@db/sqlite": "jsr:@db/sqlite@^0.12.0", 13 14 "@paralleldrive/cuid2": "npm:@paralleldrive/cuid2@^3.0.4",
+3 -1
deno.lock
··· 3 3 "specifiers": { 4 4 "jsr:@cliffy/command@^1.0.0-rc.8": "1.0.0-rc.8", 5 5 "jsr:@cliffy/flags@1.0.0-rc.8": "1.0.0-rc.8", 6 + "jsr:@cliffy/flags@^1.0.0-rc.8": "1.0.0-rc.8", 6 7 "jsr:@cliffy/internal@1.0.0-rc.8": "1.0.0-rc.8", 7 8 "jsr:@cliffy/table@1.0.0-rc.8": "1.0.0-rc.8", 8 9 "jsr:@cliffy/table@^1.0.0-rc.8": "1.0.0-rc.8", ··· 34 35 "@cliffy/command@1.0.0-rc.8": { 35 36 "integrity": "758147790797c74a707e5294cc7285df665422a13d2a483437092ffce40b5557", 36 37 "dependencies": [ 37 - "jsr:@cliffy/flags", 38 + "jsr:@cliffy/flags@1.0.0-rc.8", 38 39 "jsr:@cliffy/internal", 39 40 "jsr:@cliffy/table@1.0.0-rc.8", 40 41 "jsr:@std/fmt@~1.0.2", ··· 157 158 "workspace": { 158 159 "dependencies": [ 159 160 "jsr:@cliffy/command@^1.0.0-rc.8", 161 + "jsr:@cliffy/flags@^1.0.0-rc.8", 160 162 "jsr:@cliffy/table@^1.0.0-rc.8", 161 163 "jsr:@db/sqlite@0.12", 162 164 "jsr:@soapbox/kysely-deno-sqlite@^2.2.0",
+36 -1
main.ts
··· 137 137 }) 138 138 .command("start", "Start a virtual machine") 139 139 .arguments("<vm-name:string>") 140 - .option("--detach, -d", "Run VM in the background and print VM name") 140 + .option("-c, --cpu <type:string>", "Type of CPU to emulate", { 141 + default: "host", 142 + }) 143 + .option("-C, --cpus <number:number>", "Number of CPU cores", { 144 + default: 2, 145 + }) 146 + .option("-m, --memory <size:string>", "Amount of memory for the VM", { 147 + default: "2G", 148 + }) 149 + .option("-i, --image <path:string>", "Path to VM disk image") 150 + .option( 151 + "--disk-format <format:string>", 152 + "Disk image format (e.g., qcow2, raw)", 153 + { 154 + default: "raw", 155 + }, 156 + ) 157 + .option( 158 + "--size <size:string>", 159 + "Size of the VM disk image to create if it doesn't exist (e.g., 20G)", 160 + { 161 + default: "20G", 162 + }, 163 + ) 164 + .option( 165 + "-b, --bridge <name:string>", 166 + "Name of the network bridge to use for networking (e.g., br0)", 167 + ) 168 + .option( 169 + "-d, --detach", 170 + "Run VM in the background and print VM name", 171 + ) 172 + .option( 173 + "-p, --port-forward <mappings:string>", 174 + "Port forwarding rules in the format hostPort:guestPort (comma-separated for multiple)", 175 + ) 141 176 .action(async (options: unknown, vmName: string) => { 142 177 await start(vmName, Boolean((options as { detach: boolean }).detach)); 143 178 })
+20 -1
src/subcommands/start.ts
··· 1 + import { parseFlags } from "@cliffy/flags"; 1 2 import _ from "lodash"; 2 3 import { LOGS_DIR } from "../constants.ts"; 4 + import type { VirtualMachine } from "../db.ts"; 3 5 import { getInstanceState, updateInstanceState } from "../state.ts"; 4 6 import { setupFirmwareFilesIfNeeded, setupNATNetworkArgs } from "../utils.ts"; 5 7 6 8 export default async function (name: string, detach: boolean = false) { 7 - const vm = await getInstanceState(name); 9 + let vm = await getInstanceState(name); 8 10 if (!vm) { 9 11 console.error( 10 12 `Virtual machine with name or ID ${name} not found.`, ··· 13 15 } 14 16 15 17 console.log(`Starting virtual machine ${vm.name} (ID: ${vm.id})...`); 18 + 19 + vm = mergeFlags(vm); 16 20 17 21 const qemu = Deno.build.arch === "aarch64" 18 22 ? "qemu-system-aarch64" ··· 103 107 } 104 108 } 105 109 } 110 + 111 + function mergeFlags(vm: VirtualMachine): VirtualMachine { 112 + const { flags } = parseFlags(Deno.args); 113 + return { 114 + ...vm, 115 + memory: flags.memory ? String(flags.memory) : vm.memory, 116 + cpus: flags.cpus ? Number(flags.cpus) : vm.cpus, 117 + cpu: flags.cpu ? String(flags.cpu) : vm.cpu, 118 + diskFormat: flags.diskFormat ? String(flags.diskFormat) : vm.diskFormat, 119 + portForward: flags.portForward ? String(flags.portForward) : vm.portForward, 120 + drivePath: flags.image ? String(flags.image) : vm.drivePath, 121 + bridge: flags.bridge ? String(flags.bridge) : vm.bridge, 122 + diskSize: flags.size ? String(flags.size) : vm.diskSize, 123 + }; 124 + }