mirror of
https://github.com/apple/container.git
synced 2026-09-27 01:21:04 -04:00
cli: Add support for --stop-signal (#1462)
- Closes #1581. - This adds stop signal support to the cli. The priority is: 1. If an explicit stop signal is passed on the cli use this. 2. If not, check if there is a stop signal in the image config. 3. Finally, use the default (TERM).
This commit is contained in:
@@ -19,7 +19,6 @@ import ContainerAPIClient
|
||||
import ContainerResource
|
||||
import Containerization
|
||||
import ContainerizationError
|
||||
import ContainerizationOS
|
||||
import Foundation
|
||||
import Logging
|
||||
|
||||
@@ -35,7 +34,7 @@ extension Application {
|
||||
var all = false
|
||||
|
||||
@Option(name: .shortAndLong, help: "Signal to send to the containers")
|
||||
var signal: String = "SIGTERM"
|
||||
var signal: String?
|
||||
|
||||
@Option(name: .shortAndLong, help: "Seconds to wait before killing the containers")
|
||||
var time: Int32 = 5
|
||||
@@ -68,7 +67,7 @@ extension Application {
|
||||
|
||||
let opts = ContainerStopOptions(
|
||||
timeoutInSeconds: self.time,
|
||||
signal: try Signal(self.signal).rawValue
|
||||
signal: self.signal
|
||||
)
|
||||
try await Self.stopContainers(
|
||||
client: client,
|
||||
|
||||
@@ -66,8 +66,7 @@ extension Application {
|
||||
log.info("stopping containers", metadata: ["stopTimeoutSeconds": "\(Self.stopTimeoutSeconds)"])
|
||||
do {
|
||||
let containers = try await client.list().map { $0.id }
|
||||
let signal = Signal.term.rawValue
|
||||
let opts = ContainerStopOptions(timeoutInSeconds: Self.stopTimeoutSeconds, signal: signal)
|
||||
let opts = ContainerStopOptions(timeoutInSeconds: Self.stopTimeoutSeconds, signal: nil)
|
||||
try await ContainerStop.stopContainers(
|
||||
client: client,
|
||||
containers: containers,
|
||||
|
||||
@@ -59,6 +59,8 @@ public struct ContainerConfiguration: Sendable, Codable {
|
||||
public var capDrop: [String] = []
|
||||
/// Size of /dev/shm in bytes. When nil, the default size is used.
|
||||
public var shmSize: UInt64?
|
||||
/// Signal to send to the container process on stop (from image config).
|
||||
public var stopSignal: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
@@ -82,6 +84,7 @@ public struct ContainerConfiguration: Sendable, Codable {
|
||||
case capAdd
|
||||
case capDrop
|
||||
case shmSize
|
||||
case stopSignal
|
||||
}
|
||||
|
||||
/// Create a configuration from the supplied Decoder, initializing missing
|
||||
@@ -116,6 +119,7 @@ public struct ContainerConfiguration: Sendable, Codable {
|
||||
capAdd = try container.decodeIfPresent([String].self, forKey: .capAdd) ?? []
|
||||
capDrop = try container.decodeIfPresent([String].self, forKey: .capDrop) ?? []
|
||||
shmSize = try container.decodeIfPresent(UInt64.self, forKey: .shmSize)
|
||||
stopSignal = try container.decodeIfPresent(String.self, forKey: .stopSignal)
|
||||
}
|
||||
|
||||
public struct DNSConfiguration: Sendable, Codable {
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
import Foundation
|
||||
|
||||
public struct ContainerStopOptions: Sendable, Codable {
|
||||
public let timeoutInSeconds: Int32
|
||||
public let signal: Int32
|
||||
public var timeoutInSeconds: Int32
|
||||
public var signal: String?
|
||||
|
||||
public static let `default` = ContainerStopOptions(
|
||||
timeoutInSeconds: 5,
|
||||
signal: SIGTERM
|
||||
signal: nil
|
||||
)
|
||||
|
||||
public init(timeoutInSeconds: Int32, signal: Int32) {
|
||||
public init(timeoutInSeconds: Int32, signal: String?) {
|
||||
self.timeoutInSeconds = timeoutInSeconds
|
||||
self.signal = signal
|
||||
}
|
||||
|
||||
@@ -262,6 +262,7 @@ public struct Utility {
|
||||
let caps = try Parser.capabilities(capAdd: management.capAdd, capDrop: management.capDrop)
|
||||
config.capAdd = caps.capAdd
|
||||
config.capDrop = caps.capDrop
|
||||
config.stopSignal = imageConfig?.stopSignal
|
||||
|
||||
if let runtime = management.runtime {
|
||||
config.runtimeHandler = runtime
|
||||
|
||||
@@ -636,8 +636,13 @@ public actor ContainersService {
|
||||
return
|
||||
}
|
||||
|
||||
var resolvedOptions = options
|
||||
if resolvedOptions.signal == nil, let stopSignal = state.snapshot.configuration.stopSignal {
|
||||
resolvedOptions.signal = stopSignal
|
||||
}
|
||||
|
||||
do {
|
||||
try await client.stop(options: options)
|
||||
try await client.stop(options: resolvedOptions)
|
||||
} catch let err as ContainerizationError {
|
||||
if err.code != .interrupted {
|
||||
throw err
|
||||
@@ -842,7 +847,7 @@ public actor ContainersService {
|
||||
}
|
||||
let opts = ContainerStopOptions(
|
||||
timeoutInSeconds: 5,
|
||||
signal: SIGKILL
|
||||
signal: "SIGKILL"
|
||||
)
|
||||
let client = try state.getClient()
|
||||
try await client.stop(options: opts)
|
||||
|
||||
@@ -1204,7 +1204,8 @@ public actor RuntimeService {
|
||||
try await lc.wait()
|
||||
}
|
||||
group.addTask {
|
||||
try await lc.kill(Signal(rawValue: stopOpts.signal))
|
||||
let signal = try Signal(stopOpts.signal ?? "SIGTERM")
|
||||
try await lc.kill(signal)
|
||||
try await Task.sleep(for: .seconds(stopOpts.timeoutInSeconds))
|
||||
try await lc.kill(.kill)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user