Shutdown VM gracefully from created state (#495)

This PR enables gracefully shutting down VM even when the
`LinuxContainer` is in `created` state.
This commit is contained in:
jwhur
2026-01-26 15:56:24 -08:00
committed by GitHub
parent 7d4bd80fc8
commit fd62f311b4
+39 -22
View File
@@ -606,12 +606,25 @@ extension LinuxContainer {
return
}
let startedState = try state.startedState("stop")
let vm = startedState.vm
let vm: any VirtualMachineInstance
let relayManager: UnixSocketRelayManager
let fileMountContext: FileMountContext
let startedState = try? state.startedState("stop")
if let startedState {
vm = startedState.vm
relayManager = startedState.relayManager
fileMountContext = startedState.fileMountContext
} else {
let createdState = try state.createdState("stop")
vm = createdState.vm
relayManager = createdState.relayManager
fileMountContext = createdState.fileMountContext
}
var firstError: Error?
do {
try await startedState.relayManager.stopAll()
try await relayManager.stopAll()
} catch {
self.logger?.error("failed to stop relay manager: \(error)")
firstError = firstError ?? error
@@ -634,15 +647,17 @@ extension LinuxContainer {
}
}
// Now lets ensure every process is donezo.
try await agent.kill(pid: -1, signal: SIGKILL)
if let _ = startedState {
// Now lets ensure every process is donezo.
try await agent.kill(pid: -1, signal: SIGKILL)
// Wait on init proc exit. Give it 5 seconds of leeway.
_ = try await agent.waitProcess(
id: self.id,
containerID: self.id,
timeoutInSeconds: 5
)
// Wait on init proc exit. Give it 5 seconds of leeway.
_ = try await agent.waitProcess(
id: self.id,
containerID: self.id,
timeoutInSeconds: 5
)
}
// Today, we leave EBUSY looping and other fun logic up to the
// guest agent.
@@ -658,24 +673,26 @@ extension LinuxContainer {
firstError = firstError ?? error
}
for process in startedState.vendedProcesses.values {
if let startedState {
for process in startedState.vendedProcesses.values {
do {
try await process._delete()
} catch {
self.logger?.error("failed to delete process \(process.id): \(error)")
firstError = firstError ?? error
}
}
do {
try await process._delete()
try await startedState.process.delete()
} catch {
self.logger?.error("failed to delete process \(process.id): \(error)")
self.logger?.error("failed to delete init process: \(error)")
firstError = firstError ?? error
}
}
do {
try await startedState.process.delete()
} catch {
self.logger?.error("failed to delete init process: \(error)")
firstError = firstError ?? error
}
// Clean up file mount temporary directories.
startedState.fileMountContext.cleanup()
fileMountContext.cleanup()
do {
try await vm.stop()