From 5559dd5a3d677f8aa2ae0a92873a6e5ac0804135 Mon Sep 17 00:00:00 2001 From: Danny Canter Date: Wed, 25 Jun 2025 11:11:23 -0700 Subject: [PATCH] VZVirtualMachineInstance: Rework installRosetta flow (#169) Because we were installing rosetta directly in the constructor for VZVirtualMachineInstance, and we'd prefer to not have the constructor async as it pollutes so much more, we had devised this gnarly callback approach for the install that is a bit of an eyesore. This changes focus is on moving the install flow to a method that is already async so we can piggyback off of it, and removing the install logic from the config -> VZConfig conversion. Now the install will occur during start() if rosetta is not installed. --- .../VZVirtualMachineInstance.swift | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Sources/Containerization/VZVirtualMachineInstance.swift b/Sources/Containerization/VZVirtualMachineInstance.swift index b6fc4717..de450957 100644 --- a/Sources/Containerization/VZVirtualMachineInstance.swift +++ b/Sources/Containerization/VZVirtualMachineInstance.swift @@ -131,6 +131,9 @@ extension VZVirtualMachineInstance { ) } + // Do any necessary setup needed prior to starting the guest. + try await self.prestart() + try await self.vm.start(queue: self.queue) let agent = Vminitd( @@ -203,23 +206,19 @@ extension VZVirtualMachineInstance { port: port ) } + + func prestart() async throws { + if self.config.rosetta && VZLinuxRosettaDirectoryShare.availability == .notInstalled { + self.logger?.info("installing rosetta") + try await VZVirtualMachineInstance.Configuration.installRosetta() + } + } } extension VZVirtualMachineInstance.Configuration { - public static func installRosetta() throws { - #if arch(arm64) + public static func installRosetta() async throws { do { - let _err: Mutex = .init(nil) - VZLinuxRosettaDirectoryShare.installRosetta(completionHandler: { error in - _err.withLock { - $0 = error - } - }) - let err = _err.withLock { $0 } - guard let err else { - return - } - throw err + try await VZLinuxRosettaDirectoryShare.installRosetta() } catch { throw ContainerizationError( .internalError, @@ -227,8 +226,8 @@ extension VZVirtualMachineInstance.Configuration { cause: error ) } - #endif } + private func serialPort(path: URL) throws -> [VZVirtioConsoleDeviceSerialPortConfiguration] { let c = VZVirtioConsoleDeviceSerialPortConfiguration() c.attachment = try VZFileSerialPortAttachment(url: path, append: true) @@ -261,7 +260,8 @@ extension VZVirtualMachineInstance.Configuration { message: "rosetta was requested but is not supported on this machine" ) case .notInstalled: - try Self.installRosetta() + // NOTE: If rosetta isn't installed, we'll error with a nice error message + // during .start() of the virtual machine instance. fallthrough case .installed: let share = try VZLinuxRosettaDirectoryShare()