This is an automated email from the ASF dual-hosted git repository.

weizhou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 45daa1ce591a43442c30cc6ec9a70124440063eb
Merge: 19f79b1d94f 44aa08c02a3
Author: Wei Zhou <weiz...@apache.org>
AuthorDate: Fri Apr 12 16:40:07 2024 +0200

    Merge remote-tracking branch 'apache/4.19'

 .../java/com/cloud/storage/VolumeApiService.java   |   2 +
 api/src/main/java/com/cloud/vm/UserVmService.java  |   2 +-
 .../api/command/user/vm/RestoreVMCmd.java          |  45 ++-
 .../java/com/cloud/vm/VirtualMachineManager.java   |   2 +-
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |  18 +-
 .../src/main/java/com/cloud/vm/VmWorkRestore.java  |  27 +-
 .../engine/orchestration/CloudOrchestrator.java    |   7 +-
 .../engine/orchestration/VolumeOrchestrator.java   |  65 ++---
 .../com/cloud/storage/VolumeApiServiceImpl.java    |  14 +-
 .../main/java/com/cloud/vm/UserVmManagerImpl.java  | 124 +++++++--
 .../cloudstack/vm/UnmanagedVMsManagerImpl.java     |  11 +-
 .../java/com/cloud/vm/UserVmManagerImplTest.java   |  26 +-
 ui/src/config/section/compute.js                   |  27 +-
 ui/src/views/compute/ReinstallVm.vue               | 307 +++++++++++++++++++++
 14 files changed, 542 insertions(+), 135 deletions(-)

diff --cc 
api/src/main/java/org/apache/cloudstack/api/command/user/vm/RestoreVMCmd.java
index e1c4dd5f678,17c4e97eb3b..3839049eee5
--- 
a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RestoreVMCmd.java
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RestoreVMCmd.java
@@@ -16,9 -16,12 +16,9 @@@
  // under the License.
  package org.apache.cloudstack.api.command.user.vm;
  
- import org.apache.cloudstack.api.ApiCommandResourceType;
- 
+ import com.cloud.vm.VmDetailConstants;
 -import org.apache.cloudstack.api.ApiCommandResourceType;
 -import org.apache.cloudstack.api.response.DiskOfferingResponse;
 -import org.apache.log4j.Logger;
 -
  import org.apache.cloudstack.acl.SecurityChecker.AccessType;
++import org.apache.cloudstack.api.ApiCommandResourceType;
  import org.apache.cloudstack.api.ACL;
  import org.apache.cloudstack.api.APICommand;
  import org.apache.cloudstack.api.ApiConstants;
@@@ -28,6 -31,6 +28,7 @@@ import org.apache.cloudstack.api.Parame
  import org.apache.cloudstack.api.ResponseObject.ResponseView;
  import org.apache.cloudstack.api.ServerApiException;
  import org.apache.cloudstack.api.command.user.UserCmd;
++import org.apache.cloudstack.api.response.DiskOfferingResponse;
  import org.apache.cloudstack.api.response.TemplateResponse;
  import org.apache.cloudstack.api.response.UserVmResponse;
  import org.apache.cloudstack.context.CallContext;
diff --cc 
engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
index 4372741de66,243613907ff..9f743668cd5
--- 
a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
+++ 
b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
@@@ -5691,8 -5610,20 +5691,8 @@@ public class VirtualMachineManagerImpl 
          return workJob;
      }
  
 -    protected void resourceCountIncrement (long accountId, Long cpu, Long 
memory) {
 -        _resourceLimitMgr.incrementResourceCount(accountId, 
ResourceType.user_vm);
 -        _resourceLimitMgr.incrementResourceCount(accountId, ResourceType.cpu, 
cpu);
 -        _resourceLimitMgr.incrementResourceCount(accountId, 
ResourceType.memory, memory);
 -    }
 -
 -    protected void resourceCountDecrement (long accountId, Long cpu, Long 
memory) {
 -        _resourceLimitMgr.decrementResourceCount(accountId, 
ResourceType.user_vm);
 -        _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.cpu, 
cpu);
 -        _resourceLimitMgr.decrementResourceCount(accountId, 
ResourceType.memory, memory);
 -    }
 -
      @Override
