From e29135282848de191f1075d35e5cefe64bb25fb0 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 21 Feb 2025 20:54:27 +0100 Subject: [PATCH] Prepare usage of guest os command. --- .../runner/qemu/GuestAgentClient.java | 39 ++++++++++++++++++- .../vmoperator/runner/qemu/Runner.java | 9 ++++- .../templates/Standard-VM-latest.ftl.yaml | 4 ++ 3 files changed, 49 insertions(+), 3 deletions(-) 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 f3928f5..afe3d26 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 @@ -20,6 +20,7 @@ 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; @@ -28,6 +29,8 @@ 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; @@ -65,6 +68,8 @@ public class GuestAgentClient extends Component { private EventPipeline rep; private Path socketPath; + private List> guestAgentCmds; + private String guestAgentCmd; private SocketIOChannel gaChannel; private final Queue executing = new LinkedList<>(); @@ -72,6 +77,7 @@ public class GuestAgentClient extends Component { * Instantiates a new guest agent client. * * @param componentChannel the component channel + * @param guestAgentCmds * @throws IOException Signals that an I/O exception has occurred. */ @SuppressWarnings({ "PMD.AssignmentToNonFinalStatic", @@ -87,10 +93,20 @@ public class GuestAgentClient extends Component { * forwarded from the {@link Runner} instead. * * @param socketPath the socket path + * @param guestAgentCmds * @param powerdownTimeout */ - /* default */ void configure(Path socketPath) { + @SuppressWarnings("PMD.EmptyCatchBlock") + /* default */ void configure(Path socketPath, ArrayNode guestAgentCmds) { this.socketPath = socketPath; + try { + this.guestAgentCmds = mapper.convertValue(guestAgentCmds, + mapper.constructType(getClass() + .getDeclaredField("guestAgentCmds").getGenericType())); + } catch (IllegalArgumentException | NoSuchFieldException + | SecurityException e) { + // Cannot happen + } } /** @@ -193,7 +209,7 @@ public class GuestAgentClient extends Component { () -> String.format("(Previous \"guest agent(in)\" is " + "result from executing %s)", executed)); if (executed instanceof QmpGuestGetOsinfo) { - rep.fire(new OsinfoEvent(response.get("return"))); + processOsInfo(response); } } } catch (JsonProcessingException e) { @@ -201,6 +217,25 @@ public class GuestAgentClient extends Component { } } + private void processOsInfo(ObjectNode response) { + var osInfo = new OsinfoEvent(response.get("return")); + var osId = osInfo.osinfo().get("id").asText(); + for (var cmdDef : guestAgentCmds) { + if (osId.equals(cmdDef.get("osId")) + || "*".equals(cmdDef.get("osId"))) { + guestAgentCmd = cmdDef.get("executable"); + break; + } + } + if (guestAgentCmd == null) { + logger.warning(() -> "No guest agent command for OS " + osId); + } else { + logger.fine(() -> "Guest agent command for OS " + osId + + " is " + guestAgentCmd); + } + rep.fire(osInfo); + } + /** * On closed. * diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Runner.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Runner.java index b258e1a..e0cd837 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Runner.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Runner.java @@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; import freemarker.core.ParseException; @@ -197,6 +198,7 @@ public class Runner extends Component { private static final String QEMU = "qemu"; private static final String SWTPM = "swtpm"; private static final String CLOUD_INIT_IMG = "cloudInitImg"; + private static final String GUEST_AGENT_CMDS = "guestAgentCmds"; private static final String TEMPLATE_DIR = "/opt/" + APP_NAME.replace("-", "") + "/templates"; private static final String DEFAULT_TEMPLATE @@ -348,11 +350,16 @@ public class Runner extends Component { .map(d -> new CommandDefinition(CLOUD_INIT_IMG, d)) .orElse(null); logger.finest(() -> cloudInitImgDefinition.toString()); + var guestAgentCmds = (ArrayNode) tplData.get(GUEST_AGENT_CMDS); + if (guestAgentCmds != null) { + logger.finest( + () -> "GuestAgentCmds: " + guestAgentCmds.toString()); + } // Forward some values to child components qemuMonitor.configure(config.monitorSocket, config.vm.powerdownTimeout); - guestAgentClient.configure(config.guestAgentSocket); + guestAgentClient.configure(config.guestAgentSocket, guestAgentCmds); } catch (IllegalArgumentException | IOException | TemplateException e) { logger.log(Level.SEVERE, e, () -> "Invalid configuration: " + e.getMessage()); diff --git a/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml b/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml index e2610ba..3eacfa3 100644 --- a/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml +++ b/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml @@ -233,3 +233,7 @@ + +"guestAgentCmds": + - "osId": "*" + "executable": "/usr/local/libexec/vm-operator-cmd"