A Docker-like CLI and HTTP API for managing headless VMs

Merge pull request #3 from tsirysndr/feat/fedora

feat: add support for fedora server

+72 -1
+31 -1
main.ts
··· 31 31 import tag from "./src/subcommands/tag.ts"; 32 32 import * as volumes from "./src/subcommands/volume.ts"; 33 33 import { 34 + constructFedoraImageURL, 34 35 constructNixOSImageURL, 35 36 createDriveImageIfNeeded, 36 37 downloadIso, ··· 195 196 ); 196 197 197 198 if (nixOSIsoURL) { 198 - isoPath = yield* downloadIso(nixOSIsoURL, options); 199 + const cached = yield* pipe( 200 + basename(nixOSIsoURL), 201 + fileExists, 202 + Effect.flatMap(() => Effect.succeed(true)), 203 + Effect.catchAll(() => Effect.succeed(false)), 204 + ); 205 + if (!cached) { 206 + isoPath = yield* downloadIso(nixOSIsoURL, options); 207 + } else { 208 + isoPath = basename(nixOSIsoURL); 209 + } 210 + } 211 + 212 + const fedoraImageURL = yield* pipe( 213 + constructFedoraImageURL(input), 214 + Effect.catchAll(() => Effect.succeed(null)), 215 + ); 216 + 217 + if (fedoraImageURL) { 218 + const cached = yield* pipe( 219 + basename(fedoraImageURL), 220 + fileExists, 221 + Effect.flatMap(() => Effect.succeed(true)), 222 + Effect.catchAll(() => Effect.succeed(false)), 223 + ); 224 + if (!cached) { 225 + isoPath = yield* downloadIso(fedoraImageURL, options); 226 + } else { 227 + isoPath = basename(fedoraImageURL); 228 + } 199 229 } 200 230 } 201 231
+3
src/constants.ts
··· 17 17 export const NIXOS_DEFAULT_VERSION: string = "25.05"; 18 18 export const NIXOS_ISO_URL: string = 19 19 `https://channels.nixos.org/nixos-${NIXOS_DEFAULT_VERSION}/latest-nixos-minimal-${Deno.build.arch}-linux.iso`; 20 + 21 + export const FEDORA_IMG_URL: string = 22 + `https://download.fedoraproject.org/pub/fedora/linux/releases/43/Server/${Deno.build.arch}/images/Fedora-Server-Guest-Generic-43-1.6.${Deno.build.arch}.qcow2`;
+38
src/utils.ts
··· 8 8 EMPTY_DISK_THRESHOLD_KB, 9 9 FEDORA_COREOS_DEFAULT_VERSION, 10 10 FEDORA_COREOS_IMG_URL, 11 + FEDORA_IMG_URL, 11 12 LOGS_DIR, 12 13 NIXOS_DEFAULT_VERSION, 13 14 NIXOS_ISO_URL, ··· 325 326 return []; 326 327 }); 327 328 329 + export const setupFedoraArgs = (imagePath?: string | null) => 330 + Effect.sync(() => { 331 + if ( 332 + imagePath && 333 + imagePath.endsWith(".qcow2") && 334 + imagePath.includes("Fedora-Server") 335 + ) { 336 + return ["-drive", `file=${imagePath},format=qcow2,if=virtio`]; 337 + } 338 + 339 + return []; 340 + }); 341 + 328 342 export const runQemu = (isoPath: string | null, options: Options) => 329 343 Effect.gen(function* () { 330 344 const macAddress = yield* generateRandomMacAddress(); ··· 335 349 336 350 const firmwareFiles = yield* setupFirmwareFilesIfNeeded(); 337 351 let coreosArgs: string[] = yield* setupCoreOSArgs(isoPath || options.image); 352 + let fedoraArgs: string[] = yield* setupFedoraArgs(isoPath || options.image); 338 353 339 354 if (coreosArgs.length > 0 && !isoPath) { 340 355 coreosArgs = coreosArgs.slice(2); 356 + } 357 + 358 + if (fedoraArgs.length > 0 && !isoPath) { 359 + fedoraArgs = []; 341 360 } 342 361 343 362 const qemuArgs = [ ··· 367 386 "chardev:con0", 368 387 ...firmwareFiles, 369 388 ...coreosArgs, 389 + ...fedoraArgs, 370 390 ..._.compact( 371 391 options.image && [ 372 392 "-drive", ··· 666 686 }), 667 687 ); 668 688 }; 689 + 690 + export const constructFedoraImageURL = ( 691 + image: string, 692 + ): Effect.Effect<string, InvalidImageNameError, never> => { 693 + // detect with regex if image matches Fedora pattern: fedora 694 + const fedoraRegex = /^(fedora)$/; 695 + const match = image.match(fedoraRegex); 696 + if (match) { 697 + return Effect.succeed(FEDORA_IMG_URL); 698 + } 699 + 700 + return Effect.fail( 701 + new InvalidImageNameError({ 702 + image, 703 + cause: "Image name does not match Fedora naming conventions.", 704 + }), 705 + ); 706 + };