3131import io .kubernetes .client .openapi .models .EventsV1Event ;
3232import java .io .IOException ;
3333import java .math .BigDecimal ;
34+ import java .math .BigInteger ;
35+ import java .time .Instant ;
3436import java .util .Optional ;
3537import java .util .logging .Level ;
3638import static org .jdrupes .vmoperator .common .Constants .APP_NAME ;
5557import org .jdrupes .vmoperator .runner .qemu .events .VmopAgentLoggedOut ;
5658import org .jdrupes .vmoperator .util .GsonPtr ;
5759import org .jgrapes .core .Channel ;
60+ import org .jgrapes .core .Components ;
61+ import org .jgrapes .core .Components .Timer ;
5862import org .jgrapes .core .annotation .Handler ;
5963import org .jgrapes .core .events .HandlingError ;
6064import org .jgrapes .core .events .Start ;
6165
6266/**
6367 * Updates the CR status.
6468 */
65- @ SuppressWarnings ("PMD.DataflowAnomalyAnalysis" )
69+ @ SuppressWarnings ({ "PMD.DataflowAnomalyAnalysis" ,
70+ "PMD.CouplingBetweenObjects" })
6671public class StatusUpdater extends VmDefUpdater {
6772
6873 @ SuppressWarnings ("PMD.FieldNamingConventions" )
@@ -76,6 +81,10 @@ public class StatusUpdater extends VmDefUpdater {
7681 private boolean shutdownByGuest ;
7782 private VmDefinitionStub vmStub ;
7883 private String loggedInUser ;
84+ private BigInteger lastRamValue ;
85+ private Instant lastRamChange ;
86+ private Timer balloonTimer ;
87+ private BigInteger targetRamValue ;
7988
8089 /**
8190 * Instantiates a new status updater.
@@ -151,6 +160,7 @@ public void onConfigureQemu(ConfigureQemu event)
151160 throws ApiException {
152161 guestShutdownStops = event .configuration ().guestShutdownStops ;
153162 loggedInUser = event .configuration ().vm .display .loggedInUser ;
163+ targetRamValue = event .configuration ().vm .currentRam ;
154164
155165 // Remainder applies only if we have a connection to k8s.
156166 if (vmStub == null ) {
@@ -279,7 +289,11 @@ private void updateUserLoggedIn(VmDefinition from) {
279289 }
280290
281291 /**
282- * On ballon change.
292+ * Update the current RAM size in the status. Balloon changes happen
293+ * more than once every second during changes. While this is nice
294+ * to watch, this puts a heavy load on the system. Therefore we
295+ * only update the status once every 15 seconds or when the target
296+ * value is reached.
283297 *
284298 * @param event the event
285299 * @throws ApiException
@@ -289,10 +303,44 @@ public void onBallonChange(BalloonChangeEvent event) throws ApiException {
289303 if (vmStub == null ) {
290304 return ;
291305 }
306+ Instant now = Instant .now ();
307+ if (lastRamChange == null
308+ || lastRamChange .isBefore (now .minusSeconds (15 ))
309+ || event .size ().equals (targetRamValue )) {
310+ if (balloonTimer != null ) {
311+ balloonTimer .cancel ();
312+ balloonTimer = null ;
313+ }
314+ lastRamChange = now ;
315+ lastRamValue = event .size ();
316+ updateRam (lastRamValue );
317+ return ;
318+ }
319+
320+ // Save for later processing and maybe start timer
321+ lastRamChange = now ;
322+ lastRamValue = event .size ();
323+ if (balloonTimer != null ) {
324+ return ;
325+ }
326+ balloonTimer = Components .schedule (t -> {
327+ activeEventPipeline ().submit ("Update RAM size" , () -> {
328+ try {
329+ updateRam (lastRamValue );
330+ } catch (ApiException e ) {
331+ logger .log (Level .WARNING , e ,
332+ () -> "Failed to update ram size: " + e .getMessage ());
333+ }
334+ balloonTimer = null ;
335+ });
336+ }, now .plusSeconds (15 ));
337+ }
338+
339+ private void updateRam (BigInteger size ) throws ApiException {
292340 vmStub .updateStatus (from -> {
293341 JsonObject status = from .statusJson ();
294342 status .addProperty (Status .RAM ,
295- new Quantity (new BigDecimal (event . size () ), Format .BINARY_SI )
343+ new Quantity (new BigDecimal (size ), Format .BINARY_SI )
296344 .toSuffixedString ());
297345 return status ;
298346 });
0 commit comments