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;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@ -81,34 +81,28 @@ public class CpuController extends Component {
/**
* On monitor result.
*
* @param result the result
* @param event the result
*/
@Handler
public void onHotpluggableCpuStatus(HotpluggableCpuStatus result) {
if (!result.successful()) {
public void onHotpluggableCpuStatus(HotpluggableCpuStatus event) {
if (!event.successful()) {
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) {
return;
}
// Process
int diff = used.size() - desiredCpus;
diff = addCpus(used, unused, diff);
deleteCpus(used, diff);
currentCpus = event.usedCpus().size();
int diff = currentCpus - desiredCpus;
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")
@ -123,22 +117,24 @@ public class CpuController extends Component {
}
}
int nextId = 1;
while (diff < 0 && !unused.isEmpty()) {
List<ObjectNode> remaining = new LinkedList<>(unused);
while (diff < 0 && !remaining.isEmpty()) {
String id;
do {
id = "cpu-" + nextId++;
} while (usedIds.contains(id));
fire(new MonitorCommand(new QmpAddCpu(unused.get(0), id)));
unused.remove(0);
fire(new MonitorCommand(new QmpAddCpu(remaining.get(0), id)));
remaining.remove(0);
diff += 1;
}
return diff;
}
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private int deleteCpus(List<ObjectNode> used, int diff) {
while (diff > 0 && !used.isEmpty()) {
ObjectNode cpu = used.remove(0);
private int removeCpus(List<ObjectNode> used, int diff) {
List<ObjectNode> removable = new LinkedList<>(used);
while (diff > 0 && !removable.isEmpty()) {
ObjectNode cpu = removable.remove(0);
String qomPath = cpu.get("qom-path").asText();
if (!qomPath.startsWith("/machine/peripheral/cpu-")) {
continue;

View file

@ -37,6 +37,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
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.RunnerStateChange;
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.State;
@ -223,8 +224,10 @@ public class StatusUpdater extends Component {
if (event.state() == State.STARTING) {
status.addProperty("ram", GsonPtr.to(from.getRaw())
.getAsString("spec", "vm", "maximumRam").orElse("0"));
status.addProperty("cpus", 1);
} else if (event.state() == State.STOPPED) {
status.addProperty("ram", "0");
status.addProperty("cpus", 0);
}
return status;
});
@ -273,4 +276,24 @@ public class StatusUpdater extends Component {
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;
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;
/**
@ -26,6 +30,9 @@ import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand;
*/
public class HotpluggableCpuStatus extends MonitorResult {
private List<ObjectNode> usedCpus = new ArrayList<>();
private List<ObjectNode> unusedCpus = new ArrayList<>();
/**
* Instantiates a new hotpluggable cpu result.
*
@ -34,6 +41,39 @@ public class HotpluggableCpuStatus extends MonitorResult {
*/
public HotpluggableCpuStatus(QmpCommand command, JsonNode 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;
}
}