diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index c7a176e6c1b..164fabce17a 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -77,6 +77,9 @@ import org.libvirt.DomainSnapshot; import org.libvirt.LibvirtException; import org.libvirt.MemoryStatistic; import org.libvirt.Network; +import org.libvirt.SchedParameter; +import org.libvirt.SchedUlongParameter; +import org.libvirt.VcpuInfo; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -186,7 +189,6 @@ import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VmDetailConstants; import org.apache.commons.lang3.StringUtils; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; -import org.libvirt.VcpuInfo; /** * LibvirtComputingResource execute requests on the computing/routing host using @@ -4621,4 +4623,35 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv VcpuInfo vcpus[] = dm.getVcpusInfo(); return Arrays.stream(vcpus).filter(vcpu -> vcpu.state.equals(VcpuInfo.VcpuState.VIR_VCPU_RUNNING)).count(); } + + /** + * Retrieves the cpu_shares (priority) of the running VM
+ * @param dm domain of the VM. + * @return the value of cpu_shares of the running VM. + * @throws org.libvirt.LibvirtException + **/ + public static Integer getCpuShares(Domain dm) throws LibvirtException { + for (SchedParameter c : dm.getSchedulerParameters()) { + if (c.field.equals("cpu_shares")) { + return Integer.parseInt(c.getValueAsString()); + } + } + s_logger.warn(String.format("Could not get cpu_shares of domain: [%s]. Returning default value of 0. ", dm.getName())); + return 0; + } + + /** + * Sets the cpu_shares (priority) of the running VM
+ * @param dm domain of the VM. + * @param cpuShares new priority of the running VM. + * @throws org.libvirt.LibvirtException + **/ + public static void setCpuShares(Domain dm, Integer cpuShares) throws LibvirtException { + SchedUlongParameter[] params = new SchedUlongParameter[1]; + params[0] = new SchedUlongParameter(); + params[0].field = "cpu_shares"; + params[0].value = cpuShares; + + dm.setSchedulerParameters(params); + } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java index 384d5cc8b15..96c3e844abf 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapper.java @@ -39,8 +39,10 @@ public class LibvirtScaleVmCommandWrapper extends CommandWrapper { + if (schedParameters == null || schedParameters.length > 1 || !(schedParameters[0] instanceof SchedUlongParameter)) { + return false; + } + SchedUlongParameter param = (SchedUlongParameter) schedParameters[0]; + if (param.field != "cpu_shares" || param.value != 2000) { + return false; + } + return true; + })); + } } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java index a0851e747f1..6079a70ddd1 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtScaleVmCommandWrapperTest.java @@ -78,7 +78,8 @@ public class LibvirtScaleVmCommandWrapperTest extends TestCase { long memory = ByteScaleUtils.bytesToKib(vmTo.getMaxRam()); int vcpus = vmTo.getCpus(); - scalingDetails = String.format("%s memory to [%s KiB] and CPU cores to [%s]", vmTo.toString(), memory, vcpus); + int cpuShares = vcpus * vmTo.getSpeed(); + scalingDetails = String.format("%s memory to [%s KiB], CPU cores to [%s] and cpu_shares to [%s]", vmTo.toString(), memory, vcpus, cpuShares); PowerMockito.mockStatic(LibvirtComputingResource.class); } @@ -241,4 +242,40 @@ public class LibvirtScaleVmCommandWrapperTest extends TestCase { libvirtScaleVmCommandWrapperSpy.execute(scaleVmCommandMock, libvirtComputingResourceMock); } + + @Test + public void updateCpuSharesTestOldSharesLessThanNewSharesUpdateShares() throws LibvirtException { + int oldShares = 2000; + int newShares = 3000; + + PowerMockito.when(LibvirtComputingResource.getCpuShares(Mockito.any())).thenReturn(oldShares); + libvirtScaleVmCommandWrapperSpy.updateCpuShares(domainMock, newShares); + + PowerMockito.verifyStatic(LibvirtComputingResource.class, Mockito.times(1)); + libvirtComputingResourceMock.setCpuShares(domainMock, newShares); + } + + @Test + public void updateCpuSharesTestOldSharesHigherThanNewSharesDoNothing() throws LibvirtException { + int oldShares = 3000; + int newShares = 2000; + + PowerMockito.when(LibvirtComputingResource.getCpuShares(Mockito.any())).thenReturn(oldShares); + libvirtScaleVmCommandWrapperSpy.updateCpuShares(domainMock, newShares); + + PowerMockito.verifyStatic(LibvirtComputingResource.class, Mockito.times(0)); + libvirtComputingResourceMock.setCpuShares(domainMock, newShares); + } + + @Test + public void updateCpuSharesTestOldSharesEqualsNewSharesDoNothing() throws LibvirtException { + int oldShares = 2000; + int newShares = 2000; + + PowerMockito.when(LibvirtComputingResource.getCpuShares(Mockito.any())).thenReturn(oldShares); + libvirtScaleVmCommandWrapperSpy.updateCpuShares(domainMock, newShares); + + PowerMockito.verifyStatic(LibvirtComputingResource.class, Mockito.times(0)); + libvirtComputingResourceMock.setCpuShares(domainMock, newShares); + } }