diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-13 11:22:40 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-13 11:22:40 +0200 |
| commit | 87cd101eb3c55d0ad7e8f2142fcce90865da7d39 (patch) | |
| tree | a2bc25c6af717d13caadfbef008ab89b00770190 /vm-manager/Virsh.qml | |
| parent | f84176cf1c866da4d263d278774932acb81b4b8d (diff) | |
| download | quickshell-87cd101eb3c55d0ad7e8f2142fcce90865da7d39.tar.gz quickshell-87cd101eb3c55d0ad7e8f2142fcce90865da7d39.zip | |
feat(vm-manager): offer to discard a saved state that will not restore
A VM saved rather than shut down restores its memory image on the next
start. When that image cannot be restored the start fails every time with
"unable to execute QEMU command 'migrate-incoming'", and the panel showed
an ordinary "shut off" with a Start button that could never work.
Detection is virsh dominfo grepped for "Managed save: yes", polled per VM
on every list refresh the way the agent rows are. domstats does not report
it: the shut-off reason reads "failed", from the failed start, not from
the save. virsh list --all --managed-save does print "saved" in the state
column, but not together with --name, which is the form the panel lists
with.
The button appears only when a saved image exists, since managedsave-remove
fails without one and would be noise on every other VM. It takes a
confirmation click but not a typed name: it deletes the memory image and
leaves the disk alone, so the cost of a misclick is a cold boot.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lo1FG4qTr1inavmhqhfobe
Diffstat (limited to 'vm-manager/Virsh.qml')
| -rw-r--r-- | vm-manager/Virsh.qml | 45 |
1 files changed, 43 insertions, 2 deletions
diff --git a/vm-manager/Virsh.qml b/vm-manager/Virsh.qml index 309781c..14bd368 100644 --- a/vm-manager/Virsh.qml +++ b/vm-manager/Virsh.qml @@ -21,7 +21,7 @@ import QtQuick Singleton { id: root - // name -> { state, cpu, memUsed, memTotal, fsUsed, fsTotal, ip, vcpus, agent } + // name -> { state, cpu, memUsed, memTotal, fsUsed, fsTotal, ip, vcpus, agent, saved } property var vms: ({}) property var names: [] property var snapshots: ({}) // name -> [{ name, created, state, current }] @@ -33,7 +33,8 @@ Singleton { function _vm(name) { return vms[name] ?? { state: "unknown", cpu: -1, memUsed: -1, memTotal: -1, - fsUsed: -1, fsTotal: -1, ip: "", vcpus: 0, agent: false }; + fsUsed: -1, fsTotal: -1, ip: "", vcpus: 0, agent: false, + saved: false }; } function _set(name, fields) { @@ -52,6 +53,7 @@ Singleton { const found = text.trim().split("\n").map(s => s.trim()).filter(s => s.length); root.names = found; for (const n of found) if (!(n in root.vms)) root._set(n, {}); + root._pollSaved(); root.refresh(); } } @@ -191,6 +193,44 @@ Singleton { onExited: code => { if (code !== 0) { root._set(vm, { ip: "" }); root._nextAgent(); } } } + // --- managed save ---------------------------------------------------- + // + // A shut-off VM can still carry a saved memory image, and `virsh start` + // then restores it rather than booting. When that image cannot be + // restored the start fails every time with a QEMU migrate-incoming + // error, and nothing in the panel said why. `domstats` does not report + // it: the shut-off reason reads "failed", from the failed start, not + // from the save. `dominfo` is the only cheap source, so it is polled per + // VM the way the agent rows are. + + property var _savedQueue: [] + + function _pollSaved() { + _savedQueue = names.slice(); + _nextSaved(); + } + + function _nextSaved() { + if (_savedQueue.length === 0) return; + const vm = _savedQueue[0]; + _savedQueue = _savedQueue.slice(1); + savedProc.vm = vm; + savedProc.command = ["virsh", "dominfo", vm]; + savedProc.running = true; + } + + Process { + id: savedProc + property string vm: "" + stdout: StdioCollector { + onStreamFinished: { + root._set(savedProc.vm, { saved: /^Managed save:\s+yes$/m.test(text) }); + root._nextSaved(); + } + } + onExited: code => { if (code !== 0) { root._set(vm, { saved: false }); root._nextSaved(); } } + } + // --- snapshots ------------------------------------------------------- Process { @@ -227,6 +267,7 @@ Singleton { destroy: v => ["virsh", "destroy", v], suspend: v => ["virsh", "suspend", v], resume: v => ["virsh", "resume", v], + discardsave: v => ["virsh", "managedsave-remove", v], }) function act(vm, action) { |
