diff --git a/dev-example/vmop-agent/99-vmop-agent.rules b/dev-example/vmop-agent/99-vmop-agent.rules
new file mode 100644
index 0000000..4a18472
--- /dev/null
+++ b/dev-example/vmop-agent/99-vmop-agent.rules
@@ -0,0 +1,2 @@
+SUBSYSTEM=="virtio-ports", ATTR{name}=="org.jdrupes.vmop_agent.0", \
+ TAG+="systemd" ENV{SYSTEMD_WANTS}="vmop-agent.service"
diff --git a/dev-example/vmop-agent/vmop-agent b/dev-example/vmop-agent/vmop-agent
new file mode 100755
index 0000000..b3157b9
--- /dev/null
+++ b/dev-example/vmop-agent/vmop-agent
@@ -0,0 +1,19 @@
+#!/usr/bin/bash
+
+hostSerial="/dev/virtio-ports/org.jdrupes.vmop_agent.0"
+
+if [ ! -w "$hostSerial" ]; then
+ echo >&2 "Device $hostSerial not writable"
+ exit 1
+fi
+
+if ! exec {con}<>"$hostSerial"; then
+ echo >&2 "Cannot open device $hostSerial"
+ exit 1
+fi
+
+echo >&${con} "220 Hello"
+
+while read line <&${con}; do
+ true
+done
diff --git a/dev-example/vmop-agent/vmop-agent.service b/dev-example/vmop-agent/vmop-agent.service
new file mode 100644
index 0000000..11c64f2
--- /dev/null
+++ b/dev-example/vmop-agent/vmop-agent.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=VM-Operator (Guest) Agent
+BindsTo=dev-virtio\x2dports-org.jdrupes.vmop_agent.0.device
+After=dev-virtio\x2dports-org.jdrupes.vmop_agent.0.device multi-user.target
+IgnoreOnIsolate=True
+
+[Service]
+UMask=0077
+#EnvironmentFile=/etc/sysconfig/vmop-agent
+ExecStart=/usr/local/libexec/vmop-agent
+Restart=always
+RestartSec=0
+
+[Install]
+WantedBy=dev-virtio\x2dports-org.jdrupes.vmop_agent.0.device
diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java
index f9644c8..fa0e3ab 100644
--- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java
+++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java
@@ -47,6 +47,7 @@ import org.jdrupes.vmoperator.runner.qemu.events.OsinfoEvent;
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange;
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState;
import org.jdrupes.vmoperator.runner.qemu.events.ShutdownEvent;
+import org.jdrupes.vmoperator.runner.qemu.events.VmopAgentConnected;
import org.jdrupes.vmoperator.util.GsonPtr;
import org.jgrapes.core.Channel;
import org.jgrapes.core.annotation.Handler;
@@ -192,20 +193,21 @@ public class StatusUpdater extends VmDefUpdater {
status.addProperty("ram", GsonPtr.to(from.data())
.getAsString("spec", "vm", "maximumRam").orElse("0"));
status.addProperty("cpus", 1);
-
- // In case we had an irregular shutdown
- status.remove("osinfo");
} else if (event.runState() == RunState.STOPPED) {
status.addProperty("ram", "0");
status.addProperty("cpus", 0);
- status.remove("osinfo");
}
- // In case console connection was still present
if (!running) {
+ // In case console connection was still present
status.addProperty("consoleClient", "");
updateCondition(from, status, "ConsoleConnected", false,
- "VmStopped", "The VM has been shut down");
+ "VmStopped", "The VM is not running");
+
+ // In case we had an irregular shutdown
+ status.remove("osinfo");
+ updateCondition(vmDef, vmDef.statusJson(), "VmopAgentConnected",
+ false, "VmStopped", "The VM is not running");
}
return status;
});
@@ -322,4 +324,24 @@ public class StatusUpdater extends VmDefUpdater {
});
}
+
+ /**
+ * @param event the event
+ * @throws ApiException
+ */
+ @Handler
+ @SuppressWarnings("PMD.AssignmentInOperand")
+ public void onVmopAgentConnected(VmopAgentConnected event)
+ throws ApiException {
+ VmDefinition vmDef;
+ if (vmStub == null || (vmDef = vmStub.model().orElse(null)) == null) {
+ return;
+ }
+ vmStub.updateStatus(from -> {
+ JsonObject status = from.statusJson();
+ updateCondition(vmDef, status, "VmopAgentConnected",
+ true, "VmopAgentStarted", "The VM operator agent is running");
+ return status;
+ });
+ }
}
diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java
index a74432b..89fdaa2 100644
--- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java
+++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java
@@ -19,6 +19,7 @@
package org.jdrupes.vmoperator.runner.qemu;
import java.io.IOException;
+import org.jdrupes.vmoperator.runner.qemu.events.VmopAgentConnected;
import org.jgrapes.core.Channel;
/**
@@ -42,7 +43,9 @@ public class VmopAgentClient extends AgentConnector {
@Override
protected void processInput(String line) throws IOException {
- // TODO Auto-generated method stub
+ if (line.startsWith("220 ")) {
+ rep().fire(new VmopAgentConnected());
+ }
}
}
diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/VmopAgentConnected.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/VmopAgentConnected.java
new file mode 100644
index 0000000..dc13569
--- /dev/null
+++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/VmopAgentConnected.java
@@ -0,0 +1,27 @@
+/*
+ * VM-Operator
+ * Copyright (C) 2025 Michael N. Lipp
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jdrupes.vmoperator.runner.qemu.events;
+
+import org.jgrapes.core.Event;
+
+/**
+ * Signals information about the guest OS.
+ */
+public class VmopAgentConnected extends Event {
+}