diff --git a/api/src/com/cloud/agent/api/ScaleVmCommand.java b/api/src/com/cloud/agent/api/ScaleVmCommand.java index e5078d5e8c0..35d22ad9d96 100644 --- a/api/src/com/cloud/agent/api/ScaleVmCommand.java +++ b/api/src/com/cloud/agent/api/ScaleVmCommand.java @@ -40,14 +40,14 @@ public class ScaleVmCommand extends Command { } public ScaleVmCommand(String vmName, int cpus, - Integer speed, long minRam, long maxRam) { + Integer speed, long minRam, long maxRam, boolean limitCpuUse) { super(); this.vmName = vmName; this.cpus = cpus; - //this.speed = speed; + this.speed = speed; this.minRam = minRam; this.maxRam = maxRam; - this.vm = new VirtualMachineTO(1L, vmName, null, cpus, null, minRam, maxRam, null, null, false, false, null); + this.vm = new VirtualMachineTO(1L, vmName, null, cpus, speed, minRam, maxRam, null, null, false, false, null); /*vm.setName(vmName); vm.setCpus(cpus); vm.setRam(minRam, maxRam);*/ diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index ef226722b49..8f807d450c7 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -41,7 +41,6 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I Destroyed(false, "VM is marked for destroy."), Expunging(true, "VM is being expunged."), Migrating(true, "VM is being migrated. host id holds to from host"), - Reconfiguring(true, "VM is being reconfigured to a new service offering"), Error(false, "VM is in error"), Unknown(false, "VM state is unknown."), Shutdowned(false, "VM is shutdowned from inside"); @@ -96,9 +95,6 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I s_fsm.addTransition(State.Running, VirtualMachine.Event.StopRequested, State.Stopping); s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportMigrated, State.Running); - s_fsm.addTransition(State.Running, VirtualMachine.Event.ReconfiguringRequested, State.Reconfiguring); - s_fsm.addTransition(State.Reconfiguring, VirtualMachine.Event.OperationSucceeded, State.Running); - s_fsm.addTransition(State.Reconfiguring, VirtualMachine.Event.OperationFailed, State.Running); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.MigrationRequested, State.Migrating); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationSucceeded, State.Running); s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationFailed, State.Running); @@ -181,7 +177,6 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I AgentReportMigrated, RevertRequested, SnapshotRequested, - ReconfiguringRequested }; public enum Type { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index e38231cc19a..6e9cd43d88e 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -339,7 +339,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Inject protected SecurityGroupDao _securityGroupDao; @Inject - protected CapacityManager _capacityMgr;; + protected CapacityManager _capacityMgr; @Inject protected VMInstanceDao _vmInstanceDao; @Inject @@ -1043,7 +1043,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use public UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws InvalidParameterValueException { Long vmId = cmd.getId(); - Long newSvcOffId = cmd.getServiceOfferingId(); + Long newServiceOfferingId = cmd.getServiceOfferingId(); Account caller = UserContext.current().getCaller(); // Verify input parameters @@ -1055,14 +1055,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _accountMgr.checkAccess(caller, null, true, vmInstance); // Check that the specified service offering ID is valid - _itMgr.checkIfCanUpgrade(vmInstance, newSvcOffId); + _itMgr.checkIfCanUpgrade(vmInstance, newServiceOfferingId); //Check if its a scale "up" - ServiceOffering newServiceOffering = _configMgr.getServiceOffering(newSvcOffId); + ServiceOffering newServiceOffering = _configMgr.getServiceOffering(newServiceOfferingId); ServiceOffering oldServiceOffering = _configMgr.getServiceOffering(vmInstance.getServiceOfferingId()); if(newServiceOffering.getSpeed() <= oldServiceOffering.getSpeed() && newServiceOffering.getRamSize() <= oldServiceOffering.getRamSize()){ - throw new InvalidParameterValueException("Only scaling up the vm is supported"); + throw new InvalidParameterValueException("Only scaling up the vm is supported, new service offering should have both cpu and memory greater than the old values"); } // Dynamically upgrade the running vms @@ -1073,38 +1073,41 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use try{ // #1 Check existing host has capacity boolean existingHostHasCapacity = _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), newServiceOffering.getSpeed() - oldServiceOffering.getSpeed(), - (newServiceOffering.getRamSize() - oldServiceOffering.getRamSize()) * 1024L * 1024L, false, ApiDBUtils.getCpuOverprovisioningFactor(), 1f, false); + (newServiceOffering.getRamSize() - oldServiceOffering.getRamSize()) * 1024L * 1024L, false, ApiDBUtils.getCpuOverprovisioningFactor(), 1f, false); // TO DO fill it with mem. // #2 migrate the vm if host doesn't have capacity if (!existingHostHasCapacity){ - vmInstance = _itMgr.scale(vmInstance.getType(), vmInstance, newSvcOffId); - }else{ - vmInstance.setSameHost(existingHostHasCapacity); + vmInstance = _itMgr.findHostAndMigrate(vmInstance.getType(), vmInstance, newServiceOfferingId); } // #3 scale the vm now - vmInstance = _itMgr.reConfigureVm(vmInstance, newServiceOffering, existingHostHasCapacity); + _itMgr.upgradeVmDb(vmId, newServiceOfferingId); + vmInstance = _vmInstanceDao.findById(vmId); + vmInstance = _itMgr.reConfigureVm(vmInstance, oldServiceOffering, existingHostHasCapacity); success = true; + return _vmDao.findById(vmInstance.getId()); }catch(InsufficientCapacityException e ){ - s_logger.warn("Recieved exception while scaling ",e); + s_logger.warn("Received exception while scaling ",e); } catch (ResourceUnavailableException e) { - s_logger.warn("Recieved exception while scaling ",e); + s_logger.warn("Received exception while scaling ",e); } catch (ConcurrentOperationException e) { - s_logger.warn("Recieved exception while scaling ",e); + s_logger.warn("Received exception while scaling ",e); } catch (VirtualMachineMigrationException e) { - s_logger.warn("Recieved exception while scaling ",e); + s_logger.warn("Received exception while scaling ",e); } catch (ManagementServerException e) { - s_logger.warn("Recieved exception while scaling ",e); + s_logger.warn("Received exception while scaling ",e); + }finally{ + if(!success){ + _itMgr.upgradeVmDb(vmId, oldServiceOffering.getId()); // rollback + } } } if (!success) return null; } - //Update the DB. - _itMgr.upgradeVmDb(vmId, newSvcOffId); - return _vmDao.findById(vmInstance.getId()); + } @Override diff --git a/server/src/com/cloud/vm/VirtualMachineManager.java b/server/src/com/cloud/vm/VirtualMachineManager.java index b81d5330896..4a30d97cc54 100644 --- a/server/src/com/cloud/vm/VirtualMachineManager.java +++ b/server/src/com/cloud/vm/VirtualMachineManager.java @@ -190,7 +190,7 @@ public interface VirtualMachineManager extends Manager { VMInstanceVO reConfigureVm(VMInstanceVO vm, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException; - VMInstanceVO scale(VirtualMachine.Type vmType, VMInstanceVO vm, Long newSvcOfferingId) throws InsufficientCapacityException, + VMInstanceVO findHostAndMigrate(VirtualMachine.Type vmType, VMInstanceVO vm, Long newSvcOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, VirtualMachineMigrationException, ManagementServerException; diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 7631c2d9104..c845830bab1 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -36,6 +36,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.capacity.CapacityManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -175,6 +176,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected UserVmDao _userVmDao; @Inject + protected CapacityManager _capacityMgr; + @Inject protected NicDao _nicsDao; @Inject protected AccountManager _accountMgr; @@ -2659,7 +2662,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } @Override - public VMInstanceVO scale(VirtualMachine.Type vmType, VMInstanceVO vm, Long newSvcOfferingId) + public VMInstanceVO findHostAndMigrate(VirtualMachine.Type vmType, VMInstanceVO vm, Long newSvcOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, VirtualMachineMigrationException, ManagementServerException { VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); @@ -2729,53 +2732,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } - @Override - public VMInstanceVO reConfigureVm(VMInstanceVO vm , ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException { - ScaleVmCommand reconfigureCmd = new ScaleVmCommand(vm.getInstanceName(), newServiceOffering.getCpu(), - newServiceOffering.getSpeed(), newServiceOffering.getRamSize(), newServiceOffering.getRamSize()); - - Long dstHostId = vm.getHostId(); - ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Reconfiguring, vm.getType(), vm.getId()); - work.setStep(Step.Prepare); - work.setResourceType(ItWorkVO.ResourceType.Host); - work.setResourceId(vm.getHostId()); - work = _workDao.persist(work); - boolean success = false; - try { - vm.setNewSvcOfferingId(newServiceOffering.getId()); // Capacity update should be delta (new - old) offering - changeState(vm, Event.ReconfiguringRequested, dstHostId, work, Step.Reconfiguring); - - Answer reconfigureAnswer = _agentMgr.send(vm.getHostId(), reconfigureCmd); - if (!reconfigureAnswer.getResult()) { - s_logger.error("Unable to reconfigure due to " + reconfigureAnswer.getDetails()); - return null; - } - - changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Done); - success = true; - } catch (OperationTimedoutException e) { - throw new AgentUnavailableException("Operation timed out on reconfiguring " + vm, dstHostId); - } catch (AgentUnavailableException e) { - throw e; - } catch (NoTransitionException e) { - s_logger.info("Unable to change the state : " + e.getMessage()); - throw new ConcurrentOperationException("Unable to change the state : " + e.getMessage()); - }finally{ - work.setStep(Step.Done); - _workDao.update(work.getId(), work); - if(!success){ - try { - stateTransitTo(vm, Event.OperationFailed, vm.getHostId()); - } catch (NoTransitionException e) { - s_logger.warn(e.getMessage()); - } - } - } - - return vm; - - } - @Override public T migrateForScale(T vm, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException { @@ -2881,10 +2837,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } try { + long newServiceOfferingId = vm.getServiceOfferingId(); vm.setServiceOfferingId(oldSvcOfferingId); // release capacity for the old service offering only if (!changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Started)) { throw new ConcurrentOperationException("Unable to change the state for " + vm); } + vm.setServiceOfferingId(newServiceOfferingId); } catch (NoTransitionException e1) { throw new ConcurrentOperationException("Unable to change state due to " + e1.getMessage()); } @@ -2928,6 +2886,56 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac _workDao.update(work.getId(), work); } } + @Override + public VMInstanceVO reConfigureVm(VMInstanceVO vm , ServiceOffering oldServiceOffering, boolean reconfiguringOnExistingHost) throws ResourceUnavailableException, ConcurrentOperationException { + + long newServiceofferingId = vm.getServiceOfferingId(); + ServiceOffering newServiceOffering = _configMgr.getServiceOffering(newServiceofferingId); + ScaleVmCommand reconfigureCmd = new ScaleVmCommand(vm.getInstanceName(), newServiceOffering.getCpu(), + newServiceOffering.getSpeed(), newServiceOffering.getRamSize(), newServiceOffering.getRamSize(), newServiceOffering.getLimitCpuUse()); + + Long dstHostId = vm.getHostId(); + ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Running, vm.getType(), vm.getId()); + work.setStep(Step.Prepare); + work.setResourceType(ItWorkVO.ResourceType.Host); + work.setResourceId(vm.getHostId()); + work = _workDao.persist(work); + boolean success = false; + try { + if(reconfiguringOnExistingHost){ + vm.setServiceOfferingId(oldServiceOffering.getId()); + _capacityMgr.releaseVmCapacity(vm, false, false, vm.getHostId()); //release the old capacity + vm.setServiceOfferingId(newServiceofferingId); + _capacityMgr.allocateVmCapacity(vm, false); // lock the new capacity + } + //vm.setNewSvcOfferingId(newServiceOffering.getId()); // Capacity update should be delta (new - old) offering + //changeState(vm, Event.ReconfiguringRequested, dstHostId, work, Step.Reconfiguring); + + Answer reconfigureAnswer = _agentMgr.send(vm.getHostId(), reconfigureCmd); + if (!reconfigureAnswer.getResult()) { + s_logger.error("Unable to reconfigure due to " + reconfigureAnswer.getDetails()); + return null; + } + + //changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Done); + success = true; + } catch (OperationTimedoutException e) { + throw new AgentUnavailableException("Operation timed out on reconfiguring " + vm, dstHostId); + } catch (AgentUnavailableException e) { + throw e; + } finally{ + work.setStep(Step.Done); + _workDao.update(work.getId(), work); + if(!success){ + _capacityMgr.releaseVmCapacity(vm, false, false, vm.getHostId()); // release the new capacity + vm.setServiceOfferingId(oldServiceOffering.getId()); + _capacityMgr.allocateVmCapacity(vm, false); // allocate the old capacity + } + } + + return vm; + + } }