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

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


The following commit(s) were added to refs/heads/4.22 by this push:
     new a5954f94cf6 fix domain cleanup when a removed account owns templates 
(#13630)
a5954f94cf6 is described below

commit a5954f94cf6bcd4f9ccdad864d7e8827d065ed67
Author: Daman Arora <[email protected]>
AuthorDate: Wed Sep 2 04:10:27 2026 -0400

    fix domain cleanup when a removed account owns templates (#13630)
---
 .../src/main/java/com/cloud/acl/DomainChecker.java |  2 +-
 .../resourcelimit/ResourceLimitManagerImpl.java    |  2 +-
 .../test/java/com/cloud/acl/DomainCheckerTest.java | 27 ++++++++++++++-----
 .../ResourceLimitManagerImplTest.java              | 31 ++++++++++++++++++++++
 4 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/server/src/main/java/com/cloud/acl/DomainChecker.java 
b/server/src/main/java/com/cloud/acl/DomainChecker.java
index 24b6346d0af..282e2040852 100644
--- a/server/src/main/java/com/cloud/acl/DomainChecker.java
+++ b/server/src/main/java/com/cloud/acl/DomainChecker.java
@@ -229,7 +229,7 @@ public class DomainChecker extends AdapterBase implements 
SecurityChecker {
             return;
         }
 
-        Account owner = _accountDao.findById(entity.getAccountId());
+        Account owner = 
_accountDao.findByIdIncludingRemoved(entity.getAccountId());
         String entityLog = String.format("entity [owner: %s, type: %s]", 
owner, entity.getEntityType().getSimpleName());
         if (owner == null) {
             logger.error(String.format("Owner not found for %s", entityLog));
diff --git 
a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java 
b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
index fad2da89cf2..a79b074685d 100644
--- a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
+++ b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
@@ -1147,7 +1147,7 @@ public class ResourceLimitManagerImpl extends ManagerBase 
implements ResourceLim
         }
         _accountMgr.checkAccess(callerAccount, domain);
         if (accountId != null) {
-            Account account = _entityMgr.findById(Account.class, accountId);
+            Account account = 
_entityMgr.findByIdIncludingRemoved(Account.class, accountId);
             if (account == null) {
                 throw new InvalidParameterValueException("Unable to find 
account " + accountId);
             }
diff --git a/server/src/test/java/com/cloud/acl/DomainCheckerTest.java 
b/server/src/test/java/com/cloud/acl/DomainCheckerTest.java
index a5ec41306d8..f046c0d9cbe 100644
--- a/server/src/test/java/com/cloud/acl/DomainCheckerTest.java
+++ b/server/src/test/java/com/cloud/acl/DomainCheckerTest.java
@@ -82,7 +82,7 @@ public class DomainCheckerTest {
         Account caller = Mockito.mock(Account.class);
         Mockito.when(caller.getId()).thenReturn(1L);
         ControlledEntity entity = getMockedEntity(2L);
-        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(null);
+        
Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(null);
 
         domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ModifyProject);
     }
@@ -96,7 +96,22 @@ public class DomainCheckerTest {
         ControlledEntity entity = getMockedEntity(2L);
         AccountVO owner = Mockito.mock(AccountVO.class);
         Mockito.when(owner.getDomainId()).thenReturn(101L);
-        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(owner);
+        
Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(owner);
+        Mockito.when(_domainDao.isChildDomain(100L, 101L)).thenReturn(true);
+
+        domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ModifyProject);
+    }
+
+    @Test
+    public void testDomainAdminHasAccessToRemovedOwner() {
+        Account caller = Mockito.mock(Account.class);
+        Mockito.when(caller.getId()).thenReturn(1L);
+        Mockito.when(caller.getDomainId()).thenReturn(100L);
+        Mockito.when(caller.getType()).thenReturn(Account.Type.DOMAIN_ADMIN);
+        ControlledEntity entity = getMockedEntity(2L);
+        AccountVO removedOwner = Mockito.mock(AccountVO.class);
+        Mockito.when(removedOwner.getDomainId()).thenReturn(101L);
+        
Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(removedOwner);
         Mockito.when(_domainDao.isChildDomain(100L, 101L)).thenReturn(true);
 
         domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ModifyProject);
@@ -119,7 +134,7 @@ public class DomainCheckerTest {
         Account caller = resources.first();
         ControlledEntity entity = resources.second();
         AccountVO projectAccount = resources.third();
-        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(projectAccount);
+        
Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(projectAccount);
         Mockito.when(_projectMgr.canModifyProjectAccount(caller, 
projectAccount.getId())).thenReturn(true);
         
Mockito.doReturn(true).when(domainChecker).checkOperationPermitted(caller, 
entity);
 
@@ -132,7 +147,7 @@ public class DomainCheckerTest {
         Account caller = resources.first();
         ControlledEntity entity = resources.second();
         AccountVO projectAccount = resources.third();
-        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(projectAccount);
+        
Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(projectAccount);
         Mockito.when(_projectMgr.canModifyProjectAccount(caller, 
projectAccount.getId())).thenReturn(false);
 
         domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ModifyProject);
@@ -144,7 +159,7 @@ public class DomainCheckerTest {
         Account caller = resources.first();
         ControlledEntity entity = resources.second();
         AccountVO projectAccount = resources.third();
-        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(projectAccount);
+        
Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(projectAccount);
         Mockito.when(_projectMgr.canAccessProjectAccount(caller, 
projectAccount.getId())).thenReturn(true);
         
Mockito.doReturn(true).when(domainChecker).checkOperationPermitted(caller, 
entity);
 
@@ -157,7 +172,7 @@ public class DomainCheckerTest {
         Account caller = resources.first();
         ControlledEntity entity = resources.second();
         AccountVO projectAccount = resources.third();
-        
Mockito.when(_accountDao.findById(entity.getAccountId())).thenReturn(projectAccount);
+        
Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(projectAccount);
         Mockito.when(_projectMgr.canAccessProjectAccount(caller, 
projectAccount.getId())).thenReturn(false);
 
         domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, 
SecurityChecker.AccessType.ListEntry);
diff --git 
a/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java
 
b/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java
index 83619c92e8f..b7d3a4d0f4c 100644
--- 
a/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java
+++ 
b/server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java
@@ -56,6 +56,7 @@ import org.mockito.junit.MockitoJUnitRunner;
 import com.cloud.api.query.dao.UserVmJoinDao;
 import com.cloud.api.query.vo.UserVmJoinVO;
 import com.cloud.configuration.Resource;
+import com.cloud.configuration.ResourceCount;
 import com.cloud.configuration.ResourceCountVO;
 import com.cloud.configuration.ResourceLimit;
 import com.cloud.configuration.ResourceLimitVO;
@@ -66,6 +67,7 @@ import com.cloud.domain.DomainVO;
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEventUtils;
 import com.cloud.event.EventTypes;
+import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.offering.DiskOffering;
 import com.cloud.offering.ServiceOffering;
@@ -681,6 +683,35 @@ public class ResourceLimitManagerImplTest {
         Mockito.verify(resourceLimitManager, 
Mockito.times(1)).recalculateResourceCount(accountId, domainId, typeId, null);
     }
 
+    @Test
+    public void testRecalculateResourceCountRemovedAccount() {
+        Long accountId = 10L;
+        Long domainId = 2L;
+        Resource.ResourceType type = Resource.ResourceType.secondary_storage;
+        
Mockito.when(domainDao.findById(domainId)).thenReturn(Mockito.mock(DomainVO.class));
+        Account removedAccount = Mockito.mock(Account.class);
+        Mockito.when(entityManager.findByIdIncludingRemoved(Account.class, 
accountId)).thenReturn(removedAccount);
+        
Mockito.doNothing().when(resourceLimitManager).removeResourceLimitAndCountForNonMatchingTags(Mockito.anyLong(),
+                Mockito.any(), Mockito.anyList(), Mockito.anyList());
+        
Mockito.doReturn(1L).when(resourceLimitManager).recalculateAccountResourceCount(accountId,
 type, null);
+        Mockito.doReturn(new 
ArrayList<>()).when(resourceLimitManager).recalculateAccountTaggedResourceCount(
+                Mockito.eq(accountId.longValue()), Mockito.eq(type), 
Mockito.anyList(), Mockito.anyList());
+
+        List<? extends ResourceCount> result = 
resourceLimitManager.recalculateResourceCount(accountId, domainId, 
type.getOrdinal(), null);
+
+        Assert.assertEquals(1, result.size());
+        
Mockito.verify(accountManager).verifyCallerPrivilegeForUserOrAccountOperations(removedAccount);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testRecalculateResourceCountAccountNotFound() {
+        Long accountId = 10L;
+        Long domainId = 2L;
+        
Mockito.when(domainDao.findById(domainId)).thenReturn(Mockito.mock(DomainVO.class));
+        Mockito.when(entityManager.findByIdIncludingRemoved(Account.class, 
accountId)).thenReturn(null);
+        resourceLimitManager.recalculateResourceCount(accountId, domainId, 
Resource.ResourceType.secondary_storage.getOrdinal(), null);
+    }
+
     @Test
     public void testGetVmsWithAccountAndTagNoTag() throws 
NoSuchFieldException, IllegalAccessException {
         
overrideDefaultConfigValue(VirtualMachineManager.ResourceCountRunningVMsonly, 
"_defaultValue", "false");

Reply via email to