Skip to content

Commit c582763

Browse files
committed
Merge branch 'feature/booted-status'
2 parents e4bba58 + 777ae73 commit c582763

File tree

16 files changed

+701
-32
lines changed

16 files changed

+701
-32
lines changed

org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand;
3434
import org.jdrupes.vmoperator.runner.qemu.commands.QmpGuestGetOsinfo;
3535
import org.jdrupes.vmoperator.runner.qemu.events.GuestAgentCommand;
36-
import org.jdrupes.vmoperator.runner.qemu.events.MonitorReady;
3736
import org.jdrupes.vmoperator.runner.qemu.events.OsinfoEvent;
3837
import org.jdrupes.vmoperator.runner.qemu.events.VserportChangeEvent;
3938
import org.jgrapes.core.Channel;
@@ -188,10 +187,6 @@ private void processGuestAgentInput(String line)
188187
logger.fine(() -> "guest agent(in): " + line);
189188
try {
190189
var response = mapper.readValue(line, ObjectNode.class);
191-
if (response.has("QMP")) {
192-
rep.fire(new MonitorReady());
193-
return;
194-
}
195190
if (response.has("return") || response.has("error")) {
196191
QmpCommand executed = executing.poll();
197192
logger.fine(

org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Runner.java

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu;
6262
import org.jdrupes.vmoperator.runner.qemu.events.Exit;
6363
import org.jdrupes.vmoperator.runner.qemu.events.MonitorCommand;
64+
import org.jdrupes.vmoperator.runner.qemu.events.OsinfoEvent;
6465
import org.jdrupes.vmoperator.runner.qemu.events.QmpConfigured;
6566
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange;
6667
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState;
@@ -619,8 +620,8 @@ public void onInput(Input<?> event, ProcessChannel channel) {
619620
}
620621

621622
/**
622-
* On monitor ready.
623-
*
623+
* When the monitor is ready, send QEMU its initial configuration.
624+
*
624625
* @param event the event
625626
*/
626627
@Handler
@@ -629,34 +630,50 @@ public void onQmpConfigured(QmpConfigured event) {
629630
}
630631

631632
/**
632-
* On configure qemu.
633+
* Whenever a new QEMU configuration is available, check if it
634+
* is supposed to trigger a reset.
633635
*
634636
* @param event the event
635637
*/
638+
@Handler
639+
public void onConfigureQemu(ConfigureQemu event) {
640+
if (state.vmActive()) {
641+
if (resetCounter != null
642+
&& event.configuration().resetCounter != null
643+
&& event.configuration().resetCounter > resetCounter) {
644+
fire(new MonitorCommand(new QmpReset()));
645+
}
646+
resetCounter = event.configuration().resetCounter;
647+
}
648+
}
649+
650+
/**
651+
* As last step when handling a new configuration, check if
652+
* QEMU is suspended after startup and should be continued.
653+
*
654+
* @param event the event
655+
*/
636656
@Handler(priority = -1000)
637657
public void onConfigureQemuFinal(ConfigureQemu event) {
638658
if (state == RunState.STARTING) {
659+
state = RunState.BOOTING;
639660
fire(new MonitorCommand(new QmpCont()));
640-
state = RunState.RUNNING;
641661
rep.fire(new RunnerStateChange(state, "VmStarted",
642662
"Qemu has been configured and is continuing"));
643663
}
644664
}
645665

646666
/**
647-
* On configure qemu.
667+
* Receiving the OSinfo means that the OS has been booted.
648668
*
649669
* @param event the event
650670
*/
651671
@Handler
652-
public void onConfigureQemu(ConfigureQemu event) {
653-
if (state == RunState.RUNNING) {
654-
if (resetCounter != null
655-
&& event.configuration().resetCounter != null
656-
&& event.configuration().resetCounter > resetCounter) {
657-
fire(new MonitorCommand(new QmpReset()));
658-
}
659-
resetCounter = event.configuration().resetCounter;
672+
public void onOsinfo(OsinfoEvent event) {
673+
if (state == RunState.BOOTING) {
674+
state = RunState.BOOTED;
675+
rep.fire(new RunnerStateChange(state, "VmBooted",
676+
"The VM has started the guest agent."));
660677
}
661678
}
662679

@@ -675,6 +692,7 @@ public void onProcessExited(ProcessExited event, ProcessChannel channel) {
675692
mayBeStartQemu(QemuPreps.CloudInit);
676693
return;
677694
}
695+
678696
// No other process(es) may exit during startup
679697
if (state == RunState.STARTING) {
680698
logger.severe(() -> "Process " + procDef.name
@@ -683,7 +701,9 @@ public void onProcessExited(ProcessExited event, ProcessChannel channel) {
683701
rep.fire(new Stop());
684702
return;
685703
}
686-
if (procDef.equals(qemuDefinition) && state == RunState.RUNNING) {
704+
705+
// No processes may exit while the VM is running normally
706+
if (procDef.equals(qemuDefinition) && state.vmActive()) {
687707
rep.fire(new Exit(event.exitValue()));
688708
}
689709
logger.info(() -> "Process " + procDef.name

org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* VM-Operator
3-
* Copyright (C) 2023,2024 Michael N. Lipp
3+
* Copyright (C) 2023,2025 Michael N. Lipp
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Affero General Public License as
@@ -31,7 +31,6 @@
3131
import io.kubernetes.client.openapi.models.EventsV1Event;
3232
import java.io.IOException;
3333
import java.math.BigDecimal;
34-
import java.util.Set;
3534
import java.util.logging.Level;
3635
import static org.jdrupes.vmoperator.common.Constants.APP_NAME;
3736
import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP;
@@ -66,9 +65,6 @@ public class StatusUpdater extends VmDefUpdater {
6665
private static final ObjectMapper objectMapper
6766
= new ObjectMapper().registerModule(new JavaTimeModule());
6867

69-
private static final Set<RunState> RUNNING_STATES
70-
= Set.of(RunState.RUNNING, RunState.TERMINATING);
71-
7268
private long observedGeneration;
7369
private boolean guestShutdownStops;
7470
private boolean shutdownByGuest;
@@ -186,16 +182,23 @@ public void onRunnerStateChanged(RunnerStateChange event)
186182
}
187183
vmStub.updateStatus(vmDef, from -> {
188184
JsonObject status = from.statusJson();
189-
boolean running = RUNNING_STATES.contains(event.runState());
185+
boolean running = event.runState().vmRunning();
190186
updateCondition(vmDef, vmDef.statusJson(), "Running", running,
191187
event.reason(), event.message());
188+
updateCondition(vmDef, vmDef.statusJson(), "Booted",
189+
event.runState() == RunState.BOOTED, event.reason(),
190+
event.message());
192191
if (event.runState() == RunState.STARTING) {
193192
status.addProperty("ram", GsonPtr.to(from.data())
194193
.getAsString("spec", "vm", "maximumRam").orElse("0"));
195194
status.addProperty("cpus", 1);
195+
196+
// In case we had an irregular shutdown
197+
status.remove("osinfo");
196198
} else if (event.runState() == RunState.STOPPED) {
197199
status.addProperty("ram", "0");
198200
status.addProperty("cpus", 0);
201+
status.remove("osinfo");
199202
}
200203

201204
// In case console connection was still present

org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/RunnerStateChange.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
package org.jdrupes.vmoperator.runner.qemu.events;
2020

21+
import java.util.EnumSet;
2122
import org.jgrapes.core.Channel;
2223
import org.jgrapes.core.Components;
2324
import org.jgrapes.core.Event;
@@ -29,10 +30,28 @@
2930
public class RunnerStateChange extends Event<Void> {
3031

3132
/**
32-
* The state.
33+
* The states.
3334
*/
3435
public enum RunState {
35-
INITIALIZING, STARTING, RUNNING, TERMINATING, STOPPED
36+
INITIALIZING, STARTING, BOOTING, BOOTED, TERMINATING, STOPPED;
37+
38+
/**
39+
* Checks if the state is one of the states in which the VM is running.
40+
*
41+
* @return true, if is running
42+
*/
43+
public boolean vmRunning() {
44+
return EnumSet.of(BOOTING, BOOTED, TERMINATING).contains(this);
45+
}
46+
47+
/**
48+
* Checks if the state is one of the states in which the VM is active.
49+
*
50+
* @return true, if is active
51+
*/
52+
public boolean vmActive() {
53+
return EnumSet.of(BOOTING, BOOTED).contains(this);
54+
}
3655
}
3756

3857
private final RunState state;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
almalinux.svg:
2+
Source: https://commons.wikimedia.org/wiki/File:AlmaLinux_Icon_Logo.svg
3+
License: https://github.com/AlmaLinux/wiki/blob/master/LICENSE
4+
5+
archlinux.svg:
6+
Source: https://commons.wikimedia.org/wiki/File:Arch_Linux_%22Crystal%22_icon.svghttps://commons.wikimedia.org/wiki/File:Arch_Linux_%22Crystal%22_icon.svg
7+
License: GPL v2 or later
8+
9+
debian.svg:
10+
Source: https://commons.wikimedia.org/wiki/File:Openlogo-debianV2.svg
11+
License : LGPL
12+
13+
tux.svg:
14+
Source: https://commons.wikimedia.org/wiki/File:Tux.svghttps://commons.wikimedia.org/wiki/File:Tux.svg
15+
License: Creative Commons CC0 1.0 Universal Public Domain Dedication. Creative Commons CC0 1.0 Universal Public Domain Dedication.
16+
Lines changed: 16 additions & 0 deletions
Loading
Lines changed: 20 additions & 0 deletions
Loading
Lines changed: 9 additions & 0 deletions
Loading
40.3 KB
Loading

0 commit comments

Comments
 (0)