mirror of
https://github.com/apple/container.git
synced 2026-09-22 07:35:36 +00:00
Add new FileHandle option for serial console output (#410)
Taking in a filehandle gives the user quite a bit more freedom on how to handle boot log output. They can set up a kqueue watch on it and redirect output somewhere else etc etc. The implementation for this has us take in a new BootLog type that has two options: 1. .file, which is analogous to what we had prior. Just provide a URL and a true by default append field. 2. .fileHandle which is the new addition. Can pass any fd that is writable, and the VMM should write serial console output to it.
This commit is contained in:
@@ -417,7 +417,7 @@ public struct ContainerManager: Sendable {
|
||||
config.interfaces = [interface]
|
||||
config.dns = .init(nameservers: [interface.gateway!])
|
||||
}
|
||||
config.bootlog = self.containerRoot.appendingPathComponent(id).appendingPathComponent("bootlog.log")
|
||||
config.bootLog = BootLog.file(path: self.containerRoot.appendingPathComponent(id).appendingPathComponent("bootlog.log"))
|
||||
try configuration(&config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ public final class LinuxContainer: Container, Sendable {
|
||||
public var hosts: Hosts?
|
||||
/// Enable nested virtualization support.
|
||||
public var virtualization: Bool = false
|
||||
/// Optional file path to store serial boot logs.
|
||||
public var bootlog: URL?
|
||||
/// Optional destination for serial boot logs.
|
||||
public var bootLog: BootLog?
|
||||
|
||||
public init() {}
|
||||
|
||||
@@ -77,7 +77,7 @@ public final class LinuxContainer: Container, Sendable {
|
||||
dns: DNS? = nil,
|
||||
hosts: Hosts? = nil,
|
||||
virtualization: Bool = false,
|
||||
bootlog: URL? = nil
|
||||
bootLog: BootLog? = nil
|
||||
) {
|
||||
self.process = process
|
||||
self.cpus = cpus
|
||||
@@ -90,7 +90,7 @@ public final class LinuxContainer: Container, Sendable {
|
||||
self.dns = dns
|
||||
self.hosts = hosts
|
||||
self.virtualization = virtualization
|
||||
self.bootlog = bootlog
|
||||
self.bootLog = bootLog
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ extension LinuxContainer {
|
||||
memoryInBytes: self.memoryInBytes,
|
||||
interfaces: self.interfaces,
|
||||
mountsByID: [self.id: [self.rootfs] + self.config.mounts],
|
||||
bootlog: self.config.bootlog,
|
||||
bootLog: self.config.bootLog,
|
||||
nestedVirtualization: self.config.virtualization
|
||||
)
|
||||
let creationConfig = StandardVMConfig(configuration: vmConfig)
|
||||
|
||||
@@ -49,7 +49,7 @@ public final class LinuxPod: Sendable {
|
||||
/// Whether nested virtualization should be turned on for the pod.
|
||||
public var virtualization: Bool = false
|
||||
/// Optional file path to store serial boot logs.
|
||||
public var bootlog: URL?
|
||||
public var bootLog: BootLog?
|
||||
|
||||
public init() {}
|
||||
}
|
||||
@@ -293,7 +293,7 @@ extension LinuxPod {
|
||||
memoryInBytes: self.config.memoryInBytes,
|
||||
interfaces: self.config.interfaces,
|
||||
mountsByID: mountsByID,
|
||||
bootlog: self.config.bootlog,
|
||||
bootLog: self.config.bootLog,
|
||||
nestedVirtualization: self.config.virtualization
|
||||
)
|
||||
let creationConfig = StandardVMConfig(configuration: vmConfig)
|
||||
|
||||
@@ -17,6 +17,37 @@
|
||||
import ContainerizationOCI
|
||||
import Foundation
|
||||
|
||||
/// Destination for boot log (serial console) output.
|
||||
public struct BootLog: Sendable {
|
||||
/// The underlying representation of the boot log destination.
|
||||
internal enum Representation: Sendable {
|
||||
case file(path: URL, append: Bool)
|
||||
case fileHandle(FileHandle)
|
||||
}
|
||||
|
||||
internal var base: Representation
|
||||
|
||||
/// Write boot logs to a file at the specified path.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - path: The URL of the file to write boot logs to.
|
||||
/// - append: Whether to append to an existing file or overwrite it. Defaults to true.
|
||||
///
|
||||
/// - Returns: A boot log destination that writes to a file.
|
||||
public static func file(path: URL, append: Bool = true) -> BootLog {
|
||||
self.init(base: .file(path: path, append: append))
|
||||
}
|
||||
|
||||
/// Write boot logs to a file handle.
|
||||
///
|
||||
/// - Parameter fileHandle: The file handle to write boot logs to.
|
||||
///
|
||||
/// - Returns: A boot log destination that writes to a file handle.
|
||||
public static func fileHandle(_ fileHandle: FileHandle) -> BootLog {
|
||||
self.init(base: .fileHandle(fileHandle))
|
||||
}
|
||||
}
|
||||
|
||||
/// Protocol for VM creation configuration. Allows VMMs to extend with specific settings
|
||||
/// while maintaining a common core configuration.
|
||||
public protocol VMCreationConfig: Sendable {
|
||||
@@ -44,8 +75,8 @@ public struct VMConfiguration: Sendable {
|
||||
/// Mounts organized by metadata ID (e.g. container ID).
|
||||
/// Each ID maps to an array of mounts for that workload.
|
||||
public var mountsByID: [String: [Mount]]
|
||||
/// Optional file path to store serial boot logs.
|
||||
public var bootlog: URL?
|
||||
/// Optional destination for serial boot logs.
|
||||
public var bootLog: BootLog?
|
||||
/// Enable nested virtualization support. If the VirtualMachineManager
|
||||
/// does not support this feature, it MUST return an .unsupported ContainerizationError.
|
||||
public var nestedVirtualization: Bool
|
||||
@@ -55,14 +86,14 @@ public struct VMConfiguration: Sendable {
|
||||
memoryInBytes: UInt64 = 1024 * 1024 * 1024,
|
||||
interfaces: [any Interface] = [],
|
||||
mountsByID: [String: [Mount]] = [:],
|
||||
bootlog: URL? = nil,
|
||||
bootLog: BootLog? = nil,
|
||||
nestedVirtualization: Bool = false
|
||||
) {
|
||||
self.cpus = cpus
|
||||
self.memoryInBytes = memoryInBytes
|
||||
self.interfaces = interfaces
|
||||
self.mountsByID = mountsByID
|
||||
self.bootlog = bootlog
|
||||
self.bootLog = bootLog
|
||||
self.nestedVirtualization = nestedVirtualization
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ struct VZVirtualMachineInstance: Sendable {
|
||||
public var kernel: Kernel?
|
||||
/// The root filesystem.
|
||||
public var initialFilesystem: Mount?
|
||||
/// File path to store the virtual machine's boot logs.
|
||||
public var bootlog: URL?
|
||||
/// Destination for the virtual machine's boot logs.
|
||||
public var bootLog: BootLog?
|
||||
|
||||
init() {
|
||||
self.cpus = 4
|
||||
@@ -298,9 +298,17 @@ extension VZVirtualMachineInstance.Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
private func serialPort(path: URL) throws -> [VZVirtioConsoleDeviceSerialPortConfiguration] {
|
||||
private func serialPort(destination: BootLog) throws -> [VZVirtioConsoleDeviceSerialPortConfiguration] {
|
||||
let c = VZVirtioConsoleDeviceSerialPortConfiguration()
|
||||
c.attachment = try VZFileSerialPortAttachment(url: path, append: true)
|
||||
switch destination.base {
|
||||
case .file(let path, let append):
|
||||
c.attachment = try VZFileSerialPortAttachment(url: path, append: append)
|
||||
case .fileHandle(let fileHandle):
|
||||
c.attachment = VZFileHandleSerialPortAttachment(
|
||||
fileHandleForReading: nil,
|
||||
fileHandleForWriting: fileHandle
|
||||
)
|
||||
}
|
||||
return [c]
|
||||
}
|
||||
|
||||
@@ -312,11 +320,11 @@ extension VZVirtualMachineInstance.Configuration {
|
||||
config.entropyDevices = [VZVirtioEntropyDeviceConfiguration()]
|
||||
config.socketDevices = [VZVirtioSocketDeviceConfiguration()]
|
||||
|
||||
if let bootlog = self.bootlog {
|
||||
config.serialPorts = try serialPort(path: bootlog)
|
||||
if let bootLog = self.bootLog {
|
||||
config.serialPorts = try serialPort(destination: bootLog)
|
||||
} else {
|
||||
// We always supply a serial console. If no explicit path was provided just send em to the void.
|
||||
config.serialPorts = try serialPort(path: URL(filePath: "/dev/null"))
|
||||
config.serialPorts = try serialPort(destination: .file(path: URL(filePath: "/dev/null")))
|
||||
}
|
||||
|
||||
config.networkDevices = try self.interfaces.map {
|
||||
|
||||
@@ -62,8 +62,8 @@ public struct VZVirtualMachineManager: VirtualMachineManager {
|
||||
instanceConfig.kernel = self.kernel
|
||||
instanceConfig.initialFilesystem = self.initialFilesystem
|
||||
|
||||
if let bootlog = vmConfig.bootlog {
|
||||
instanceConfig.bootlog = bootlog
|
||||
if let bootLog = vmConfig.bootLog {
|
||||
instanceConfig.bootLog = bootLog
|
||||
}
|
||||
|
||||
instanceConfig.interfaces = vmConfig.interfaces
|
||||
|
||||
@@ -30,7 +30,7 @@ extension IntegrationSuite {
|
||||
let bs = try await bootstrap(id)
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/true"]
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -50,7 +50,7 @@ extension IntegrationSuite {
|
||||
let bs = try await bootstrap(id)
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/false"]
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -115,7 +115,7 @@ extension IntegrationSuite {
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/echo", "hi"]
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -145,7 +145,7 @@ extension IntegrationSuite {
|
||||
let bs = try await bootstrap(id)
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/sleep", "1000"]
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -188,7 +188,7 @@ extension IntegrationSuite {
|
||||
let bs = try await bootstrap(id)
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/sleep", "1000"]
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -262,7 +262,7 @@ extension IntegrationSuite {
|
||||
config.process.arguments = ["/usr/bin/id"]
|
||||
config.process.user = .init(uid: 1, gid: 1, additionalGids: [1])
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -287,7 +287,7 @@ extension IntegrationSuite {
|
||||
// Try some uid that doesn't exist. This is supported.
|
||||
config.process.user = .init(uid: 40000, gid: 40000)
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -312,7 +312,7 @@ extension IntegrationSuite {
|
||||
// Try some uid that doesn't exist. This is supported.
|
||||
config.process.user = .init(username: "40000:40000")
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -337,7 +337,7 @@ extension IntegrationSuite {
|
||||
// Now for our final trick, try and run a username that doesn't exist.
|
||||
config.process.user = .init(username: "thisdoesntexist")
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -359,7 +359,7 @@ extension IntegrationSuite {
|
||||
config.process.arguments = ["env"]
|
||||
config.process.terminal = true
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -394,7 +394,7 @@ extension IntegrationSuite {
|
||||
config.process.arguments = ["env"]
|
||||
config.process.user = .init(uid: 0, gid: 0)
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -430,7 +430,7 @@ extension IntegrationSuite {
|
||||
config.process.environmentVariables.append(customHomeEnvvar)
|
||||
config.process.user = .init(uid: 0, gid: 0)
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -461,7 +461,7 @@ extension IntegrationSuite {
|
||||
config.process.arguments = ["/bin/hostname"]
|
||||
config.hostname = "foo-bar"
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -491,7 +491,7 @@ extension IntegrationSuite {
|
||||
config.process.arguments = ["cat", "/etc/hosts"]
|
||||
config.hosts = Hosts(entries: [entry])
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -520,7 +520,7 @@ extension IntegrationSuite {
|
||||
config.process.arguments = ["cat"]
|
||||
config.process.stdin = StdinBuffer(data: "Hello from test".data(using: .utf8)!)
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -550,7 +550,7 @@ extension IntegrationSuite {
|
||||
config.process.arguments = ["/bin/cat", "/mnt/hi.txt"]
|
||||
config.mounts.append(.share(source: directory.path, destination: "/mnt"))
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -578,7 +578,7 @@ extension IntegrationSuite {
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/true"]
|
||||
config.virtualization = true
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -618,7 +618,7 @@ extension IntegrationSuite {
|
||||
) { config in
|
||||
config.process.arguments = ["/bin/echo", "ContainerManager test"]
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -656,7 +656,7 @@ extension IntegrationSuite {
|
||||
) { config in
|
||||
config.process.arguments = ["/bin/echo", "please stop me"]
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -695,7 +695,7 @@ extension IntegrationSuite {
|
||||
) { config in
|
||||
config.process.arguments = ["/bin/echo", "ContainerManager test"]
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -749,7 +749,7 @@ extension IntegrationSuite {
|
||||
config.process.arguments = ["mount"]
|
||||
config.process.terminal = true
|
||||
config.process.stdout = buffer
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await container.create()
|
||||
@@ -779,7 +779,7 @@ extension IntegrationSuite {
|
||||
let bs = try await bootstrap(id)
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["sleep", "infinity"]
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -825,7 +825,7 @@ extension IntegrationSuite {
|
||||
config.process.arguments = ["sleep", "infinity"]
|
||||
config.cpus = 2
|
||||
config.memoryInBytes = 512.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -948,7 +948,7 @@ extension IntegrationSuite {
|
||||
direction: .into
|
||||
)
|
||||
]
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -1029,13 +1029,60 @@ extension IntegrationSuite {
|
||||
return dir
|
||||
}
|
||||
|
||||
func testBootLogFileHandle() async throws {
|
||||
let id = "test-bootlog-filehandle"
|
||||
|
||||
let bs = try await bootstrap(id)
|
||||
|
||||
// Create a pipe to capture boot log data
|
||||
let pipe = Pipe()
|
||||
let bootLog = BootLog.fileHandle(pipe.fileHandleForWriting)
|
||||
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/echo", "test complete"]
|
||||
config.bootLog = bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
try await container.create()
|
||||
try await container.start()
|
||||
|
||||
let status = try await container.wait()
|
||||
try await container.stop()
|
||||
|
||||
guard status.exitCode == 0 else {
|
||||
throw IntegrationError.assert(msg: "process status \(status) != 0")
|
||||
}
|
||||
|
||||
try pipe.fileHandleForWriting.close()
|
||||
let bootLogData = try pipe.fileHandleForReading.readToEnd()
|
||||
guard let bootLogData = bootLogData, bootLogData.count > 0 else {
|
||||
throw IntegrationError.assert(
|
||||
msg: "expected to receive boot log data from pipe, but got no data")
|
||||
}
|
||||
|
||||
guard let bootLogString = String(data: bootLogData, encoding: .utf8) else {
|
||||
throw IntegrationError.assert(
|
||||
msg: "failed to convert boot log data to UTF8 string")
|
||||
}
|
||||
|
||||
guard bootLogString.count > 100 else {
|
||||
throw IntegrationError.assert(
|
||||
msg: "boot log output smaller than expected: got \(bootLogString.count)")
|
||||
}
|
||||
} catch {
|
||||
try? await container.stop()
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
func testLargeStdioOutput() async throws {
|
||||
let id = "test-large-stdout-stderr-output"
|
||||
|
||||
let bs = try await bootstrap(id)
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/sleep", "1000"]
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -1098,7 +1145,7 @@ extension IntegrationSuite {
|
||||
let bs = try await bootstrap(id)
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/sleep", "1000"]
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -1136,7 +1183,7 @@ extension IntegrationSuite {
|
||||
let bs = try await bootstrap(id)
|
||||
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
|
||||
config.process.arguments = ["/bin/sleep", "1000"]
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
@@ -37,7 +37,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await pod.addContainer("container1", rootfs: bs.rootfs) { config in
|
||||
@@ -62,7 +62,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await pod.addContainer("container1", rootfs: try cloneRootfs(bs.rootfs, testID: id, containerID: "container1")) { config in
|
||||
@@ -99,7 +99,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
let buffer = BufferWriter()
|
||||
@@ -131,7 +131,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
// Add 5 containers
|
||||
@@ -176,7 +176,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await pod.addContainer("container1", rootfs: bs.rootfs) { config in
|
||||
@@ -217,7 +217,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
let buffer = BufferWriter()
|
||||
@@ -250,7 +250,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await pod.addContainer("container1", rootfs: bs.rootfs) { config in
|
||||
@@ -279,7 +279,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
let containerIDs = ["container1", "container2", "container3"]
|
||||
@@ -307,7 +307,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await pod.addContainer("container1", rootfs: try cloneRootfs(bs.rootfs, testID: id, containerID: "container1")) { config in
|
||||
@@ -363,7 +363,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await pod.addContainer("container1", rootfs: bs.rootfs) { config in
|
||||
@@ -434,7 +434,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await pod.addContainer("container1", rootfs: try cloneRootfs(bs.rootfs, testID: id, containerID: "container1")) { config in
|
||||
@@ -505,7 +505,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
try await pod.addContainer("container1", rootfs: try cloneRootfs(bs.rootfs, testID: id, containerID: "container1")) { config in
|
||||
@@ -586,7 +586,7 @@ extension IntegrationSuite {
|
||||
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
|
||||
config.cpus = 4
|
||||
config.memoryInBytes = 1024.mib()
|
||||
config.bootlog = bs.bootlog
|
||||
config.bootLog = bs.bootLog
|
||||
}
|
||||
|
||||
// Container1 with 1 CPU and 128 MiB memory
|
||||
|
||||
@@ -162,7 +162,7 @@ struct IntegrationSuite: AsyncParsableCommand {
|
||||
|
||||
static let eventLoop = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
|
||||
|
||||
func bootstrap(_ testID: String) async throws -> (rootfs: Containerization.Mount, vmm: VirtualMachineManager, image: Containerization.Image, bootlog: URL) {
|
||||
func bootstrap(_ testID: String) async throws -> (rootfs: Containerization.Mount, vmm: VirtualMachineManager, image: Containerization.Image, bootLog: BootLog) {
|
||||
let reference = "ghcr.io/linuxcontainers/alpine:3.20"
|
||||
let store = Self.imageStore
|
||||
|
||||
@@ -214,7 +214,7 @@ struct IntegrationSuite: AsyncParsableCommand {
|
||||
|
||||
let cl = try fs.clone(to: clPath)
|
||||
|
||||
// Create bootlog directory and per-container bootlog path
|
||||
// Create bootLog directory and per-container bootLog path
|
||||
let bootlogDirURL = URL(filePath: bootlogDir)
|
||||
try? FileManager.default.createDirectory(at: bootlogDirURL, withIntermediateDirectories: true)
|
||||
let bootlogURL = bootlogDirURL.appendingPathComponent("\(testID).log")
|
||||
@@ -227,7 +227,7 @@ struct IntegrationSuite: AsyncParsableCommand {
|
||||
group: Self.eventLoop
|
||||
),
|
||||
image,
|
||||
bootlogURL
|
||||
BootLog.file(path: bootlogURL)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -299,6 +299,7 @@ struct IntegrationSuite: AsyncParsableCommand {
|
||||
Test("container test large stdio ingest", testLargeStdioOutput),
|
||||
Test("process delete idempotency", testProcessDeleteIdempotency),
|
||||
Test("multiple execs without delete", testMultipleExecsWithoutDelete),
|
||||
Test("container bootlog using filehandle", testBootLogFileHandle),
|
||||
|
||||
// Pods
|
||||
Test("pod single container", testPodSingleContainer),
|
||||
|
||||
Reference in New Issue
Block a user