diff --git a/dev-example/test-vm.tpl.yaml b/dev-example/test-vm.tpl.yaml
index 50031bb..260341e 100644
--- a/dev-example/test-vm.tpl.yaml
+++ b/dev-example/test-vm.tpl.yaml
@@ -14,7 +14,7 @@ spec:
# repository: ghcr.io
# path: mnlipp/org.jdrupes.vmoperator.runner.qemu-alpine
# version: "3.0.0"
- source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:testing
+ source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:feature-auto-login
pullPolicy: Always
permissions:
diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/AgentConnector.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/AgentConnector.java
new file mode 100644
index 0000000..40db84a
--- /dev/null
+++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/AgentConnector.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import org.jdrupes.vmoperator.runner.qemu.events.VserportChangeEvent;
+import org.jgrapes.core.Channel;
+import org.jgrapes.core.annotation.Handler;
+import org.jgrapes.util.events.ConfigurationUpdate;
+
+/**
+ * A component that handles the communication with an agent
+ * running in the VM.
+ *
+ * If the log level for this class is set to fine, the messages
+ * exchanged on the socket are logged.
+ */
+public abstract class AgentConnector extends QemuConnector {
+
+ protected String channelId;
+
+ /**
+ * Instantiates a new agent connector.
+ *
+ * @param componentChannel the component channel
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public AgentConnector(Channel componentChannel) throws IOException {
+ super(componentChannel);
+ }
+
+ /**
+ * As the initial configuration of this component depends on the
+ * configuration of the {@link Runner}, it doesn't have a handler
+ * for the {@link ConfigurationUpdate} event. The values are
+ * forwarded from the {@link Runner} instead.
+ *
+ * @param channelId the channel id
+ * @param socketPath the socket path
+ */
+ /* default */ void configure(String channelId, Path socketPath) {
+ super.configure(socketPath);
+ this.channelId = channelId;
+ logger.fine(() -> getClass().getSimpleName() + " configured with"
+ + " channelId=" + channelId);
+ }
+
+ /**
+ * When the virtual serial port with the configured channel id has
+ * been opened call {@link #agentConnected()}.
+ *
+ * @param event the event
+ */
+ @Handler
+ public void onVserportChanged(VserportChangeEvent event) {
+ if (event.id().equals(channelId) && event.isOpen()) {
+ agentConnected();
+ }
+ }
+
+ /**
+ * Called when the agent in the VM opens the connection. The
+ * default implementation does nothing.
+ */
+ @SuppressWarnings("PMD.EmptyMethodInAbstractClassShouldBeAbstract")
+ protected void agentConnected() {
+ // Default is to do nothing.
+ }
+}
diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Configuration.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Configuration.java
index 086f085..20d4c66 100644
--- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Configuration.java
+++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Configuration.java
@@ -39,7 +39,7 @@ import org.jdrupes.vmoperator.util.FsdUtils;
/**
* The configuration information from the configuration file.
*/
-@SuppressWarnings("PMD.ExcessivePublicCount")
+@SuppressWarnings({ "PMD.ExcessivePublicCount", "PMD.TooManyFields" })
public class Configuration implements Dto {
private static final String CI_INSTANCE_ID = "instance-id";
@@ -67,9 +67,6 @@ public class Configuration implements Dto {
/** The monitor socket. */
public Path monitorSocket;
- /** The guest agent socket socket. */
- public Path guestAgentSocket;
-
/** The firmware rom. */
public Path firmwareRom;
@@ -344,7 +341,6 @@ public class Configuration implements Dto {
runtimeDir.toFile().mkdir();
swtpmSocket = runtimeDir.resolve("swtpm-sock");
monitorSocket = runtimeDir.resolve("monitor.sock");
- guestAgentSocket = runtimeDir.resolve("org.qemu.guest_agent.0");
}
if (!Files.isDirectory(runtimeDir) || !Files.isWritable(runtimeDir)) {
logger.severe(() -> String.format(
diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java
index fba975e..2e5e059 100644
--- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java
+++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java
@@ -19,58 +19,26 @@
package org.jdrupes.vmoperator.runner.qemu;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
-import java.io.Writer;
-import java.lang.reflect.UndeclaredThrowableException;
-import java.net.UnixDomainSocketAddress;
-import java.nio.file.Files;
-import java.nio.file.Path;
import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
import java.util.Queue;
import java.util.logging.Level;
import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand;
import org.jdrupes.vmoperator.runner.qemu.commands.QmpGuestGetOsinfo;
import org.jdrupes.vmoperator.runner.qemu.events.GuestAgentCommand;
import org.jdrupes.vmoperator.runner.qemu.events.OsinfoEvent;
-import org.jdrupes.vmoperator.runner.qemu.events.VserportChangeEvent;
import org.jgrapes.core.Channel;
-import org.jgrapes.core.Component;
-import org.jgrapes.core.EventPipeline;
import org.jgrapes.core.annotation.Handler;
-import org.jgrapes.core.events.Start;
-import org.jgrapes.core.events.Stop;
-import org.jgrapes.io.events.Closed;
-import org.jgrapes.io.events.ConnectError;
-import org.jgrapes.io.events.Input;
-import org.jgrapes.io.events.OpenSocketConnection;
-import org.jgrapes.io.util.ByteBufferWriter;
-import org.jgrapes.io.util.LineCollector;
-import org.jgrapes.net.SocketIOChannel;
-import org.jgrapes.net.events.ClientConnected;
-import org.jgrapes.util.events.ConfigurationUpdate;
/**
- * A component that handles the communication over the guest agent
- * socket.
+ * A component that handles the communication with the guest agent.
*
* If the log level for this class is set to fine, the messages
* exchanged on the monitor socket are logged.
*/
-@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
-public class GuestAgentClient extends Component {
+public class GuestAgentClient extends AgentConnector {
- private static ObjectMapper mapper = new ObjectMapper();
-
- private EventPipeline rep;
- private Path socketPath;
- private List