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");