Skip to content
Open
Show file tree
Hide file tree
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
7 changes: 6 additions & 1 deletion Sources/ContainerClient/Core/ClientContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ extension ClientContainer {
public static func create(
configuration: ContainerConfiguration,
options: ContainerCreateOptions = .default,
kernel: Kernel
kernel: Kernel,
initImage: String? = nil
) async throws -> ClientContainer {
do {
let client = Self.newXPCClient()
Expand All @@ -86,6 +87,10 @@ extension ClientContainer {
request.set(key: .kernel, value: kdata)
request.set(key: .containerOptions, value: odata)

if let initImage {
request.set(key: .initImage, value: initImage)
}

try await xpcSend(client: client, message: request)
return ClientContainer(configuration: configuration)
} catch {
Expand Down
3 changes: 3 additions & 0 deletions Sources/ContainerClient/Core/XPC+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ public enum XPCKeys: String {
case systemPlatform
case kernelForce

/// Init image reference
case initImage

/// Volume
case volume
case volumes
Expand Down
6 changes: 6 additions & 0 deletions Sources/ContainerClient/Flags.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ public struct Flags {
)
public var kernel: String?

@Option(
name: .long,
help: .init("Use a custom init image instead of the default", valueName: "image")
)
public var initImage: String?

@Option(name: [.short, .customLong("label")], help: "Add a key=value label to the container")
public var labels: [String] = []

Expand Down
23 changes: 2 additions & 21 deletions Sources/ContainerClient/Utility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public struct Utility {
resource: Flags.Resource,
registry: Flags.Registry,
progressUpdate: @escaping ProgressUpdateHandler
) async throws -> (ContainerConfiguration, Kernel) {
) async throws -> (ContainerConfiguration, Kernel, String?) {
var requestedPlatform = Parser.platform(os: management.os, arch: management.arch)
// Prefer --platform
if let platform = management.platform {
Expand Down Expand Up @@ -132,25 +132,6 @@ public struct Utility {

let kernel = try await self.getKernel(management: management)

// Pull and unpack the initial filesystem
await progressUpdate([
.setDescription("Fetching init image"),
.setItemsName("blobs"),
])
let fetchInitTask = await taskManager.startTask()
let initImage = try await ClientImage.fetch(
reference: ClientImage.initImageRef, platform: .current, scheme: scheme,
progressUpdate: ProgressTaskCoordinator.handler(for: fetchInitTask, from: progressUpdate))

await progressUpdate([
.setDescription("Unpacking init image"),
.setItemsName("entries"),
])
let unpackInitTask = await taskManager.startTask()
_ = try await initImage.getCreateSnapshot(
platform: .current,
progressUpdate: ProgressTaskCoordinator.handler(for: unpackInitTask, from: progressUpdate))

await taskManager.finish()

let imageConfig = try await img.config(for: requestedPlatform).config
Expand Down Expand Up @@ -248,7 +229,7 @@ public struct Utility {

config.ssh = management.ssh

return (config, kernel)
return (config, kernel, management.initImage)
}

static func getAttachmentConfigurations(containerId: String, networks: [Parser.ParsedNetwork]) throws -> [AttachmentConfiguration] {
Expand Down
2 changes: 1 addition & 1 deletion Sources/ContainerCommands/Container/ContainerCreate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ extension Application {
)

let options = ContainerCreateOptions(autoRemove: managementFlags.remove)
let container = try await ClientContainer.create(configuration: ck.0, options: options, kernel: ck.1)
let container = try await ClientContainer.create(configuration: ck.0, options: options, kernel: ck.1, initImage: ck.2)

if !self.managementFlags.cidfile.isEmpty {
let path = self.managementFlags.cidfile
Expand Down
3 changes: 2 additions & 1 deletion Sources/ContainerCommands/Container/ContainerRun.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ extension Application {
let container = try await ClientContainer.create(
configuration: ck.0,
options: options,
kernel: ck.1
kernel: ck.1,
initImage: ck.2
)

let detach = self.managementFlags.detach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,9 @@ public struct ContainersHarness: Sendable {
let config = try JSONDecoder().decode(ContainerConfiguration.self, from: data)
let kernel = try JSONDecoder().decode(Kernel.self, from: kdata)

try await service.create(configuration: config, kernel: kernel, options: options)
let initImage = message.string(key: .initImage)

try await service.create(configuration: config, kernel: kernel, options: options, initImage: initImage)
return message.reply()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public actor ContainersService {
}

/// Create a new container from the provided id and configuration.
public func create(configuration: ContainerConfiguration, kernel: Kernel, options: ContainerCreateOptions) async throws {
public func create(configuration: ContainerConfiguration, kernel: Kernel, options: ContainerCreateOptions, initImage: String? = nil) async throws {
self.log.debug("\(#function)")

try await self.lock.withLock { context in
Expand Down Expand Up @@ -241,11 +241,14 @@ public actor ContainersService {

let path = self.containerRoot.appendingPathComponent(configuration.id)
let systemPlatform = kernel.platform
let initFs = try await self.getInitBlock(for: systemPlatform.ociPlatform())

// Fetch init image (custom or default)
self.log.info("Using init image: \(initImage ?? ClientImage.initImageRef)")
let initFilesystem = try await self.getInitBlock(for: systemPlatform.ociPlatform(), imageRef: initImage)

let bundle = try ContainerClient.Bundle.create(
path: path,
initialFilesystem: initFs,
initialFilesystem: initFilesystem,
kernel: kernel,
containerConfiguration: configuration
)
Expand Down Expand Up @@ -597,8 +600,9 @@ public actor ContainersService {
return options
}

private func getInitBlock(for platform: Platform) async throws -> Filesystem {
let initImage = try await ClientImage.fetch(reference: ClientImage.initImageRef, platform: platform)
private func getInitBlock(for platform: Platform, imageRef: String? = nil) async throws -> Filesystem {
let ref = imageRef ?? ClientImage.initImageRef
let initImage = try await ClientImage.fetch(reference: ref, platform: platform)
var fs = try await initImage.getCreateSnapshot(platform: platform)
fs.options = ["ro"]
return fs
Expand Down