diff --git a/Sources/tart/Commands/Run.swift b/Sources/tart/Commands/Run.swift index 3fbb586..6ff7083 100644 --- a/Sources/tart/Commands/Run.swift +++ b/Sources/tart/Commands/Run.swift @@ -429,7 +429,13 @@ struct Run: AsyncParsableCommand { + " configured memory size of \(vmConfig.memorySize / 1024 / 1024) MB") } - let minimumAllowedMemorySize = VZVirtualMachineConfiguration.minimumAllowedMemorySize + var minimumAllowedMemorySize = VZVirtualMachineConfiguration.minimumAllowedMemorySize + if vmConfig.os == .darwin { + // macOS guests additionally have a minimum supported memory size + // dictated by the restore image they were created from, similarly + // to how "tart set --memory" restricts the configured memory size + minimumAllowedMemorySize = max(minimumAllowedMemorySize, vmConfig.memorySizeMin) + } if targetMemoryBytes < minimumAllowedMemorySize { throw ValidationError("--balloon-target-memory (\(targetMemoryMB) MB) is too small," + " it should be at least \(minimumAllowedMemorySize / 1024 / 1024) MB") diff --git a/Tests/TartTests/MemoryBalloonTests.swift b/Tests/TartTests/MemoryBalloonTests.swift index d22f76c..3e01709 100644 --- a/Tests/TartTests/MemoryBalloonTests.swift +++ b/Tests/TartTests/MemoryBalloonTests.swift @@ -78,6 +78,25 @@ final class MemoryBalloonTests: XCTestCase { XCTAssertNoThrow(try Run.validateBalloonTargetMemory(4096, vmConfig: vmConfig)) } + func testBalloonTargetMemoryValidationRespectsDarwinMinimum() throws { + // A macOS guest whose restore image requires 4096 MB of memory at minimum + var vmConfig = VMConfig(platform: Linux(), cpuCountMin: 1, memorySizeMin: 4096 * 1024 * 1024) + vmConfig.os = .darwin + vmConfig.memoryBalloon = true + try vmConfig.setMemory(memorySize: 8192 * 1024 * 1024) + + // Target below the restore image's minimum supported memory size + XCTAssertThrowsError(try Run.validateBalloonTargetMemory(2048, vmConfig: vmConfig)) + + // Target at the restore image's minimum supported memory size + XCTAssertNoThrow(try Run.validateBalloonTargetMemory(4096, vmConfig: vmConfig)) + + // The same minimum doesn't apply to Linux guests, similarly + // to how "tart set --memory" doesn't restrict them + vmConfig.os = .linux + XCTAssertNoThrow(try Run.validateBalloonTargetMemory(2048, vmConfig: vmConfig)) + } + func testBalloonDeviceOnlyConfiguredWhenEnabled() throws { // Disabled by default XCTAssertEqual(try craftConfiguration().memoryBalloonDevices.count, 0)