With the 'on_reboot' lifecycle action set to 'destroy' (QEMU -action reboot=shutdown), a guest-initiated reboot is converted into a shutdown. The QMP SHUTDOWN event carries a 'reason' field distinguishing 'guest-reset' (guest requested a reboot) from 'guest-shutdown' (guest powered off), but libvirt discarded it. Thread the reason through the monitor shutdown callback and map 'guest-reset' to a new VIR_DOMAIN_EVENT_SHUTDOWN_GUEST_RESET lifecycle detail so that management applications can tell a reboot apart from a poweroff when handling the SHUTDOWN event. Signed-off-by: Jean-Louis Dupond <jean-louis@dupond.be> --- examples/c/misc/event-test.c | 3 +++ include/libvirt/libvirt-domain.h | 5 +++++ src/qemu/qemu_monitor.c | 2 +- src/qemu/qemu_monitor.h | 3 ++- src/qemu/qemu_process.c | 35 +++++++++++++++++++------------- tools/virsh-domain-event.c | 3 ++- 6 files changed, 34 insertions(+), 17 deletions(-) diff --git a/examples/c/misc/event-test.c b/examples/c/misc/event-test.c index 601f5eafcf..f43f73fa6f 100644 --- a/examples/c/misc/event-test.c +++ b/examples/c/misc/event-test.c @@ -252,6 +252,9 @@ eventDetailToString(int event, case VIR_DOMAIN_EVENT_SHUTDOWN_HOST: return "Host request"; + case VIR_DOMAIN_EVENT_SHUTDOWN_GUEST_RESET: + return "Guest reboot request"; + case VIR_DOMAIN_EVENT_SHUTDOWN_LAST: break; } diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 99208137c3..0c68755ec4 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -5806,6 +5806,11 @@ typedef enum { */ VIR_DOMAIN_EVENT_SHUTDOWN_HOST = 2, + /* Domain finished shutting down because the guest requested a reboot + * while the 'on_reboot' lifecycle action was set to 'destroy' (Since: 13.0.0) + */ + VIR_DOMAIN_EVENT_SHUTDOWN_GUEST_RESET = 3, + # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_SHUTDOWN_LAST /* (Since: 0.9.10) */ # endif diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 21df06ebd8..2763a5fb4c 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1082,7 +1082,7 @@ qemuMonitorEmitShutdown(qemuMonitor *mon, virTristateBool guest, qemuDomainSetFakeReboot(vm, true); } - QEMU_MONITOR_CALLBACK(mon, domainShutdown, mon->vm, guest); + QEMU_MONITOR_CALLBACK(mon, domainShutdown, mon->vm, guest, reason); } diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index e560618bf4..17d1018cd0 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -208,7 +208,8 @@ typedef void (*qemuMonitorDomainEventCallback)(qemuMonitor *mon, const char *details); typedef void (*qemuMonitorDomainShutdownCallback)(qemuMonitor *mon, virDomainObj *vm, - virTristateBool guest); + virTristateBool guest, + const char *reason); typedef void (*qemuMonitorDomainResetCallback)(qemuMonitor *mon, virDomainObj *vm); typedef void (*qemuMonitorDomainStopCallback)(qemuMonitor *mon, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index aaa9046146..d28cede5e8 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -746,14 +746,16 @@ qemuProcessHandleEvent(qemuMonitor *mon G_GNUC_UNUSED, static void qemuProcessHandleShutdown(qemuMonitor *mon G_GNUC_UNUSED, virDomainObj *vm, - virTristateBool guest_initiated) + virTristateBool guest_initiated, + const char *reason) { virQEMUDriver *driver; qemuDomainObjPrivate *priv; virObjectEvent *event = NULL; int detail = 0; - VIR_DEBUG("vm=%p", vm); + VIR_DEBUG("vm=%p guest=%u reason=%s", vm, guest_initiated, + NULLSTR(reason)); virObjectLock(vm); @@ -780,20 +782,25 @@ qemuProcessHandleShutdown(qemuMonitor *mon G_GNUC_UNUSED, VIR_DOMAIN_SHUTDOWN, VIR_DOMAIN_SHUTDOWN_UNKNOWN); - switch (guest_initiated) { - case VIR_TRISTATE_BOOL_YES: - detail = VIR_DOMAIN_EVENT_SHUTDOWN_GUEST; - break; + if (guest_initiated == VIR_TRISTATE_BOOL_YES && + STREQ_NULLABLE(reason, "guest-reset")) { + detail = VIR_DOMAIN_EVENT_SHUTDOWN_GUEST_RESET; + } else { + switch (guest_initiated) { + case VIR_TRISTATE_BOOL_YES: + detail = VIR_DOMAIN_EVENT_SHUTDOWN_GUEST; + break; - case VIR_TRISTATE_BOOL_NO: - detail = VIR_DOMAIN_EVENT_SHUTDOWN_HOST; - break; + case VIR_TRISTATE_BOOL_NO: + detail = VIR_DOMAIN_EVENT_SHUTDOWN_HOST; + break; - case VIR_TRISTATE_BOOL_ABSENT: - case VIR_TRISTATE_BOOL_LAST: - default: - detail = VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED; - break; + case VIR_TRISTATE_BOOL_ABSENT: + case VIR_TRISTATE_BOOL_LAST: + default: + detail = VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED; + break; + } } event = virDomainEventLifecycleNewFromObj(vm, diff --git a/tools/virsh-domain-event.c b/tools/virsh-domain-event.c index a541b155f4..6e6d0de93e 100644 --- a/tools/virsh-domain-event.c +++ b/tools/virsh-domain-event.c @@ -114,7 +114,8 @@ VIR_ENUM_IMPL(virshDomainEventShutdown, VIR_DOMAIN_EVENT_SHUTDOWN_LAST, N_("Finished"), N_("Finished after guest request"), - N_("Finished after host request")); + N_("Finished after host request"), + N_("Finished after guest reboot request")); VIR_ENUM_DECL(virshDomainEventPMSuspended); VIR_ENUM_IMPL(virshDomainEventPMSuspended, -- 2.55.0