diff --git a/pkg/rancher-desktop/backend/lima.ts b/pkg/rancher-desktop/backend/lima.ts index f7c259f9fe2..8edc7df95a7 100644 --- a/pkg/rancher-desktop/backend/lima.ts +++ b/pkg/rancher-desktop/backend/lima.ts @@ -133,6 +133,21 @@ export type LimaConfiguration = { networks?: Array>; }; +/** + * QEMU Image formats + */ +enum ImageFormat { + QCOW2 = 'qcow2', + RAW = 'raw', +} + +/** + * QEMU Image Information as returned by `qemu-img info --output=json ...` + */ +type QEMUImageInfo = { + format: string; +}; + /** * Options passed to spawnWithCapture method */ @@ -764,6 +779,10 @@ export default class LimaBackend extends events.EventEmitter implements VMBacken return path.join(paths.resources, os.platform(), 'lima', 'bin', limactlBin); } + protected static get qemuImg() { + return path.join(paths.resources, os.platform(), 'lima', 'bin', 'qemu-img'); + } + protected static get limaEnv() { const binDir = path.join(paths.resources, os.platform(), 'lima', 'bin'); const VMNETDir = path.join(VMNET_DIR, 'bin'); @@ -937,6 +956,28 @@ export default class LimaBackend extends events.EventEmitter implements VMBacken })(); } + protected imageInfo(fileName: string): Promise { + return (async() => { + try { + const { stdout } = await this.spawnWithCapture(LimaBackend.qemuImg, 'info', '--output=json', '--force-share', fileName); + + return JSON.parse(stdout) as QEMUImageInfo; + } catch { + return { format: 'unknown' } as QEMUImageInfo; + } + })(); + } + + protected convertToRaw(fileName: string): Promise { + return (async() => { + const rawFileName = `${ fileName }.raw`; + + await this.spawnWithCapture(LimaBackend.qemuImg, 'convert', fileName, rawFileName); + await fs.promises.unlink(fileName); + await fs.promises.rename(rawFileName, fileName); + })(); + } + protected get isRegistered(): Promise { return this.status.then(defined); } @@ -1732,8 +1773,21 @@ export default class LimaBackend extends events.EventEmitter implements VMBacken } const vmStatus = await this.status; - const isVMAlreadyRunning = vmStatus?.status === 'Running'; + let isVMAlreadyRunning = vmStatus?.status === 'Running'; + + // Virtualization Framework only supports RAW disks + if (vmStatus && config.experimental.virtualMachine.type === VMType.VZ) { + const diffdisk = path.join(paths.lima, MACHINE_NAME, 'diffdisk'); + const { format } = await this.imageInfo(diffdisk); + if (format === ImageFormat.QCOW2) { + if (isVMAlreadyRunning) { + await this.lima('stop', MACHINE_NAME); + isVMAlreadyRunning = false; + } + await this.convertToRaw(diffdisk); + } + } // Start the VM; if it's already running, this does nothing. await this.startVM();