Report current CPUs in status.

This commit is contained in:
Michael Lipp 2023-09-15 11:51:19 +02:00
parent 7f512082f0
commit 8a7d9d6621
3 changed files with 86 additions and 27 deletions

View file

@ -19,8 +19,8 @@
package org.jdrupes.vmoperator.runner.qemu; package org.jdrupes.vmoperator.runner.qemu;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -81,34 +81,28 @@ public class CpuController extends Component {
/** /**
* On monitor result. * On monitor result.
* *
* @param result the result * @param event the result
*/ */
@Handler @Handler
public void onHotpluggableCpuStatus(HotpluggableCpuStatus result) { public void onHotpluggableCpuStatus(HotpluggableCpuStatus event) {
if (!result.successful()) { if (!event.successful()) {
logger.warning(() -> "Failed to get hotpluggable CPU status " logger.warning(() -> "Failed to get hotpluggable CPU status "
+ "(won't adjust number of CPUs.): " + result.errorMessage()); + "(won't adjust number of CPUs.): " + event.errorMessage());
} }
// Sort
List<ObjectNode> used = new ArrayList<>();
List<ObjectNode> unused = new ArrayList<>();
for (var itr = result.values().iterator(); itr.hasNext();) {
ObjectNode cpu = (ObjectNode) itr.next();
if (cpu.has("qom-path")) {
used.add(cpu);
} else {
unused.add(cpu);
}
}
currentCpus = used.size();
if (desiredCpus == null) { if (desiredCpus == null) {
return; return;
} }
// Process // Process
int diff = used.size() - desiredCpus; currentCpus = event.usedCpus().size();
diff = addCpus(used, unused, diff); int diff = currentCpus - desiredCpus;
deleteCpus(used, diff); if (diff == 0) {
return;
}
diff = addCpus(event.usedCpus(), event.unusedCpus(), diff);
removeCpus(event.usedCpus(), diff);
// Report result
fire(new MonitorCommand(new QmpQueryHotpluggableCpus()));
} }
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
@ -123,22 +117,24 @@ public class CpuController extends Component {
} }
} }
int nextId = 1; int nextId = 1;
while (diff < 0 && !unused.isEmpty()) { List<ObjectNode> remaining = new LinkedList<>(unused);
while (diff < 0 && !remaining.isEmpty()) {
String id; String id;
do { do {
id = "cpu-" + nextId++; id = "cpu-" + nextId++;
} while (usedIds.contains(id)); } while (usedIds.contains(id));
fire(new MonitorCommand(new QmpAddCpu(unused.get(0), id))); fire(new MonitorCommand(new QmpAddCpu(remaining.get(0), id)));
unused.remove(0); remaining.remove(0);
diff += 1; diff += 1;
} }
return diff; return diff;
} }
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private int deleteCpus(List<ObjectNode> used, int diff) { private int removeCpus(List<ObjectNode> used, int diff) {
while (diff > 0 && !used.isEmpty()) { List<ObjectNode> removable = new LinkedList<>(used);
ObjectNode cpu = used.remove(0); while (diff > 0 && !removable.isEmpty()) {
ObjectNode cpu = removable.remove(0);
String qomPath = cpu.get("qom-path").asText(); String qomPath = cpu.get("qom-path").asText();
if (!qomPath.startsWith("/machine/peripheral/cpu-")) { if (!qomPath.startsWith("/machine/peripheral/cpu-")) {
continue; continue;

View file

@ -37,6 +37,7 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.jdrupes.vmoperator.runner.qemu.events.BalloonChangeEvent; import org.jdrupes.vmoperator.runner.qemu.events.BalloonChangeEvent;
import org.jdrupes.vmoperator.runner.qemu.events.HotpluggableCpuStatus;
import org.jdrupes.vmoperator.runner.qemu.events.RunnerConfigurationUpdate; import org.jdrupes.vmoperator.runner.qemu.events.RunnerConfigurationUpdate;
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange;
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.State; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.State;
@ -223,8 +224,10 @@ public class StatusUpdater extends Component {
if (event.state() == State.STARTING) { if (event.state() == State.STARTING) {
status.addProperty("ram", GsonPtr.to(from.getRaw()) status.addProperty("ram", GsonPtr.to(from.getRaw())
.getAsString("spec", "vm", "maximumRam").orElse("0")); .getAsString("spec", "vm", "maximumRam").orElse("0"));
status.addProperty("cpus", 1);
} else if (event.state() == State.STOPPED) { } else if (event.state() == State.STOPPED) {
status.addProperty("ram", "0"); status.addProperty("ram", "0");
status.addProperty("cpus", 0);
} }
return status; return status;
}); });
@ -273,4 +276,24 @@ public class StatusUpdater extends Component {
return status; return status;
}); });
} }
/**
* On ballon change.
*
* @param event the event
* @throws ApiException
*/
@Handler
public void onCpuChange(HotpluggableCpuStatus event) throws ApiException {
if (vmCrApi == null) {
return;
}
var vmCr
= vmCrApi.get(namespace, vmName).throwsApiException().getObject();
vmCrApi.updateStatus(vmCr, from -> {
JsonObject status = currentStatus(from);
status.addProperty("cpus", event.usedCpus().size());
return status;
});
}
} }

View file

@ -19,6 +19,10 @@
package org.jdrupes.vmoperator.runner.qemu.events; package org.jdrupes.vmoperator.runner.qemu.events;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand; import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand;
/** /**
@ -26,6 +30,9 @@ import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand;
*/ */
public class HotpluggableCpuStatus extends MonitorResult { public class HotpluggableCpuStatus extends MonitorResult {
private List<ObjectNode> usedCpus = new ArrayList<>();
private List<ObjectNode> unusedCpus = new ArrayList<>();
/** /**
* Instantiates a new hotpluggable cpu result. * Instantiates a new hotpluggable cpu result.
* *
@ -34,6 +41,39 @@ public class HotpluggableCpuStatus extends MonitorResult {
*/ */
public HotpluggableCpuStatus(QmpCommand command, JsonNode response) { public HotpluggableCpuStatus(QmpCommand command, JsonNode response) {
super(command, response); super(command, response);
if (!successful()) {
return;
}
// Sort
for (var itr = values().iterator(); itr.hasNext();) {
ObjectNode cpu = (ObjectNode) itr.next();
if (cpu.has("qom-path")) {
usedCpus.add(cpu);
} else {
unusedCpus.add(cpu);
}
}
usedCpus = Collections.unmodifiableList(usedCpus);
unusedCpus = Collections.unmodifiableList(unusedCpus);
}
/**
* Gets the used cpus.
*
* @return the usedCpus
*/
public List<ObjectNode> usedCpus() {
return usedCpus;
}
/**
* Gets the unused cpus.
*
* @return the unusedCpus
*/
public List<ObjectNode> unusedCpus() {
return unusedCpus;
} }
} }