mirror of
https://github.com/apple/container.git
synced 2026-11-01 19:46:50 +00:00
LinuxContainer/LinuxProcess: Have wait return ExitStatus (#300)
Have wait return a struct containing the exit code and the time at which the process actually exited. This is useful so higher level tools (like container) don't need to craft a date themselves, and it will be more accurate as it's taken in the guest directly after the process exits.
This commit is contained in:
1 parent
511dd59e19
commit
82f2d887dd
14 files changed
+100
-39
No files matched your search
@@ -0,0 +1,26 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Copyright © 2025 Apple Inc. and the Containerization project authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// ExitStatus contains the exit code for a given container process,
|
||||
/// as well as the timestamp at which it exited.
|
||||
public struct ExitStatus: Sendable {
|
||||
/// The exit code for the process.
|
||||
public var exitCode: Int32
|
||||
/// The timestamp when the process exited.
|
||||
public var exitedAt: Date
|
||||
}
|
||||
@@ -742,7 +742,7 @@ extension LinuxContainer {
|
||||
|
||||
/// Wait for the container to exit. Returns the exit code.
|
||||
@discardableResult
|
||||
public func wait(timeoutInSeconds: Int64? = nil) async throws -> Int32 {
|
||||
public func wait(timeoutInSeconds: Int64? = nil) async throws -> ExitStatus {
|
||||
let state = try self.state.withLock { try $0.startedState("wait") }
|
||||
return try await state.process.wait(timeoutInSeconds: timeoutInSeconds)
|
||||
}
|
||||
|
||||
@@ -343,15 +343,15 @@ extension LinuxProcess {
|
||||
|
||||
/// Wait on the process to exit with an optional timeout. Returns the exit code of the process.
|
||||
@discardableResult
|
||||
public func wait(timeoutInSeconds: Int64? = nil) async throws -> Int32 {
|
||||
public func wait(timeoutInSeconds: Int64? = nil) async throws -> ExitStatus {
|
||||
do {
|
||||
let code = try await self.agent.waitProcess(
|
||||
let exitStatus = try await self.agent.waitProcess(
|
||||
id: self.id,
|
||||
containerID: self.owningContainer,
|
||||
timeoutInSeconds: timeoutInSeconds
|
||||
)
|
||||
await self.waitIoComplete()
|
||||
return code
|
||||
return exitStatus
|
||||
} catch {
|
||||
if error is ContainerizationError {
|
||||
throw error
|
||||
|
||||
@@ -476,9 +476,20 @@ public struct Com_Apple_Containerization_Sandbox_V3_WaitProcessResponse: Sendabl
|
||||
|
||||
public var exitCode: Int32 = 0
|
||||
|
||||
public var exitedAt: SwiftProtobuf.Google_Protobuf_Timestamp {
|
||||
get {return _exitedAt ?? SwiftProtobuf.Google_Protobuf_Timestamp()}
|
||||
set {_exitedAt = newValue}
|
||||
}
|
||||
/// Returns true if `exitedAt` has been explicitly set.
|
||||
public var hasExitedAt: Bool {return self._exitedAt != nil}
|
||||
/// Clears the value of `exitedAt`. Subsequent reads from it will return its default value.
|
||||
public mutating func clearExitedAt() {self._exitedAt = nil}
|
||||
|
||||
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
public init() {}
|
||||
|
||||
fileprivate var _exitedAt: SwiftProtobuf.Google_Protobuf_Timestamp? = nil
|
||||
}
|
||||
|
||||
public struct Com_Apple_Containerization_Sandbox_V3_ResizeProcessRequest: Sendable {
|
||||
@@ -1765,6 +1776,7 @@ extension Com_Apple_Containerization_Sandbox_V3_WaitProcessResponse: SwiftProtob
|
||||
public static let protoMessageName: String = _protobuf_package + ".WaitProcessResponse"
|
||||
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "exitCode"),
|
||||
2: .standard(proto: "exited_at"),
|
||||
]
|
||||
|
||||
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
@@ -1774,20 +1786,29 @@ extension Com_Apple_Containerization_Sandbox_V3_WaitProcessResponse: SwiftProtob
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularInt32Field(value: &self.exitCode) }()
|
||||
case 2: try { try decoder.decodeSingularMessageField(value: &self._exitedAt) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
if self.exitCode != 0 {
|
||||
try visitor.visitSingularInt32Field(value: self.exitCode, fieldNumber: 1)
|
||||
}
|
||||
try { if let v = self._exitedAt {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
} }()
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_WaitProcessResponse, rhs: Com_Apple_Containerization_Sandbox_V3_WaitProcessResponse) -> Bool {
|
||||
if lhs.exitCode != rhs.exitCode {return false}
|
||||
if lhs._exitedAt != rhs._exitedAt {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ syntax = "proto3";
|
||||
|
||||
package com.apple.containerization.sandbox.v3;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
// Context for interacting with a container's runtime environment.
|
||||
service SandboxContext {
|
||||
// Mount a filesystem.
|
||||
@@ -155,6 +157,7 @@ message WaitProcessRequest {
|
||||
|
||||
message WaitProcessResponse {
|
||||
int32 exitCode = 1;
|
||||
google.protobuf.Timestamp exited_at = 2;
|
||||
}
|
||||
|
||||
message ResizeProcessRequest {
|
||||
|
||||
@@ -57,7 +57,7 @@ public protocol VirtualMachineAgent: Sendable {
|
||||
func startProcess(id: String, containerID: String?) async throws -> Int32
|
||||
func signalProcess(id: String, containerID: String?, signal: Int32) async throws
|
||||
func resizeProcess(id: String, containerID: String?, columns: UInt32, rows: UInt32) async throws
|
||||
func waitProcess(id: String, containerID: String?, timeoutInSeconds: Int64?) async throws -> Int32
|
||||
func waitProcess(id: String, containerID: String?, timeoutInSeconds: Int64?) async throws -> ExitStatus
|
||||
func deleteProcess(id: String, containerID: String?) async throws
|
||||
func closeProcessStdin(id: String, containerID: String?) async throws
|
||||
|
||||
|
||||
File renamed without changes.
File renamed without changes.
+6
-2
@@ -183,7 +183,11 @@ extension Vminitd: VirtualMachineAgent {
|
||||
_ = try await client.resizeProcess(request)
|
||||
}
|
||||
|
||||
public func waitProcess(id: String, containerID: String?, timeoutInSeconds: Int64? = nil) async throws -> Int32 {
|
||||
public func waitProcess(
|
||||
id: String,
|
||||
containerID: String?,
|
||||
timeoutInSeconds: Int64? = nil
|
||||
) async throws -> ExitStatus {
|
||||
let request = Com_Apple_Containerization_Sandbox_V3_WaitProcessRequest.with {
|
||||
$0.id = id
|
||||
if let containerID {
|
||||
@@ -198,7 +202,7 @@ extension Vminitd: VirtualMachineAgent {
|
||||
}
|
||||
do {
|
||||
let resp = try await client.waitProcess(request, callOptions: callOpts)
|
||||
return resp.exitCode
|
||||
return ExitStatus(exitCode: resp.exitCode, exitedAt: resp.exitedAt.date)
|
||||
} catch {
|
||||
if let err = error as? GRPCError.RPCTimedOut {
|
||||
throw ContainerizationError(
|
||||
Reference in new issue
Block a user