From 5ca45d76202df8b976ec41c1ce72ae26bb6351ec Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 16 Mar 2025 23:12:22 +0100 Subject: [PATCH 1/2] Minor edit. --- deploy/vmop-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/vmop-deployment.yaml b/deploy/vmop-deployment.yaml index 4a22d9e..b1f5075 100644 --- a/deploy/vmop-deployment.yaml +++ b/deploy/vmop-deployment.yaml @@ -21,12 +21,12 @@ spec: - name: vm-operator image: >- ghcr.io/mnlipp/org.jdrupes.vmoperator.manager:latest + imagePullPolicy: Always volumeMounts: - name: config mountPath: /etc/opt/vmoperator - name: vmop-image-repository mountPath: /var/local/vmop-image-repository - imagePullPolicy: Always securityContext: capabilities: drop: From 3b0a4c8a2314604aadad7af5ae3539ae6f3d8b58 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 17 Mar 2025 16:49:10 +0100 Subject: [PATCH 2/2] Rate limit for RAM size updates. --- .../vmoperator/runner/qemu/StatusUpdater.java | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java index bd4ddb4..17f1915 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java @@ -31,6 +31,8 @@ import io.kubernetes.client.openapi.JSON; import io.kubernetes.client.openapi.models.EventsV1Event; import java.io.IOException; import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; import java.util.Optional; import java.util.logging.Level; import static org.jdrupes.vmoperator.common.Constants.APP_NAME; @@ -55,6 +57,8 @@ import org.jdrupes.vmoperator.runner.qemu.events.VmopAgentLoggedIn; import org.jdrupes.vmoperator.runner.qemu.events.VmopAgentLoggedOut; import org.jdrupes.vmoperator.util.GsonPtr; import org.jgrapes.core.Channel; +import org.jgrapes.core.Components; +import org.jgrapes.core.Components.Timer; import org.jgrapes.core.annotation.Handler; import org.jgrapes.core.events.HandlingError; import org.jgrapes.core.events.Start; @@ -62,7 +66,8 @@ import org.jgrapes.core.events.Start; /** * Updates the CR status. */ -@SuppressWarnings("PMD.DataflowAnomalyAnalysis") +@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", + "PMD.CouplingBetweenObjects" }) public class StatusUpdater extends VmDefUpdater { @SuppressWarnings("PMD.FieldNamingConventions") @@ -76,6 +81,10 @@ public class StatusUpdater extends VmDefUpdater { private boolean shutdownByGuest; private VmDefinitionStub vmStub; private String loggedInUser; + private BigInteger lastRamValue; + private Instant lastRamChange; + private Timer balloonTimer; + private BigInteger targetRamValue; /** * Instantiates a new status updater. @@ -151,6 +160,7 @@ public class StatusUpdater extends VmDefUpdater { throws ApiException { guestShutdownStops = event.configuration().guestShutdownStops; loggedInUser = event.configuration().vm.display.loggedInUser; + targetRamValue = event.configuration().vm.currentRam; // Remainder applies only if we have a connection to k8s. if (vmStub == null) { @@ -279,7 +289,11 @@ public class StatusUpdater extends VmDefUpdater { } /** - * On ballon change. + * Update the current RAM size in the status. Balloon changes happen + * more than once every second during changes. While this is nice + * to watch, this puts a heavy load on the system. Therefore we + * only update the status once every 15 seconds or when the target + * value is reached. * * @param event the event * @throws ApiException @@ -289,10 +303,44 @@ public class StatusUpdater extends VmDefUpdater { if (vmStub == null) { return; } + Instant now = Instant.now(); + if (lastRamChange == null + || lastRamChange.isBefore(now.minusSeconds(15)) + || event.size().equals(targetRamValue)) { + if (balloonTimer != null) { + balloonTimer.cancel(); + balloonTimer = null; + } + lastRamChange = now; + lastRamValue = event.size(); + updateRam(lastRamValue); + return; + } + + // Save for later processing and maybe start timer + lastRamChange = now; + lastRamValue = event.size(); + if (balloonTimer != null) { + return; + } + balloonTimer = Components.schedule(t -> { + activeEventPipeline().submit("Update RAM size", () -> { + try { + updateRam(lastRamValue); + } catch (ApiException e) { + logger.log(Level.WARNING, e, + () -> "Failed to update ram size: " + e.getMessage()); + } + balloonTimer = null; + }); + }, now.plusSeconds(15)); + } + + private void updateRam(BigInteger size) throws ApiException { vmStub.updateStatus(from -> { JsonObject status = from.statusJson(); status.addProperty(Status.RAM, - new Quantity(new BigDecimal(event.size()), Format.BINARY_SI) + new Quantity(new BigDecimal(size), Format.BINARY_SI) .toSuffixedString()); return status; });