mirror of
https://github.com/apple/container.git
synced 2026-09-26 09:35:37 +00:00
LinuxContainer: Allow reuse after being stopped (#240)
After the container is stopped it's a bit odd how we don't allow the object to be restarted. If someone wanted to continuously rerun the same container they'd need to make a new object every time even though all guest state is blown away on stop() so it's a clean slate. This change makes it so that you can create+start again after stop (although create stands out like a sore thumb now as stop -> create is just strange).
This commit is contained in:
@@ -194,7 +194,7 @@ public final class LinuxContainer: Container, Sendable {
|
||||
|
||||
mutating func setCreating() throws {
|
||||
switch self {
|
||||
case .initialized:
|
||||
case .initialized, .stopped:
|
||||
self = .creating(.init())
|
||||
default:
|
||||
throw ContainerizationError(
|
||||
|
||||
@@ -211,6 +211,7 @@ struct IntegrationSuite: AsyncParsableCommand {
|
||||
"container mount": testMounts,
|
||||
"nested virt": testNestedVirtualizationEnabled,
|
||||
"container manager": testContainerManagerCreate,
|
||||
"container reuse": testContainerReuse,
|
||||
]
|
||||
|
||||
var passed = 0
|
||||
|
||||
@@ -121,6 +121,57 @@ extension IntegrationSuite {
|
||||
}
|
||||
}
|
||||
|
||||
func testContainerReuse() async throws {
|
||||
let id = "test-container-reuse"
|
||||
|
||||
// Get the kernel from bootstrap
|
||||
let bs = try await bootstrap()
|
||||
|
||||
// Create ContainerManager with kernel and initfs reference
|
||||
let manager = try ContainerManager(vmm: bs.vmm)
|
||||
defer {
|
||||
try? manager.delete(id)
|
||||
}
|
||||
|
||||
let buffer = BufferWriter()
|
||||
let container = try await manager.create(
|
||||
id,
|
||||
image: bs.image,
|
||||
rootfs: bs.rootfs
|
||||
) { config in
|
||||
config.process.arguments = ["/bin/echo", "ContainerManager test"]
|
||||
config.process.stdout = buffer
|
||||
}
|
||||
|
||||
// Start the container
|
||||
try await container.create()
|
||||
try await container.start()
|
||||
|
||||
// Wait for completion
|
||||
var status = try await container.wait()
|
||||
guard status == 0 else {
|
||||
throw IntegrationError.assert(msg: "process status \(status) != 0")
|
||||
}
|
||||
try await container.stop()
|
||||
|
||||
// Recreate things.
|
||||
try await container.create()
|
||||
try await container.start()
|
||||
|
||||
// Wait for completion.. again.
|
||||
status = try await container.wait()
|
||||
guard status == 0 else {
|
||||
throw IntegrationError.assert(msg: "process status \(status) != 0")
|
||||
}
|
||||
|
||||
let output = String(data: buffer.data, encoding: .utf8)
|
||||
let expected = "ContainerManager test\nContainerManager test\n"
|
||||
guard output == expected else {
|
||||
throw IntegrationError.assert(
|
||||
msg: "process should have returned '\(expected)' != '\(output ?? "nil")'")
|
||||
}
|
||||
}
|
||||
|
||||
private func createMountDirectory() throws -> URL {
|
||||
let dir = FileManager.default.uniqueTemporaryDirectory(create: true)
|
||||
try "hello".write(to: dir.appendingPathComponent("hi.txt"), atomically: true, encoding: .utf8)
|
||||
|
||||
Reference in New Issue
Block a user