Initial Commit
This commit is contained in:
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
# =====================================================================
|
||||
# Presses the virtual power button, from the unit's ExecStop=.
|
||||
#
|
||||
# WHY THIS EXISTS
|
||||
#
|
||||
# Stopping the unit used to SIGTERM qemu, which from inside the machine
|
||||
# is indistinguishable from pulling the plug out of the wall. For a
|
||||
# session that is fine - the overlay is thrown away either side of it -
|
||||
# but a MAINTENANCE boot is the operator editing the base image that
|
||||
# every future session runs from, and yanking power on that is how a
|
||||
# frozen image acquires a dirty filesystem, or a half-written registry.
|
||||
#
|
||||
# ExecStop= runs while the main process is still alive, so this sends
|
||||
# `system_powerdown` over QMP and returns. systemd then waits for qemu
|
||||
# to exit by itself, up to TimeoutStopSec - and if the guest ignores the
|
||||
# button, or has already hung, the SIGTERM still happens afterwards. So
|
||||
# this is a courtesy with a deadline, not a new way to get stuck.
|
||||
#
|
||||
# Deliberately never fails: a stop path that can error is a stop path
|
||||
# that leaves the unit in `failed` and the next start blocked.
|
||||
# =====================================================================
|
||||
set -u
|
||||
|
||||
SESSION="${1:-${OWUIVM_SESSION:-}}"
|
||||
[[ "$SESSION" =~ ^[0-9a-f]{32}$ ]] || exit 0
|
||||
SOCK="/run/owuivm/$SESSION/qmp.sock"
|
||||
[ -S "$SOCK" ] || exit 0
|
||||
|
||||
/usr/bin/python3 - "$SOCK" <<'PY' 2>/dev/null || true
|
||||
import json, socket, sys, time
|
||||
path = sys.argv[1]
|
||||
try:
|
||||
s = socket.socket(socket.AF_UNIX); s.settimeout(5); s.connect(path)
|
||||
f = s.makefile("rwb")
|
||||
f.readline() # greeting
|
||||
f.write(b'{"execute":"qmp_capabilities"}\n'); f.flush(); f.readline()
|
||||
f.write(b'{"execute":"system_powerdown"}\n'); f.flush(); f.readline()
|
||||
# Give the guest a moment to notice the button before systemd starts
|
||||
# counting; an OS that has begun shutting down will not be helped by
|
||||
# being asked twice.
|
||||
deadline = time.monotonic() + 90
|
||||
while time.monotonic() < deadline:
|
||||
f.write(b'{"execute":"query-status"}\n'); f.flush()
|
||||
line = f.readline()
|
||||
if not line:
|
||||
break # qemu has gone: done
|
||||
try:
|
||||
if not (json.loads(line).get("return") or {}).get("running", True):
|
||||
break
|
||||
except ValueError:
|
||||
pass
|
||||
time.sleep(1)
|
||||
except Exception:
|
||||
pass
|
||||
PY
|
||||
exit 0
|
||||
Reference in New Issue
Block a user