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 4bcd509193fcbcfdbeb88743b029584882aa7e30
Author: Abhisar Sinha <[email protected]>
AuthorDate: Fri Feb 20 10:54:08 2026 +0530

    Fix resource limit reservation and check during StartVirtualMachine
---
 .../main/java/com/cloud/vm/UserVmManagerImpl.java  | 270 +++++++++++----------
 1 file changed, 140 insertions(+), 130 deletions(-)

diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java 
b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index 0e1c3bb9194..7fcf242ea20 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -5493,13 +5493,135 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         return startVirtualMachine(vmId, podId, clusterId, hostId, 
additionalParams, deploymentPlannerToUse, true);
     }
 
+    private Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> 
startVirtualMachineUnchecked(UserVmVO vm, VMTemplateVO template, Long podId,
+            Long clusterId, Long hostId, @NotNull 
Map<VirtualMachineProfile.Param, Object> additionalParams, String 
deploymentPlannerToUse,
+            boolean isExplicitHost, boolean isRootAdmin) throws 
ResourceUnavailableException, InsufficientCapacityException {
+
+        // check if vm is security group enabled
+        if (_securityGroupMgr.isVmSecurityGroupEnabled(vm.getId()) && 
_securityGroupMgr.getSecurityGroupsForVm(vm.getId()).isEmpty()
+                && 
!_securityGroupMgr.isVmMappedToDefaultSecurityGroup(vm.getId()) && 
_networkModel.canAddDefaultSecurityGroup()) {
+            // if vm is not mapped to security group, create a mapping
+            if (logger.isDebugEnabled()) {
+                logger.debug("Vm " + vm + " is security group enabled, but not 
mapped to default security group; creating the mapping automatically");
+            }
+
+            SecurityGroup defaultSecurityGroup = 
_securityGroupMgr.getDefaultSecurityGroup(vm.getAccountId());
+            if (defaultSecurityGroup != null) {
+                List<Long> groupList = new ArrayList<>();
+                groupList.add(defaultSecurityGroup.getId());
+                _securityGroupMgr.addInstanceToGroups(vm, groupList);
+            }
+        }
+
+        // Choose deployment planner
+        // Host takes 1st preference, Cluster takes 2nd preference and Pod 
takes 3rd
+        // Default behaviour is invoked when host, cluster or pod are not 
specified
+        Pod destinationPod = getDestinationPod(podId, isRootAdmin);
+        Cluster destinationCluster = getDestinationCluster(clusterId, 
isRootAdmin);
+        HostVO destinationHost = getDestinationHost(hostId, isRootAdmin, 
isExplicitHost);
+        DataCenterDeployment plan = null;
+        boolean deployOnGivenHost = false;
+        if (destinationHost != null) {
+            logger.debug("Destination Host to deploy the VM is specified, 
specifying a deployment plan to deploy the VM");
+            _hostDao.loadHostTags(destinationHost);
+            validateStrictHostTagCheck(vm, destinationHost);
+
+            final ServiceOfferingVO offering = 
serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
+            Pair<Boolean, Boolean> cpuCapabilityAndCapacity = 
_capacityMgr.checkIfHostHasCpuCapabilityAndCapacity(destinationHost, offering, 
false);
+            if (!cpuCapabilityAndCapacity.first() || 
!cpuCapabilityAndCapacity.second()) {
+                String errorMsg;
+                if (!cpuCapabilityAndCapacity.first()) {
+                    errorMsg = String.format("Cannot deploy the VM to 
specified host %s, requested CPU and speed is more than the host capability", 
destinationHost);
+                } else {
+                    errorMsg = String.format("Cannot deploy the VM to 
specified host %s, host does not have enough free CPU or RAM, please check the 
logs", destinationHost);
+                }
+                logger.info(errorMsg);
+                if (!AllowDeployVmIfGivenHostFails.value()) {
+                    throw new InvalidParameterValueException(errorMsg);
+                }
+            } else {
+                plan = new DataCenterDeployment(vm.getDataCenterId(), 
destinationHost.getPodId(), destinationHost.getClusterId(), 
destinationHost.getId(), null, null);
+                if (!AllowDeployVmIfGivenHostFails.value()) {
+                    deployOnGivenHost = true;
+                }
+            }
+        } else if (destinationCluster != null) {
+            logger.debug("Destination Cluster to deploy the VM is specified, 
specifying a deployment plan to deploy the VM");
+            plan = new DataCenterDeployment(vm.getDataCenterId(), 
destinationCluster.getPodId(), destinationCluster.getId(), null, null, null);
+            if (!AllowDeployVmIfGivenHostFails.value()) {
+                deployOnGivenHost = true;
+            }
+        } else if (destinationPod != null) {
+            logger.debug("Destination Pod to deploy the VM is specified, 
specifying a deployment plan to deploy the VM");
+            plan = new DataCenterDeployment(vm.getDataCenterId(), 
destinationPod.getId(), null, null, null, null);
+            if (!AllowDeployVmIfGivenHostFails.value()) {
+                deployOnGivenHost = true;
+            }
+        }
+
+        // Set parameters
+        Map<VirtualMachineProfile.Param, Object> params = null;
+        if (vm.isUpdateParameters()) {
+            _vmDao.loadDetails(vm);
+            String password = 
getCurrentVmPasswordOrDefineNewPassword(String.valueOf(additionalParams.getOrDefault(VirtualMachineProfile.Param.VmPassword,
 "")), vm, template);
+            if (!validPassword(password)) {
+                throw new InvalidParameterValueException("A valid password for 
this virtual machine was not provided.");
+            }
+            // Check if an SSH key pair was selected for the instance and if so
+            // use it to encrypt & save the vm password
+            encryptAndStorePassword(vm, password);
+            params = createParameterInParameterMap(params, additionalParams, 
VirtualMachineProfile.Param.VmPassword, password);
+        }
+
+        if 
(additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) {
+            if (!HypervisorType.VMware.equals(vm.getHypervisorType())) {
+                throw new 
InvalidParameterValueException(ApiConstants.BOOT_INTO_SETUP + " makes no sense 
for " + vm.getHypervisorType());
+            }
+            Object paramValue = 
additionalParams.get(VirtualMachineProfile.Param.BootIntoSetup);
+            if (logger.isTraceEnabled()) {
+                logger.trace("It was specified whether to enter setup mode: " 
+ paramValue.toString());
+            }
+            params = createParameterInParameterMap(params, additionalParams, 
VirtualMachineProfile.Param.BootIntoSetup, paramValue);
+        }
+
+        VirtualMachineEntity vmEntity = 
_orchSrvc.getVirtualMachine(vm.getUuid());
+
+        DeploymentPlanner planner = null;
+        if (deploymentPlannerToUse != null) {
+            // if set to null, the deployment planner would be later figured 
out either from global config var, or from
+            // the service offering
+            planner = 
_planningMgr.getDeploymentPlannerByName(deploymentPlannerToUse);
+            if (planner == null) {
+                throw new InvalidParameterValueException("Can't find a planner 
by name " + deploymentPlannerToUse);
+            }
+        }
+        vmEntity.setParamsToEntity(additionalParams);
+
+        UserVO callerUser = 
_userDao.findById(CallContext.current().getCallingUserId());
+        String reservationId = vmEntity.reserve(planner, plan, new 
ExcludeList(), Long.toString(callerUser.getId()));
+        vmEntity.deploy(reservationId, Long.toString(callerUser.getId()), 
params, deployOnGivenHost);
+
+        Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> vmParamPair = 
new Pair(vm, params);
+        if (vm.isUpdateParameters()) {
+            // this value is not being sent to the backend; need only for api
+            // display purposes
+            if (template.isEnablePassword()) {
+                if (vm.getDetail(VmDetailConstants.PASSWORD) != null) {
+                    userVmDetailsDao.removeDetail(vm.getId(), 
VmDetailConstants.PASSWORD);
+                }
+                vm.setUpdateParameters(false);
+                _vmDao.update(vm.getId(), vm);
+            }
+        }
+        return vmParamPair;
+    }
+
     @Override
     public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> 
startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId,
             @NotNull Map<VirtualMachineProfile.Param, Object> 
additionalParams, String deploymentPlannerToUse, boolean isExplicitHost)
             throws ConcurrentOperationException, ResourceUnavailableException, 
InsufficientCapacityException, ResourceAllocationException {
         // Input validation
         final Account callerAccount = 
CallContext.current().getCallingAccount();
-        UserVO callerUser = 
_userDao.findById(CallContext.current().getCallingUserId());
 
         // if account is removed, return error
         if (callerAccount == null || callerAccount.getRemoved() != null) {
@@ -5527,138 +5649,26 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         if (owner.getState() == Account.State.DISABLED) {
             throw new PermissionDeniedException(String.format("The owner of %s 
is disabled: %s", vm, owner));
         }
-        Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> vmParamPair;
-        try (CheckedReservation vmReservation = new CheckedReservation(owner, 
ResourceType.user_vm, vm.getId(), null, 1L, reservationDao, _resourceLimitMgr)) 
{
-            VMTemplateVO template = 
_templateDao.findByIdIncludingRemoved(vm.getTemplateId());
-            if (VirtualMachineManager.ResourceCountRunningVMsonly.value()) {
-                // check if account/domain is with in resource limits to start 
a new vm
-                ServiceOfferingVO offering = 
serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
-                resourceLimitService.checkVmResourceLimit(owner, 
vm.isDisplayVm(), offering, template);
-            }
-            // check if vm is security group enabled
-            if (_securityGroupMgr.isVmSecurityGroupEnabled(vmId) && 
_securityGroupMgr.getSecurityGroupsForVm(vmId).isEmpty()
-                    && 
!_securityGroupMgr.isVmMappedToDefaultSecurityGroup(vmId) && 
_networkModel.canAddDefaultSecurityGroup()) {
-                // if vm is not mapped to security group, create a mapping
-                if (logger.isDebugEnabled()) {
-                    logger.debug("Vm " + vm + " is security group enabled, but 
not mapped to default security group; creating the mapping automatically");
-                }
-
-                SecurityGroup defaultSecurityGroup = 
_securityGroupMgr.getDefaultSecurityGroup(vm.getAccountId());
-                if (defaultSecurityGroup != null) {
-                    List<Long> groupList = new ArrayList<>();
-                    groupList.add(defaultSecurityGroup.getId());
-                    _securityGroupMgr.addInstanceToGroups(vm, groupList);
-                }
-            }
-            // Choose deployment planner
-            // Host takes 1st preference, Cluster takes 2nd preference and Pod 
takes 3rd
-            // Default behaviour is invoked when host, cluster or pod are not 
specified
-            boolean isRootAdmin = 
_accountService.isRootAdmin(callerAccount.getId());
-            Pod destinationPod = getDestinationPod(podId, isRootAdmin);
-            Cluster destinationCluster = getDestinationCluster(clusterId, 
isRootAdmin);
-            HostVO destinationHost = getDestinationHost(hostId, isRootAdmin, 
isExplicitHost);
-            DataCenterDeployment plan = null;
-            boolean deployOnGivenHost = false;
-            if (destinationHost != null) {
-                logger.debug("Destination Host to deploy the VM is specified, 
specifying a deployment plan to deploy the VM");
-                _hostDao.loadHostTags(destinationHost);
-                validateStrictHostTagCheck(vm, destinationHost);
-
-                final ServiceOfferingVO offering = 
serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
-                Pair<Boolean, Boolean> cpuCapabilityAndCapacity = 
_capacityMgr.checkIfHostHasCpuCapabilityAndCapacity(destinationHost, offering, 
false);
-                if (!cpuCapabilityAndCapacity.first() || 
!cpuCapabilityAndCapacity.second()) {
-                    String errorMsg;
-                    if (!cpuCapabilityAndCapacity.first()) {
-                        errorMsg = String.format("Cannot deploy the VM to 
specified host %s, requested CPU and speed is more than the host capability", 
destinationHost);
-                    } else {
-                        errorMsg = String.format("Cannot deploy the VM to 
specified host %s, host does not have enough free CPU or RAM, please check the 
logs", destinationHost);
-                    }
-                    logger.info(errorMsg);
-                    if (!AllowDeployVmIfGivenHostFails.value()) {
-                        throw new InvalidParameterValueException(errorMsg);
-                    }
-                } else {
-                    plan = new DataCenterDeployment(vm.getDataCenterId(), 
destinationHost.getPodId(), destinationHost.getClusterId(), 
destinationHost.getId(), null, null);
-                    if (!AllowDeployVmIfGivenHostFails.value()) {
-                        deployOnGivenHost = true;
-                    }
-                }
-            } else if (destinationCluster != null) {
-                logger.debug("Destination Cluster to deploy the VM is 
specified, specifying a deployment plan to deploy the VM");
-                plan = new DataCenterDeployment(vm.getDataCenterId(), 
destinationCluster.getPodId(), destinationCluster.getId(), null, null, null);
-                if (!AllowDeployVmIfGivenHostFails.value()) {
-                    deployOnGivenHost = true;
-                }
-            } else if (destinationPod != null) {
-                logger.debug("Destination Pod to deploy the VM is specified, 
specifying a deployment plan to deploy the VM");
-                plan = new DataCenterDeployment(vm.getDataCenterId(), 
destinationPod.getId(), null, null, null, null);
-                if (!AllowDeployVmIfGivenHostFails.value()) {
-                    deployOnGivenHost = true;
-                }
-            }
-
-            // Set parameters
-            Map<VirtualMachineProfile.Param, Object> params = null;
-            if (vm.isUpdateParameters()) {
-                _vmDao.loadDetails(vm);
-
-                String password = 
getCurrentVmPasswordOrDefineNewPassword(String.valueOf(additionalParams.getOrDefault(VirtualMachineProfile.Param.VmPassword,
 "")), vm, template);
-
-                if (!validPassword(password)) {
-                    throw new InvalidParameterValueException("A valid password 
for this virtual machine was not provided.");
-                }
-
-                // Check if an SSH key pair was selected for the instance and 
if so
-                // use it to encrypt & save the vm password
-                encryptAndStorePassword(vm, password);
-
-                params = createParameterInParameterMap(params, 
additionalParams, VirtualMachineProfile.Param.VmPassword, password);
-            }
-
-            if 
(additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) {
-                if (!HypervisorType.VMware.equals(vm.getHypervisorType())) {
-                    throw new 
InvalidParameterValueException(ApiConstants.BOOT_INTO_SETUP + " makes no sense 
for " + vm.getHypervisorType());
-                }
-                Object paramValue = 
additionalParams.get(VirtualMachineProfile.Param.BootIntoSetup);
-                if (logger.isTraceEnabled()) {
-                    logger.trace("It was specified whether to enter setup 
mode: " + paramValue.toString());
-                }
-                params = createParameterInParameterMap(params, 
additionalParams, VirtualMachineProfile.Param.BootIntoSetup, paramValue);
-            }
-
-            VirtualMachineEntity vmEntity = 
_orchSrvc.getVirtualMachine(vm.getUuid());
-
-            DeploymentPlanner planner = null;
-            if (deploymentPlannerToUse != null) {
-                // if set to null, the deployment planner would be later 
figured out either from global config var, or from
-                // the service offering
-                planner = 
_planningMgr.getDeploymentPlannerByName(deploymentPlannerToUse);
-                if (planner == null) {
-                    throw new InvalidParameterValueException("Can't find a 
planner by name " + deploymentPlannerToUse);
-                }
-            }
-            vmEntity.setParamsToEntity(additionalParams);
-
-            String reservationId = vmEntity.reserve(planner, plan, new 
ExcludeList(), Long.toString(callerUser.getId()));
-            vmEntity.deploy(reservationId, Long.toString(callerUser.getId()), 
params, deployOnGivenHost);
+        boolean isRootAdmin = 
_accountService.isRootAdmin(callerAccount.getId());
 
-            vmParamPair = new Pair(vm, params);
-            if (vm != null && vm.isUpdateParameters()) {
-                // this value is not being sent to the backend; need only for 
api
-                // display purposes
-                if (template.isEnablePassword()) {
-                    if (vm.getDetail(VmDetailConstants.PASSWORD) != null) {
-                        userVmDetailsDao.removeDetail(vm.getId(), 
VmDetailConstants.PASSWORD);
-                    }
-                    vm.setUpdateParameters(false);
-                    _vmDao.update(vm.getId(), vm);
-                }
+        VMTemplateVO template = 
_templateDao.findByIdIncludingRemoved(vm.getTemplateId());
+        if (VirtualMachineManager.ResourceCountRunningVMsonly.value()) {
+            ServiceOfferingVO offering = 
serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
+            List<String> resourceLimitHostTags = 
resourceLimitService.getResourceLimitHostTags(offering, template);
+            try (CheckedReservation vmReservation = new 
CheckedReservation(owner, ResourceType.user_vm, resourceLimitHostTags, 1l, 
reservationDao, resourceLimitService);
+                 CheckedReservation cpuReservation = new 
CheckedReservation(owner, ResourceType.cpu, resourceLimitHostTags, 
Long.valueOf(offering.getCpu()), reservationDao, resourceLimitService);
+                 CheckedReservation memReservation = new 
CheckedReservation(owner, ResourceType.memory, resourceLimitHostTags, 
Long.valueOf(offering.getRamSize()), reservationDao, resourceLimitService);
+            ) {
+                return startVirtualMachineUnchecked(vm, template, podId, 
clusterId, hostId, additionalParams, deploymentPlannerToUse, isExplicitHost, 
isRootAdmin);
+            } catch (ResourceAllocationException | CloudRuntimeException  e) {
+                throw e;
+            } catch (Exception e) {
+                logger.error("Failed to start VM {} : error during resource 
reservation and allocation", e);
+                throw new CloudRuntimeException(e);
             }
-        } catch (Exception e) {
-            logger.error("Failed to start VM {}", vm, e);
-            throw new CloudRuntimeException("Failed to start VM " + vm, e);
+        } else {
+            return startVirtualMachineUnchecked(vm, template, podId, 
clusterId, hostId, additionalParams, deploymentPlannerToUse, isExplicitHost, 
isRootAdmin);
         }
-        return vmParamPair;
     }
 
     /**

Reply via email to