Report current RAM usage in status.
This commit is contained in:
parent
a045cba998
commit
9d29266907
3 changed files with 130 additions and 50 deletions
|
|
@ -19,6 +19,8 @@
|
||||||
package org.jdrupes.vmoperator.runner.qemu;
|
package org.jdrupes.vmoperator.runner.qemu;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import io.kubernetes.client.custom.Quantity;
|
||||||
|
import io.kubernetes.client.custom.Quantity.Format;
|
||||||
import io.kubernetes.client.openapi.ApiException;
|
import io.kubernetes.client.openapi.ApiException;
|
||||||
import io.kubernetes.client.openapi.apis.ApiextensionsV1Api;
|
import io.kubernetes.client.openapi.apis.ApiextensionsV1Api;
|
||||||
import io.kubernetes.client.openapi.models.V1CustomResourceDefinitionVersion;
|
import io.kubernetes.client.openapi.models.V1CustomResourceDefinitionVersion;
|
||||||
|
|
@ -26,6 +28,7 @@ import io.kubernetes.client.util.Config;
|
||||||
import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesApi;
|
import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesApi;
|
||||||
import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject;
|
import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
@ -33,11 +36,13 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
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.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;
|
||||||
import static org.jdrupes.vmoperator.util.Constants.VM_OP_CRD_NAME;
|
import static org.jdrupes.vmoperator.util.Constants.VM_OP_CRD_NAME;
|
||||||
import static org.jdrupes.vmoperator.util.Constants.VM_OP_GROUP;
|
import static org.jdrupes.vmoperator.util.Constants.VM_OP_GROUP;
|
||||||
|
import org.jdrupes.vmoperator.util.GsonPtr;
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.Component;
|
import org.jgrapes.core.Component;
|
||||||
import org.jgrapes.core.annotation.Handler;
|
import org.jgrapes.core.annotation.Handler;
|
||||||
|
|
@ -161,55 +166,6 @@ public class StatusUpdater extends Component {
|
||||||
return vmCr.getRaw().getAsJsonObject("status").deepCopy();
|
return vmCr.getRaw().getAsJsonObject("status").deepCopy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* On runner state changed.
|
|
||||||
*
|
|
||||||
* @param event the event
|
|
||||||
8 * @throws ApiException the api exception
|
|
||||||
*/
|
|
||||||
@Handler
|
|
||||||
public void onRunnerStateChanged(RunnerStateChange event)
|
|
||||||
throws ApiException {
|
|
||||||
if (vmCrApi == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var vmCr = vmCrApi.get(namespace, vmName)
|
|
||||||
.throwsApiException().getObject();
|
|
||||||
vmCrApi.updateStatus(vmCr, from -> {
|
|
||||||
JsonObject status = currentStatus(from);
|
|
||||||
status.getAsJsonArray("conditions").asList().stream()
|
|
||||||
.map(cond -> (JsonObject) cond)
|
|
||||||
.forEach(cond -> {
|
|
||||||
if ("Running".equals(cond.get("type").getAsString())) {
|
|
||||||
updateRunningCondition(event, from, cond);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return status;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateRunningCondition(RunnerStateChange event,
|
|
||||||
DynamicKubernetesObject from, JsonObject cond) {
|
|
||||||
boolean reportedRunning
|
|
||||||
= "True".equals(cond.get("status").getAsString());
|
|
||||||
if (RUNNING_STATES.contains(event.state())
|
|
||||||
&& !reportedRunning) {
|
|
||||||
cond.addProperty("status", "True");
|
|
||||||
cond.addProperty("lastTransitionTime",
|
|
||||||
Instant.now().toString());
|
|
||||||
}
|
|
||||||
if (!RUNNING_STATES.contains(event.state())
|
|
||||||
&& reportedRunning) {
|
|
||||||
cond.addProperty("status", "False");
|
|
||||||
cond.addProperty("lastTransitionTime",
|
|
||||||
Instant.now().toString());
|
|
||||||
}
|
|
||||||
cond.addProperty("reason", event.reason());
|
|
||||||
cond.addProperty("message", event.message());
|
|
||||||
cond.addProperty("observedGeneration",
|
|
||||||
from.getMetadata().getGeneration());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On runner configuration update.
|
* On runner configuration update.
|
||||||
*
|
*
|
||||||
|
|
@ -241,4 +197,78 @@ public class StatusUpdater extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On runner state changed.
|
||||||
|
*
|
||||||
|
* @param event the event
|
||||||
|
* @throws ApiException the api exception
|
||||||
|
*/
|
||||||
|
@Handler
|
||||||
|
public void onRunnerStateChanged(RunnerStateChange event)
|
||||||
|
throws ApiException {
|
||||||
|
if (vmCrApi == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var vmCr = vmCrApi.get(namespace, vmName)
|
||||||
|
.throwsApiException().getObject();
|
||||||
|
vmCrApi.updateStatus(vmCr, from -> {
|
||||||
|
JsonObject status = currentStatus(from);
|
||||||
|
status.getAsJsonArray("conditions").asList().stream()
|
||||||
|
.map(cond -> (JsonObject) cond)
|
||||||
|
.forEach(cond -> {
|
||||||
|
if ("Running".equals(cond.get("type").getAsString())) {
|
||||||
|
updateRunningCondition(event, from, cond);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (event.state() == State.STARTING) {
|
||||||
|
status.addProperty("ram", GsonPtr.to(from.getRaw())
|
||||||
|
.getAsString("spec", "vm", "maximumRam").orElse("0"));
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRunningCondition(RunnerStateChange event,
|
||||||
|
DynamicKubernetesObject from, JsonObject cond) {
|
||||||
|
boolean reportedRunning
|
||||||
|
= "True".equals(cond.get("status").getAsString());
|
||||||
|
if (RUNNING_STATES.contains(event.state())
|
||||||
|
&& !reportedRunning) {
|
||||||
|
cond.addProperty("status", "True");
|
||||||
|
cond.addProperty("lastTransitionTime",
|
||||||
|
Instant.now().toString());
|
||||||
|
}
|
||||||
|
if (!RUNNING_STATES.contains(event.state())
|
||||||
|
&& reportedRunning) {
|
||||||
|
cond.addProperty("status", "False");
|
||||||
|
cond.addProperty("lastTransitionTime",
|
||||||
|
Instant.now().toString());
|
||||||
|
}
|
||||||
|
cond.addProperty("reason", event.reason());
|
||||||
|
cond.addProperty("message", event.message());
|
||||||
|
cond.addProperty("observedGeneration",
|
||||||
|
from.getMetadata().getGeneration());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On ballon change.
|
||||||
|
*
|
||||||
|
* @param event the event
|
||||||
|
* @throws ApiException
|
||||||
|
*/
|
||||||
|
@Handler
|
||||||
|
public void onBallonChange(BalloonChangeEvent 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("ram",
|
||||||
|
new Quantity(new BigDecimal(event.size()), Format.BINARY_SI)
|
||||||
|
.toSuffixedString());
|
||||||
|
return status;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* VM-Operator
|
||||||
|
* Copyright (C) 2023 Michael N. Lipp
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jdrupes.vmoperator.runner.qemu.events;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals a change of the balloon.
|
||||||
|
*/
|
||||||
|
public class BalloonChangeEvent extends MonitorEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new tray moved.
|
||||||
|
*
|
||||||
|
* @param kind the kind
|
||||||
|
* @param data the data
|
||||||
|
*/
|
||||||
|
public BalloonChangeEvent(Kind kind, JsonNode data) {
|
||||||
|
super(kind, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the actual value.
|
||||||
|
*
|
||||||
|
* @return the actual value
|
||||||
|
*/
|
||||||
|
public BigInteger size() {
|
||||||
|
return new BigInteger(data().get("actual").asText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,7 +32,7 @@ public class MonitorEvent extends Event<Void> {
|
||||||
* The kind of monitor event.
|
* The kind of monitor event.
|
||||||
*/
|
*/
|
||||||
public enum Kind {
|
public enum Kind {
|
||||||
READY, POWERDOWN, DEVICE_TRAY_MOVED
|
READY, POWERDOWN, DEVICE_TRAY_MOVED, BALLOON_CHANGE
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Kind kind;
|
private final Kind kind;
|
||||||
|
|
@ -55,6 +55,9 @@ public class MonitorEvent extends Event<Void> {
|
||||||
case DEVICE_TRAY_MOVED:
|
case DEVICE_TRAY_MOVED:
|
||||||
return Optional
|
return Optional
|
||||||
.of(new TrayMovedEvent(kind, response.get("data")));
|
.of(new TrayMovedEvent(kind, response.get("data")));
|
||||||
|
case BALLOON_CHANGE:
|
||||||
|
return Optional
|
||||||
|
.of(new BalloonChangeEvent(kind, response.get("data")));
|
||||||
default:
|
default:
|
||||||
return Optional
|
return Optional
|
||||||
.of(new MonitorEvent(kind, response.get("data")));
|
.of(new MonitorEvent(kind, response.get("data")));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue