mirror of
https://github.com/apple/container.git
synced 2026-09-22 07:35:36 +00:00
APIServer: Add support for filtering to list rpc (#1175)
This is not intended to be used to support `--filter` or similar on the CLIs list yet, it's solely to clean up our rather awkward use of `ContainerClient.list()` today in the CLI. The list RPC simply returns all of the containers we have created. Because of this, for a LOT of our commands we filter to what we need client side, which feels like a waste.. This change introduces a filter struct that we can provide an array of container IDs, labels, and the status of the containers to filter the `list()` output from. This additionally, because it was killing (pun not intended) me and I was already having to change this area for the `list()` additions, changes container kill slightly to return an error if you try and kill a container that doesn't exist.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
import ArgumentParser
|
||||
import ContainerAPIClient
|
||||
import ContainerResource
|
||||
import ContainerizationError
|
||||
import ContainerizationOS
|
||||
import Darwin
|
||||
@@ -50,16 +51,13 @@ extension Application {
|
||||
}
|
||||
|
||||
public mutating func run() async throws {
|
||||
let set = Set<String>(containerIds)
|
||||
let client = ContainerClient()
|
||||
|
||||
var containers = try await client.list().filter { c in
|
||||
c.status == .running
|
||||
}
|
||||
if !self.all {
|
||||
containers = containers.filter { c in
|
||||
set.contains(c.id)
|
||||
}
|
||||
let containers: [String]
|
||||
if self.all {
|
||||
containers = try await client.list(filters: ContainerListFilters(status: .running)).map { $0.id }
|
||||
} else {
|
||||
containers = containerIds
|
||||
}
|
||||
|
||||
let signalNumber = try Signals.parseSignal(signal)
|
||||
@@ -67,8 +65,8 @@ extension Application {
|
||||
var errors: [any Error] = []
|
||||
for container in containers {
|
||||
do {
|
||||
try await client.kill(id: container.id, signal: signalNumber)
|
||||
print(container.id)
|
||||
try await client.kill(id: container, signal: signalNumber)
|
||||
print(container)
|
||||
} catch {
|
||||
errors.append(error)
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ extension Application {
|
||||
|
||||
public func run() async throws {
|
||||
let client = ContainerClient()
|
||||
let containers = try await client.list()
|
||||
let filters = self.all ? ContainerListFilters.all : ContainerListFilters(status: .running)
|
||||
let containers = try await client.list(filters: filters)
|
||||
try printContainers(containers: containers, format: format)
|
||||
}
|
||||
|
||||
@@ -65,9 +66,6 @@ extension Application {
|
||||
|
||||
if self.quiet {
|
||||
containers.forEach {
|
||||
if !self.all && $0.status != .running {
|
||||
return
|
||||
}
|
||||
print($0.id)
|
||||
}
|
||||
return
|
||||
@@ -75,9 +73,6 @@ extension Application {
|
||||
|
||||
var rows = createHeader()
|
||||
for container in containers {
|
||||
if !self.all && container.status != .running {
|
||||
continue
|
||||
}
|
||||
rows.append(container.asRow)
|
||||
}
|
||||
|
||||
|
||||
@@ -63,25 +63,23 @@ extension Application {
|
||||
|
||||
private func runStatic() async throws {
|
||||
let client = ContainerClient()
|
||||
let allContainers = try await client.list()
|
||||
|
||||
let containersToShow: [ContainerSnapshot]
|
||||
if containers.isEmpty {
|
||||
// No containers specified - show all running containers
|
||||
containersToShow = allContainers.filter { $0.status == .running }
|
||||
containersToShow = try await client.list(filters: ContainerListFilters(status: .running))
|
||||
} else {
|
||||
// Validate all specified containers exist before proceeding
|
||||
var found: [ContainerSnapshot] = []
|
||||
// Fetch specified containers by ID
|
||||
containersToShow = try await client.list(filters: ContainerListFilters(ids: containers))
|
||||
// Validate all specified containers were found
|
||||
for containerId in containers {
|
||||
guard let container = allContainers.first(where: { $0.id == containerId || $0.id.starts(with: containerId) }) else {
|
||||
guard containersToShow.contains(where: { $0.id == containerId }) else {
|
||||
throw ContainerizationError(
|
||||
.notFound,
|
||||
message: "no such container: \(containerId)"
|
||||
)
|
||||
}
|
||||
found.append(container)
|
||||
}
|
||||
containersToShow = found
|
||||
}
|
||||
|
||||
let statsData = try await collectStats(client: client, for: containersToShow)
|
||||
@@ -101,9 +99,9 @@ extension Application {
|
||||
|
||||
// If containers were specified, validate they all exist upfront
|
||||
if !containers.isEmpty {
|
||||
let allContainers = try await client.list()
|
||||
let specifiedContainers = try await client.list(filters: ContainerListFilters(ids: containers))
|
||||
for containerId in containers {
|
||||
guard allContainers.first(where: { $0.id == containerId || $0.id.starts(with: containerId) }) != nil else {
|
||||
guard specifiedContainers.contains(where: { $0.id == containerId }) else {
|
||||
throw ContainerizationError(
|
||||
.notFound,
|
||||
message: "no such container: \(containerId)"
|
||||
@@ -118,19 +116,11 @@ extension Application {
|
||||
|
||||
while true {
|
||||
do {
|
||||
let allContainers = try await client.list()
|
||||
|
||||
let containersToShow: [ContainerSnapshot]
|
||||
if containers.isEmpty {
|
||||
containersToShow = allContainers.filter { $0.status == .running }
|
||||
containersToShow = try await client.list(filters: ContainerListFilters(status: .running))
|
||||
} else {
|
||||
var found: [ContainerSnapshot] = []
|
||||
for containerId in containers {
|
||||
if let container = allContainers.first(where: { $0.id == containerId || $0.id.starts(with: containerId) }) {
|
||||
found.append(container)
|
||||
}
|
||||
}
|
||||
containersToShow = found
|
||||
containersToShow = try await client.list(filters: ContainerListFilters(ids: containers))
|
||||
}
|
||||
|
||||
let statsData = try await collectStats(client: client, for: containersToShow)
|
||||
|
||||
@@ -79,9 +79,8 @@ extension Application {
|
||||
log.info("waiting for containers to exit")
|
||||
do {
|
||||
for _ in 0..<Self.shutdownTimeoutSeconds {
|
||||
let anyRunning = try await client.list()
|
||||
.contains { $0.status == .running }
|
||||
guard anyRunning else {
|
||||
let runningContainers = try await client.list(filters: ContainerListFilters(status: .running))
|
||||
guard !runningContainers.isEmpty else {
|
||||
break
|
||||
}
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
Reference in New Issue
Block a user