Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions Sources/Containerization/ContainerManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ public struct ContainerManager: Sendable {
writableLayerSizeInBytes: UInt64? = nil,
readOnly: Bool = false,
networking: Bool = true,
platform: Platform = .current,
progress: ProgressHandler? = nil,
configuration: (inout LinuxContainer.Configuration) throws -> Void
) async throws -> LinuxContainer {
Expand All @@ -216,6 +217,7 @@ public struct ContainerManager: Sendable {
writableLayerSizeInBytes: writableLayerSizeInBytes,
readOnly: readOnly,
networking: networking,
platform: platform,
progress: progress,
configuration: configuration
)
Expand All @@ -231,6 +233,11 @@ public struct ContainerManager: Sendable {
/// - readOnly: Whether to mount the root filesystem as read-only.
/// - networking: Whether to create a network interface for this container. Defaults to `true`.
/// When `false`, no network resources are allocated and `releaseNetwork`/`delete` remain safe to call.
/// - platform: Which platform's image variant to use. Defaults to `.current`, preserving the
/// previous behaviour. A caller running a FOREIGN-architecture image (e.g. an x86_64 image
/// on an arm64 host under Rosetta) must pass that image's platform: resolving the config
/// and unpacking the rootfs both need the variant that actually exists in the image, and
/// `.current` fails before any translation layer is consulted.
/// - progress: Optional handler for tracking rootfs unpacking progress.
public mutating func create(
_ id: String,
Expand All @@ -239,6 +246,7 @@ public struct ContainerManager: Sendable {
writableLayerSizeInBytes: UInt64? = nil,
readOnly: Bool = false,
networking: Bool = true,
platform: Platform = .current,
progress: ProgressHandler? = nil,
configuration: (inout LinuxContainer.Configuration) throws -> Void
) async throws -> LinuxContainer {
Expand All @@ -248,6 +256,7 @@ public struct ContainerManager: Sendable {
image: image,
destination: path.appendingPathComponent("rootfs.ext4"),
size: rootfsSizeInBytes,
platform: platform,
progress: progress
)
if readOnly {
Expand All @@ -269,6 +278,7 @@ public struct ContainerManager: Sendable {
rootfs: rootfs,
writableLayer: writableLayer,
networking: networking,
platform: platform,
configuration: configuration
)
}
Expand All @@ -290,9 +300,10 @@ public struct ContainerManager: Sendable {
rootfs: Mount,
writableLayer: Mount? = nil,
networking: Bool = true,
platform: Platform = .current,
configuration: (inout LinuxContainer.Configuration) throws -> Void
) async throws -> LinuxContainer {
let imageConfig = try await image.config(for: .current).config
let imageConfig = try await image.config(for: platform).config
return try LinuxContainer(
id,
rootfs: rootfs,
Expand Down Expand Up @@ -340,10 +351,13 @@ public struct ContainerManager: Sendable {
return path
}

private func unpack(image: Image, destination: URL, size: UInt64, progress: ProgressHandler? = nil) async throws -> Mount {
private func unpack(
image: Image, destination: URL, size: UInt64, platform: Platform = .current,
progress: ProgressHandler? = nil
) async throws -> Mount {
do {
let unpacker = EXT4Unpacker(capacityInBytes: size)
return try await unpacker.unpack(image, for: .current, at: destination, progress: progress)
return try await unpacker.unpack(image, for: platform, at: destination, progress: progress)
} catch let err as ContainerizationError {
if err.code == .exists {
return .block(
Expand Down