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

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


The following commit(s) were added to refs/heads/4.20 by this push:
     new 9ae696d1c82 Preserve VM settings on Instance Snapshot revert for 
Custom Service Offering (#12555)
9ae696d1c82 is described below

commit 9ae696d1c82efb6ade3a365600f909bba2660197
Author: Abhisar Sinha <[email protected]>
AuthorDate: Tue Feb 3 18:45:09 2026 +0530

    Preserve VM settings on Instance Snapshot revert for Custom Service 
Offering (#12555)
---
 .../cloud/vm/snapshot/VMSnapshotManagerImpl.java   | 23 +++++++-----
 .../cloud/vm/snapshot/VMSnapshotManagerTest.java   | 42 +++++++++++++++-------
 2 files changed, 44 insertions(+), 21 deletions(-)

diff --git 
a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java 
b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
index 43270e6a029..cdbb7119e9e 100644
--- a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
@@ -23,6 +23,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
@@ -182,6 +183,11 @@ public class VMSnapshotManagerImpl extends 
MutualExclusiveIdsManagerBase impleme
             Long.class, "vm.job.check.interval", "3000",
             "Interval in milliseconds to check if the job is complete", false);
 
+    private static final Set<String> 
VM_SNAPSHOT_CUSTOM_SERVICE_OFFERING_DETAILS = Set.of(
+            VmDetailConstants.CPU_NUMBER.toLowerCase(),
+            VmDetailConstants.CPU_SPEED.toLowerCase(),
+            VmDetailConstants.MEMORY.toLowerCase());
+
     @Override
     public boolean configure(String name, Map<String, Object> params) throws 
ConfigurationException {
         _name = name;
@@ -473,7 +479,8 @@ public class VMSnapshotManagerImpl extends 
MutualExclusiveIdsManagerBase impleme
     }
 
     /**
-     * Add entries on vm_snapshot_details if service offering is dynamic. This 
will allow setting details when revert to vm snapshot
+     * Add entries about cpu, cpu_speed and memory in vm_snapshot_details if 
service offering is dynamic.
+     * This will allow setting details when revert to vm snapshot.
      * @param vmId vm id
      * @param serviceOfferingId service offering id
      * @param vmSnapshotId vm snapshot id
@@ -484,7 +491,7 @@ public class VMSnapshotManagerImpl extends 
MutualExclusiveIdsManagerBase impleme
             List<UserVmDetailVO> vmDetails = 
_userVmDetailsDao.listDetails(vmId);
             List<VMSnapshotDetailsVO> vmSnapshotDetails = new 
ArrayList<VMSnapshotDetailsVO>();
             for (UserVmDetailVO detail : vmDetails) {
-                
if(detail.getName().equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || 
detail.getName().equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || 
detail.getName().equalsIgnoreCase(VmDetailConstants.MEMORY)) {
+                if 
(VM_SNAPSHOT_CUSTOM_SERVICE_OFFERING_DETAILS.contains(detail.getName().toLowerCase()))
 {
                     vmSnapshotDetails.add(new 
VMSnapshotDetailsVO(vmSnapshotId, detail.getName(), detail.getValue(), 
detail.isDisplay()));
                 }
             }
@@ -931,7 +938,7 @@ public class VMSnapshotManagerImpl extends 
MutualExclusiveIdsManagerBase impleme
             Transaction.execute(new 
TransactionCallbackWithExceptionNoReturn<CloudRuntimeException>() {
                 @Override
                 public void doInTransactionWithoutResult(TransactionStatus 
status) throws CloudRuntimeException {
-                    revertUserVmDetailsFromVmSnapshot(userVm, vmSnapshotVo);
+                    revertCustomServiceOfferingDetailsFromVmSnapshot(userVm, 
vmSnapshotVo);
                     updateUserVmServiceOffering(userVm, vmSnapshotVo);
                 }
             });
@@ -943,19 +950,19 @@ public class VMSnapshotManagerImpl extends 
MutualExclusiveIdsManagerBase impleme
     }
 
     /**
-     * Update or add user vm details from vm snapshot for vms with custom 
service offerings
+     * Update or add user vm details (cpu, cpu_speed and memory) from vm 
snapshot for vms with custom service offerings
      * @param userVm user vm
      * @param vmSnapshotVo vm snapshot
      */
-    protected void revertUserVmDetailsFromVmSnapshot(UserVmVO userVm, 
VMSnapshotVO vmSnapshotVo) {
+    protected void revertCustomServiceOfferingDetailsFromVmSnapshot(UserVmVO 
userVm, VMSnapshotVO vmSnapshotVo) {
         ServiceOfferingVO serviceOfferingVO = 
_serviceOfferingDao.findById(vmSnapshotVo.getServiceOfferingId());
         if (serviceOfferingVO.isDynamic()) {
             List<VMSnapshotDetailsVO> vmSnapshotDetails = 
_vmSnapshotDetailsDao.listDetails(vmSnapshotVo.getId());
-            List<UserVmDetailVO> userVmDetails = new 
ArrayList<UserVmDetailVO>();
             for (VMSnapshotDetailsVO detail : vmSnapshotDetails) {
-                userVmDetails.add(new UserVmDetailVO(userVm.getId(), 
detail.getName(), detail.getValue(), detail.isDisplay()));
+                if 
(VM_SNAPSHOT_CUSTOM_SERVICE_OFFERING_DETAILS.contains(detail.getName().toLowerCase()))
 {
+                    _userVmDetailsDao.addDetail(userVm.getId(), 
detail.getName(), detail.getValue(), detail.isDisplay());
+                }
             }
-            _userVmDetailsDao.saveDetails(userVmDetails);
         }
     }
 
diff --git 
a/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java 
b/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java
index 06c917a1244..8d48fc4dac5 100644
--- a/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java
+++ b/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java
@@ -51,6 +51,7 @@ import com.cloud.vm.UserVmManager;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.VirtualMachineManager;
+import com.cloud.vm.VmDetailConstants;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.UserVmDetailsDao;
 import com.cloud.vm.dao.VMInstanceDao;
@@ -67,7 +68,6 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
-import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
@@ -79,13 +79,18 @@ import java.util.List;
 import java.util.Map;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -225,13 +230,13 @@ public class VMSnapshotManagerTest {
         
when(_serviceOfferingDao.findById(SERVICE_OFFERING_ID)).thenReturn(serviceOffering);
 
         for (ResourceDetail detail : Arrays.asList(userVmDetailCpuNumber, 
vmSnapshotDetailCpuNumber)) {
-            when(detail.getName()).thenReturn("cpuNumber");
+            when(detail.getName()).thenReturn(VmDetailConstants.CPU_NUMBER);
             when(detail.getValue()).thenReturn("2");
             when(detail.isDisplay()).thenReturn(true);
         }
 
         for (ResourceDetail detail : Arrays.asList(userVmDetailMemory, 
vmSnapshotDetailMemory)) {
-            when(detail.getName()).thenReturn("memory");
+            when(detail.getName()).thenReturn(VmDetailConstants.MEMORY);
             when(detail.getValue()).thenReturn("2048");
             when(detail.isDisplay()).thenReturn(true);
         }
@@ -348,12 +353,12 @@ public class VMSnapshotManagerTest {
     @Test
     public void testUpdateUserVmServiceOfferingDifferentServiceOffering() 
throws ConcurrentOperationException, ResourceUnavailableException, 
ManagementServerException, VirtualMachineMigrationException {
         
when(userVm.getServiceOfferingId()).thenReturn(SERVICE_OFFERING_DIFFERENT_ID);
-        
when(_userVmManager.upgradeVirtualMachine(ArgumentMatchers.eq(TEST_VM_ID), 
ArgumentMatchers.eq(SERVICE_OFFERING_ID), 
mapDetailsCaptor.capture())).thenReturn(true);
+        when(_userVmManager.upgradeVirtualMachine(eq(TEST_VM_ID), 
eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(true);
         _vmSnapshotMgr.updateUserVmServiceOffering(userVm, vmSnapshotVO);
 
         verify(_vmSnapshotMgr).changeUserVmServiceOffering(userVm, 
vmSnapshotVO);
         verify(_vmSnapshotMgr).getVmMapDetails(userVm);
-        
verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(ArgumentMatchers.eq(userVm),
 ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
+        verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(eq(userVm), 
eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
     }
 
     @Test
@@ -368,18 +373,18 @@ public class VMSnapshotManagerTest {
 
     @Test
     public void testChangeUserVmServiceOffering() throws 
ConcurrentOperationException, ResourceUnavailableException, 
ManagementServerException, VirtualMachineMigrationException {
-        
when(_userVmManager.upgradeVirtualMachine(ArgumentMatchers.eq(TEST_VM_ID), 
ArgumentMatchers.eq(SERVICE_OFFERING_ID), 
mapDetailsCaptor.capture())).thenReturn(true);
+        when(_userVmManager.upgradeVirtualMachine(eq(TEST_VM_ID), 
eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(true);
         _vmSnapshotMgr.changeUserVmServiceOffering(userVm, vmSnapshotVO);
         verify(_vmSnapshotMgr).getVmMapDetails(userVm);
-        
verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(ArgumentMatchers.eq(userVm),
 ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
+        verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(eq(userVm), 
eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
     }
 
     @Test(expected=CloudRuntimeException.class)
     public void 
testChangeUserVmServiceOfferingFailOnUpgradeVMServiceOffering() throws 
ConcurrentOperationException, ResourceUnavailableException, 
ManagementServerException, VirtualMachineMigrationException {
-        
when(_userVmManager.upgradeVirtualMachine(ArgumentMatchers.eq(TEST_VM_ID), 
ArgumentMatchers.eq(SERVICE_OFFERING_ID), 
mapDetailsCaptor.capture())).thenReturn(false);
+        when(_userVmManager.upgradeVirtualMachine(eq(TEST_VM_ID), 
eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(false);
         _vmSnapshotMgr.changeUserVmServiceOffering(userVm, vmSnapshotVO);
         verify(_vmSnapshotMgr).getVmMapDetails(userVm);
-        
verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(ArgumentMatchers.eq(userVm),
 ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
+        verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(eq(userVm), 
eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
     }
 
     @Test
@@ -396,16 +401,27 @@ public class VMSnapshotManagerTest {
 
     @Test
     public void 
testRevertUserVmDetailsFromVmSnapshotNotDynamicServiceOffering() {
-        _vmSnapshotMgr.revertUserVmDetailsFromVmSnapshot(vmMock, vmSnapshotVO);
+        
_vmSnapshotMgr.revertCustomServiceOfferingDetailsFromVmSnapshot(vmMock, 
vmSnapshotVO);
         verify(_vmSnapshotDetailsDao, never()).listDetails(anyLong());
     }
 
     @Test
     public void testRevertUserVmDetailsFromVmSnapshotDynamicServiceOffering() {
         when(serviceOffering.isDynamic()).thenReturn(true);
-        _vmSnapshotMgr.revertUserVmDetailsFromVmSnapshot(vmMock, vmSnapshotVO);
+        VMSnapshotDetailsVO uefiSnapshotDetail = new 
VMSnapshotDetailsVO(VM_SNAPSHOT_ID, "UEFI", "SECURE", true);
+        List<VMSnapshotDetailsVO> snapshotDetailsWithUefi = Arrays.asList(
+                vmSnapshotDetailCpuNumber, vmSnapshotDetailMemory, 
uefiSnapshotDetail);
+        
when(_vmSnapshotDetailsDao.listDetails(VM_SNAPSHOT_ID)).thenReturn(snapshotDetailsWithUefi);
+
+        
_vmSnapshotMgr.revertCustomServiceOfferingDetailsFromVmSnapshot(vmMock, 
vmSnapshotVO);
+
         verify(_vmSnapshotDetailsDao).listDetails(VM_SNAPSHOT_ID);
-        
verify(_userVmDetailsDao).saveDetails(listUserVmDetailsCaptor.capture());
+        verify(_userVmDetailsDao, never()).saveDetails(any());
+        ArgumentCaptor<String> detailNameCaptor = 
ArgumentCaptor.forClass(String.class);
+        verify(_userVmDetailsDao, times(2)).addDetail(eq(TEST_VM_ID), 
detailNameCaptor.capture(), anyString(), anyBoolean());
+        List<String> appliedNames = detailNameCaptor.getAllValues();
+        assertTrue(appliedNames.contains(VmDetailConstants.CPU_NUMBER));
+        assertTrue(appliedNames.contains(VmDetailConstants.MEMORY));
+        assertFalse("UEFI must not be applied from snapshot so that existing 
UEFI setting is preserved", appliedNames.contains("UEFI"));
     }
-
 }

Reply via email to