@@ -5493,13 +5493,135 @@ public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMach
54935493 return startVirtualMachine (vmId , podId , clusterId , hostId , additionalParams , deploymentPlannerToUse , true );
54945494 }
54955495
5496+ private Pair <UserVmVO , Map <VirtualMachineProfile .Param , Object >> startVirtualMachineUnchecked (UserVmVO vm , VMTemplateVO template , Long podId ,
5497+ Long clusterId , Long hostId , @ NotNull Map <VirtualMachineProfile .Param , Object > additionalParams , String deploymentPlannerToUse ,
5498+ boolean isExplicitHost , boolean isRootAdmin ) throws ResourceUnavailableException , InsufficientCapacityException {
5499+
5500+ // check if vm is security group enabled
5501+ if (_securityGroupMgr .isVmSecurityGroupEnabled (vm .getId ()) && _securityGroupMgr .getSecurityGroupsForVm (vm .getId ()).isEmpty ()
5502+ && !_securityGroupMgr .isVmMappedToDefaultSecurityGroup (vm .getId ()) && _networkModel .canAddDefaultSecurityGroup ()) {
5503+ // if vm is not mapped to security group, create a mapping
5504+ if (logger .isDebugEnabled ()) {
5505+ logger .debug ("Vm " + vm + " is security group enabled, but not mapped to default security group; creating the mapping automatically" );
5506+ }
5507+
5508+ SecurityGroup defaultSecurityGroup = _securityGroupMgr .getDefaultSecurityGroup (vm .getAccountId ());
5509+ if (defaultSecurityGroup != null ) {
5510+ List <Long > groupList = new ArrayList <>();
5511+ groupList .add (defaultSecurityGroup .getId ());
5512+ _securityGroupMgr .addInstanceToGroups (vm , groupList );
5513+ }
5514+ }
5515+
5516+ // Choose deployment planner
5517+ // Host takes 1st preference, Cluster takes 2nd preference and Pod takes 3rd
5518+ // Default behaviour is invoked when host, cluster or pod are not specified
5519+ Pod destinationPod = getDestinationPod (podId , isRootAdmin );
5520+ Cluster destinationCluster = getDestinationCluster (clusterId , isRootAdmin );
5521+ HostVO destinationHost = getDestinationHost (hostId , isRootAdmin , isExplicitHost );
5522+ DataCenterDeployment plan = null ;
5523+ boolean deployOnGivenHost = false ;
5524+ if (destinationHost != null ) {
5525+ logger .debug ("Destination Host to deploy the VM is specified, specifying a deployment plan to deploy the VM" );
5526+ _hostDao .loadHostTags (destinationHost );
5527+ validateStrictHostTagCheck (vm , destinationHost );
5528+
5529+ final ServiceOfferingVO offering = serviceOfferingDao .findById (vm .getId (), vm .getServiceOfferingId ());
5530+ Pair <Boolean , Boolean > cpuCapabilityAndCapacity = _capacityMgr .checkIfHostHasCpuCapabilityAndCapacity (destinationHost , offering , false );
5531+ if (!cpuCapabilityAndCapacity .first () || !cpuCapabilityAndCapacity .second ()) {
5532+ String errorMsg ;
5533+ if (!cpuCapabilityAndCapacity .first ()) {
5534+ errorMsg = String .format ("Cannot deploy the VM to specified host %s, requested CPU and speed is more than the host capability" , destinationHost );
5535+ } else {
5536+ 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 );
5537+ }
5538+ logger .info (errorMsg );
5539+ if (!AllowDeployVmIfGivenHostFails .value ()) {
5540+ throw new InvalidParameterValueException (errorMsg );
5541+ }
5542+ } else {
5543+ plan = new DataCenterDeployment (vm .getDataCenterId (), destinationHost .getPodId (), destinationHost .getClusterId (), destinationHost .getId (), null , null );
5544+ if (!AllowDeployVmIfGivenHostFails .value ()) {
5545+ deployOnGivenHost = true ;
5546+ }
5547+ }
5548+ } else if (destinationCluster != null ) {
5549+ logger .debug ("Destination Cluster to deploy the VM is specified, specifying a deployment plan to deploy the VM" );
5550+ plan = new DataCenterDeployment (vm .getDataCenterId (), destinationCluster .getPodId (), destinationCluster .getId (), null , null , null );
5551+ if (!AllowDeployVmIfGivenHostFails .value ()) {
5552+ deployOnGivenHost = true ;
5553+ }
5554+ } else if (destinationPod != null ) {
5555+ logger .debug ("Destination Pod to deploy the VM is specified, specifying a deployment plan to deploy the VM" );
5556+ plan = new DataCenterDeployment (vm .getDataCenterId (), destinationPod .getId (), null , null , null , null );
5557+ if (!AllowDeployVmIfGivenHostFails .value ()) {
5558+ deployOnGivenHost = true ;
5559+ }
5560+ }
5561+
5562+ // Set parameters
5563+ Map <VirtualMachineProfile .Param , Object > params = null ;
5564+ if (vm .isUpdateParameters ()) {
5565+ _vmDao .loadDetails (vm );
5566+ String password = getCurrentVmPasswordOrDefineNewPassword (String .valueOf (additionalParams .getOrDefault (VirtualMachineProfile .Param .VmPassword , "" )), vm , template );
5567+ if (!validPassword (password )) {
5568+ throw new InvalidParameterValueException ("A valid password for this virtual machine was not provided." );
5569+ }
5570+ // Check if an SSH key pair was selected for the instance and if so
5571+ // use it to encrypt & save the vm password
5572+ encryptAndStorePassword (vm , password );
5573+ params = createParameterInParameterMap (params , additionalParams , VirtualMachineProfile .Param .VmPassword , password );
5574+ }
5575+
5576+ if (additionalParams .containsKey (VirtualMachineProfile .Param .BootIntoSetup )) {
5577+ if (!HypervisorType .VMware .equals (vm .getHypervisorType ())) {
5578+ throw new InvalidParameterValueException (ApiConstants .BOOT_INTO_SETUP + " makes no sense for " + vm .getHypervisorType ());
5579+ }
5580+ Object paramValue = additionalParams .get (VirtualMachineProfile .Param .BootIntoSetup );
5581+ if (logger .isTraceEnabled ()) {
5582+ logger .trace ("It was specified whether to enter setup mode: " + paramValue .toString ());
5583+ }
5584+ params = createParameterInParameterMap (params , additionalParams , VirtualMachineProfile .Param .BootIntoSetup , paramValue );
5585+ }
5586+
5587+ VirtualMachineEntity vmEntity = _orchSrvc .getVirtualMachine (vm .getUuid ());
5588+
5589+ DeploymentPlanner planner = null ;
5590+ if (deploymentPlannerToUse != null ) {
5591+ // if set to null, the deployment planner would be later figured out either from global config var, or from
5592+ // the service offering
5593+ planner = _planningMgr .getDeploymentPlannerByName (deploymentPlannerToUse );
5594+ if (planner == null ) {
5595+ throw new InvalidParameterValueException ("Can't find a planner by name " + deploymentPlannerToUse );
5596+ }
5597+ }
5598+ vmEntity .setParamsToEntity (additionalParams );
5599+
5600+ UserVO callerUser = _userDao .findById (CallContext .current ().getCallingUserId ());
5601+ String reservationId = vmEntity .reserve (planner , plan , new ExcludeList (), Long .toString (callerUser .getId ()));
5602+ vmEntity .deploy (reservationId , Long .toString (callerUser .getId ()), params , deployOnGivenHost );
5603+
5604+ Pair <UserVmVO , Map <VirtualMachineProfile .Param , Object >> vmParamPair = new Pair (vm , params );
5605+ if (vm .isUpdateParameters ()) {
5606+ // this value is not being sent to the backend; need only for api
5607+ // display purposes
5608+ if (template .isEnablePassword ()) {
5609+ if (vm .getDetail (VmDetailConstants .PASSWORD ) != null ) {
5610+ userVmDetailsDao .removeDetail (vm .getId (), VmDetailConstants .PASSWORD );
5611+ }
5612+ vm .setUpdateParameters (false );
5613+ _vmDao .update (vm .getId (), vm );
5614+ }
5615+ }
5616+ return vmParamPair ;
5617+ }
5618+
54965619 @ Override
54975620 public Pair <UserVmVO , Map <VirtualMachineProfile .Param , Object >> startVirtualMachine (long vmId , Long podId , Long clusterId , Long hostId ,
54985621 @ NotNull Map <VirtualMachineProfile .Param , Object > additionalParams , String deploymentPlannerToUse , boolean isExplicitHost )
54995622 throws ConcurrentOperationException , ResourceUnavailableException , InsufficientCapacityException , ResourceAllocationException {
55005623 // Input validation
55015624 final Account callerAccount = CallContext .current ().getCallingAccount ();
5502- UserVO callerUser = _userDao .findById (CallContext .current ().getCallingUserId ());
55035625
55045626 // if account is removed, return error
55055627 if (callerAccount == null || callerAccount .getRemoved () != null ) {
@@ -5527,138 +5649,26 @@ public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMach
55275649 if (owner .getState () == Account .State .DISABLED ) {
55285650 throw new PermissionDeniedException (String .format ("The owner of %s is disabled: %s" , vm , owner ));
55295651 }
5530- Pair <UserVmVO , Map <VirtualMachineProfile .Param , Object >> vmParamPair ;
5531- try (CheckedReservation vmReservation = new CheckedReservation (owner , ResourceType .user_vm , vm .getId (), null , 1L , reservationDao , _resourceLimitMgr )) {
5532- VMTemplateVO template = _templateDao .findByIdIncludingRemoved (vm .getTemplateId ());
5533- if (VirtualMachineManager .ResourceCountRunningVMsonly .value ()) {
5534- // check if account/domain is with in resource limits to start a new vm
5535- ServiceOfferingVO offering = serviceOfferingDao .findById (vm .getId (), vm .getServiceOfferingId ());
5536- resourceLimitService .checkVmResourceLimit (owner , vm .isDisplayVm (), offering , template );
5537- }
5538- // check if vm is security group enabled
5539- if (_securityGroupMgr .isVmSecurityGroupEnabled (vmId ) && _securityGroupMgr .getSecurityGroupsForVm (vmId ).isEmpty ()
5540- && !_securityGroupMgr .isVmMappedToDefaultSecurityGroup (vmId ) && _networkModel .canAddDefaultSecurityGroup ()) {
5541- // if vm is not mapped to security group, create a mapping
5542- if (logger .isDebugEnabled ()) {
5543- logger .debug ("Vm " + vm + " is security group enabled, but not mapped to default security group; creating the mapping automatically" );
5544- }
5545-
5546- SecurityGroup defaultSecurityGroup = _securityGroupMgr .getDefaultSecurityGroup (vm .getAccountId ());
5547- if (defaultSecurityGroup != null ) {
5548- List <Long > groupList = new ArrayList <>();
5549- groupList .add (defaultSecurityGroup .getId ());
5550- _securityGroupMgr .addInstanceToGroups (vm , groupList );
5551- }
5552- }
5553- // Choose deployment planner
5554- // Host takes 1st preference, Cluster takes 2nd preference and Pod takes 3rd
5555- // Default behaviour is invoked when host, cluster or pod are not specified
5556- boolean isRootAdmin = _accountService .isRootAdmin (callerAccount .getId ());
5557- Pod destinationPod = getDestinationPod (podId , isRootAdmin );
5558- Cluster destinationCluster = getDestinationCluster (clusterId , isRootAdmin );
5559- HostVO destinationHost = getDestinationHost (hostId , isRootAdmin , isExplicitHost );
5560- DataCenterDeployment plan = null ;
5561- boolean deployOnGivenHost = false ;
5562- if (destinationHost != null ) {
5563- logger .debug ("Destination Host to deploy the VM is specified, specifying a deployment plan to deploy the VM" );
5564- _hostDao .loadHostTags (destinationHost );
5565- validateStrictHostTagCheck (vm , destinationHost );
5566-
5567- final ServiceOfferingVO offering = serviceOfferingDao .findById (vm .getId (), vm .getServiceOfferingId ());
5568- Pair <Boolean , Boolean > cpuCapabilityAndCapacity = _capacityMgr .checkIfHostHasCpuCapabilityAndCapacity (destinationHost , offering , false );
5569- if (!cpuCapabilityAndCapacity .first () || !cpuCapabilityAndCapacity .second ()) {
5570- String errorMsg ;
5571- if (!cpuCapabilityAndCapacity .first ()) {
5572- errorMsg = String .format ("Cannot deploy the VM to specified host %s, requested CPU and speed is more than the host capability" , destinationHost );
5573- } else {
5574- 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 );
5575- }
5576- logger .info (errorMsg );
5577- if (!AllowDeployVmIfGivenHostFails .value ()) {
5578- throw new InvalidParameterValueException (errorMsg );
5579- }
5580- } else {
5581- plan = new DataCenterDeployment (vm .getDataCenterId (), destinationHost .getPodId (), destinationHost .getClusterId (), destinationHost .getId (), null , null );
5582- if (!AllowDeployVmIfGivenHostFails .value ()) {
5583- deployOnGivenHost = true ;
5584- }
5585- }
5586- } else if (destinationCluster != null ) {
5587- logger .debug ("Destination Cluster to deploy the VM is specified, specifying a deployment plan to deploy the VM" );
5588- plan = new DataCenterDeployment (vm .getDataCenterId (), destinationCluster .getPodId (), destinationCluster .getId (), null , null , null );
5589- if (!AllowDeployVmIfGivenHostFails .value ()) {
5590- deployOnGivenHost = true ;
5591- }
5592- } else if (destinationPod != null ) {
5593- logger .debug ("Destination Pod to deploy the VM is specified, specifying a deployment plan to deploy the VM" );
5594- plan = new DataCenterDeployment (vm .getDataCenterId (), destinationPod .getId (), null , null , null , null );
5595- if (!AllowDeployVmIfGivenHostFails .value ()) {
5596- deployOnGivenHost = true ;
5597- }
5598- }
5599-
5600- // Set parameters
5601- Map <VirtualMachineProfile .Param , Object > params = null ;
5602- if (vm .isUpdateParameters ()) {
5603- _vmDao .loadDetails (vm );
5604-
5605- String password = getCurrentVmPasswordOrDefineNewPassword (String .valueOf (additionalParams .getOrDefault (VirtualMachineProfile .Param .VmPassword , "" )), vm , template );
5606-
5607- if (!validPassword (password )) {
5608- throw new InvalidParameterValueException ("A valid password for this virtual machine was not provided." );
5609- }
5610-
5611- // Check if an SSH key pair was selected for the instance and if so
5612- // use it to encrypt & save the vm password
5613- encryptAndStorePassword (vm , password );
5614-
5615- params = createParameterInParameterMap (params , additionalParams , VirtualMachineProfile .Param .VmPassword , password );
5616- }
5617-
5618- if (additionalParams .containsKey (VirtualMachineProfile .Param .BootIntoSetup )) {
5619- if (!HypervisorType .VMware .equals (vm .getHypervisorType ())) {
5620- throw new InvalidParameterValueException (ApiConstants .BOOT_INTO_SETUP + " makes no sense for " + vm .getHypervisorType ());
5621- }
5622- Object paramValue = additionalParams .get (VirtualMachineProfile .Param .BootIntoSetup );
5623- if (logger .isTraceEnabled ()) {
5624- logger .trace ("It was specified whether to enter setup mode: " + paramValue .toString ());
5625- }
5626- params = createParameterInParameterMap (params , additionalParams , VirtualMachineProfile .Param .BootIntoSetup , paramValue );
5627- }
5628-
5629- VirtualMachineEntity vmEntity = _orchSrvc .getVirtualMachine (vm .getUuid ());
5630-
5631- DeploymentPlanner planner = null ;
5632- if (deploymentPlannerToUse != null ) {
5633- // if set to null, the deployment planner would be later figured out either from global config var, or from
5634- // the service offering
5635- planner = _planningMgr .getDeploymentPlannerByName (deploymentPlannerToUse );
5636- if (planner == null ) {
5637- throw new InvalidParameterValueException ("Can't find a planner by name " + deploymentPlannerToUse );
5638- }
5639- }
5640- vmEntity .setParamsToEntity (additionalParams );
5641-
5642- String reservationId = vmEntity .reserve (planner , plan , new ExcludeList (), Long .toString (callerUser .getId ()));
5643- vmEntity .deploy (reservationId , Long .toString (callerUser .getId ()), params , deployOnGivenHost );
5652+ boolean isRootAdmin = _accountService .isRootAdmin (callerAccount .getId ());
56445653
5645- vmParamPair = new Pair (vm , params );
5646- if (vm != null && vm .isUpdateParameters ()) {
5647- // this value is not being sent to the backend; need only for api
5648- // display purposes
5649- if (template .isEnablePassword ()) {
5650- if (vm .getDetail (VmDetailConstants .PASSWORD ) != null ) {
5651- userVmDetailsDao .removeDetail (vm .getId (), VmDetailConstants .PASSWORD );
5652- }
5653- vm .setUpdateParameters (false );
5654- _vmDao .update (vm .getId (), vm );
5655- }
5654+ VMTemplateVO template = _templateDao .findByIdIncludingRemoved (vm .getTemplateId ());
5655+ if (VirtualMachineManager .ResourceCountRunningVMsonly .value ()) {
5656+ ServiceOfferingVO offering = serviceOfferingDao .findById (vm .getId (), vm .getServiceOfferingId ());
5657+ List <String > resourceLimitHostTags = resourceLimitService .getResourceLimitHostTags (offering , template );
5658+ try (CheckedReservation vmReservation = new CheckedReservation (owner , ResourceType .user_vm , resourceLimitHostTags , 1l , reservationDao , resourceLimitService );
5659+ CheckedReservation cpuReservation = new CheckedReservation (owner , ResourceType .cpu , resourceLimitHostTags , Long .valueOf (offering .getCpu ()), reservationDao , resourceLimitService );
5660+ CheckedReservation memReservation = new CheckedReservation (owner , ResourceType .memory , resourceLimitHostTags , Long .valueOf (offering .getRamSize ()), reservationDao , resourceLimitService );
5661+ ) {
5662+ return startVirtualMachineUnchecked (vm , template , podId , clusterId , hostId , additionalParams , deploymentPlannerToUse , isExplicitHost , isRootAdmin );
5663+ } catch (ResourceAllocationException | CloudRuntimeException e ) {
5664+ throw e ;
5665+ } catch (Exception e ) {
5666+ logger .error ("Failed to start VM {} : error during resource reservation and allocation" , e );
5667+ throw new CloudRuntimeException (e );
56565668 }
5657- } catch (Exception e ) {
5658- logger .error ("Failed to start VM {}" , vm , e );
5659- throw new CloudRuntimeException ("Failed to start VM " + vm , e );
5669+ } else {
5670+ return startVirtualMachineUnchecked (vm , template , podId , clusterId , hostId , additionalParams , deploymentPlannerToUse , isExplicitHost , isRootAdmin );
56605671 }
5661- return vmParamPair ;
56625672 }
56635673
56645674 /**
0 commit comments