From 36877666f38c0a7f93a14963a5e7045c50bd67bf Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 12 Mar 2025 20:59:36 +0100 Subject: [PATCH 1/3] No QMP poweroff if QMP not available. --- .../vmoperator/runner/qemu/QemuMonitor.java | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java index 21c3a0f..9f6e48e 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java @@ -199,28 +199,31 @@ public class QemuMonitor extends QemuConnector { @Handler(priority = 100) @SuppressWarnings("PMD.AvoidSynchronizedStatement") public void onStop(Stop event) { - if (qemuChannel() != null) { - // We have a connection to Qemu, attempt ACPI shutdown. - event.suspendHandling(); - suspendedStop = event; - - // Attempt powerdown command. If not confirmed, assume - // "hanging" qemu process. - powerdownTimer = Components.schedule(t -> { - // Powerdown not confirmed - logger.fine(() -> "QMP powerdown command has not effect."); - synchronized (this) { - powerdownTimer = null; - if (suspendedStop != null) { - suspendedStop.resumeHandling(); - suspendedStop = null; - } - } - }, Duration.ofSeconds(1)); - logger.fine(() -> "Attempting QMP powerdown."); - powerdownStartedAt = Instant.now(); - fire(new MonitorCommand(new QmpPowerdown())); + if (!monitorReady) { + logger.fine(() -> "No QMP connection," + + " cannot send powerdown command"); + return; } + // We have a connection to Qemu, attempt ACPI shutdown. + event.suspendHandling(); + suspendedStop = event; + + // Attempt powerdown command. If not confirmed, assume + // "hanging" qemu process. + powerdownTimer = Components.schedule(t -> { + // Powerdown not confirmed + logger.fine(() -> "QMP powerdown command not confirmed"); + synchronized (this) { + powerdownTimer = null; + if (suspendedStop != null) { + suspendedStop.resumeHandling(); + suspendedStop = null; + } + } + }, Duration.ofSeconds(1)); + logger.fine(() -> "Attempting QMP powerdown."); + powerdownStartedAt = Instant.now(); + fire(new MonitorCommand(new QmpPowerdown())); } /** @@ -238,7 +241,9 @@ public class QemuMonitor extends QemuConnector { } // (Re-)schedule timer as fallback - logger.fine(() -> "QMP powerdown confirmed, waiting..."); + var waitUntil = powerdownStartedAt.plusSeconds(powerdownTimeout); + logger.fine(() -> "QMP powerdown confirmed, waiting for" + + " termination until " + waitUntil); powerdownTimer = Components.schedule(t -> { logger.fine(() -> "Powerdown timeout reached."); synchronized (this) { @@ -247,7 +252,7 @@ public class QemuMonitor extends QemuConnector { suspendedStop = null; } } - }, powerdownStartedAt.plusSeconds(powerdownTimeout)); + }, waitUntil); powerdownConfirmed = true; } } From 2a33f468f2d99f614c60237dcaccf4531965162e Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 12 Mar 2025 21:46:46 +0100 Subject: [PATCH 2/3] Track connection closing. --- .../src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java index 9f6e48e..75310f8 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java @@ -139,8 +139,9 @@ public class QemuMonitor extends QemuConnector { @SuppressWarnings({ "PMD.AvoidSynchronizedStatement", "PMD.AvoidDuplicateLiterals" }) public void onClosed(Closed event, SocketIOChannel channel) { - logger.finer(() -> "Closing QMP socket."); super.onClosed(event, channel); + logger.finer(() -> "QMP socket closed."); + monitorReady = false; channel.associated(this, getClass()).ifPresent(qm -> { synchronized (this) { if (powerdownTimer != null) { From ecb43db83e8e71501262ccb063a3e527a38f8803 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 12 Mar 2025 21:48:18 +0100 Subject: [PATCH 3/3] Test configuration. --- dev-example/test-vm.tpl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-example/test-vm.tpl.yaml b/dev-example/test-vm.tpl.yaml index 12057f9..18709f7 100644 --- a/dev-example/test-vm.tpl.yaml +++ b/dev-example/test-vm.tpl.yaml @@ -10,7 +10,7 @@ spec: image: # source: ghcr.io/mnlipp/org.jdrupes.vmoperator.runner.qemu-arch:3.3.1 # source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:testing - source: docker-registry.lan.mnl.de/vmoperator/org.jdrupes.vmoperator.runner.qemu-arch:feature-pools + source: docker-registry.lan.mnl.de/vmoperator/org.jdrupes.vmoperator.runner.qemu-arch:fix-runner-poweroff pullPolicy: Always permissions: