Skip to content
Merged
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
4 changes: 2 additions & 2 deletions Sources/ContainerCommands/BuildCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,10 @@ extension Application {
}

group.addTask { [vsockPort, cpus, memory, log, dnsNameservers] in
let client = ContainerClient()
while true {
do {
let container = try await ClientContainer.get(id: "buildkit")
let fh = try await container.dial(vsockPort)
let fh = try await client.dial(id: "buildkit", port: vsockPort)

let threadGroup: MultiThreadedEventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
let b = try Builder(socket: fh, group: threadGroup)
Expand Down
7 changes: 4 additions & 3 deletions Sources/ContainerCommands/Builder/BuilderDelete.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ extension Application {

public func run() async throws {
do {
let container = try await ClientContainer.get(id: "buildkit")
let client = ContainerClient()
let container = try await client.get(id: "buildkit")
if container.status != .stopped {
guard force else {
throw ContainerizationError(.invalidState, message: "BuildKit container is not stopped, use --force to override")
}
try await container.stop()
try await client.stop(id: container.id)
}
try await container.delete()
try await client.delete(id: container.id)
} catch {
if error is ContainerizationError {
if (error as? ContainerizationError)?.code == .notFound {
Expand Down
68 changes: 36 additions & 32 deletions Sources/ContainerCommands/Builder/BuilderStart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ extension Application {
}
targetEnvVars.sort()

let existingContainer = try? await ClientContainer.get(id: "buildkit")
let client = ContainerClient()
let existingContainer = try? await client.get(id: "buildkit")
if let existingContainer {
let existingImage = existingContainer.configuration.image.reference
let existingResources = existingContainer.configuration.resources
Expand Down Expand Up @@ -174,16 +175,16 @@ extension Application {
return
}
// If they changed, stop and delete the existing builder
try await existingContainer.stop()
try await existingContainer.delete()
try await client.stop(id: existingContainer.id)
try await client.delete(id: existingContainer.id)
case .stopped:
// If the builder is stopped and matches our requirements, start it
// Otherwise, delete it and create a new one
guard imageChanged || cpuChanged || memChanged || envChanged || dnsChanged else {
try await existingContainer.startBuildKit(progressUpdate, nil)
try await startBuildKit(client: client, id: existingContainer.id, progressUpdate, nil)
return
}
try await existingContainer.delete()
try await client.delete(id: existingContainer.id)
case .stopping:
throw ContainerizationError(
.invalidState,
Expand Down Expand Up @@ -296,43 +297,46 @@ extension Application {
.setDescription("Starting BuildKit container")
])

let container = try await ClientContainer.create(
try await client.create(
configuration: config,
options: .default,
kernel: kernel
)

try await container.startBuildKit(progressUpdate, taskManager)
try await startBuildKit(client: client, id: Builder.builderContainerId, progressUpdate, taskManager)
log.debug("starting BuildKit and BuildKit-shim")
}
}
}

// MARK: - ClientContainer Extension for BuildKit

extension ClientContainer {
/// Starts the BuildKit process within the container
/// This method handles bootstrapping the container and starting the BuildKit process
fileprivate func startBuildKit(_ progress: @escaping ProgressUpdateHandler, _ taskManager: ProgressTaskCoordinator? = nil) async throws {
do {
let io = try ProcessIO.create(
tty: false,
interactive: false,
detach: true
)
defer { try? io.close() }

let process = try await bootstrap(stdio: io.stdio)
try await process.start()
await taskManager?.finish()
try io.closeAfterStart()
} catch {
try? await stop()
try? await delete()
if error is ContainerizationError {
throw error
}
throw ContainerizationError(.internalError, message: "failed to start BuildKit: \(error)")
// MARK: - BuildKit Start Helper

/// Starts the BuildKit process within the container
/// This function handles bootstrapping the container and starting the BuildKit process
private func startBuildKit(
client: ContainerClient,
id: String,
_ progress: @escaping ProgressUpdateHandler,
_ taskManager: ProgressTaskCoordinator? = nil
) async throws {
do {
let io = try ProcessIO.create(
tty: false,
interactive: false,
detach: true
)
defer { try? io.close() }

let process = try await client.bootstrap(id: id, stdio: io.stdio)
try await process.start()
await taskManager?.finish()
try io.closeAfterStart()
} catch {
try? await client.stop(id: id)
try? await client.delete(id: id)
if error is ContainerizationError {
throw error
}
throw ContainerizationError(.internalError, message: "failed to start BuildKit: \(error)")
}
}
8 changes: 5 additions & 3 deletions Sources/ContainerCommands/Builder/BuilderStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import ArgumentParser
import ContainerAPIClient
import ContainerResource
import ContainerizationError
import ContainerizationExtras
import Foundation
Expand All @@ -42,7 +43,8 @@ extension Application {

public func run() async throws {
do {
let container = try await ClientContainer.get(id: "buildkit")
let client = ContainerClient()
let container = try await client.get(id: "buildkit")
try printContainers(containers: [container], format: format)
} catch {
if error is ContainerizationError {
Expand All @@ -59,7 +61,7 @@ extension Application {
[["ID", "IMAGE", "STATE", "ADDR", "CPUS", "MEMORY"]]
}

private func printContainers(containers: [ClientContainer], format: ListFormat) throws {
private func printContainers(containers: [ContainerSnapshot], format: ListFormat) throws {
if format == .json {
let printables = containers.map {
PrintableContainer($0)
Expand Down Expand Up @@ -88,7 +90,7 @@ extension Application {
}
}

extension ClientContainer {
extension ContainerSnapshot {
fileprivate var asRow: [String] {
[
self.id,
Expand Down
4 changes: 2 additions & 2 deletions Sources/ContainerCommands/Builder/BuilderStop.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ extension Application {

public func run() async throws {
do {
let container = try await ClientContainer.get(id: "buildkit")
try await container.stop()
let client = ContainerClient()
try await client.stop(id: "buildkit")
} catch {
if error is ContainerizationError {
if (error as? ContainerizationError)?.code == .notFound {
Expand Down
7 changes: 4 additions & 3 deletions Sources/ContainerCommands/Container/ContainerCreate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,12 @@ extension Application {
)

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

if !self.managementFlags.cidfile.isEmpty {
let path = self.managementFlags.cidfile
let data = container.id.data(using: .utf8)
let data = id.data(using: .utf8)
var attributes = [FileAttributeKey: Any]()
attributes[.posixPermissions] = 0o644
let success = FileManager.default.createFile(
Expand All @@ -101,7 +102,7 @@ extension Application {
}
progress.finish()

print(container.id)
print(id)
}
}
}
10 changes: 6 additions & 4 deletions Sources/ContainerCommands/Container/ContainerDelete.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import ArgumentParser
import ContainerAPIClient
import ContainerResource
import ContainerizationError
import Foundation

Expand Down Expand Up @@ -54,12 +55,13 @@ extension Application {

public mutating func run() async throws {
let set = Set<String>(containerIds)
var containers = [ClientContainer]()
let client = ContainerClient()
var containers = [ContainerSnapshot]()

if all {
containers = try await ClientContainer.list()
containers = try await client.list()
} else {
let ctrs = try await ClientContainer.list()
let ctrs = try await client.list()
containers = ctrs.filter { c in
set.contains(c.id)
}
Expand Down Expand Up @@ -94,7 +96,7 @@ extension Application {
return nil // Skip running container when using --all
}

try await container.delete(force: force)
try await client.delete(id: container.id, force: force)
print(container.id)
return nil
} catch {
Expand Down
8 changes: 5 additions & 3 deletions Sources/ContainerCommands/Container/ContainerExec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ extension Application {

public func run() async throws {
var exitCode: Int32 = 127
let container = try await ClientContainer.get(id: containerId)
let client = ContainerClient()
let container = try await client.get(id: containerId)
try ensureRunning(container: container)

let stdin = self.processFlags.interactive
Expand Down Expand Up @@ -79,8 +80,9 @@ extension Application {
try? io.close()
}

let process = try await container.createProcess(
id: UUID().uuidString.lowercased(),
let process = try await client.createProcess(
containerId: container.id,
processId: UUID().uuidString.lowercased(),
configuration: config,
stdio: io.stdio
)
Expand Down
4 changes: 3 additions & 1 deletion Sources/ContainerCommands/Container/ContainerInspect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import ArgumentParser
import ContainerAPIClient
import ContainerResource
import Foundation
import SwiftProtobuf

Expand All @@ -34,7 +35,8 @@ extension Application {
var containerIds: [String]

public func run() async throws {
let objects: [any Codable] = try await ClientContainer.list().filter {
let client = ContainerClient()
let objects: [any Codable] = try await client.list().filter {
containerIds.contains($0.id)
}.map {
PrintableContainer($0)
Expand Down
5 changes: 3 additions & 2 deletions Sources/ContainerCommands/Container/ContainerKill.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ extension Application {

public mutating func run() async throws {
let set = Set<String>(containerIds)
let client = ContainerClient()

var containers = try await ClientContainer.list().filter { c in
var containers = try await client.list().filter { c in
c.status == .running
}
if !self.all {
Expand All @@ -66,7 +67,7 @@ extension Application {
var failed: [String] = []
for container in containers {
do {
try await container.kill(signalNumber)
try await client.kill(id: container.id, signal: signalNumber)
print(container.id)
} catch {
log.error("failed to kill container \(container.id): \(error)")
Expand Down
13 changes: 7 additions & 6 deletions Sources/ContainerCommands/Container/ContainerList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@ extension Application {
public init() {}

public func run() async throws {
let containers = try await ClientContainer.list()
let client = ContainerClient()
let containers = try await client.list()
try printContainers(containers: containers, format: format)
}

private func createHeader() -> [[String]] {
[["ID", "IMAGE", "OS", "ARCH", "STATE", "ADDR", "CPUS", "MEMORY", "STARTED"]]
}

private func printContainers(containers: [ClientContainer], format: ListFormat) throws {
private func printContainers(containers: [ContainerSnapshot], format: ListFormat) throws {
if format == .json {
let printables = containers.map {
PrintableContainer($0)
Expand Down Expand Up @@ -86,13 +87,13 @@ extension Application {
}
}

extension ClientContainer {
extension ContainerSnapshot {
fileprivate var asRow: [String] {
[
self.id,
self.configuration.image.reference,
self.configuration.platform.os,
self.configuration.platform.architecture,
self.platform.os,
self.platform.architecture,
self.status.rawValue,
self.networks.compactMap { $0.ipv4Address.description }.joined(separator: ","),
"\(self.configuration.resources.cpus)",
Expand All @@ -108,7 +109,7 @@ struct PrintableContainer: Codable {
let networks: [Attachment]
let startedDate: Date?

init(_ container: ClientContainer) {
init(_ container: ContainerSnapshot) {
self.status = container.status
self.configuration = container.configuration
self.networks = container.networks
Expand Down
25 changes: 9 additions & 16 deletions Sources/ContainerCommands/Container/ContainerLogs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,15 @@ extension Application {
var containerId: String

public func run() async throws {
do {
let container = try await ClientContainer.get(id: containerId)
let fhs = try await container.logs()
let fileHandle = boot ? fhs[1] : fhs[0]

try await Self.tail(
fh: fileHandle,
n: numLines,
follow: follow
)
} catch {
throw ContainerizationError(
.invalidArgument,
message: "failed to fetch container logs for \(containerId): \(error)"
)
}
let client = ContainerClient()
let fhs = try await client.logs(id: containerId)
let fileHandle = boot ? fhs[1] : fhs[0]

try await Self.tail(
fh: fileHandle,
n: numLines,
follow: follow
)
}

private static func tail(
Expand Down
7 changes: 4 additions & 3 deletions Sources/ContainerCommands/Container/ContainerPrune.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ extension Application {
public var logOptions: Flags.Logging

public func run() async throws {
let containersToPrune = try await ClientContainer.list().filter { $0.status == .stopped }
let client = ContainerClient()
let containersToPrune = try await client.list().filter { $0.status == .stopped }

var prunedContainerIds = [String]()
var totalSize: UInt64 = 0

for container in containersToPrune {
do {
let actualSize = try await ClientContainer.containerDiskUsage(id: container.id)
let actualSize = try await client.diskUsage(id: container.id)
totalSize += actualSize
try await container.delete()
try await client.delete(id: container.id)
prunedContainerIds.append(container.id)
} catch {
log.error("Failed to prune container \(container.id): \(error)")
Expand Down
Loading