Skip to content

Commit 241481e

Browse files
feat: add init-image flag to allow specifying custom init filesystem images per VM
1 parent 1e19a4d commit 241481e

8 files changed

Lines changed: 32 additions & 30 deletions

File tree

Sources/ContainerClient/Core/ClientContainer.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ extension ClientContainer {
7373
public static func create(
7474
configuration: ContainerConfiguration,
7575
options: ContainerCreateOptions = .default,
76-
kernel: Kernel
76+
kernel: Kernel,
77+
initImage: String? = nil
7778
) async throws -> ClientContainer {
7879
do {
7980
let client = Self.newXPCClient()
@@ -86,6 +87,10 @@ extension ClientContainer {
8687
request.set(key: .kernel, value: kdata)
8788
request.set(key: .containerOptions, value: odata)
8889

90+
if let initImage {
91+
request.set(key: .initImage, value: initImage)
92+
}
93+
8994
try await xpcSend(client: client, message: request)
9095
return ClientContainer(configuration: configuration)
9196
} catch {

Sources/ContainerClient/Core/XPC+.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ public enum XPCKeys: String {
106106
case systemPlatform
107107
case kernelForce
108108

109+
/// Init image reference
110+
case initImage
111+
109112
/// Volume
110113
case volume
111114
case volumes

Sources/ContainerClient/Flags.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ public struct Flags {
142142
)
143143
public var kernel: String?
144144

145+
@Option(
146+
name: .long,
147+
help: .init("Use a custom init image instead of the default", valueName: "image")
148+
)
149+
public var initImage: String?
150+
145151
@Option(name: [.short, .customLong("label")], help: "Add a key=value label to the container")
146152
public var labels: [String] = []
147153

Sources/ContainerClient/Utility.swift

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public struct Utility {
9494
resource: Flags.Resource,
9595
registry: Flags.Registry,
9696
progressUpdate: @escaping ProgressUpdateHandler
97-
) async throws -> (ContainerConfiguration, Kernel) {
97+
) async throws -> (ContainerConfiguration, Kernel, String?) {
9898
var requestedPlatform = Parser.platform(os: management.os, arch: management.arch)
9999
// Prefer --platform
100100
if let platform = management.platform {
@@ -132,25 +132,6 @@ public struct Utility {
132132

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

135-
// Pull and unpack the initial filesystem
136-
await progressUpdate([
137-
.setDescription("Fetching init image"),
138-
.setItemsName("blobs"),
139-
])
140-
let fetchInitTask = await taskManager.startTask()
141-
let initImage = try await ClientImage.fetch(
142-
reference: ClientImage.initImageRef, platform: .current, scheme: scheme,
143-
progressUpdate: ProgressTaskCoordinator.handler(for: fetchInitTask, from: progressUpdate))
144-
145-
await progressUpdate([
146-
.setDescription("Unpacking init image"),
147-
.setItemsName("entries"),
148-
])
149-
let unpackInitTask = await taskManager.startTask()
150-
_ = try await initImage.getCreateSnapshot(
151-
platform: .current,
152-
progressUpdate: ProgressTaskCoordinator.handler(for: unpackInitTask, from: progressUpdate))
153-
154135
await taskManager.finish()
155136

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

249230
config.ssh = management.ssh
250231

251-
return (config, kernel)
232+
return (config, kernel, management.initImage)
252233
}
253234

254235
static func getAttachmentConfigurations(containerId: String, networks: [Parser.ParsedNetwork]) throws -> [AttachmentConfiguration] {

Sources/ContainerCommands/Container/ContainerCreate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ extension Application {
7777
)
7878

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

8282
if !self.managementFlags.cidfile.isEmpty {
8383
let path = self.managementFlags.cidfile

Sources/ContainerCommands/Container/ContainerRun.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ extension Application {
106106
let container = try await ClientContainer.create(
107107
configuration: ck.0,
108108
options: options,
109-
kernel: ck.1
109+
kernel: ck.1,
110+
initImage: ck.2
110111
)
111112

112113
let detach = self.managementFlags.detach

Sources/Services/ContainerAPIService/Containers/ContainersHarness.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,9 @@ public struct ContainersHarness: Sendable {
187187
let config = try JSONDecoder().decode(ContainerConfiguration.self, from: data)
188188
let kernel = try JSONDecoder().decode(Kernel.self, from: kdata)
189189

190-
try await service.create(configuration: config, kernel: kernel, options: options)
190+
let initImage = message.string(key: .initImage)
191+
192+
try await service.create(configuration: config, kernel: kernel, options: options, initImage: initImage)
191193
return message.reply()
192194
}
193195

Sources/Services/ContainerAPIService/Containers/ContainersService.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ public actor ContainersService {
197197
}
198198

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

203203
try await self.lock.withLock { context in
@@ -241,11 +241,14 @@ public actor ContainersService {
241241

242242
let path = self.containerRoot.appendingPathComponent(configuration.id)
243243
let systemPlatform = kernel.platform
244-
let initFs = try await self.getInitBlock(for: systemPlatform.ociPlatform())
244+
245+
// Fetch init image (custom or default)
246+
self.log.info("Using init image: \(initImage ?? ClientImage.initImageRef)")
247+
let initFilesystem = try await self.getInitBlock(for: systemPlatform.ociPlatform(), imageRef: initImage)
245248

246249
let bundle = try ContainerClient.Bundle.create(
247250
path: path,
248-
initialFilesystem: initFs,
251+
initialFilesystem: initFilesystem,
249252
kernel: kernel,
250253
containerConfiguration: configuration
251254
)
@@ -597,8 +600,9 @@ public actor ContainersService {
597600
return options
598601
}
599602

600-
private func getInitBlock(for platform: Platform) async throws -> Filesystem {
601-
let initImage = try await ClientImage.fetch(reference: ClientImage.initImageRef, platform: platform)
603+
private func getInitBlock(for platform: Platform, imageRef: String? = nil) async throws -> Filesystem {
604+
let ref = imageRef ?? ClientImage.initImageRef
605+
let initImage = try await ClientImage.fetch(reference: ref, platform: platform)
602606
var fs = try await initImage.getCreateSnapshot(platform: platform)
603607
fs.options = ["ro"]
604608
return fs

0 commit comments

Comments
 (0)