mirror of
https://github.com/vdsm/virtual-dsm.git
synced 2026-08-28 20:06:05 +00:00
feat: Preserve graceful shutdown for interactive console (#1312)
This commit is contained in:
+1
-1
@@ -36,7 +36,7 @@ if ! interactive; then
|
||||
"${cmd[@]}" ${ARGS:+ $ARGS} &
|
||||
else
|
||||
startConsole
|
||||
setsid -w "${cmd[@]}" ${ARGS:+ $ARGS} </dev/null &
|
||||
startQemu "${cmd[@]}" ${ARGS:+ $ARGS}
|
||||
fi
|
||||
|
||||
pid=$!
|
||||
|
||||
+81
-25
@@ -15,6 +15,7 @@ SHUTDOWN_SIGNAL=0
|
||||
QEMU_END="$QEMU_DIR/qemu.end"
|
||||
CONSOLE_PID="$QEMU_DIR/console.pid"
|
||||
CONSOLE_SOCKET="$QEMU_DIR/console.sock"
|
||||
QEMU_START_PID="$QEMU_DIR/qemu.start.pid"
|
||||
|
||||
_trap() {
|
||||
|
||||
@@ -67,19 +68,55 @@ displayReason() {
|
||||
readQemuPid() {
|
||||
|
||||
local -n _pid="$1"
|
||||
local file
|
||||
|
||||
if [ ! -s "$QEMU_PID" ] || ! read -r _pid <"$QEMU_PID"; then
|
||||
return 1
|
||||
fi
|
||||
for file in "$QEMU_START_PID" "$QEMU_PID"; do
|
||||
if [ -s "$file" ] && read -r _pid < "$file"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
qemuPidFile() {
|
||||
|
||||
local -n _file="$1"
|
||||
|
||||
_file="$QEMU_PID"
|
||||
[ -s "$QEMU_START_PID" ] && _file="$QEMU_START_PID"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
waitQemuExit() {
|
||||
|
||||
local timeout="${1:-10}"
|
||||
local file=""
|
||||
|
||||
qemuPidFile file
|
||||
waitPidFile "$file" "$timeout"
|
||||
}
|
||||
|
||||
waitQemuPid() {
|
||||
|
||||
local -n _pid="$1"
|
||||
local cnt=0 value=""
|
||||
|
||||
while ! readQemuPid value; do
|
||||
sleep 0.02
|
||||
cnt=$((cnt + 1))
|
||||
(( cnt >= 50 )) && return 1
|
||||
done
|
||||
|
||||
_pid="$value"
|
||||
return 0
|
||||
}
|
||||
|
||||
forceKillQemu() {
|
||||
|
||||
local reason="$1"
|
||||
local pid=""
|
||||
local display
|
||||
local pid="" display
|
||||
|
||||
! readQemuPid pid && return 0
|
||||
! isAlive "$pid" && return 0
|
||||
@@ -108,8 +145,7 @@ cleanupHelpers() {
|
||||
startConsole() {
|
||||
|
||||
local output="${1:-/dev/tty}"
|
||||
local cnt=0
|
||||
local pid=""
|
||||
local cnt=0 pid=""
|
||||
|
||||
rm -f -- "$CONSOLE_SOCKET" "$CONSOLE_PID"
|
||||
|
||||
@@ -154,10 +190,34 @@ stopConsole() {
|
||||
return 0
|
||||
}
|
||||
|
||||
startQemu() {
|
||||
|
||||
rm -f -- "$QEMU_START_PID"
|
||||
|
||||
(
|
||||
trap '' INT QUIT
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
exec setsid -f -w sh -c '
|
||||
file=$1
|
||||
shift
|
||||
|
||||
"$@" &
|
||||
pid=$!
|
||||
printf "%s\n" "$pid" > "$file" || exit 1
|
||||
|
||||
rc=0
|
||||
wait "$pid" 2>/dev/null || rc=$?
|
||||
exit "$rc"
|
||||
' sh "$QEMU_START_PID" "$@"
|
||||
) </dev/null &
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
finish() {
|
||||
|
||||
local reason=$1
|
||||
local failed=0
|
||||
local reason=$1 failed=0
|
||||
|
||||
if [ ! -f "$QEMU_END" ] && (( reason != 0 )); then
|
||||
failed=1
|
||||
@@ -168,7 +228,7 @@ finish() {
|
||||
forceKillQemu "$reason"
|
||||
cleanupHelpers
|
||||
|
||||
if ! waitPidFile "$QEMU_PID" 10; then
|
||||
if ! waitQemuExit 10; then
|
||||
warn "Timed out while waiting for $(app) to exit!"
|
||||
fi
|
||||
|
||||
@@ -186,8 +246,7 @@ finish() {
|
||||
sendGuestShutdown() {
|
||||
|
||||
local pid="$1"
|
||||
local response
|
||||
local url
|
||||
local response url
|
||||
|
||||
# Don't send the powerdown signal because vDSM ignores ACPI signals
|
||||
# nc -q 1 -w 1 -U "$QEMU_DIR/monitor.sock" &> /dev/null <<<'system_powerdown' || :
|
||||
@@ -218,9 +277,6 @@ normalizeTimeout() {
|
||||
|
||||
local term_grace=3 # seconds before loop ends to send SIGTERM
|
||||
local cleanup_grace=3 # seconds reserved after the loop for cleanup
|
||||
local elapsed
|
||||
local timeout_left
|
||||
local min
|
||||
|
||||
TIMEOUT=$(strip "$TIMEOUT")
|
||||
if [[ ! "$TIMEOUT" =~ ^[0-9]+$ ]]; then
|
||||
@@ -235,10 +291,10 @@ normalizeTimeout() {
|
||||
cleanup_grace=4
|
||||
fi
|
||||
|
||||
elapsed=$((SECONDS - start))
|
||||
timeout_left=$((TIMEOUT - elapsed))
|
||||
local elapsed=$((SECONDS - start))
|
||||
local timeout_left=$((TIMEOUT - elapsed))
|
||||
|
||||
min=$((term_grace + cleanup_grace + 1))
|
||||
local min=$((term_grace + cleanup_grace + 1))
|
||||
(( timeout_left < min )) && timeout_left=$min
|
||||
|
||||
wait_until=$((timeout_left - cleanup_grace))
|
||||
@@ -252,18 +308,17 @@ waitForShutdown() {
|
||||
local cnt=0
|
||||
local pid="$1"
|
||||
local name="$APP"
|
||||
local slp
|
||||
|
||||
while (( cnt <= wait_until && SHUTDOWN_SKIP == 0 )); do
|
||||
|
||||
sleep 1 &
|
||||
slp=$!
|
||||
local slp=$!
|
||||
|
||||
# Stop waiting if the process has exited
|
||||
! isAlive "$pid" && break
|
||||
|
||||
# Workaround for stale/zombie QEMU pid file
|
||||
[ ! -s "$QEMU_PID" ] && break
|
||||
[ ! -s "$QEMU_START_PID" ] && [ ! -s "$QEMU_PID" ] && break
|
||||
|
||||
if (( cnt == sigterm_at )); then
|
||||
info "${name^} is still running, sending SIGTERM... ($cnt/$wait_until)"
|
||||
@@ -283,8 +338,7 @@ waitForShutdown() {
|
||||
graceful_shutdown() {
|
||||
|
||||
local sig="$1"
|
||||
local pid=""
|
||||
local code=0
|
||||
local pid="" code=0
|
||||
|
||||
[[ $BASHPID != "$TRAP_PID" ]] && return
|
||||
|
||||
@@ -310,8 +364,10 @@ graceful_shutdown() {
|
||||
echo && info "Received $sig signal, sending shutdown command..."
|
||||
|
||||
if ! readQemuPid pid; then
|
||||
warn "QEMU PID file ($QEMU_PID) does not exist?"
|
||||
finish "$code"
|
||||
if ! interactive || ! waitQemuPid pid; then
|
||||
warn "QEMU PID file does not exist?"
|
||||
finish "$code"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$pid" ] || ! isAlive "$pid"; then
|
||||
|
||||
Reference in New Issue
Block a user