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
3 changes: 2 additions & 1 deletion Sources/ContainerCommands/Network/NetworkCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import ArgumentParser

extension Application {
public struct NetworkCommand: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "network",
abstract: "Manage container networks",
Expand All @@ -30,5 +29,7 @@ extension Application {
],
aliases: ["n"]
)

public init() {}
}
}
9 changes: 5 additions & 4 deletions Sources/ContainerCommands/Network/NetworkCreate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,21 @@ import TerminalProgress

extension Application {
public struct NetworkCreate: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "create",
abstract: "Create a new network")

@Option(name: .customLong("label"), help: "Set metadata for a network")
var labels: [String] = []

@OptionGroup
var global: Flags.Global

@Option(name: .customLong("label"), help: "Set metadata on a network")
var labels: [String] = []

@Argument(help: "Network name")
var name: String

public init() {}

public func run() async throws {
let parsedLabels = Utility.parseKeyValuePairs(labels)
let config = try NetworkConfiguration(id: self.name, mode: .nat, labels: parsedLabels)
Expand Down
9 changes: 5 additions & 4 deletions Sources/ContainerCommands/Network/NetworkDelete.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,22 @@ import Foundation

extension Application {
public struct NetworkDelete: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "delete",
abstract: "Delete one or more networks",
aliases: ["rm"])

@Flag(name: .shortAndLong, help: "Delete all networks")
var all = false

@OptionGroup
var global: Flags.Global

@Flag(name: .shortAndLong, help: "Remove all networks")
var all = false

@Argument(help: "Network names")
var networkNames: [String] = []

public init() {}

public func validate() throws {
if networkNames.count == 0 && !all {
throw ContainerizationError(.invalidArgument, message: "no networks specified and --all not supplied")
Expand Down
7 changes: 4 additions & 3 deletions Sources/ContainerCommands/Network/NetworkInspect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,17 @@ import SwiftProtobuf

extension Application {
public struct NetworkInspect: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "inspect",
abstract: "Display information about one or more networks")

@Argument(help: "Networks to inspect")
var networks: [String]

@OptionGroup
var global: Flags.Global

@Argument(help: "Networks to inspect")
var networks: [String]
public init() {}

public func run() async throws {
let objects: [any Codable] = try await ClientNetwork.list().filter {
Expand Down
9 changes: 5 additions & 4 deletions Sources/ContainerCommands/Network/NetworkList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,22 @@ import SwiftProtobuf

extension Application {
public struct NetworkList: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "list",
abstract: "List networks",
aliases: ["ls"])

@Flag(name: .shortAndLong, help: "Only output the network name")
var quiet = false

@Option(name: .long, help: "Format of the output")
var format: ListFormat = .table

@Flag(name: .shortAndLong, help: "Only output the network name")
var quiet = false

@OptionGroup
var global: Flags.Global

public init() {}

public func run() async throws {
let networks = try await ClientNetwork.list()
try printNetworks(networks: networks, format: format)
Expand Down
3 changes: 2 additions & 1 deletion Sources/ContainerCommands/Volume/VolumeCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import ArgumentParser

extension Application {
public struct VolumeCommand: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "volume",
abstract: "Manage container volumes",
Expand All @@ -30,5 +29,7 @@ extension Application {
],
aliases: ["v"]
)

public init() {}
}
}
14 changes: 9 additions & 5 deletions Sources/ContainerCommands/Volume/VolumeCreate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,28 @@ import Foundation

extension Application.VolumeCommand {
public struct VolumeCreate: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "create",
abstract: "Create a volume"
)

@Option(name: .customShort("s"), help: "Size of the volume (default: 512GB). Examples: 1G, 512MB, 2T")
var size: String?
@Option(name: .customLong("label"), help: "Set metadata for a volume")
var labels: [String] = []

@Option(name: .customLong("opt"), help: "Set driver specific options")
var driverOpts: [String] = []

@Option(name: .customLong("label"), help: "Set metadata on a volume")
var labels: [String] = []
@Option(name: .short, help: "Size of the volume in bytes, with optional K, M, G, T, or P suffix")
var size: String?

@OptionGroup
var global: Flags.Global

@Argument(help: "Volume name")
var name: String

public init() {}

public func run() async throws {
var parsedDriverOpts = Utility.parseKeyValuePairs(driverOpts)
let parsedLabels = Utility.parseKeyValuePairs(labels)
Expand Down
73 changes: 66 additions & 7 deletions Sources/ContainerCommands/Volume/VolumeDelete.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,83 @@

import ArgumentParser
import ContainerClient
import ContainerizationError
import Foundation

extension Application.VolumeCommand {
public struct VolumeDelete: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "delete",
abstract: "Remove one or more volumes",
abstract: "Delete one or more volumes",
aliases: ["rm"]
)

@Argument(help: "Volume name(s)")
var names: [String]
@Flag(name: .shortAndLong, help: "Delete all volumes")
var all = false

@OptionGroup
var global: Flags.Global

@Argument(help: "Volume names")
var names: [String] = []

public init() {}

public func run() async throws {
for name in names {
try await ClientVolume.delete(name: name)
print(name)
let uniqueVolumeNames = Set<String>(names)
let volumes: [Volume]

if all {
volumes = try await ClientVolume.list()
} else {
volumes = try await ClientVolume.list()
.filter { v in
uniqueVolumeNames.contains(v.id)
}

// If one of the volumes requested isn't present lets throw. We don't need to do
// this for --all as --all should be perfectly usable with no volumes to remove,
// otherwise it'd be quite clunky.
if volumes.count != uniqueVolumeNames.count {
let missing = uniqueVolumeNames.filter { id in
!volumes.contains { v in
v.id == id
}
}
throw ContainerizationError(
.notFound,
message: "failed to delete one or more volumes: \(missing)"
)
}
}

var failed = [String]()
try await withThrowingTaskGroup(of: Volume?.self) { group in
for volume in volumes {
group.addTask {
do {
// delete atomically disables the IP allocator, then deletes
// the allocator disable fails if any IPs are still in use
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit but can we do

Suggested change
// the allocator disable fails if any IPs are still in use
// the allocator. Disable fails if any IPs are still in use

or split the sentence by different comment lines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do this fix in the registry PR which is yet to be approved.

try await ClientVolume.delete(name: volume.id)
print(volume.id)
return nil
} catch {
log.error("failed to delete volume \(volume.id): \(error)")
return volume
}
}
}

for try await volume in group {
guard let volume else {
continue
}
failed.append(volume.id)
}
}

if failed.count > 0 {
throw ContainerizationError(.internalError, message: "delete failed for one or more volumes: \(failed)")
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions Sources/ContainerCommands/Volume/VolumeInspect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@ import Foundation

extension Application.VolumeCommand {
public struct VolumeInspect: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "inspect",
abstract: "Display detailed information on one or more volumes"
abstract: "Display information about one or more volumes"
)

@Argument(help: "Volume name(s)")
@OptionGroup
var global: Flags.Global

@Argument(help: "Volume names")
var names: [String]

public init() {}

public func run() async throws {
var volumes: [Volume] = []

Expand Down
12 changes: 8 additions & 4 deletions Sources/ContainerCommands/Volume/VolumeList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,23 @@ import Foundation

extension Application.VolumeCommand {
public struct VolumeList: AsyncParsableCommand {
public init() {}
public static let configuration = CommandConfiguration(
commandName: "list",
abstract: "List volumes",
aliases: ["ls"]
)

@Flag(name: .shortAndLong, help: "Only display volume names")
var quiet: Bool = false

@Option(name: .long, help: "Format of the output")
var format: Application.ListFormat = .table

@Flag(name: .shortAndLong, help: "Only output the volume name")
var quiet: Bool = false

@OptionGroup
var global: Flags.Global

public init() {}

public func run() async throws {
let volumes = try await ClientVolume.list()
try printVolumes(volumes: volumes, format: format)
Expand Down