From 7cb70427a78376236713c423b0f725e2be6754f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Wed, 10 Sep 2025 12:26:59 -0300 Subject: [PATCH 1/4] change vmsnapshotmax config scope --- .../src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java | 2 +- .../main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java b/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java index 997b413c099c..2d450e9f6ace 100644 --- a/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java +++ b/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java @@ -31,7 +31,7 @@ public interface VMSnapshotManager extends VMSnapshotService, Manager { static final ConfigKey VMSnapshotExpireInterval = new ConfigKey("Advanced", Integer.class, "vmsnapshot.expire.interval", "-1", "VM Snapshot expire interval in hours", true, ConfigKey.Scope.Account); - ConfigKey VMSnapshotMax = new ConfigKey("Advanced", Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a single vm", true, ConfigKey.Scope.Global); + ConfigKey VMSnapshotMax = new ConfigKey("Advanced", Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a single vm", true, ConfigKey.Scope.Account); /** * Delete all VM snapshots belonging to one VM 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 0dae0c265fc5..ff29798a7810 100644 --- a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -400,7 +400,7 @@ public VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDesc _accountMgr.checkAccess(caller, null, true, userVmVo); // check max snapshot limit for per VM - int vmSnapshotMax = VMSnapshotManager.VMSnapshotMax.value(); + int vmSnapshotMax = VMSnapshotManager.VMSnapshotMax.valueIn(userVmVo.getAccountId()); if (_vmSnapshotDao.findByVm(vmId).size() >= vmSnapshotMax) { throw new CloudRuntimeException("Creating vm snapshot failed due to a VM can just have : " + vmSnapshotMax + " VM snapshots. Please delete old ones"); From 8daad166c4ee905ed8bbff096535c0039d069eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Mon, 20 Oct 2025 19:50:05 -0300 Subject: [PATCH 2/4] apply suggestion --- .../java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 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 ff29798a7810..0acb23527f8d 100644 --- a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -400,10 +400,11 @@ public VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDesc _accountMgr.checkAccess(caller, null, true, userVmVo); // check max snapshot limit for per VM - int vmSnapshotMax = VMSnapshotManager.VMSnapshotMax.valueIn(userVmVo.getAccountId()); - + boolean vmBelongsToProject = _accountMgr.getAccount(userVmVo.getAccountId()).getType() == Account.Type.PROJECT; + long accountIdToRetrieveConfigurationValueFrom = vmBelongsToProject ? caller.getId() : userVmVo.getAccountId(); + int vmSnapshotMax = VMSnapshotManager.VMSnapshotMax.valueIn(accountIdToRetrieveConfigurationValueFrom); if (_vmSnapshotDao.findByVm(vmId).size() >= vmSnapshotMax) { - throw new CloudRuntimeException("Creating vm snapshot failed due to a VM can just have : " + vmSnapshotMax + " VM snapshots. Please delete old ones"); + throw new CloudRuntimeException(String.format("Each VM can have at most [%s] VM snapshots.", vmSnapshotMax)); } // check if there are active volume snapshots tasks From 38208055ed9b2e64028909f758ba329af2a4b0ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Thu, 23 Oct 2025 19:52:47 -0300 Subject: [PATCH 3/4] fix unit tests --- .../cloud/vm/snapshot/VMSnapshotManagerTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 a0f09981a401..b696d743ac64 100644 --- a/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java +++ b/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java @@ -41,6 +41,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; @@ -136,6 +137,8 @@ public class VMSnapshotManagerTest { VMSnapshotDetailsDao _vmSnapshotDetailsDao; @Mock UserVmManager _userVmManager; + @Mock + private AccountVO accountVOMock; private static final long TEST_VM_ID = 3L; private static final long SERVICE_OFFERING_ID = 1L; @@ -285,8 +288,12 @@ public void testCreateVMSnapshotF3() throws AgentUnavailableException, Operation @SuppressWarnings("unchecked") @Test(expected = CloudRuntimeException.class) public void testAllocVMSnapshotF4() throws ResourceAllocationException { + long accountId = 1L; List mockList = mock(List.class); when(mockList.size()).thenReturn(10); + when(_userVMDao.findById(TEST_VM_ID)).thenReturn(vmMock); + when(userVm.getAccountId()).thenReturn(accountId); + when(_accountMgr.getAccount(accountId)).thenReturn(accountVOMock); when(_vmSnapshotDao.findByVm(TEST_VM_ID)).thenReturn(mockList); _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID, "", "", true); } @@ -295,8 +302,12 @@ public void testAllocVMSnapshotF4() throws ResourceAllocationException { @SuppressWarnings("unchecked") @Test(expected = CloudRuntimeException.class) public void testAllocVMSnapshotF5() throws ResourceAllocationException { + long accountId = 1L; List mockList = mock(List.class); when(mockList.size()).thenReturn(1); + when(_userVMDao.findById(TEST_VM_ID)).thenReturn(vmMock); + when(userVm.getAccountId()).thenReturn(accountId); + when(_accountMgr.getAccount(accountId)).thenReturn(accountVOMock); when(_snapshotDao.listByInstanceId(TEST_VM_ID, Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp)).thenReturn(mockList); _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID, "", "", true); } @@ -304,6 +315,10 @@ public void testAllocVMSnapshotF5() throws ResourceAllocationException { // successful creation case @Test public void testCreateVMSnapshot() throws AgentUnavailableException, OperationTimedoutException, ResourceAllocationException, NoTransitionException { + long accountId = 1L; + when(_userVMDao.findById(TEST_VM_ID)).thenReturn(vmMock); + when(userVm.getAccountId()).thenReturn(accountId); + when(_accountMgr.getAccount(accountId)).thenReturn(accountVOMock); when(vmMock.getState()).thenReturn(State.Running); _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID, "", "", true); } From 53ca91ffa979771d5a5bf6a740f6b4078eed93e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Thu, 6 Nov 2025 12:27:26 -0300 Subject: [PATCH 4/4] Update engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java Co-authored-by: Lucas Martins <56271185+lucas-a-martins@users.noreply.github.com> --- .../src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java b/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java index 2d450e9f6ace..c942f3435f63 100644 --- a/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java +++ b/engine/components-api/src/main/java/com/cloud/vm/snapshot/VMSnapshotManager.java @@ -31,7 +31,7 @@ public interface VMSnapshotManager extends VMSnapshotService, Manager { static final ConfigKey VMSnapshotExpireInterval = new ConfigKey("Advanced", Integer.class, "vmsnapshot.expire.interval", "-1", "VM Snapshot expire interval in hours", true, ConfigKey.Scope.Account); - ConfigKey VMSnapshotMax = new ConfigKey("Advanced", Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a single vm", true, ConfigKey.Scope.Account); + ConfigKey VMSnapshotMax = new ConfigKey("Advanced", Integer.class, "vmsnapshot.max", "10", "Maximum VM snapshots for a single VM", true, ConfigKey.Scope.Account); /** * Delete all VM snapshots belonging to one VM