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

commit 1593944553fb92431a1efd3f500574f120363fa6
Author: dahn <[email protected]>
AuthorDate: Fri Feb 20 17:19:58 2026 +0100

    [20.3] Implement/fix limit validation for projects
---
 .../com/cloud/projects/ProjectManagerImpl.java     | 51 ++++++++++++++++++----
 .../cloud/resourcelimit/CheckedReservation.java    |  4 +-
 .../java/com/cloud/resourcelimit/Reserver.java     | 24 ++++++++++
 .../resourcelimit/ResourceLimitManagerImpl.java    |  5 ---
 4 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java 
b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java
index 7a743e3ce76..8302f0ddf15 100644
--- a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java
+++ b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java
@@ -36,6 +36,7 @@ import javax.inject.Inject;
 import javax.mail.MessagingException;
 import javax.naming.ConfigurationException;
 
+import com.cloud.resourcelimit.CheckedReservation;
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.ProjectRole;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
@@ -47,6 +48,7 @@ import 
org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.framework.messagebus.MessageBus;
 import org.apache.cloudstack.framework.messagebus.PublishScope;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
+import org.apache.cloudstack.reservation.dao.ReservationDao;
 import org.apache.cloudstack.utils.mailing.MailAddress;
 import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
 import org.apache.cloudstack.utils.mailing.SMTPMailSender;
@@ -159,6 +161,8 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
     private VpcManager _vpcMgr;
     @Inject
     MessageBus messageBus;
+    @Inject
+    private ReservationDao reservationDao;
 
     protected boolean _invitationRequired = false;
     protected long _invitationTimeOut = 86400000;
@@ -272,8 +276,7 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
             owner = _accountDao.findById(user.getAccountId());
         }
 
-        //do resource limit check
-        _resourceLimitMgr.checkResourceLimit(owner, ResourceType.project);
+        try (CheckedReservation projectReservation = new 
CheckedReservation(owner, ResourceType.project, null, null, 1L, reservationDao, 
_resourceLimitMgr)) {
 
         final Account ownerFinal = owner;
         User finalUser = user;
@@ -308,6 +311,7 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
         messageBus.publish(_name, 
ProjectManager.MESSAGE_CREATE_TUNGSTEN_PROJECT_EVENT, PublishScope.LOCAL, 
project);
 
         return project;
+        }
     }
 
     @Override
@@ -491,6 +495,9 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
         //remove account
         ProjectAccountVO projectAccount = 
_projectAccountDao.findByProjectIdAccountId(projectId, account.getId());
         success = _projectAccountDao.remove(projectAccount.getId());
+        if (projectAccount.getAccountRole() == Role.Admin) {
+            _resourceLimitMgr.decrementResourceCount(account.getId(), 
ResourceType.project);
+        }
 
         //remove all invitations for account
         if (success) {
@@ -594,12 +601,22 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
             if (username == null) {
                 throw new InvalidParameterValueException("User information 
(ID) is required to add user to the project");
             }
+
+            boolean shouldIncrementResourceCount = projectRole != null && 
Role.Admin == projectRole;
+            try (CheckedReservation cr = new CheckedReservation(userAccount, 
ResourceType.project, shouldIncrementResourceCount ? 1L : 0L, reservationDao, 
_resourceLimitMgr)) {
             if (assignUserToProject(project, user.getId(), 
user.getAccountId(), projectRole,
                     
Optional.ofNullable(role).map(ProjectRole::getId).orElse(null)) != null) {
+                if (shouldIncrementResourceCount) {
+                    
_resourceLimitMgr.incrementResourceCount(userAccount.getId(), 
ResourceType.project);
+                }
                 return true;
+            } else {
+                logger.warn("Failed to add user to project: {}", project);
+                return false;
+            }
+            } catch (ResourceAllocationException e) {
+                throw new RuntimeException(e);
             }
-            logger.warn("Failed to add user to project: {}", project);
-            return false;
         }
     }
 
@@ -652,14 +669,18 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
     }
 
     private void updateProjectAccount(ProjectAccountVO futureOwner, Role 
newAccRole, Long accountId) throws ResourceAllocationException {
-        
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(accountId), 
ResourceType.project);
+        Account account = _accountMgr.getAccount(accountId);
+        boolean shouldIncrementResourceCount = Role.Admin == newAccRole;
+
+        try (CheckedReservation checkedReservation = new 
CheckedReservation(account, ResourceType.project, shouldIncrementResourceCount 
? 1L : 0L, reservationDao, _resourceLimitMgr)) {
         futureOwner.setAccountRole(newAccRole);
         _projectAccountDao.update(futureOwner.getId(), futureOwner);
-        if (newAccRole != null && Role.Admin == newAccRole) {
+        if (shouldIncrementResourceCount) {
             _resourceLimitMgr.incrementResourceCount(accountId, 
ResourceType.project);
         } else {
             _resourceLimitMgr.decrementResourceCount(accountId, 
ResourceType.project);
         }
+        }
     }
 
     @Override
