mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Fix memory stats for KVM (#6358)
Co-authored-by: joseflauzino <jose@scclouds.com.br>
This commit is contained in:
parent
5b09340420
commit
1843632c24
@ -202,6 +202,10 @@ hypervisor.type=kvm
|
||||
# Disable memory ballooning on vm guests for overcommit, by default overcommit
|
||||
# feature enables balloon and sets currentMemory to a minimum value.
|
||||
#
|
||||
# The time interval (in seconds) at which the balloon driver will get memory stats updates.
|
||||
# This is equivalent to Libvirt's --period parameter when using the dommemstat command.
|
||||
# vm.memballoon.stats.period=0
|
||||
#
|
||||
# vm.diskactivity.checkenabled=false
|
||||
# Set to true to check disk activity on VM's disks before starting a VM. This only applies
|
||||
# to QCOW2 files, and ensures that there is no other running instance accessing
|
||||
|
||||
@ -100,7 +100,7 @@ import com.cloud.utils.script.Script;
|
||||
*
|
||||
**/
|
||||
public class Agent implements HandlerFactory, IAgentControl {
|
||||
private static final Logger s_logger = Logger.getLogger(Agent.class.getName());
|
||||
protected static Logger s_logger = Logger.getLogger(Agent.class);
|
||||
|
||||
public enum ExitStatus {
|
||||
Normal(0), // Normal status = 0.
|
||||
@ -303,6 +303,7 @@ public class Agent implements HandlerFactory, IAgentControl {
|
||||
}
|
||||
_shell.updateConnectedHost();
|
||||
scavengeOldAgentObjects();
|
||||
|
||||
}
|
||||
|
||||
public void stop(final String reason, final String detail) {
|
||||
|
||||
@ -54,6 +54,21 @@ public class AgentProperties{
|
||||
*/
|
||||
public static final Property<Boolean> ENABLE_MANUALLY_SETTING_CPU_TOPOLOGY_ON_KVM_VM = new Property<Boolean>("enable.manually.setting.cpu.topology.on.kvm.vm", true);
|
||||
|
||||
/**
|
||||
* Disables memory ballooning on VM guests for overcommit.<br>
|
||||
* By default overcommit feature enables balloon and sets currentMemory to a minimum value.<br>
|
||||
* Data type: Boolean.<br>
|
||||
* Default value: <code>false</code>
|
||||
*/
|
||||
public static final Property<Boolean> VM_MEMBALLOON_DISABLE = new Property<>("vm.memballoon.disable", false);
|
||||
|
||||
/**
|
||||
* The time interval (in seconds) at which the balloon driver will get memory stats updates. This is equivalent to Libvirt's <code>--period</code> parameter when using the dommemstat command.
|
||||
* Data type: Integer.<br>
|
||||
* Default value: <code>0</code>
|
||||
*/
|
||||
public static final Property<Integer> VM_MEMBALLOON_STATS_PERIOD = new Property<>("vm.memballoon.stats.period", 0);
|
||||
|
||||
public static class Property <T>{
|
||||
private final String name;
|
||||
private final T defaultValue;
|
||||
|
||||
@ -147,6 +147,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestResourceDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InputDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.MemBalloonDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef.RngBackendModel;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SCSIDef;
|
||||
@ -221,7 +222,7 @@ import static com.cloud.host.Host.HOST_VOLUME_ENCRYPTION;
|
||||
* pool | the parent of the storage pool hierarchy * }
|
||||
**/
|
||||
public class LibvirtComputingResource extends ServerResourceBase implements ServerResource, VirtualRouterDeployer {
|
||||
private static final Logger s_logger = Logger.getLogger(LibvirtComputingResource.class);
|
||||
protected static Logger s_logger = Logger.getLogger(LibvirtComputingResource.class);
|
||||
|
||||
private static final String CONFIG_VALUES_SEPARATOR = ",";
|
||||
|
||||
@ -448,6 +449,15 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||
|
||||
protected Boolean enableManuallySettingCpuTopologyOnKvmVm = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.ENABLE_MANUALLY_SETTING_CPU_TOPOLOGY_ON_KVM_VM);
|
||||
|
||||
protected LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
|
||||
|
||||
/**
|
||||
* Virsh command to set the memory balloon stats period.<br><br>
|
||||
* 1st parameter: the VM ID or name;<br>
|
||||
* 2nd parameter: the period (in seconds).
|
||||
*/
|
||||
private static final String COMMAND_SET_MEM_BALLOON_STATS_PERIOD = "virsh dommemstat %s --period %s --live";
|
||||
|
||||
protected long getHypervisorLibvirtVersion() {
|
||||
return _hypervisorLibvirtVersion;
|
||||
}
|
||||
@ -1298,9 +1308,84 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||
s_logger.info("iscsi session clean up is disabled");
|
||||
}
|
||||
|
||||
setupMemoryBalloonStatsPeriod(conn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID list of the VMs to set memory balloon stats period.
|
||||
* @param conn the Libvirt connection.
|
||||
* @return the list of VM IDs.
|
||||
*/
|
||||
protected List<Integer> getVmsToSetMemoryBalloonStatsPeriod(Connect conn) {
|
||||
List<Integer> vmIdList = new ArrayList<>();
|
||||
Integer[] vmIds = null;
|
||||
try {
|
||||
vmIds = ArrayUtils.toObject(conn.listDomains());
|
||||
} catch (final LibvirtException e) {
|
||||
s_logger.error("Unable to get the list of Libvirt domains on this host.", e);
|
||||
return vmIdList;
|
||||
}
|
||||
vmIdList.addAll(Arrays.asList(vmIds));
|
||||
s_logger.debug(String.format("We have found a total of [%s] VMs (Libvirt domains) on this host: [%s].", vmIdList.size(), vmIdList.toString()));
|
||||
|
||||
if (vmIdList.isEmpty()) {
|
||||
s_logger.info("Skipping the memory balloon stats period setting, since there are no VMs (active Libvirt domains) on this host.");
|
||||
}
|
||||
return vmIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current VM balloon stats period from the agent.properties file.
|
||||
* @return the current VM balloon stats period.
|
||||
*/
|
||||
protected Integer getCurrentVmBalloonStatsPeriod() {
|
||||
if (Boolean.TRUE.equals(AgentPropertiesFileHandler.getPropertyValue(AgentProperties.VM_MEMBALLOON_DISABLE))) {
|
||||
s_logger.info(String.format("The [%s] property is set to 'true', so the memory balloon stats period will be set to 0 for all VMs.",
|
||||
AgentProperties.VM_MEMBALLOON_DISABLE.getName()));
|
||||
return 0;
|
||||
}
|
||||
Integer vmBalloonStatsPeriod = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.VM_MEMBALLOON_STATS_PERIOD);
|
||||
if (vmBalloonStatsPeriod == 0) {
|
||||
s_logger.info(String.format("The [%s] property is set to '0', this prevents memory statistics from being displayed correctly. "
|
||||
+ "Adjust (increase) the value of this parameter to correct this.", AgentProperties.VM_MEMBALLOON_STATS_PERIOD.getName()));
|
||||
}
|
||||
return vmBalloonStatsPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the balloon driver of each VM to get the memory stats at the time interval defined in the agent.properties file.
|
||||
* @param conn the Libvirt connection.
|
||||
*/
|
||||
protected void setupMemoryBalloonStatsPeriod(Connect conn) {
|
||||
List<Integer> vmIdList = getVmsToSetMemoryBalloonStatsPeriod(conn);
|
||||
Integer currentVmBalloonStatsPeriod = getCurrentVmBalloonStatsPeriod();
|
||||
for (Integer vmId : vmIdList) {
|
||||
Domain dm = null;
|
||||
try {
|
||||
dm = conn.domainLookupByID(vmId);
|
||||
parser.parseDomainXML(dm.getXMLDesc(0));
|
||||
MemBalloonDef memBalloon = parser.getMemBalloon();
|
||||
if (!MemBalloonDef.MemBalloonModel.VIRTIO.equals(memBalloon.getMemBalloonModel())) {
|
||||
s_logger.debug(String.format("Skipping the memory balloon stats period setting for the VM (Libvirt Domain) with ID [%s] and name [%s] because this VM has no memory"
|
||||
+ " balloon.", vmId, dm.getName()));
|
||||
}
|
||||
String setMemBalloonStatsPeriodCommand = String.format(COMMAND_SET_MEM_BALLOON_STATS_PERIOD, vmId, currentVmBalloonStatsPeriod);
|
||||
String setMemBalloonStatsPeriodResult = Script.runSimpleBashScript(setMemBalloonStatsPeriodCommand);
|
||||
if (StringUtils.isNotBlank(setMemBalloonStatsPeriodResult)) {
|
||||
s_logger.error(String.format("Unable to set up memory balloon stats period for VM (Libvirt Domain) with ID [%s] due to an error when running the [%s] "
|
||||
+ "command. Output: [%s].", vmId, setMemBalloonStatsPeriodCommand, setMemBalloonStatsPeriodResult));
|
||||
continue;
|
||||
}
|
||||
s_logger.debug(String.format("The memory balloon stats period [%s] has been set successfully for the VM (Libvirt Domain) with ID [%s] and name [%s].",
|
||||
currentVmBalloonStatsPeriod, vmId, dm.getName()));
|
||||
} catch (final LibvirtException e) {
|
||||
s_logger.warn("Failed to set up memory balloon stats period." + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void enableSSLForKvmAgent(final Map<String, Object> params) {
|
||||
final File keyStoreFile = PropertiesUtil.findConfigFile(KeyStoreUtils.KS_FILENAME);
|
||||
if (keyStoreFile == null) {
|
||||
|
||||
@ -41,6 +41,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.NicModel;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.MemBalloonDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef.RngBackendModel;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef;
|
||||
@ -50,6 +51,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogModel;
|
||||
public class LibvirtDomainXMLParser {
|
||||
private static final Logger s_logger = Logger.getLogger(LibvirtDomainXMLParser.class);
|
||||
private final List<InterfaceDef> interfaces = new ArrayList<InterfaceDef>();
|
||||
private MemBalloonDef memBalloonDef = new MemBalloonDef();
|
||||
private final List<DiskDef> diskDefs = new ArrayList<DiskDef>();
|
||||
private final List<RngDef> rngDefs = new ArrayList<RngDef>();
|
||||
private final List<ChannelDef> channels = new ArrayList<ChannelDef>();
|
||||
@ -206,6 +208,8 @@ public class LibvirtDomainXMLParser {
|
||||
diskDefs.add(def);
|
||||
}
|
||||
|
||||
memBalloonDef = parseMemBalloonTag(devices);
|
||||
|
||||
NodeList nics = devices.getElementsByTagName("interface");
|
||||
for (int i = 0; i < nics.getLength(); i++) {
|
||||
Element nic = (Element)nics.item(i);
|
||||
@ -342,6 +346,25 @@ public class LibvirtDomainXMLParser {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the memballoon tag.
|
||||
* @param devices the devices tag.
|
||||
* @return the MemBalloonDef.
|
||||
*/
|
||||
private MemBalloonDef parseMemBalloonTag(Element devices) {
|
||||
MemBalloonDef def = new MemBalloonDef();
|
||||
NodeList memBalloons = devices.getElementsByTagName("memballoon");
|
||||
if (memBalloons != null && memBalloons.getLength() != 0) {
|
||||
Element memBalloon = (Element)memBalloons.item(0);
|
||||
String model = memBalloon.getAttribute("model");
|
||||
if (model.equalsIgnoreCase("virtio")) {
|
||||
String statsPeriod = getAttrValue("stats", "period", memBalloon);
|
||||
def.defVirtioMemBalloon(statsPeriod);
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
private static String getTagValue(String tag, Element eElement) {
|
||||
NodeList tagNodeList = eElement.getElementsByTagName(tag);
|
||||
if (tagNodeList == null || tagNodeList.getLength() == 0) {
|
||||
@ -372,6 +395,10 @@ public class LibvirtDomainXMLParser {
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
public MemBalloonDef getMemBalloon() {
|
||||
return memBalloonDef;
|
||||
}
|
||||
|
||||
public List<DiskDef> getDisks() {
|
||||
return diskDefs;
|
||||
}
|
||||
|
||||
@ -27,6 +27,9 @@ import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.agent.properties.AgentProperties;
|
||||
import com.cloud.agent.properties.AgentPropertiesFileHandler;
|
||||
|
||||
public class LibvirtVMDef {
|
||||
private static final Logger s_logger = Logger.getLogger(LibvirtVMDef.class);
|
||||
|
||||
@ -236,6 +239,7 @@ public class LibvirtVMDef {
|
||||
private int vcpu = -1;
|
||||
private int maxVcpu = -1;
|
||||
private boolean memoryBalloning = false;
|
||||
private int memoryBalloonStatsPeriod = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.VM_MEMBALLOON_STATS_PERIOD);
|
||||
|
||||
public void setMemorySize(long mem) {
|
||||
this.memory = mem;
|
||||
@ -276,7 +280,14 @@ public class LibvirtVMDef {
|
||||
response.append(String.format("<cpu> <numa> <cell id='0' cpus='0-%s' memory='%s' unit='KiB'/> </numa> </cpu>\n", this.maxVcpu - 1, this.currentMemory));
|
||||
}
|
||||
|
||||
response.append(String.format("<devices>\n<memballoon model='%s'/>\n</devices>\n", this.memoryBalloning ? "virtio" : "none"));
|
||||
MemBalloonDef memBalloonDef = new MemBalloonDef();
|
||||
if (this.memoryBalloning) {
|
||||
memBalloonDef.defVirtioMemBalloon(String.valueOf(memoryBalloonStatsPeriod));
|
||||
} else {
|
||||
memBalloonDef.defNoneMemBalloon();
|
||||
}
|
||||
response.append(String.format("<devices>%n%s%n</devices>%n", memBalloonDef.toString()));
|
||||
|
||||
response.append(String.format("<vcpu current=\"%s\">%s</vcpu>\n", this.vcpu, this.maxVcpu));
|
||||
return response.toString();
|
||||
}
|
||||
@ -1172,6 +1183,53 @@ public class LibvirtVMDef {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MemBalloonDef {
|
||||
private MemBalloonModel memBalloonModel;
|
||||
private String memBalloonStatsPeriod;
|
||||
|
||||
public enum MemBalloonModel {
|
||||
NONE("none"), VIRTIO("virtio");
|
||||
String model;
|
||||
|
||||
MemBalloonModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
public void defNoneMemBalloon() {
|
||||
memBalloonModel = MemBalloonModel.NONE;
|
||||
}
|
||||
|
||||
public void defVirtioMemBalloon(String period) {
|
||||
memBalloonModel = MemBalloonModel.VIRTIO;
|
||||
memBalloonStatsPeriod = period;
|
||||
}
|
||||
|
||||
public MemBalloonModel getMemBalloonModel() {
|
||||
return memBalloonModel;
|
||||
}
|
||||
|
||||
public String getMemBalloonStatsPeriod() {
|
||||
return memBalloonStatsPeriod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder memBalloonBuilder = new StringBuilder();
|
||||
memBalloonBuilder.append("<memballoon model='" + memBalloonModel + "'>\n");
|
||||
if (StringUtils.isNotBlank(memBalloonStatsPeriod)) {
|
||||
memBalloonBuilder.append("<stats period='" + memBalloonStatsPeriod +"'/>\n");
|
||||
}
|
||||
memBalloonBuilder.append("</memballoon>");
|
||||
return memBalloonBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class InterfaceDef {
|
||||
public enum GuestNetType {
|
||||
BRIDGE("bridge"), DIRECT("direct"), NETWORK("network"), USER("user"), ETHERNET("ethernet"), INTERNAL("internal"), VHOSTUSER("vhostuser");
|
||||
|
||||
@ -61,8 +61,10 @@ import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
|
||||
import org.apache.cloudstack.utils.linux.CPUStat;
|
||||
import org.apache.cloudstack.utils.linux.MemStat;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.SystemUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
@ -164,6 +166,8 @@ import com.cloud.agent.api.to.NicTO;
|
||||
import com.cloud.agent.api.to.StorageFilerTO;
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.agent.properties.AgentProperties;
|
||||
import com.cloud.agent.properties.AgentPropertiesFileHandler;
|
||||
import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource;
|
||||
import com.cloud.exception.InternalErrorException;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
@ -181,6 +185,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestDef.GuestType;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestResourceDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InputDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.MemBalloonDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SCSIDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SerialDef;
|
||||
@ -213,7 +218,7 @@ import com.cloud.vm.VirtualMachine.PowerState;
|
||||
import com.cloud.vm.VirtualMachine.Type;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest(value = {MemStat.class, SshHelper.class})
|
||||
@PrepareForTest(value = {MemStat.class, SshHelper.class, AgentPropertiesFileHandler.class, AgentProperties.class, Script.class})
|
||||
@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*"})
|
||||
public class LibvirtComputingResourceTest {
|
||||
|
||||
@ -223,6 +228,13 @@ public class LibvirtComputingResourceTest {
|
||||
VirtualMachineTO vmTO;
|
||||
@Mock
|
||||
LibvirtVMDef vmDef;
|
||||
@Mock
|
||||
Logger loggerMock;
|
||||
@Mock
|
||||
Connect connMock;
|
||||
@Mock
|
||||
LibvirtDomainXMLParser parserMock;
|
||||
|
||||
@Spy
|
||||
private LibvirtComputingResource libvirtComputingResourceSpy = Mockito.spy(LibvirtComputingResource.class);
|
||||
|
||||
@ -245,8 +257,10 @@ public class LibvirtComputingResourceTest {
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
libvirtComputingResourceSpy._qemuSocketsPath = new File("/var/run/qemu");
|
||||
libvirtComputingResourceSpy.parser = parserMock;
|
||||
Scanner scanner = new Scanner(memInfo);
|
||||
PowerMockito.whenNew(Scanner.class).withAnyArguments().thenReturn(scanner);
|
||||
LibvirtComputingResource.s_logger = loggerMock;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5928,4 +5942,142 @@ public class LibvirtComputingResourceTest {
|
||||
configLocalStorageTests(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVmsToSetMemoryBalloonStatsPeriodTestLibvirtError() throws LibvirtException {
|
||||
Mockito.when(connMock.listDomains()).thenThrow(LibvirtException.class);
|
||||
|
||||
List<Integer> result = libvirtComputingResourceSpy.getVmsToSetMemoryBalloonStatsPeriod(connMock);
|
||||
|
||||
Mockito.verify(loggerMock).error(Mockito.anyString(), Mockito.any());
|
||||
Assert.assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVmsToSetMemoryBalloonStatsPeriodTestWithNoVMs() throws LibvirtException {
|
||||
Mockito.when(connMock.listDomains()).thenReturn(new int[0]);
|
||||
|
||||
List<Integer> result = libvirtComputingResourceSpy.getVmsToSetMemoryBalloonStatsPeriod(connMock);
|
||||
|
||||
Mockito.verify(loggerMock).info("Skipping the memory balloon stats period setting, since there are no VMs (active Libvirt domains) on this host.");
|
||||
Assert.assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVmsToSetMemoryBalloonStatsPeriodTestWhenSuccessfullyGetVmIds() throws LibvirtException {
|
||||
int[] fakeList = new int[]{1};
|
||||
List<Integer> expected = Arrays.asList(ArrayUtils.toObject(fakeList));
|
||||
Mockito.when(connMock.listDomains()).thenReturn(fakeList);
|
||||
|
||||
List<Integer> result = libvirtComputingResourceSpy.getVmsToSetMemoryBalloonStatsPeriod(connMock);
|
||||
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentVmBalloonStatsPeriodTestWhenMemBalloonIsDisabled() {
|
||||
Integer expected = 0;
|
||||
PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
|
||||
PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.eq(AgentProperties.VM_MEMBALLOON_DISABLE))).thenReturn(true);
|
||||
|
||||
Integer result = libvirtComputingResourceSpy.getCurrentVmBalloonStatsPeriod();
|
||||
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentVmBalloonStatsPeriodTestWhenStatsPeriodIsZero() {
|
||||
Integer expected = 0;
|
||||
PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
|
||||
PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.eq(AgentProperties.VM_MEMBALLOON_DISABLE))).thenReturn(false);
|
||||
PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.eq(AgentProperties.VM_MEMBALLOON_STATS_PERIOD))).thenReturn(0);
|
||||
|
||||
Integer result = libvirtComputingResourceSpy.getCurrentVmBalloonStatsPeriod();
|
||||
|
||||
Mockito.verify(loggerMock).info(String.format("The [%s] property is set to '0', this prevents memory statistics from being displayed correctly. "
|
||||
+ "Adjust (increase) the value of this parameter to correct this.", AgentProperties.VM_MEMBALLOON_STATS_PERIOD.getName()));
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentVmBalloonStatsPeriodTestSuccess() {
|
||||
Integer expected = 60;
|
||||
PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
|
||||
PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.eq(AgentProperties.VM_MEMBALLOON_DISABLE))).thenReturn(false);
|
||||
PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.eq(AgentProperties.VM_MEMBALLOON_STATS_PERIOD))).thenReturn(60);
|
||||
|
||||
Integer result = libvirtComputingResourceSpy.getCurrentVmBalloonStatsPeriod();
|
||||
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
|
||||
private void prepareMocksToSetupMemoryBalloonStatsPeriod(Integer currentVmBalloonStatsPeriod) throws LibvirtException {
|
||||
Integer[] fakeList = ArrayUtils.toObject(new int[]{1});
|
||||
Mockito.doReturn(Arrays.asList(fakeList)).when(libvirtComputingResourceSpy).getVmsToSetMemoryBalloonStatsPeriod(connMock);
|
||||
Mockito.doReturn(currentVmBalloonStatsPeriod).when(libvirtComputingResourceSpy).getCurrentVmBalloonStatsPeriod();
|
||||
Mockito.when(domainMock.getXMLDesc(Mockito.anyInt())).thenReturn("");
|
||||
Mockito.when(domainMock.getName()).thenReturn("fake-VM-name");
|
||||
Mockito.when(connMock.domainLookupByID(1)).thenReturn(domainMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setupMemoryBalloonStatsPeriodTestMemBalloonPropertyDisabled() throws LibvirtException {
|
||||
prepareMocksToSetupMemoryBalloonStatsPeriod(0);
|
||||
MemBalloonDef memBalloonDef = new MemBalloonDef();
|
||||
memBalloonDef.defVirtioMemBalloon("60");
|
||||
Mockito.when(parserMock.parseDomainXML(Mockito.anyString())).thenReturn(true);
|
||||
Mockito.when(parserMock.getMemBalloon()).thenReturn(memBalloonDef);
|
||||
PowerMockito.mockStatic(Script.class);
|
||||
PowerMockito.when(Script.runSimpleBashScript(Mockito.any())).thenReturn(null);
|
||||
|
||||
libvirtComputingResourceSpy.setupMemoryBalloonStatsPeriod(connMock);
|
||||
|
||||
Mockito.verify(loggerMock).debug("The memory balloon stats period [0] has been set successfully for the VM (Libvirt Domain) with ID [1] and name [fake-VM-name].");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setupMemoryBalloonStatsPeriodTestErrorWhenSetNewPeriod() throws LibvirtException {
|
||||
prepareMocksToSetupMemoryBalloonStatsPeriod(60);
|
||||
MemBalloonDef memBalloonDef = new MemBalloonDef();
|
||||
memBalloonDef.defVirtioMemBalloon("0");
|
||||
Mockito.when(parserMock.parseDomainXML(Mockito.anyString())).thenReturn(true);
|
||||
Mockito.when(parserMock.getMemBalloon()).thenReturn(memBalloonDef);
|
||||
PowerMockito.mockStatic(Script.class);
|
||||
PowerMockito.when(Script.runSimpleBashScript(Mockito.eq("virsh dommemstat 1 --period 60 --live"))).thenReturn("some-fake-error");
|
||||
|
||||
libvirtComputingResourceSpy.setupMemoryBalloonStatsPeriod(connMock);
|
||||
|
||||
Mockito.verify(loggerMock).error("Unable to set up memory balloon stats period for VM (Libvirt Domain) with ID [1] due to an error when running the [virsh "
|
||||
+ "dommemstat 1 --period 60 --live] command. Output: [some-fake-error].");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setupMemoryBalloonStatsPeriodTestSetNewPeriodSuccessfully() throws LibvirtException {
|
||||
prepareMocksToSetupMemoryBalloonStatsPeriod(60);
|
||||
MemBalloonDef memBalloonDef = new MemBalloonDef();
|
||||
memBalloonDef.defVirtioMemBalloon("0");
|
||||
Mockito.when(parserMock.parseDomainXML(Mockito.anyString())).thenReturn(true);
|
||||
Mockito.when(parserMock.getMemBalloon()).thenReturn(memBalloonDef);
|
||||
PowerMockito.mockStatic(Script.class);
|
||||
PowerMockito.when(Script.runSimpleBashScript(Mockito.eq("virsh dommemstat 1 --period 60 --live"))).thenReturn(null);
|
||||
|
||||
libvirtComputingResourceSpy.setupMemoryBalloonStatsPeriod(connMock);
|
||||
|
||||
PowerMockito.verifyStatic(Script.class);
|
||||
Script.runSimpleBashScript("virsh dommemstat 1 --period 60 --live");
|
||||
Mockito.verify(loggerMock, Mockito.never()).error(Mockito.anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setupMemoryBalloonStatsPeriodTestSkipVm() throws LibvirtException {
|
||||
prepareMocksToSetupMemoryBalloonStatsPeriod(60);
|
||||
MemBalloonDef memBalloonDef = new MemBalloonDef();
|
||||
memBalloonDef.defNoneMemBalloon();
|
||||
Mockito.when(parserMock.parseDomainXML(Mockito.anyString())).thenReturn(true);
|
||||
Mockito.when(parserMock.getMemBalloon()).thenReturn(memBalloonDef);
|
||||
|
||||
libvirtComputingResourceSpy.setupMemoryBalloonStatsPeriod(connMock);
|
||||
|
||||
Mockito.verify(loggerMock).debug("Skipping the memory balloon stats period setting for the VM (Libvirt Domain) with ID [1] and name [fake-VM-name] because this"
|
||||
+ " VM has no memory balloon.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ import java.util.List;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.MemBalloonDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef;
|
||||
|
||||
@ -180,6 +181,7 @@ public class LibvirtDomainXMLParserTest extends TestCase {
|
||||
"<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>" +
|
||||
"</video>" +
|
||||
"<memballoon model='virtio'>" +
|
||||
"<stats period='60'/>" +
|
||||
"<alias name='balloon0'/>" +
|
||||
"<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>" +
|
||||
"</memballoon>" +
|
||||
@ -238,6 +240,10 @@ public class LibvirtDomainXMLParserTest extends TestCase {
|
||||
assertEquals("vnet" + i, ifs.get(i).getDevName());
|
||||
}
|
||||
|
||||
MemBalloonDef memBalloon = parser.getMemBalloon();
|
||||
assertEquals(MemBalloonDef.MemBalloonModel.VIRTIO, memBalloon.getMemBalloonModel());
|
||||
assertEquals("60", memBalloon.getMemBalloonStatsPeriod());
|
||||
|
||||
List<RngDef> rngs = parser.getRngs();
|
||||
assertEquals("/dev/random", rngs.get(0).getPath());
|
||||
assertEquals(RngDef.RngBackendModel.RANDOM, rngs.get(0).getRngBackendModel());
|
||||
|
||||
@ -29,6 +29,7 @@ import junit.framework.TestCase;
|
||||
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.MemBalloonDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SCSIDef;
|
||||
import org.apache.cloudstack.utils.linux.MemStat;
|
||||
import org.apache.cloudstack.utils.qemu.QemuObject;
|
||||
@ -358,6 +359,28 @@ public class LibvirtVMDefTest extends TestCase {
|
||||
assertEquals(xmlDef, expectedXml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void memBalloonDefTestNone() {
|
||||
String expectedXml = "<memballoon model='none'>\n</memballoon>";
|
||||
MemBalloonDef memBalloonDef = new MemBalloonDef();
|
||||
memBalloonDef.defNoneMemBalloon();
|
||||
|
||||
String xmlDef = memBalloonDef.toString();
|
||||
|
||||
assertEquals(xmlDef, expectedXml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void memBalloonDefTestVirtio() {
|
||||
String expectedXml = "<memballoon model='virtio'>\n<stats period='60'/>\n</memballoon>";
|
||||
MemBalloonDef memBalloonDef = new MemBalloonDef();
|
||||
memBalloonDef.defVirtioMemBalloon("60");
|
||||
|
||||
String xmlDef = memBalloonDef.toString();
|
||||
|
||||
assertEquals(xmlDef, expectedXml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHypervEnlightDef() {
|
||||
LibvirtVMDef.FeaturesDef featuresDef = new LibvirtVMDef.FeaturesDef();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user