Add logs to LibvirtComputingResource's metrics collection process (#8511)

* Add logs to LibvirtComputingResource's metrics collecting process

* Apply Joao's suggestions

Co-authored-by: João Jandre <48719461+JoaoJandre@users.noreply.github.com>

* Adjust some logs

* Print memory statistics log in one line

---------

Co-authored-by: João Jandre <48719461+JoaoJandre@users.noreply.github.com>
This commit is contained in:
Fabricio Duarte 2024-09-06 10:49:22 -03:00 committed by GitHub
parent 82f113b1e1
commit b11897cdfa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 390 additions and 191 deletions

View File

@ -44,6 +44,8 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.naming.ConfigurationException;
import javax.xml.parsers.DocumentBuilder;
@ -76,6 +78,8 @@ import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.xerces.impl.xpath.regex.Match;
@ -446,7 +450,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
protected WatchDogModel watchDogModel = WatchDogModel.I6300ESB;
private final Map <String, String> pifs = new HashMap<String, String>();
private final Map<String, VmStats> vmStats = new ConcurrentHashMap<String, VmStats>();
private final Map<String, LibvirtExtendedVmStatsEntry> vmStats = new ConcurrentHashMap<>();
private final Map<String, DomainBlockStats> vmDiskStats = new ConcurrentHashMap<>();
@ -2346,7 +2350,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
final PowerState s = convertToPowerState(vms.getInfo().state);
return s;
} catch (final LibvirtException e) {
LOGGER.warn("Can't get vm state " + vmName + e.getMessage() + "retry:" + retry);
LOGGER.error("Could not get state for VM [{}] (retry={}) due to:", vmName, retry, e);
} finally {
try {
if (vms != null) {
@ -4414,122 +4418,34 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
return null;
}
private class VmStats {
long usedTime;
long tx;
long rx;
long ioRead;
long ioWrote;
long bytesRead;
long bytesWrote;
Calendar timestamp;
private String vmToString(Domain dm) throws LibvirtException {
return String.format("{\"name\":\"%s\",\"uuid\":\"%s\"}", dm.getName(), dm.getUUIDString());
}
/**
* Returns metrics for the period since this function was last called for the specified VM.
* @param conn the Libvirt connection.
* @param vmName name of the VM.
* @return metrics for the period since last time this function was called for the VM.
* @throws LibvirtException
*/
public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws LibvirtException {
Domain dm = null;
try {
LOGGER.debug("Trying to get VM with name [{}].", vmName);
dm = getDomain(conn, vmName);
if (dm == null) {
LOGGER.warn("Could not get VM with name [{}].", vmName);
return null;
}
DomainInfo info = dm.getInfo();
final VmStatsEntry stats = new VmStatsEntry();
stats.setNumCPUs(info.nrVirtCpu);
stats.setEntityType("vm");
LibvirtExtendedVmStatsEntry newStats = getVmCurrentStats(dm);
LibvirtExtendedVmStatsEntry oldStats = vmStats.get(vmName);
stats.setMemoryKBs(info.maxMem);
stats.setTargetMemoryKBs(info.memory);
stats.setIntFreeMemoryKBs(getMemoryFreeInKBs(dm));
VmStatsEntry metrics = calculateVmMetrics(dm, oldStats, newStats);
vmStats.put(vmName, newStats);
/* get cpu utilization */
VmStats oldStats = null;
final Calendar now = Calendar.getInstance();
oldStats = vmStats.get(vmName);
long elapsedTime = 0;
if (oldStats != null) {
elapsedTime = now.getTimeInMillis() - oldStats.timestamp.getTimeInMillis();
double utilization = (info.cpuTime - oldStats.usedTime) / ((double)elapsedTime * 1000000);
utilization = utilization / info.nrVirtCpu;
if (utilization > 0) {
stats.setCPUUtilization(utilization * 100);
}
}
/* get network stats */
final List<InterfaceDef> vifs = getInterfaces(conn, vmName);
long rx = 0;
long tx = 0;
for (final InterfaceDef vif : vifs) {
final DomainInterfaceStats ifStats = dm.interfaceStats(vif.getDevName());
rx += ifStats.rx_bytes;
tx += ifStats.tx_bytes;
}
if (oldStats != null) {
final double deltarx = rx - oldStats.rx;
if (deltarx > 0) {
stats.setNetworkReadKBs(deltarx / 1024);
}
final double deltatx = tx - oldStats.tx;
if (deltatx > 0) {
stats.setNetworkWriteKBs(deltatx / 1024);
}
}
/* get disk stats */
final List<DiskDef> disks = getDisks(conn, vmName);
long io_rd = 0;
long io_wr = 0;
long bytes_rd = 0;
long bytes_wr = 0;
for (final DiskDef disk : disks) {
if (disk.getDeviceType() == DeviceType.CDROM || disk.getDeviceType() == DeviceType.FLOPPY) {
continue;
}
final DomainBlockStats blockStats = dm.blockStats(disk.getDiskLabel());
io_rd += blockStats.rd_req;
io_wr += blockStats.wr_req;
bytes_rd += blockStats.rd_bytes;
bytes_wr += blockStats.wr_bytes;
}
if (oldStats != null) {
final long deltaiord = io_rd - oldStats.ioRead;
if (deltaiord > 0) {
stats.setDiskReadIOs(deltaiord);
}
final long deltaiowr = io_wr - oldStats.ioWrote;
if (deltaiowr > 0) {
stats.setDiskWriteIOs(deltaiowr);
}
final double deltabytesrd = bytes_rd - oldStats.bytesRead;
if (deltabytesrd > 0) {
stats.setDiskReadKBs(deltabytesrd / 1024);
}
final double deltabyteswr = bytes_wr - oldStats.bytesWrote;
if (deltabyteswr > 0) {
stats.setDiskWriteKBs(deltabyteswr / 1024);
}
}
/* save to Hashmap */
final VmStats newStat = new VmStats();
newStat.usedTime = info.cpuTime;
newStat.rx = rx;
newStat.tx = tx;
newStat.ioRead = io_rd;
newStat.ioWrote = io_wr;
newStat.bytesRead = bytes_rd;
newStat.bytesWrote = bytes_wr;
newStat.timestamp = now;
vmStats.put(vmName, newStat);
return stats;
return metrics;
} finally {
if (dm != null) {
dm.free();
@ -4537,6 +4453,156 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
}
/**
* Returns a VM's current statistics.
* @param dm domain of the VM.
* @return current statistics of the VM.
* @throws LibvirtException
*/
protected LibvirtExtendedVmStatsEntry getVmCurrentStats(final Domain dm) throws LibvirtException {
final LibvirtExtendedVmStatsEntry stats = new LibvirtExtendedVmStatsEntry();
getVmCurrentCpuStats(dm, stats);
getVmCurrentNetworkStats(dm, stats);
getVmCurrentDiskStats(dm, stats);
LOGGER.debug("Retrieved statistics for VM [{}]: [{}].", vmToString(dm), stats);
stats.setTimestamp(Calendar.getInstance());
return stats;
}
/**
* Passes a VM's current CPU statistics into the provided LibvirtExtendedVmStatsEntry.
* @param dm domain of the VM.
* @param stats LibvirtExtendedVmStatsEntry that will receive the current CPU statistics.
* @throws LibvirtException
*/
protected void getVmCurrentCpuStats(final Domain dm, final LibvirtExtendedVmStatsEntry stats) throws LibvirtException {
LOGGER.trace("Getting CPU stats for VM [{}].", vmToString(dm));
stats.setCpuTime(dm.getInfo().cpuTime);
}
/**
* Passes a VM's current network statistics into the provided LibvirtExtendedVmStatsEntry.
* @param dm domain of the VM.
* @param stats LibvirtExtendedVmStatsEntry that will receive the current network statistics.
* @throws LibvirtException
*/
protected void getVmCurrentNetworkStats(final Domain dm, final LibvirtExtendedVmStatsEntry stats) throws LibvirtException {
final String vmAsString = vmToString(dm);
LOGGER.trace("Getting network stats for VM [{}].", vmAsString);
final List<InterfaceDef> vifs = getInterfaces(dm.getConnect(), dm.getName());
LOGGER.debug("Found [{}] network interface(s) for VM [{}].", vifs.size(), vmAsString);
double rx = 0;
double tx = 0;
for (final InterfaceDef vif : vifs) {
final DomainInterfaceStats ifStats = dm.interfaceStats(vif.getDevName());
rx += ifStats.rx_bytes;
tx += ifStats.tx_bytes;
}
stats.setNetworkReadKBs(rx / 1024);
stats.setNetworkWriteKBs(tx / 1024);
}
/**
* Passes a VM's current disk statistics into the provided LibvirtExtendedVmStatsEntry.
* @param dm domain of the VM.
* @param stats LibvirtExtendedVmStatsEntry that will receive the current disk statistics.
* @throws LibvirtException
*/
protected void getVmCurrentDiskStats(final Domain dm, final LibvirtExtendedVmStatsEntry stats) throws LibvirtException {
final String vmAsString = vmToString(dm);
LOGGER.trace("Getting disk stats for VM [{}].", vmAsString);
final List<DiskDef> disks = getDisks(dm.getConnect(), dm.getName());
LOGGER.debug("Found [{}] disk(s) for VM [{}].", disks.size(), vmAsString);
long io_rd = 0;
long io_wr = 0;
double bytes_rd = 0;
double bytes_wr = 0;
for (final DiskDef disk : disks) {
if (disk.getDeviceType() == DeviceType.CDROM || disk.getDeviceType() == DeviceType.FLOPPY) {
LOGGER.debug("Ignoring disk [{}] in VM [{}]'s stats since its deviceType is [{}].", disk.toString().replace("\n", ""), vmAsString, disk.getDeviceType());
continue;
}
final DomainBlockStats blockStats = dm.blockStats(disk.getDiskLabel());
io_rd += blockStats.rd_req;
io_wr += blockStats.wr_req;
bytes_rd += blockStats.rd_bytes;
bytes_wr += blockStats.wr_bytes;
}
stats.setDiskReadIOs(io_rd);
stats.setDiskWriteIOs(io_wr);
stats.setDiskReadKBs(bytes_rd / 1024);
stats.setDiskWriteKBs(bytes_wr / 1024);
}
/**
* Calculates a VM's metrics for the period between the two statistics given as parameters.
* @param dm domain of the VM.
* @param oldStats old statistics. If null, the CPU, network and disk utilization won't be calculated.
* @param newStats new statistics.
* @return metrics for the period between the two statistics.
* @throws LibvirtException
*/
protected VmStatsEntry calculateVmMetrics(final Domain dm, final LibvirtExtendedVmStatsEntry oldStats, final LibvirtExtendedVmStatsEntry newStats) throws LibvirtException {
final VmStatsEntry metrics = new VmStatsEntry();
final DomainInfo info = dm.getInfo();
final String vmAsString = vmToString(dm);
metrics.setEntityType("vm");
LOGGER.trace("Writing VM [{}]'s CPU and memory information into the metrics.", vmAsString);
metrics.setNumCPUs(info.nrVirtCpu);
metrics.setMemoryKBs(info.maxMem);
metrics.setTargetMemoryKBs(info.memory);
LOGGER.trace("Trying to get free memory for VM [{}].", vmAsString);
metrics.setIntFreeMemoryKBs(getMemoryFreeInKBs(dm));
if (oldStats != null) {
LOGGER.debug("Old stats exist for VM [{}]; therefore, the utilization will be calculated.", vmAsString);
LOGGER.trace("Calculating CPU utilization for VM [{}].", vmAsString);
final Calendar now = Calendar.getInstance();
long elapsedTime = now.getTimeInMillis() - oldStats.getTimestamp().getTimeInMillis();
double utilization = (info.cpuTime - oldStats.getCpuTime()) / ((double) elapsedTime * 1000000 * info.nrVirtCpu);
if (utilization > 0) {
metrics.setCPUUtilization(utilization * 100);
}
LOGGER.trace("Calculating network utilization for VM [{}].", vmAsString);
final double deltarx = newStats.getNetworkReadKBs() - oldStats.getNetworkReadKBs();
if (deltarx > 0) {
metrics.setNetworkReadKBs(deltarx);
}
final double deltatx = newStats.getNetworkWriteKBs() - oldStats.getNetworkWriteKBs();
if (deltatx > 0) {
metrics.setNetworkWriteKBs(deltatx);
}
LOGGER.trace("Calculating disk utilization for VM [{}].", vmAsString);
final double deltaiord = newStats.getDiskReadIOs() - oldStats.getDiskReadIOs();
if (deltaiord > 0) {
metrics.setDiskReadIOs(deltaiord);
}
final double deltaiowr = newStats.getDiskWriteIOs() - oldStats.getDiskWriteIOs();
if (deltaiowr > 0) {
metrics.setDiskWriteIOs(deltaiowr);
}
final double deltabytesrd = newStats.getDiskReadKBs() - oldStats.getDiskReadKBs();
if (deltabytesrd > 0) {
metrics.setDiskReadKBs(deltabytesrd);
}
final double deltabyteswr = newStats.getDiskWriteKBs() - oldStats.getDiskWriteKBs();
if (deltabyteswr > 0) {
metrics.setDiskWriteKBs(deltabyteswr);
}
}
String metricsAsString = new ReflectionToStringBuilder(metrics, ToStringStyle.JSON_STYLE).setExcludeFieldNames("vmId", "vmUuid").toString();
LOGGER.debug("Calculated metrics for VM [{}]: [{}].", vmAsString, metricsAsString);
return metrics;
}
/**
* This method retrieves the memory statistics from the domain given as parameters.
* If no memory statistic is found, it will return {@link NumberUtils#LONG_MINUS_ONE} as the value of free memory in the domain.
@ -4546,10 +4612,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
*/
protected long getMemoryFreeInKBs(Domain dm) throws LibvirtException {
MemoryStatistic[] memoryStats = dm.memoryStats(NUMMEMSTATS);
if(LOGGER.isTraceEnabled()){
LOGGER.trace(String.format("Retrieved memory statistics (information about tags can be found on the libvirt documentation):", ArrayUtils.toString(memoryStats)));
}
LOGGER.trace("Retrieved memory statistics (information about tags can be found on the libvirt documentation): {}.",
() -> Stream.of(memoryStats).map(stat -> stat.toString().trim().replace("\n", ",")).collect(Collectors.joining("},{", "[{", "}]")));
long freeMemory = NumberUtils.LONG_MINUS_ONE;

View File

@ -0,0 +1,51 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.hypervisor.kvm.resource;
import com.cloud.agent.api.VmStatsEntry;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import java.util.Calendar;
public class LibvirtExtendedVmStatsEntry extends VmStatsEntry {
private long cpuTime;
private Calendar timestamp;
public LibvirtExtendedVmStatsEntry() {
}
public long getCpuTime() {
return cpuTime;
}
public void setCpuTime(long cpuTime) {
this.cpuTime = cpuTime;
}
public Calendar getTimestamp() {
return timestamp;
}
public void setTimestamp(Calendar timestamp) {
this.timestamp = timestamp;
}
@Override
public String toString() {
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "cpuTime", "networkWriteKBs", "networkReadKBs", "diskReadIOs", "diskWriteIOs", "diskReadKBs", "diskWriteKBs");
}
}

View File

@ -82,6 +82,7 @@ import org.libvirt.DomainInfo.DomainState;
import org.libvirt.DomainInterfaceStats;
import org.libvirt.LibvirtException;
import org.libvirt.MemoryStatistic;
import org.libvirt.NodeInfo;
import org.libvirt.SchedUlongParameter;
import org.libvirt.StorageVol;
import org.libvirt.VcpuInfo;
@ -93,7 +94,6 @@ import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
@ -243,10 +243,18 @@ public class LibvirtComputingResourceTest {
@Mock
Domain domainMock;
@Mock
DomainInfo domainInfoMock;
@Mock
DomainInterfaceStats domainInterfaceStatsMock;
@Mock
DomainBlockStats domainBlockStatsMock;
private final static long HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IOURING = 6003000;
private final static long HYPERVISOR_QEMU_VERSION_SUPPORTS_IOURING = 5000000;
private final static String VM_NAME = "test";
String hyperVisorType = "kvm";
Random random = new Random();
final String memInfo = "MemTotal: 5830236 kB\n" +
@ -922,86 +930,6 @@ public class LibvirtComputingResourceTest {
assertEquals(uuid, oldUuid);
}
private static final String VMNAME = "test";
@Test
public void testGetVmStat() throws LibvirtException {
final Connect connect = Mockito.mock(Connect.class);
final Domain domain = Mockito.mock(Domain.class);
final DomainInfo domainInfo = new DomainInfo();
final MemoryStatistic[] domainMem = new MemoryStatistic[2];
domainMem[0] = Mockito.mock(MemoryStatistic.class);
Mockito.when(domain.getInfo()).thenReturn(domainInfo);
Mockito.when(domain.memoryStats(20)).thenReturn(domainMem);
Mockito.when(domainMem[0].getTag()).thenReturn(4);
Mockito.when(connect.domainLookupByName(VMNAME)).thenReturn(domain);
// this is testing the interface stats, returns an increasing number of sent and received bytes
Mockito.when(domain.interfaceStats(nullable(String.class))).thenAnswer(new org.mockito.stubbing.Answer<DomainInterfaceStats>() {
// increment with less than a KB, so this should be less than 1 KB
final static int increment = 1000;
int rxBytes = 1000;
int txBytes = 1000;
@Override
public DomainInterfaceStats answer(final InvocationOnMock invocation) throws Throwable {
final DomainInterfaceStats domainInterfaceStats = new DomainInterfaceStats();
domainInterfaceStats.rx_bytes = rxBytes += increment;
domainInterfaceStats.tx_bytes = txBytes += increment;
return domainInterfaceStats;
}
});
Mockito.when(domain.blockStats(nullable(String.class))).thenAnswer(new org.mockito.stubbing.Answer<DomainBlockStats>() {
// a little less than a KB
final static int increment = 1000;
int rdBytes = 0;
int wrBytes = 1024;
@Override
public DomainBlockStats answer(final InvocationOnMock invocation) throws Throwable {
final DomainBlockStats domainBlockStats = new DomainBlockStats();
domainBlockStats.rd_bytes = rdBytes += increment;
domainBlockStats.wr_bytes = wrBytes += increment;
return domainBlockStats;
}
});
final LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource() {
@Override
public List<InterfaceDef> getInterfaces(final Connect conn, final String vmName) {
final InterfaceDef interfaceDef = new InterfaceDef();
return Arrays.asList(interfaceDef);
}
@Override
public List<DiskDef> getDisks(final Connect conn, final String vmName) {
final DiskDef diskDef = new DiskDef();
return Arrays.asList(diskDef);
}
};
libvirtComputingResource.getVmStat(connect, VMNAME);
final VmStatsEntry vmStat = libvirtComputingResource.getVmStat(connect, VMNAME);
// network traffic as generated by the logic above, must be greater than zero
Assert.assertTrue(vmStat.getNetworkReadKBs() > 0);
Assert.assertTrue(vmStat.getNetworkWriteKBs() > 0);
// IO traffic as generated by the logic above, must be greater than zero
Assert.assertTrue(vmStat.getDiskReadKBs() > 0);
Assert.assertTrue(vmStat.getDiskWriteKBs() > 0);
// Memory limit of VM must be greater than zero
Assert.assertTrue(vmStat.getIntFreeMemoryKBs() >= 0);
Assert.assertTrue(vmStat.getMemoryKBs() >= 0);
Assert.assertTrue(vmStat.getTargetMemoryKBs() >= vmStat.getMemoryKBs());
}
/*
* New Tests
*/
@ -6331,4 +6259,160 @@ public class LibvirtComputingResourceTest {
Assert.assertEquals("", StringUtils.join(hostTagsList, ","));
}
}
@Test
public void getVmStatTestVmIsNullReturnsNull() throws LibvirtException {
doReturn(null).when(libvirtComputingResourceSpy).getDomain(connMock, VM_NAME);
VmStatsEntry stat = libvirtComputingResourceSpy.getVmStat(connMock, VM_NAME);
verify(libvirtComputingResourceSpy).getDomain(connMock, VM_NAME);
verify(libvirtComputingResourceSpy, never()).getVmCurrentStats(domainMock);
verify(libvirtComputingResourceSpy, never()).calculateVmMetrics(Mockito.any(), Mockito.any(), Mockito.any());
Assert.assertNull(stat);
}
@Test
public void getVmStatTestVmIsNotNullReturnsMetrics() throws LibvirtException {
doReturn(domainMock).when(libvirtComputingResourceSpy).getDomain(connMock, VM_NAME);
doReturn(Mockito.mock(LibvirtExtendedVmStatsEntry.class)).when(libvirtComputingResourceSpy).getVmCurrentStats(domainMock);
doReturn(Mockito.mock(VmStatsEntry.class)).when(libvirtComputingResourceSpy).calculateVmMetrics(Mockito.any(), Mockito.any(), Mockito.any());
VmStatsEntry stat = libvirtComputingResourceSpy.getVmStat(connMock, VM_NAME);
verify(libvirtComputingResourceSpy).getDomain(connMock, VM_NAME);
verify(libvirtComputingResourceSpy).getVmCurrentStats(domainMock);
verify(libvirtComputingResourceSpy).calculateVmMetrics(Mockito.any(), Mockito.any(), Mockito.any());
Assert.assertNotNull(stat);
}
private void prepareVmInfoForGetVmCurrentStats() throws LibvirtException {
final NodeInfo nodeInfo = new NodeInfo();
nodeInfo.cpus = 8;
nodeInfo.memory = 8 * 1024 * 1024;
nodeInfo.sockets = 2;
nodeInfo.threads = 2;
nodeInfo.model = "Foo processor";
Mockito.when(domainMock.getName()).thenReturn(VM_NAME);
Mockito.when(domainMock.getConnect()).thenReturn(connMock);
domainInfoMock.cpuTime = 500L;
domainInfoMock.nrVirtCpu = 4;
domainInfoMock.memory = 2048;
domainInfoMock.maxMem = 4096;
Mockito.when(domainMock.getInfo()).thenReturn(domainInfoMock);
final MemoryStatistic[] domainMem = new MemoryStatistic[2];
domainMem[0] = Mockito.mock(MemoryStatistic.class);
doReturn(1024L).when(libvirtComputingResourceSpy).getMemoryFreeInKBs(domainMock);
domainInterfaceStatsMock.rx_bytes = 1000L;
domainInterfaceStatsMock.tx_bytes = 2000L;
doReturn(domainInterfaceStatsMock).when(domainMock).interfaceStats(Mockito.any());
doReturn(List.of(new InterfaceDef())).when(libvirtComputingResourceSpy).getInterfaces(connMock, VM_NAME);
domainBlockStatsMock.rd_req = 3000L;
domainBlockStatsMock.rd_bytes = 4000L;
domainBlockStatsMock.wr_req = 5000L;
domainBlockStatsMock.wr_bytes = 6000L;
doReturn(domainBlockStatsMock).when(domainMock).blockStats(Mockito.any());
doReturn(List.of(new DiskDef())).when(libvirtComputingResourceSpy).getDisks(connMock, VM_NAME);
}
@Test
public void getVmCurrentStatsTestIfStatsAreAsExpected() throws LibvirtException {
prepareVmInfoForGetVmCurrentStats();
LibvirtExtendedVmStatsEntry vmStatsEntry = libvirtComputingResourceSpy.getVmCurrentStats(domainMock);
Assert.assertEquals(domainInfoMock.cpuTime, vmStatsEntry.getCpuTime());
Assert.assertEquals((double) domainInterfaceStatsMock.rx_bytes / 1024, vmStatsEntry.getNetworkReadKBs(), 0);
Assert.assertEquals((double) domainInterfaceStatsMock.tx_bytes / 1024, vmStatsEntry.getNetworkWriteKBs(), 0);
Assert.assertEquals(domainBlockStatsMock.rd_req, vmStatsEntry.getDiskReadIOs(), 0);
Assert.assertEquals((double) domainBlockStatsMock.rd_bytes / 1024, vmStatsEntry.getDiskReadKBs(), 0);
Assert.assertEquals(domainBlockStatsMock.wr_req, vmStatsEntry.getDiskWriteIOs(), 0);
Assert.assertEquals((double) domainBlockStatsMock.wr_bytes / 1024, vmStatsEntry.getDiskWriteKBs(), 0);
Assert.assertNotNull(vmStatsEntry.getTimestamp());
}
@Test
public void getVmCurrentCpuStatsTestIfStatsAreAsExpected() throws LibvirtException {
prepareVmInfoForGetVmCurrentStats();
LibvirtExtendedVmStatsEntry vmStatsEntry = new LibvirtExtendedVmStatsEntry();
libvirtComputingResourceSpy.getVmCurrentCpuStats(domainMock, vmStatsEntry);
Assert.assertEquals(domainInfoMock.cpuTime, vmStatsEntry.getCpuTime());
}
@Test
public void getVmCurrentNetworkStatsTestIfStatsAreAsExpected() throws LibvirtException {
prepareVmInfoForGetVmCurrentStats();
LibvirtExtendedVmStatsEntry vmStatsEntry = new LibvirtExtendedVmStatsEntry();
libvirtComputingResourceSpy.getVmCurrentNetworkStats(domainMock, vmStatsEntry);
Assert.assertEquals((double) domainInterfaceStatsMock.rx_bytes / 1024, vmStatsEntry.getNetworkReadKBs(), 0);
Assert.assertEquals((double) domainInterfaceStatsMock.tx_bytes / 1024, vmStatsEntry.getNetworkWriteKBs(), 0);
}
@Test
public void getVmCurrentDiskStatsTestIfStatsAreAsExpected() throws LibvirtException {
prepareVmInfoForGetVmCurrentStats();
LibvirtExtendedVmStatsEntry vmStatsEntry = new LibvirtExtendedVmStatsEntry();
libvirtComputingResourceSpy.getVmCurrentDiskStats(domainMock, vmStatsEntry);
Assert.assertEquals(domainBlockStatsMock.rd_req, vmStatsEntry.getDiskReadIOs(), 0);
Assert.assertEquals((double) domainBlockStatsMock.rd_bytes / 1024, vmStatsEntry.getDiskReadKBs(), 0);
Assert.assertEquals(domainBlockStatsMock.wr_req, vmStatsEntry.getDiskWriteIOs(), 0);
Assert.assertEquals((double) domainBlockStatsMock.wr_bytes / 1024, vmStatsEntry.getDiskWriteKBs(), 0);
}
@Test
public void calculateVmMetricsTestOldStatsIsNullDoesNotCalculateUtilization() throws LibvirtException {
prepareVmInfoForGetVmCurrentStats();
LibvirtExtendedVmStatsEntry vmStatsEntry = libvirtComputingResourceSpy.getVmCurrentStats(domainMock);
VmStatsEntry metrics = libvirtComputingResourceSpy.calculateVmMetrics(domainMock, null, vmStatsEntry);
Assert.assertEquals(domainInfoMock.nrVirtCpu, metrics.getNumCPUs());
Assert.assertEquals(domainInfoMock.maxMem, (long) metrics.getMemoryKBs());
Assert.assertEquals(libvirtComputingResourceSpy.getMemoryFreeInKBs(domainMock), (long) metrics.getIntFreeMemoryKBs());
Assert.assertEquals(domainInfoMock.memory, (long) metrics.getTargetMemoryKBs());
Assert.assertEquals(0, metrics.getCPUUtilization(), 0);
Assert.assertEquals(0, metrics.getNetworkReadKBs(), 0);
Assert.assertEquals(0, metrics.getNetworkWriteKBs(), 0);
Assert.assertEquals(0, metrics.getDiskReadKBs(), 0);
Assert.assertEquals(0, metrics.getDiskReadIOs(), 0);
Assert.assertEquals(0, metrics.getDiskWriteKBs(), 0);
Assert.assertEquals(0, metrics.getDiskWriteIOs(), 0);
}
@Test
public void calculateVmMetricsTestOldStatsIsNotNullCalculatesUtilization() throws LibvirtException {
prepareVmInfoForGetVmCurrentStats();
LibvirtExtendedVmStatsEntry oldStats = libvirtComputingResourceSpy.getVmCurrentStats(domainMock);
domainInfoMock.cpuTime *= 3;
domainInterfaceStatsMock.rx_bytes *= 3;
domainInterfaceStatsMock.tx_bytes *= 3;
domainBlockStatsMock.rd_req *= 3;
domainBlockStatsMock.rd_bytes *= 3;
domainBlockStatsMock.wr_req *= 3;
domainBlockStatsMock.wr_bytes *= 3;
LibvirtExtendedVmStatsEntry newStats = libvirtComputingResourceSpy.getVmCurrentStats(domainMock);
VmStatsEntry metrics = libvirtComputingResourceSpy.calculateVmMetrics(domainMock, oldStats, newStats);
Assert.assertEquals(domainInfoMock.nrVirtCpu, metrics.getNumCPUs());
Assert.assertEquals(domainInfoMock.maxMem, (long) metrics.getMemoryKBs());
Assert.assertEquals(libvirtComputingResourceSpy.getMemoryFreeInKBs(domainMock), (long) metrics.getIntFreeMemoryKBs());
Assert.assertEquals(domainInfoMock.memory, (long) metrics.getTargetMemoryKBs());
Assert.assertTrue(metrics.getCPUUtilization() > 0);
Assert.assertEquals(newStats.getNetworkReadKBs() - oldStats.getNetworkReadKBs(), metrics.getNetworkReadKBs(), 0);
Assert.assertEquals(newStats.getNetworkWriteKBs() - oldStats.getNetworkWriteKBs(), metrics.getNetworkWriteKBs(), 0);
Assert.assertEquals(newStats.getDiskReadIOs() - oldStats.getDiskReadIOs(), metrics.getDiskReadIOs(), 0);
Assert.assertEquals(newStats.getDiskWriteIOs() - oldStats.getDiskWriteIOs(), metrics.getDiskWriteIOs(), 0);
Assert.assertEquals(newStats.getDiskReadKBs() - oldStats.getDiskReadKBs(), metrics.getDiskReadKBs(), 0);
Assert.assertEquals(newStats.getDiskWriteKBs() - oldStats.getDiskWriteKBs(), metrics.getDiskWriteKBs(), 0);
}
}