diff --git a/Sources/Containerization/LinuxContainer.swift b/Sources/Containerization/LinuxContainer.swift index aad39051..e22ad968 100644 --- a/Sources/Containerization/LinuxContainer.swift +++ b/Sources/Containerization/LinuxContainer.swift @@ -44,6 +44,8 @@ public final class LinuxContainer: Container, Sendable { public var cpus: Int = 4 /// The memory in bytes to give to the container. public var memoryInBytes: UInt64 = 1024.mib() + /// Requested storage in bytes. + public var storageInBytes: UInt64? /// The hostname for the container. public var hostname: String = "" /// The system control options for the container. @@ -72,6 +74,7 @@ public final class LinuxContainer: Container, Sendable { process: LinuxProcessConfiguration, cpus: Int = 4, memoryInBytes: UInt64 = 1024.mib(), + storageInBytes: UInt64? = nil, hostname: String = "", sysctl: [String: String] = [:], interfaces: [any Interface] = [], @@ -86,6 +89,7 @@ public final class LinuxContainer: Container, Sendable { self.process = process self.cpus = cpus self.memoryInBytes = memoryInBytes + self.storageInBytes = storageInBytes self.hostname = hostname self.sysctl = sysctl self.interfaces = interfaces @@ -397,6 +401,7 @@ extension LinuxContainer { let vmConfig = VMConfiguration( cpus: self.cpus, memoryInBytes: self.memoryInBytes, + diskStorageBytes: self.config.storageInBytes, interfaces: self.interfaces, mountsByID: [self.id: [self.rootfs] + self.config.mounts], bootLog: self.config.bootLog, diff --git a/Sources/Containerization/VMConfiguration.swift b/Sources/Containerization/VMConfiguration.swift index cb86b7c5..e891b250 100644 --- a/Sources/Containerization/VMConfiguration.swift +++ b/Sources/Containerization/VMConfiguration.swift @@ -70,6 +70,8 @@ public struct VMConfiguration: Sendable { public var cpus: Int /// The memory in bytes to allocate. public var memoryInBytes: UInt64 + /// Storage in bytes to allocate + public var diskStorageBytes: UInt64? /// The network interfaces to attach. public var interfaces: [any Interface] /// Mounts organized by metadata ID (e.g. container ID). @@ -84,6 +86,7 @@ public struct VMConfiguration: Sendable { public init( cpus: Int = 4, memoryInBytes: UInt64 = 1024 * 1024 * 1024, + diskStorageBytes: UInt64? = nil, interfaces: [any Interface] = [], mountsByID: [String: [Mount]] = [:], bootLog: BootLog? = nil, @@ -91,6 +94,7 @@ public struct VMConfiguration: Sendable { ) { self.cpus = cpus self.memoryInBytes = memoryInBytes + self.diskStorageBytes = diskStorageBytes self.interfaces = interfaces self.mountsByID = mountsByID self.bootLog = bootLog diff --git a/Sources/Containerization/VZVirtualMachineInstance.swift b/Sources/Containerization/VZVirtualMachineInstance.swift index 3ccd37a2..5bced4a1 100644 --- a/Sources/Containerization/VZVirtualMachineInstance.swift +++ b/Sources/Containerization/VZVirtualMachineInstance.swift @@ -43,6 +43,8 @@ struct VZVirtualMachineInstance: Sendable { public var cpus: Int /// Amount of memory in bytes allocated. public var memoryInBytes: UInt64 + /// Amount of storage in bytes allocated. + public var diskStorageBytes: UInt64? /// Toggle rosetta's x86_64 emulation support. public var rosetta: Bool /// Toggle nested virtualization support. @@ -61,6 +63,7 @@ struct VZVirtualMachineInstance: Sendable { init() { self.cpus = 4 self.memoryInBytes = 1024.mib() + self.diskStorageBytes = nil self.rosetta = false self.nestedVirtualization = false self.mountsByID = [:] @@ -370,6 +373,26 @@ extension VZVirtualMachineInstance.Configuration { throw ContainerizationError(.invalidArgument, message: "rootfs cannot be nil") } + if let diskBytes = self.diskStorageBytes, initialFilesystem.isBlock { + let fileURL = URL(fileURLWithPath: initialFilesystem.source) + + if !FileManager.default.fileExists(atPath: fileURL.path) { + FileManager.default.createFile(atPath: fileURL.path, contents: nil) + } + + do { + let handle = try FileHandle(forWritingTo: fileURL) + defer { try? handle.close() } + try handle.truncate(atOffset: diskBytes) + } catch { + throw ContainerizationError( + .internalError, + message: "failed to resize rootfs to \(diskBytes) bytes", + cause: error + ) + } + } + let loader = VZLinuxBootLoader(kernelURL: kernel.path) loader.commandLine = kernel.linuxCommandline(initialFilesystem: initialFilesystem) config.bootLoader = loader diff --git a/Sources/Containerization/VZVirtualMachineManager.swift b/Sources/Containerization/VZVirtualMachineManager.swift index 531509ea..40710515 100644 --- a/Sources/Containerization/VZVirtualMachineManager.swift +++ b/Sources/Containerization/VZVirtualMachineManager.swift @@ -58,6 +58,7 @@ public struct VZVirtualMachineManager: VirtualMachineManager { with: { instanceConfig in instanceConfig.cpus = vmConfig.cpus instanceConfig.memoryInBytes = vmConfig.memoryInBytes + instanceConfig.diskStorageBytes = vmConfig.diskStorageBytes instanceConfig.kernel = self.kernel instanceConfig.initialFilesystem = self.initialFilesystem