Fix startup.

This commit is contained in:
Michael Lipp 2025-03-12 17:22:46 +01:00
parent 19968ab73e
commit 5d0c6c6423
5 changed files with 34 additions and 41 deletions

View file

@ -24,7 +24,6 @@ import java.util.List;
import org.jdrupes.vmoperator.runner.qemu.events.VserportChangeEvent; import org.jdrupes.vmoperator.runner.qemu.events.VserportChangeEvent;
import org.jgrapes.core.Channel; import org.jgrapes.core.Channel;
import org.jgrapes.core.annotation.Handler; import org.jgrapes.core.annotation.Handler;
import org.jgrapes.util.events.ConfigurationUpdate;
/** /**
* A component that handles the communication with an agent * A component that handles the communication with an agent
@ -48,16 +47,14 @@ public abstract class AgentConnector extends QemuConnector {
} }
/** /**
* As the initial configuration of this component depends on the * Extracts the channel id and the socket path from the QEMU
* configuration of the {@link Runner}, it doesn't have a handler * command line.
* for the {@link ConfigurationUpdate} event. The values are
* forwarded from the {@link Runner} instead.
* *
* @param command the command * @param command the command
* @param chardev the chardev * @param chardev the chardev
*/ */
@SuppressWarnings("PMD.CognitiveComplexity") @SuppressWarnings("PMD.CognitiveComplexity")
protected void configure(List<String> command, String chardev) { protected void configureConnection(List<String> command, String chardev) {
Path socketPath = null; Path socketPath = null;
for (var arg : command) { for (var arg : command) {
if (arg.startsWith("virtserialport,") if (arg.startsWith("virtserialport,")
@ -82,9 +79,9 @@ public abstract class AgentConnector extends QemuConnector {
+ " missing in runner template."); + " missing in runner template.");
return; return;
} }
super.configure(socketPath);
logger.fine(() -> getClass().getSimpleName() + " configured with" logger.fine(() -> getClass().getSimpleName() + " configured with"
+ " channelId=" + channelId); + " channelId=" + channelId);
super.configure(socketPath);
} }
/** /**

View file

@ -29,7 +29,6 @@ import org.jdrupes.vmoperator.runner.qemu.commands.QmpSetDisplayPassword;
import org.jdrupes.vmoperator.runner.qemu.commands.QmpSetPasswordExpiry; import org.jdrupes.vmoperator.runner.qemu.commands.QmpSetPasswordExpiry;
import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu; import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu;
import org.jdrupes.vmoperator.runner.qemu.events.MonitorCommand; import org.jdrupes.vmoperator.runner.qemu.events.MonitorCommand;
import org.jdrupes.vmoperator.runner.qemu.events.QmpConfigured;
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState;
import org.jdrupes.vmoperator.runner.qemu.events.VmopAgentConnected; import org.jdrupes.vmoperator.runner.qemu.events.VmopAgentConnected;
import org.jdrupes.vmoperator.runner.qemu.events.VmopAgentLogIn; import org.jdrupes.vmoperator.runner.qemu.events.VmopAgentLogIn;
@ -50,6 +49,7 @@ public class DisplayController extends Component {
private String currentPassword; private String currentPassword;
private String protocol; private String protocol;
private final Path configDir; private final Path configDir;
private boolean canBeUpdated;
private boolean vmopAgentConnected; private boolean vmopAgentConnected;
private String loggedInUser; private String loggedInUser;
@ -84,19 +84,7 @@ public class DisplayController extends Component {
if (event.runState() == RunState.STARTING) { if (event.runState() == RunState.STARTING) {
configurePassword(); configurePassword();
} }
} canBeUpdated = true;
/**
* When the monitor is ready, send QEMU its initial configuration.
*
* @param event the event
*/
@Handler
public void onQmpConfigured(QmpConfigured event) {
if (pendingConfig != null) {
rep.fire(new ConfigureQemu(pendingConfig, state));
pendingConfig = null;
}
} }
/** /**
@ -128,7 +116,8 @@ public class DisplayController extends Component {
@Handler @Handler
@SuppressWarnings("PMD.EmptyCatchBlock") @SuppressWarnings("PMD.EmptyCatchBlock")
public void onFileChanged(FileChanged event) { public void onFileChanged(FileChanged event) {
if (event.path().equals(configDir.resolve(DisplaySecret.PASSWORD))) { if (event.path().equals(configDir.resolve(DisplaySecret.PASSWORD))
&& canBeUpdated) {
configurePassword(); configurePassword();
} }
} }

View file

@ -202,10 +202,9 @@ public abstract class QemuConnector extends Component {
* Called when a connection attempt fails. * Called when a connection attempt fails.
* *
* @param event the event * @param event the event
* @param channel the channel
*/ */
@Handler @Handler
public void onConnectError(ConnectError event, SocketIOChannel channel) { public void onConnectError(ConnectError event) {
event.event().associated(this, getClass()).ifPresent(qc -> { event.event().associated(this, getClass()).ifPresent(qc -> {
rep.fire(new Stop()); rep.fire(new Stop());
}); });

View file

@ -164,12 +164,15 @@ public class QemuMonitor extends QemuConnector {
@Handler @Handler
@SuppressWarnings("PMD.AvoidSynchronizedStatement") @SuppressWarnings("PMD.AvoidSynchronizedStatement")
public void onMonitorCommand(MonitorCommand event) throws IOException { public void onMonitorCommand(MonitorCommand event) throws IOException {
if (!monitorReady) { // Check prerequisites
if (!monitorReady && !(event.command() instanceof QmpCapabilities)) {
logger.severe(() -> "Premature monitor command (not ready): " logger.severe(() -> "Premature monitor command (not ready): "
+ event.command()); + event.command());
rep().fire(new Stop()); rep().fire(new Stop());
return; return;
} }
// Send the command
var command = event.command(); var command = event.command();
logger.fine(() -> "monitor(out): " + command.toString()); logger.fine(() -> "monitor(out): " + command.toString());
String asText; String asText;

View file

@ -303,7 +303,10 @@ public class Runner extends Component {
} }
/** /**
* On configuration update. * Process the initial configuration. The initial configuration
* and any subsequent updates will be forwarded to other components
* only when the QMP connection is ready
* (see @link #onQmpConfigured(QmpConfigured)).
* *
* @param event the event * @param event the event
*/ */
@ -362,9 +365,9 @@ public class Runner extends Component {
// Forward some values to child components // Forward some values to child components
qemuMonitor.configure(initialConfig.monitorSocket, qemuMonitor.configure(initialConfig.monitorSocket,
initialConfig.vm.powerdownTimeout); initialConfig.vm.powerdownTimeout);
guestAgentClient.configure(qemuDefinition.command, guestAgentClient.configureConnection(qemuDefinition.command,
"guest-agent-socket"); "guest-agent-socket");
vmopAgentClient.configure(qemuDefinition.command, vmopAgentClient.configureConnection(qemuDefinition.command,
"vmop-agent-socket"); "vmop-agent-socket");
} catch (IllegalArgumentException | IOException | TemplateException e) { } catch (IllegalArgumentException | IOException | TemplateException e) {
logger.log(Level.SEVERE, e, () -> "Invalid configuration: " logger.log(Level.SEVERE, e, () -> "Invalid configuration: "
@ -443,6 +446,21 @@ public class Runner extends Component {
return yamlMapper.readValue(out.toString(), JsonNode.class); return yamlMapper.readValue(out.toString(), JsonNode.class);
} }
/**
* Note ready state and send a {@link ConfigureQemu} event for
* any pending configuration (initial or change).
*
* @param event the event
*/
@Handler
public void onQmpConfigured(QmpConfigured event) {
qmpConfigured = true;
if (pendingConfig != null) {
rep.fire(new ConfigureQemu(pendingConfig, state));
pendingConfig = null;
}
}
/** /**
* Handle the start event. * Handle the start event.
* *
@ -630,19 +648,6 @@ public class Runner extends Component {
.ifPresent(lc -> lc.feed(event))); .ifPresent(lc -> lc.feed(event)));
} }
/**
* When the monitor is ready, send QEMU its initial configuration.
*
* @param event the event
*/
@Handler
public void onQmpConfigured(QmpConfigured event) {
if (pendingConfig != null) {
rep.fire(new ConfigureQemu(pendingConfig, state));
pendingConfig = null;
}
}
/** /**
* Whenever a new QEMU configuration is available, check if it * Whenever a new QEMU configuration is available, check if it
* is supposed to trigger a reset. * is supposed to trigger a reset.