-     public UserVm restoreVirtualMachine(final long vmId, final Long 
newTemplateId) throws ResourceUnavailableException, 
InsufficientCapacityException {
+     public UserVm restoreVirtualMachine(final long vmId, final Long 
newTemplateId, final Long rootDiskOfferingId, final boolean expunge, final 
Map<String, String> details) throws ResourceUnavailableException, 
InsufficientCapacityException {
          final AsyncJobExecutionContext jobContext = 
AsyncJobExecutionContext.getCurrentExecutionContext();
          if 
(jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
              VmWorkJobVO placeHolder = null;
@@@ -5722,14 -5653,14 +5722,14 @@@
          }
      }
  
-     private UserVm orchestrateRestoreVirtualMachine(final long vmId, final 
Long newTemplateId) throws ResourceUnavailableException, 
InsufficientCapacityException {
-         logger.debug("Restoring vm " + vmId + " with new templateId " + 
newTemplateId);
+     private UserVm orchestrateRestoreVirtualMachine(final long vmId, final 
Long newTemplateId, final Long rootDiskOfferingId, final boolean expunge, final 
Map<String, String> details) throws ResourceUnavailableException, 
InsufficientCapacityException {
 -        s_logger.debug("Restoring vm " + vmId + " with templateId : " + 
newTemplateId + " diskOfferingId : " + rootDiskOfferingId + " details : " + 
details);
++        logger.debug("Restoring vm " + vmId + " with templateId : " + 
newTemplateId + " diskOfferingId : " + rootDiskOfferingId + " details : " + 
details);
          final CallContext context = CallContext.current();
          final Account account = context.getCallingAccount();
-         return _userVmService.restoreVirtualMachine(account, vmId, 
newTemplateId);
+         return _userVmService.restoreVirtualMachine(account, vmId, 
newTemplateId, rootDiskOfferingId, expunge, details);
      }
  
-     public Outcome<VirtualMachine> restoreVirtualMachineThroughJobQueue(final 
long vmId, final Long newTemplateId) {
+     public Outcome<VirtualMachine> restoreVirtualMachineThroughJobQueue(final 
long vmId, final Long newTemplateId, final Long rootDiskOfferingId, final 
boolean expunge, Map<String, String> details) {
          String commandName = VmWorkRestore.class.getName();
          Pair<VmWorkJobVO, Long> pendingWorkJob = retrievePendingWorkJob(vmId, 
commandName);
  
diff --cc server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index 97bfef9a95d,566fcb38fc9..d76713b73cb
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@@ -7825,20 -7697,38 +7848,38 @@@ public class UserVmManagerImpl extends 
              ex.addProxyObject(String.valueOf(vmId), "vmId");
              throw ex;
          }
- 
          _accountMgr.checkAccess(caller, null, true, vm);
  
+         DiskOffering diskOffering = rootDiskOfferingId != null ? 
validateAndGetDiskOffering(rootDiskOfferingId, vm, caller) : null;
+         VMTemplateVO template = _templateDao.findById(newTemplateId);
+         if (template.getSize() != null) {
+             String rootDiskSize = 
details.get(VmDetailConstants.ROOT_DISK_SIZE);
+             Long templateSize = template.getSize();
+             if (StringUtils.isNumeric(rootDiskSize)) {
+                 if (Long.parseLong(rootDiskSize) * GiB_TO_BYTES < 
templateSize) {
+                     throw new 
InvalidParameterValueException(String.format("Root disk size [%s] is smaller 
than the template size [%s]", rootDiskSize, templateSize));
+                 }
+             } else if (diskOffering != null && diskOffering.getDiskSize() < 
templateSize) {
+                 throw new InvalidParameterValueException(String.format("Disk 
size for selected offering [%s] is less than the template's size [%s]", 
diskOffering.getDiskSize(), templateSize));
+             }
+         }
+ 
          //check if there are any active snapshots on volumes associated with 
the VM
 -        s_logger.debug("Checking if there are any ongoing snapshots on the 
ROOT volumes associated with VM with ID " + vmId);
 +        logger.debug("Checking if there are any ongoing snapshots on the ROOT 
volumes associated with VM with ID " + vmId);
          if (checkStatusOfVolumeSnapshots(vmId, Volume.Type.ROOT)) {
              throw new CloudRuntimeException("There is/are unbacked up 
snapshot(s) on ROOT volume, Re-install VM is not permitted, please try again 
later.");
          }
 -        s_logger.debug("Found no ongoing snapshots on volume of type ROOT, 
for the vm with id " + vmId);
 +        logger.debug("Found no ongoing snapshots on volume of type ROOT, for 
the vm with id " + vmId);
-         return restoreVMInternal(caller, vm, newTemplateId);
+         return restoreVMInternal(caller, vm, newTemplateId, 
rootDiskOfferingId, expunge, details);
      }
  
-     public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long 
newTemplateId) throws InsufficientCapacityException, 
ResourceUnavailableException {
-         return _itMgr.restoreVirtualMachine(vm.getId(), newTemplateId);
+     public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long 
newTemplateId, Long rootDiskOfferingId, boolean expunge, Map<String, String> 
details) throws InsufficientCapacityException, ResourceUnavailableException {
+         return _itMgr.restoreVirtualMachine(vm.getId(), newTemplateId, 
rootDiskOfferingId, expunge, details);
+     }
+ 
+ 
+     public UserVm restoreVMInternal(Account caller, UserVmVO vm) throws 
InsufficientCapacityException, ResourceUnavailableException {
+         return restoreVMInternal(caller, vm, null, null, false, null);
      }
  
      private VMTemplateVO getRestoreVirtualMachineTemplate(Account caller, 
Long newTemplateId, List<VolumeVO> rootVols, UserVmVO vm) {
diff --cc server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
index 07d2e9bd59f,303a9b08b1c..1292b9e230c
--- a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
+++ b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
@@@ -1450,131 -1379,6 +1436,131 @@@ public class UserVmManagerImplTest 
          vmSnapshots.add(vmSnapshot);
          when(vmSnapshotDaoMock.findByVm(vmId)).thenReturn(vmSnapshots);
  
-         userVmManagerImpl.restoreVirtualMachine(accountMock, vmId, 
newTemplateId);
+         userVmManagerImpl.restoreVirtualMachine(accountMock, vmId, 
newTemplateId, null, false, null);
      }
 +
 +    @Test
 +    public void 
addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecifiedTestDetailsConstantIsNotNullDoNothing()
 {
 +        int currentValue = 123;
 +
 +        for (String detailsConstant : detailsConstants) {
 +            
userVmManagerImpl.addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecified(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 
addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecifiedTestNewValueIsNotNullDoNothing()
 {
 +        Map<String, String> details = new HashMap<>();
 +        int currentValue = 123;
 +
 +        for (String detailsConstant : detailsConstants) {
 +            
userVmManagerImpl.addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecified(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 
addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecifiedTestBothValuesAreNullKeepCurrentValue()
 {
 +        Map<String, String> details = new HashMap<>();
 +        int currentValue = 123;
 +
 +        for (String detailsConstant : detailsConstants) {
 +            
userVmManagerImpl.addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecified(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 
addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecifiedTestNeitherValueIsNullDoNothing()
 {
 +        int currentValue = 123;
 +
 +        for (String detailsConstant : detailsConstants) {
 +            
userVmManagerImpl.addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecified(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 
updateInstanceDetailsMapWithCurrentValuesForAbsentDetailsTestAllConstantsAreUpdated()
 {
 +        
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.updateInstanceDetailsMapWithCurrentValuesForAbsentDetails(null,
 vmInstanceMock, 0l);
 +
 +        
Mockito.verify(userVmManagerImpl).addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecified(Mockito.any(),
 Mockito.any(), Mockito.eq(VmDetailConstants.CPU_SPEED), Mockito.any());
 +        
Mockito.verify(userVmManagerImpl).addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecified(Mockito.any(),
 Mockito.any(), Mockito.eq(VmDetailConstants.MEMORY), Mockito.any());
 +        
Mockito.verify(userVmManagerImpl).addCurrentDetailValueToInstanceDetailsMapIfNewValueWasNotSpecified(Mockito.any(),
 Mockito.any(), Mockito.eq(VmDetailConstants.CPU_NUMBER), Mockito.any());
 +    }
 +
 +    @Test
 +    public void testCheckVolumesLimits() {
 +        userVmManagerImpl.resourceLimitService = resourceLimitMgr;
 +        long diskOffId1 = 1L;
 +        DiskOfferingVO diskOfferingVO1 = Mockito.mock(DiskOfferingVO.class);
 +        
Mockito.when(diskOfferingDao.findById(diskOffId1)).thenReturn(diskOfferingVO1);
 +        
Mockito.when(resourceLimitMgr.getResourceLimitStorageTags(diskOfferingVO1)).thenReturn(List.of("tag1",
 "tag2"));
 +        long diskOffId2 = 2L;
 +        DiskOfferingVO diskOfferingVO2 = Mockito.mock(DiskOfferingVO.class);
 +        
Mockito.when(diskOfferingDao.findById(diskOffId2)).thenReturn(diskOfferingVO2);
 +        
Mockito.when(resourceLimitMgr.getResourceLimitStorageTags(diskOfferingVO2)).thenReturn(List.of("tag2"));
 +        long diskOffId3 = 3L;
 +        DiskOfferingVO diskOfferingVO3 = Mockito.mock(DiskOfferingVO.class);
 +        
Mockito.when(diskOfferingDao.findById(diskOffId3)).thenReturn(diskOfferingVO3);
 +        
Mockito.when(resourceLimitMgr.getResourceLimitStorageTags(diskOfferingVO3)).thenReturn(new
 ArrayList<>());
 +
 +        VolumeVO vol1 = Mockito.mock(VolumeVO.class);
 +        Mockito.when(vol1.getDiskOfferingId()).thenReturn(diskOffId1);
 +        Mockito.when(vol1.getSize()).thenReturn(10L);
 +        Mockito.when(vol1.isDisplay()).thenReturn(true);
 +        VolumeVO undisplayedVolume = Mockito.mock(VolumeVO.class); // 
shouldn't be considered for limits
 +        Mockito.when(undisplayedVolume.isDisplay()).thenReturn(false);
 +        VolumeVO vol3 = Mockito.mock(VolumeVO.class);
 +        Mockito.when(vol3.getDiskOfferingId()).thenReturn(diskOffId2);
 +        Mockito.when(vol3.getSize()).thenReturn(30L);
 +        Mockito.when(vol3.isDisplay()).thenReturn(true);
 +        VolumeVO vol4 = Mockito.mock(VolumeVO.class);
 +        Mockito.when(vol4.getDiskOfferingId()).thenReturn(diskOffId3);
 +        Mockito.when(vol4.getSize()).thenReturn(40L);
 +        Mockito.when(vol4.isDisplay()).thenReturn(true);
 +        VolumeVO vol5 = Mockito.mock(VolumeVO.class);
 +        Mockito.when(vol5.getDiskOfferingId()).thenReturn(diskOffId1);
 +        Mockito.when(vol5.getSize()).thenReturn(50L);
 +        Mockito.when(vol5.isDisplay()).thenReturn(true);
 +
 +        List<VolumeVO> volumes = List.of(vol1, undisplayedVolume, vol3, vol4, 
vol5);
 +        Long size = 
volumes.stream().filter(VolumeVO::isDisplay).mapToLong(VolumeVO::getSize).sum();
 +        try {
 +            userVmManagerImpl.checkVolumesLimits(account, volumes);
 +            Mockito.verify(resourceLimitMgr, Mockito.times(1))
 +                    .checkResourceLimit(account, 
Resource.ResourceType.volume, 4);
 +            Mockito.verify(resourceLimitMgr, Mockito.times(1))
 +                    .checkResourceLimit(account, 
Resource.ResourceType.primary_storage, size);
 +            Mockito.verify(resourceLimitMgr, Mockito.times(1))
 +                    .checkResourceLimitWithTag(account, 
Resource.ResourceType.volume, "tag1", 2);
 +            Mockito.verify(resourceLimitMgr, Mockito.times(1))
 +                    .checkResourceLimitWithTag(account, 
Resource.ResourceType.volume, "tag2", 3);
 +            Mockito.verify(resourceLimitMgr, Mockito.times(1))
 +                    .checkResourceLimitWithTag(account, 
Resource.ResourceType.primary_storage, "tag1",
 +                            vol1.getSize() + vol5.getSize());
 +            Mockito.verify(resourceLimitMgr, Mockito.times(1))
 +                    .checkResourceLimitWithTag(account, 
Resource.ResourceType.primary_storage, "tag2",
 +                            vol1.getSize() + vol3.getSize() + vol5.getSize());
 +        } catch (ResourceAllocationException e) {
 +            Assert.fail(e.getMessage());
 +        }
 +    }
  }

Reply via email to