This is an automated email from the ASF dual-hosted git repository. gutoveronezi pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push: new a31449b1049 Allow altering only either CPU or memory during VM live scale (#8234) a31449b1049 is described below commit a31449b10490cb386d60fc961f6d3bf3bdb09ccd Author: GaOrtiga <49285692+gaort...@users.noreply.github.com> AuthorDate: Wed Feb 14 18:57:47 2024 -0300 Allow altering only either CPU or memory during VM live scale (#8234) * allow change only one parameter during live scale * Update server/src/main/java/com/cloud/vm/UserVmManagerImpl.java Co-authored-by: sato03 <henriquesato2...@gmail.com> * apply change method name * Update server/src/main/java/com/cloud/vm/UserVmManagerImpl.java Co-authored-by: João Jandre <48719461+joaojan...@users.noreply.github.com> --------- Co-authored-by: Gabriel <gabriel.fernan...@scclouds.com.br> Co-authored-by: sato03 <henriquesato2...@gmail.com> Co-authored-by: João Jandre <48719461+joaojan...@users.noreply.github.com> --- .../main/java/com/cloud/vm/UserVmManagerImpl.java | 41 +++++++++++- .../java/com/cloud/vm/UserVmManagerImplTest.java | 76 ++++++++++++++++++++++ 2 files changed, 115 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 063ed09c839..99b334a9f74 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -399,7 +399,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir @Inject private VMTemplateZoneDao _templateZoneDao; @Inject - private TemplateDataStoreDao _templateStoreDao; + protected TemplateDataStoreDao _templateStoreDao; @Inject private DomainDao _domainDao; @Inject @@ -1226,6 +1226,39 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir return userVm; } + /** + Updates the instance details map with the current values of the instance for the CPU speed, memory, and CPU number if they have not been specified. + @param details Map containing the instance details. + @param vmInstance The virtual machine instance. + @param newServiceOfferingId The ID of the new service offering. + */ + + protected void updateInstanceDetails (Map<String, String> details, VirtualMachine vmInstance, Long newServiceOfferingId) { + ServiceOfferingVO currentServiceOffering = serviceOfferingDao.findByIdIncludingRemoved(vmInstance.getId(), vmInstance.getServiceOfferingId()); + ServiceOfferingVO newServiceOffering = serviceOfferingDao.findById(newServiceOfferingId); + updateInstanceDetailsKeepCurrentValueIfNull(newServiceOffering.getSpeed(), details, VmDetailConstants.CPU_SPEED, currentServiceOffering.getSpeed()); + updateInstanceDetailsKeepCurrentValueIfNull(newServiceOffering.getRamSize(), details, VmDetailConstants.MEMORY, currentServiceOffering.getRamSize()); + updateInstanceDetailsKeepCurrentValueIfNull(newServiceOffering.getCpu(), details, VmDetailConstants.CPU_NUMBER, currentServiceOffering.getCpu()); + } + + /** + * Updates a specific instance detail with the current instance value if the new value is null. + * + * @param newValue the new value to be set + * @param details a map of instance details + * @param detailsConstant the name of the detail constant to be updated + * @param currentValue the current value of the detail constant + */ + + protected void updateInstanceDetailsKeepCurrentValueIfNull(Integer newValue, Map<String, String> details, String detailsConstant, Integer currentValue) { + if (newValue == null && details.get(detailsConstant) == null) { + String currentValueString = String.valueOf(currentValue); + logger.debug("{} was not specified, keeping the current value: {}.", detailsConstant, currentValueString); + details.put(detailsConstant, currentValueString); + } + } + + private void validateOfferingMaxResource(ServiceOfferingVO offering) { Integer maxCPUCores = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES.value() == 0 ? Integer.MAX_VALUE: ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES.value(); if (offering.getCpu() > maxCPUCores) { @@ -1891,7 +1924,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } CallContext.current().setEventDetails("Vm Id: " + vm.getUuid()); - boolean result = upgradeVirtualMachine(vmId, newServiceOfferingId, cmd.getDetails()); + Map<String, String> cmdDetails = cmd.getDetails(); + + updateInstanceDetails(cmdDetails, vm, newServiceOfferingId); + + boolean result = upgradeVirtualMachine(vmId, newServiceOfferingId, cmdDetails); if (result) { UserVmVO vmInstance = _vmDao.findById(vmId); if (vmInstance.getState().equals(State.Stopped)) { diff --git a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java index 13b937789f2..ffd0c407f13 100644 --- a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java +++ b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java @@ -267,6 +267,9 @@ public class UserVmManagerImplTest { @Mock ServiceOfferingJoinDao serviceOfferingJoinDao; + @Mock + private VMInstanceVO vmInstanceMock; + private static final long vmId = 1l; private static final long zoneId = 2L; private static final long accountId = 3L; @@ -277,6 +280,8 @@ public class UserVmManagerImplTest { private Map<String, String> customParameters = new HashMap<>(); + String[] detailsConstants = {VmDetailConstants.MEMORY, VmDetailConstants.CPU_NUMBER, VmDetailConstants.CPU_SPEED}; + private DiskOfferingVO smallerDisdkOffering = prepareDiskOffering(5l * GiB_TO_BYTES, 1l, 1L, 2L); private DiskOfferingVO largerDisdkOffering = prepareDiskOffering(10l * GiB_TO_BYTES, 2l, 10L, 20L); @@ -293,6 +298,10 @@ public class UserVmManagerImplTest { CallContext.register(callerUser, callerAccount); customParameters.put(VmDetailConstants.ROOT_DISK_SIZE, "123"); + customParameters.put(VmDetailConstants.MEMORY, "2048"); + customParameters.put(VmDetailConstants.CPU_NUMBER, "4"); + customParameters.put(VmDetailConstants.CPU_SPEED, "1000"); + lenient().doNothing().when(resourceLimitMgr).incrementResourceCount(anyLong(), any(Resource.ResourceType.class)); lenient().doNothing().when(resourceLimitMgr).decrementResourceCount(anyLong(), any(Resource.ResourceType.class), anyLong()); @@ -1443,4 +1452,71 @@ public class UserVmManagerImplTest { userVmManagerImpl.restoreVirtualMachine(accountMock, vmId, newTemplateId); } + + @Test + public void updateInstanceDetailsKeepCurrentValueIfNullTestDetailsConstantIsNotNullDoNothing() { + int currentValue = 123; + + for (String detailsConstant : detailsConstants) { + userVmManagerImpl.updateInstanceDetailsKeepCurrentValueIfNull(null, customParameters, detailsConstant, currentValue); + } + + Assert.assertEquals(customParameters.get(VmDetailConstants.MEMORY), "2048"); + Assert.assertEquals(customParameters.get(VmDetailConstants.CPU_NUMBER), "4"); + Assert.assertEquals(customParameters.get(VmDetailConstants.CPU_SPEED), "1000"); + } + + @Test + public void updateInstanceDetailsKeepCurrentValueIfNullTestNewValueIsNotNullDoNothing() { + Map<String, String> details = new HashMap<>(); + int currentValue = 123; + + for (String detailsConstant : detailsConstants) { + userVmManagerImpl.updateInstanceDetailsKeepCurrentValueIfNull(321, details, detailsConstant, currentValue); + } + + Assert.assertNull(details.get(VmDetailConstants.MEMORY)); + Assert.assertNull(details.get(VmDetailConstants.CPU_NUMBER)); + Assert.assertNull(details.get(VmDetailConstants.CPU_SPEED)); + } + + @Test + public void updateInstanceDetailsKeepCurrentValueIfNullTestBothValuesAreNullKeepCurrentValue() { + Map<String, String> details = new HashMap<>(); + int currentValue = 123; + + for (String detailsConstant : detailsConstants) { + userVmManagerImpl.updateInstanceDetailsKeepCurrentValueIfNull(null, details, detailsConstant, currentValue); + } + + Assert.assertEquals(details.get(VmDetailConstants.MEMORY), String.valueOf(currentValue)); + Assert.assertEquals(details.get(VmDetailConstants.CPU_NUMBER), String.valueOf(currentValue)); + Assert.assertEquals(details.get(VmDetailConstants.CPU_SPEED),String.valueOf(currentValue)); + } + + @Test + public void updateInstanceDetailsKeepCurrentValueIfNullTestNeitherValueIsNullDoNothing() { + int currentValue = 123; + + for (String detailsConstant : detailsConstants) { + userVmManagerImpl.updateInstanceDetailsKeepCurrentValueIfNull(321, customParameters, detailsConstant, currentValue); + } + + Assert.assertEquals(customParameters.get(VmDetailConstants.MEMORY), "2048"); + Assert.assertEquals(customParameters.get(VmDetailConstants.CPU_NUMBER), "4"); + Assert.assertEquals(customParameters.get(VmDetailConstants.CPU_SPEED),"1000"); + } + + @Test + public void updateInstanceDetailsTestAllConstantsAreUpdated() { + Mockito.doReturn(serviceOffering).when(_serviceOfferingDao).findById(Mockito.anyLong()); + Mockito.doReturn(1L).when(vmInstanceMock).getId(); + Mockito.doReturn(1L).when(vmInstanceMock).getServiceOfferingId(); + Mockito.doReturn(serviceOffering).when(_serviceOfferingDao).findByIdIncludingRemoved(Mockito.anyLong(), Mockito.anyLong()); + userVmManagerImpl.updateInstanceDetails(null, vmInstanceMock, 0l); + + Mockito.verify(userVmManagerImpl).updateInstanceDetailsKeepCurrentValueIfNull(Mockito.any(), Mockito.any(), Mockito.eq(VmDetailConstants.CPU_SPEED), Mockito.any()); + Mockito.verify(userVmManagerImpl).updateInstanceDetailsKeepCurrentValueIfNull(Mockito.any(), Mockito.any(), Mockito.eq(VmDetailConstants.MEMORY), Mockito.any()); + Mockito.verify(userVmManagerImpl).updateInstanceDetailsKeepCurrentValueIfNull(Mockito.any(), Mockito.any(), Mockito.eq(VmDetailConstants.CPU_NUMBER), Mockito.any()); + } }