diff --git a/src/components/vm/confirmDialog.jsx b/src/components/vm/confirmDialog.jsx
index a0bc44b2b..3c44fa109 100644
--- a/src/components/vm/confirmDialog.jsx
+++ b/src/components/vm/confirmDialog.jsx
@@ -27,6 +27,7 @@ import { useDialogs } from 'dialogs.jsx';
import { distanceToNow } from 'timeformat.js';
import { domainGetStartTime } from '../../libvirtApi/domain.js';
+import { Enum } from '../../libvirtApi/helpers.js';
const _ = cockpit.gettext;
@@ -60,18 +61,56 @@ export const ConfirmDialog = ({ idPrefix, actionsList, title, titleIcon, vm }) =
);
- let body = (
-
-
-
- );
+ let body;
+ if (dialogLoading) {
+ body = (
+
+
+
+ );
+ } else if (uptime) {
+ let uptimeStr = distanceToNow(new Date(uptime));
+
+ // https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainRunningReason
+ switch (vm.stateReason) {
+ case Enum.VIR_DOMAIN_RUNNING_MIGRATED:
+ case Enum.VIR_DOMAIN_RUNNING_POSTCOPY: {
+ uptimeStr = cockpit.format(_("$0 since migration"), uptimeStr);
+ break;
+ }
+ case Enum.VIR_DOMAIN_RUNNING_FROM_SNAPSHOT: {
+ uptimeStr = cockpit.format(_("$0 since reverting to snapshot"), uptimeStr);
+ break;
+ }
+ case Enum.VIR_DOMAIN_RUNNING_RESTORED:
+ case Enum.VIR_DOMAIN_RUNNING_UNPAUSED: {
+ uptimeStr = cockpit.format(_("$0 since VM was resumed"), uptimeStr);
+ break;
+ }
+ case Enum.VIR_DOMAIN_RUNNING_MIGRATION_CANCELED:
+ case Enum.VIR_DOMAIN_RUNNING_POSTCOPY_FAILED: {
+ uptimeStr = cockpit.format(_("$0 since migration was cancelled"), uptimeStr);
+ break;
+ }
+ case Enum.VIR_DOMAIN_RUNNING_SAVE_CANCELED: {
+ uptimeStr = cockpit.format(_("$0 since failed save process"), uptimeStr);
+ break;
+ }
+ case Enum.VIR_DOMAIN_RUNNING_WAKEUP: {
+ uptimeStr = cockpit.format(_("$0 since wakeup event"), uptimeStr);
+ break;
+ }
+ case Enum.VIR_DOMAIN_RUNNING_CRASHED: {
+ uptimeStr = cockpit.format(_("$0 since resumed from crash"), uptimeStr);
+ break;
+ }
+ }
- if (!dialogLoading) {
- body = (uptime &&
+ body = (
{_("Uptime")}
- {distanceToNow(new Date(uptime))}
+ {uptimeStr}
);
diff --git a/test/check-machines-lifecycle b/test/check-machines-lifecycle
index e9c546b2f..912ffbfb7 100755
--- a/test/check-machines-lifecycle
+++ b/test/check-machines-lifecycle
@@ -232,6 +232,8 @@ class TestMachinesLifecycle(VirtualMachinesCase):
self.performAction("subVmTest2", "forceOff")
b.click("#vm-subVmTest2-system-run")
+ # wait for libvirt to update the internal state (reason) of VM
+ wait(lambda: "running (booted)" in m.execute("virsh domstate --reason subVmTest2"), delay=3)
# Check uptime
b.click("#vm-subVmTest2-system-shutdown-button")
@@ -244,6 +246,19 @@ class TestMachinesLifecycle(VirtualMachinesCase):
b.click(".pf-c-modal-box__footer button:contains(Cancel)")
b.wait_not_present("#vm-subVmTest2-system-confirm-action-modal")
+ # Check uptime with VM boot message
+ # Non-privileged user doesn't have access to system-connection VM's logs
+ if superuser:
+ m.execute("virsh managedsave --domain subVmTest2")
+ m.execute("virsh start --domain subVmTest2")
+ # wait for libvirt to update the internal state (reason) of VM
+ wait(lambda: "running (restored)" in m.execute("virsh domstate --reason subVmTest2"), delay=3)
+ b.click("#vm-subVmTest2-system-shutdown-button")
+ b.wait_visible("#vm-subVmTest2-system-confirm-action-modal")
+ b.wait_in_text("#vm-subVmTest2-system-confirm-action-modal #uptime", "since VM was resumed")
+ b.click(".pf-c-modal-box__footer button:contains(Cancel)")
+ b.wait_not_present("#vm-subVmTest2-system-confirm-action-modal")
+
b.set_input_text("#text-search", "subVmTest2")
self.waitVmRow("subVmTest2")
self.waitVmRow("subVmTest1", "system", False)