@@ -701,7 +722,8 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
                                     " doesn't belong to the project. Add it to 
the project first and then change the project's ownership");
                         }
 
-                        //do resource limit check
+                        try (CheckedReservation checkedReservation = new 
CheckedReservation(futureOwnerAccount, ResourceType.project, null, null, 1L, 
reservationDao, _resourceLimitMgr)) {
+
                         
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(futureOwnerAccount.getId()),
 ResourceType.project);
 
                         //unset the role for the old owner
@@ -714,7 +736,7 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
                         futureOwner.setAccountRole(Role.Admin);
                         _projectAccountDao.update(futureOwner.getId(), 
futureOwner);
                         
_resourceLimitMgr.incrementResourceCount(futureOwnerAccount.getId(), 
ResourceType.project);
-
+                        }
                     } else {
                         logger.trace("Future owner {}is already the owner of 
the project {}", newOwnerName, project);
                     }
@@ -857,13 +879,22 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
             if (account == null) {
                 throw new InvalidParameterValueException("Account information 
is required for assigning account to the project");
             }
+
+            boolean shouldIncrementResourceCount = projectRoleType != null && 
Role.Admin == projectRoleType;
+            try (CheckedReservation cr = new CheckedReservation(account, 
ResourceType.project, shouldIncrementResourceCount ? 1L : 0L, reservationDao, 
_resourceLimitMgr)) {
             if (assignAccountToProject(project, account.getId(), 
projectRoleType, null,
                     
Optional.ofNullable(projectRole).map(ProjectRole::getId).orElse(null)) != null) 
{
+                if (shouldIncrementResourceCount) {
+                    _resourceLimitMgr.incrementResourceCount(account.getId(), 
ResourceType.project);
+                }
                 return true;
             } else {
                 logger.warn("Failed to add account {} to project {}", 
accountName, project);
                 return false;
             }
+            } catch (ResourceAllocationException e) {
+                throw new RuntimeException(e);
+            }
         }
     }
 
@@ -1042,7 +1073,9 @@ public class ProjectManagerImpl extends ManagerBase 
implements ProjectManager, C
                 boolean success = true;
                 ProjectAccountVO projectAccount = 
_projectAccountDao.findByProjectIdUserId(projectId, user.getAccountId(), 
user.getId());
                 success = _projectAccountDao.remove(projectAccount.getId());
-
+                if (projectAccount.getAccountRole() == Role.Admin) {
+                    
_resourceLimitMgr.decrementResourceCount(user.getAccountId(), 
ResourceType.project);
+                }
                 if (success) {
                     logger.debug("Removed user {} from project. Removing any 
invite sent to the user", user);
                     ProjectInvitation invite = 
_projectInvitationDao.findByUserIdProjectId(user.getId(), user.getAccountId(),  
projectId);
diff --git 
a/server/src/main/java/com/cloud/resourcelimit/CheckedReservation.java 
b/server/src/main/java/com/cloud/resourcelimit/CheckedReservation.java
index 211ca65a9d8..8d2e19d475e 100644
--- a/server/src/main/java/com/cloud/resourcelimit/CheckedReservation.java
+++ b/server/src/main/java/com/cloud/resourcelimit/CheckedReservation.java
@@ -40,7 +40,7 @@ import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.exception.CloudRuntimeException;
 
 
-public class CheckedReservation  implements AutoCloseable {
+public class CheckedReservation implements Reserver {
     protected Logger logger = LogManager.getLogger(getClass());
 
     private static final int TRY_TO_GET_LOCK_TIME = 120;
@@ -174,7 +174,7 @@ public class CheckedReservation  implements AutoCloseable {
     }
 
     @Override
-    public void close() throws Exception {
+    public void close() {
         removeAllReservations();
     }
 
diff --git a/server/src/main/java/com/cloud/resourcelimit/Reserver.java 
b/server/src/main/java/com/cloud/resourcelimit/Reserver.java
new file mode 100644
index 00000000000..4d5e3ac30c5
--- /dev/null
+++ b/server/src/main/java/com/cloud/resourcelimit/Reserver.java
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.resourcelimit;
+
+public interface Reserver extends AutoCloseable {
+
+    void close();
+
+}
diff --git 
a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java 
b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
index 8db204cf177..01dcd1125da 100644
--- a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
+++ b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
@@ -1199,11 +1199,6 @@ public class ResourceLimitManagerImpl extends 
ManagerBase implements ResourceLim
             long newResourceCount = 0L;
             ResourceCountVO domainRC = null;
 
-            // calculate project count here
-            if (type == ResourceType.project) {
-                newResourceCount += 
_projectDao.countProjectsForDomain(domainId);
-            }
-
             if (type == ResourceType.network) {
                 newResourceCount += 
networkDomainDao.listDomainNetworkMapByDomain(domainId).size();
             }

Reply via email to