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