diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 4fbab200959..b3aa91a442a 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -70,7 +70,7 @@ public class EventTypes { public static final String EVENT_VM_REBOOT = "VM.REBOOT"; public static final String EVENT_VM_UPDATE = "VM.UPDATE"; public static final String EVENT_VM_UPGRADE = "VM.UPGRADE"; - public static final String EVENT_VM_SCALE = "VM.SCALE"; + public static final String EVENT_VM_DYNAMIC_SCALE = "VM.DYNAMIC.SCALE"; public static final String EVENT_VM_RESETPASSWORD = "VM.RESETPASSWORD"; public static final String EVENT_VM_RESETSSHKEY = "VM.RESETSSHKEY"; public static final String EVENT_VM_MIGRATE = "VM.MIGRATE"; @@ -93,7 +93,6 @@ public class EventTypes { public static final String EVENT_PROXY_STOP = "PROXY.STOP"; public static final String EVENT_PROXY_REBOOT = "PROXY.REBOOT"; public static final String EVENT_PROXY_HA = "PROXY.HA"; - public static final String EVENT_PROXY_SCALE = "PROXY.SCALE"; // VNC Console Events @@ -218,7 +217,6 @@ public class EventTypes { public static final String EVENT_SSVM_STOP = "SSVM.STOP"; public static final String EVENT_SSVM_REBOOT = "SSVM.REBOOT"; public static final String EVENT_SSVM_HA = "SSVM.HA"; - public static final String EVENT_SSVM_SCALE = "SSVM.SCALE"; // Service Offerings public static final String EVENT_SERVICE_OFFERING_CREATE = "SERVICE.OFFERING.CREATE"; diff --git a/api/src/org/apache/cloudstack/api/command/admin/systemvm/ScaleSystemVMCmd.java b/api/src/org/apache/cloudstack/api/command/admin/systemvm/ScaleSystemVMCmd.java index 61b457f6edf..94040df0b32 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/systemvm/ScaleSystemVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/systemvm/ScaleSystemVMCmd.java @@ -111,23 +111,17 @@ public class ScaleSystemVMCmd extends BaseAsyncCmd { response.setResponseName(getCommandName()); this.setResponseObject(response); } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to scale system vm"); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to upgrade system vm"); } } @Override public String getEventType() { - VirtualMachine.Type type = _mgr.findSystemVMTypeById(getId()); - if(type == VirtualMachine.Type.ConsoleProxy){ - return EventTypes.EVENT_PROXY_SCALE; - } - else{ - return EventTypes.EVENT_SSVM_SCALE; - } + return EventTypes.EVENT_VM_UPGRADE; } @Override public String getEventDescription() { - return "scaling system vm: " + getId() + " to service offering: " + getServiceOfferingId(); + return "Upgrading system vm: " + getId() + " to service offering: " + getServiceOfferingId(); } } diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java index ac044197987..44f55753545 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java @@ -86,9 +86,18 @@ public class ScaleVMCmd extends BaseAsyncCmd { return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked } + @Override + public String getEventType() { + return EventTypes.EVENT_VM_UPGRADE; + } + + @Override + public String getEventDescription() { + return "upgrading vm: " + getId() + " to service offering: " + getServiceOfferingId(); + } + @Override public void execute(){ - //UserContext.current().setEventDetails("Vm Id: "+getId()); UserVm result; try { result = _userVmService.upgradeVirtualMachine(this); @@ -114,14 +123,4 @@ public class ScaleVMCmd extends BaseAsyncCmd { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to scale vm"); } } - - @Override - public String getEventType() { - return EventTypes.EVENT_VM_SCALE; - } - - @Override - public String getEventDescription() { - return "scaling volume: " + getId() + " to service offering: " + getServiceOfferingId(); - } } \ No newline at end of file diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 29b35d1d1fe..dbb2f2a86d0 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -3202,6 +3202,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe public Map listCapabilities(ListCapabilitiesCmd cmd) { Map capabilities = new HashMap(); + Account caller = CallContext.current().getCallingAccount(); boolean securityGroupsEnabled = false; boolean elasticLoadBalancerEnabled = false; String supportELB = "false"; @@ -3729,6 +3730,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } @Override + @ActionEvent(eventType = EventTypes.EVENT_VM_UPGRADE, eventDescription = "Upgrading system VM", async = true) public VirtualMachine upgradeSystemVM(ScaleSystemVMCmd cmd) throws ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException, ConcurrentOperationException { VMInstanceVO vmInstance = _vmInstanceDao.findById(cmd.getId()); @@ -3740,7 +3742,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe VirtualMachine vm = _vmInstanceDao.findById(cmd.getId()); return vm; }else{ - return null; + throw new CloudRuntimeException("Failed to upgrade System VM"); } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 227a78532f5..4e09dac20fc 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -758,14 +758,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir /* * TODO: cleanup eventually - Refactored API call */ + // This method will be deprecated as we use ScaleVMCmd for both stopped VMs and running VMs public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) throws ResourceAllocationException { Long vmId = cmd.getId(); Long svcOffId = cmd.getServiceOfferingId(); - return upgradeStoppedVirtualMachine(vmId, svcOffId); - } - - - private UserVm upgradeStoppedVirtualMachine(Long vmId, Long svcOffId) throws ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); // Verify input parameters @@ -831,6 +827,70 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir vmInstance.getServiceOfferingId(), vmInstance.getTemplateId(), vmInstance.getHypervisorType().toString(), VirtualMachine.class.getName(), vmInstance.getUuid()); return _vmDao.findById(vmInstance.getId()); + } + + private UserVm upgradeStoppedVirtualMachine(Long vmId, Long svcOffId) throws ResourceAllocationException { + Account caller = CallContext.current().getCallingAccount(); + + // Verify input parameters + //UserVmVO vmInstance = _vmDao.findById(vmId); + VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); + if (vmInstance == null) { + throw new InvalidParameterValueException( + "unable to find a virtual machine with id " + vmId); + } + + _accountMgr.checkAccess(caller, null, true, vmInstance); + + // Check resource limits for CPU and Memory. + ServiceOfferingVO newServiceOffering = _offeringDao.findById(svcOffId); + ServiceOfferingVO currentServiceOffering = _offeringDao.findByIdIncludingRemoved(vmInstance.getServiceOfferingId()); + + int newCpu = newServiceOffering.getCpu(); + int newMemory = newServiceOffering.getRamSize(); + int currentCpu = currentServiceOffering.getCpu(); + int currentMemory = currentServiceOffering.getRamSize(); + + if (newCpu > currentCpu) { + _resourceLimitMgr.checkResourceLimit(caller, ResourceType.cpu, + newCpu - currentCpu); + } + if (newMemory > currentMemory) { + _resourceLimitMgr.checkResourceLimit(caller, ResourceType.memory, + newMemory - currentMemory); + } + + // Check that the specified service offering ID is valid + _itMgr.checkIfCanUpgrade(vmInstance, svcOffId); + + // remove diskAndMemory VM snapshots + List vmSnapshots = _vmSnapshotDao.findByVm(vmId); + for (VMSnapshotVO vmSnapshotVO : vmSnapshots) { + if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory){ + if(!_vmSnapshotMgr.deleteAllVMSnapshots(vmId, VMSnapshot.Type.DiskAndMemory)){ + String errMsg = "Failed to remove VM snapshot during upgrading, snapshot id " + vmSnapshotVO.getId(); + s_logger.debug(errMsg); + throw new CloudRuntimeException(errMsg); + } + + } + } + + _itMgr.upgradeVmDb(vmId, svcOffId); + + // Increment or decrement CPU and Memory count accordingly. + if (newCpu > currentCpu) { + _resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long (newCpu - currentCpu)); + } else if (currentCpu > newCpu) { + _resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long (currentCpu - newCpu)); + } + if (newMemory > currentMemory) { + _resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (newMemory - currentMemory)); + } else if (currentMemory > newMemory) { + _resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (currentMemory - newMemory)); + } + + return _vmDao.findById(vmInstance.getId()); } @@ -1083,17 +1143,30 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } @Override - @ActionEvent(eventType = EventTypes.EVENT_VM_SCALE, eventDescription = "scaling Vm") + @ActionEvent(eventType = EventTypes.EVENT_VM_UPGRADE, eventDescription = "Upgrading VM", async = true) public UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException{ Long vmId = cmd.getId(); Long newServiceOfferingId = cmd.getServiceOfferingId(); + CallContext.current().setEventDetails("Vm Id: " + vmId); + boolean result = upgradeVirtualMachine(vmId, newServiceOfferingId); if(result){ - return _vmDao.findById(vmId); - }else{ - return null; + UserVmVO vmInstance = _vmDao.findById(vmId); + if(vmInstance.getState().equals(State.Stopped)){ + // Generate usage event for VM upgrade + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_UPGRADE, vmInstance.getAccountId(), vmInstance.getDataCenterId(), vmInstance.getId(), vmInstance.getHostName(), + vmInstance.getServiceOfferingId(), vmInstance.getTemplateId(), vmInstance.getHypervisorType().toString(), VirtualMachine.class.getName(), vmInstance.getUuid()); + } + if(vmInstance.getState().equals(State.Running)){ + // Generate usage event for Dynamic scaling of VM + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_DYNAMIC_SCALE, vmInstance.getAccountId(), vmInstance.getDataCenterId(), vmInstance.getId(), vmInstance.getHostName(), + vmInstance.getServiceOfferingId(), vmInstance.getTemplateId(), vmInstance.getHypervisorType().toString(), VirtualMachine.class.getName(), vmInstance.getUuid()); + } + return vmInstance; + } else { + throw new CloudRuntimeException("Failed to scale the VM"); } } @@ -1135,7 +1208,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir @Override public boolean upgradeVirtualMachine(Long vmId, Long newServiceOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException{ - Account caller = CallContext.current().getCallingAccount(); // Verify input parameters VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); @@ -1144,7 +1216,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir upgradeStoppedVirtualMachine(vmId, newServiceOfferingId); return true; } + if(vmInstance.getState().equals(State.Running)){ + return upgradeRunningVirtualMachine(vmId, newServiceOfferingId); + } + return false; + } + private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException{ + + Account caller = CallContext.current().getCallingAccount(); + VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); if(vmInstance.getHypervisorType() != HypervisorType.XenServer && vmInstance.getHypervisorType() != HypervisorType.VMware){ throw new InvalidParameterValueException("This operation not permitted for this hypervisor of the vm"); } @@ -1237,13 +1318,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir // Decrement CPU and Memory count accordingly. if (newCpu > currentCpu) { _resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long (newCpu - currentCpu)); - } + } if (newMemory > currentMemory) { _resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (newMemory - currentMemory)); } } - - } } } diff --git a/usage/src/com/cloud/usage/UsageManagerImpl.java b/usage/src/com/cloud/usage/UsageManagerImpl.java index aa9def580a9..8dc62c39081 100644 --- a/usage/src/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/com/cloud/usage/UsageManagerImpl.java @@ -1080,6 +1080,51 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna UsageVMInstanceVO usageInstanceNew = new UsageVMInstanceVO(UsageTypes.ALLOCATED_VM, zoneId, event.getAccountId(), vmId, vmName, soId, templateId, hypervisorType, event.getCreateDate(), null); m_usageInstanceDao.persist(usageInstanceNew); + } else if (EventTypes.EVENT_VM_DYNAMIC_SCALE.equals(event.getType())) { + // Ending the running vm event + SearchCriteria sc = m_usageInstanceDao.createSearchCriteria(); + sc.addAnd("vmInstanceId", SearchCriteria.Op.EQ, Long.valueOf(vmId)); + sc.addAnd("endDate", SearchCriteria.Op.NULL); + sc.addAnd("usageType", SearchCriteria.Op.EQ, UsageTypes.RUNNING_VM); + List usageInstances = m_usageInstanceDao.search(sc, null); + if (usageInstances != null) { + if (usageInstances.size() > 1) { + s_logger.warn("found multiple entries for a vm running with id: " + vmId + ", ending them all..."); + } + for (UsageVMInstanceVO usageInstance : usageInstances) { + usageInstance.setEndDate(event.getCreateDate()); + m_usageInstanceDao.update(usageInstance); + } + } + + sc = m_usageInstanceDao.createSearchCriteria(); + sc.addAnd("vmInstanceId", SearchCriteria.Op.EQ, Long.valueOf(vmId)); + sc.addAnd("endDate", SearchCriteria.Op.NULL); + sc.addAnd("usageType", SearchCriteria.Op.EQ, UsageTypes.ALLOCATED_VM); + usageInstances = m_usageInstanceDao.search(sc, null); + if (usageInstances == null || (usageInstances.size() == 0)) { + s_logger.error("Cannot find allocated vm entry for a vm running with id: " + vmId); + } else if (usageInstances.size() == 1) { + UsageVMInstanceVO usageInstance = usageInstances.get(0); + if(usageInstance.getSerivceOfferingId() != soId){ + //Service Offering changed after Vm creation + //End current Allocated usage and create new Allocated Vm entry with new soId + usageInstance.setEndDate(event.getCreateDate()); + m_usageInstanceDao.update(usageInstance); + usageInstance.setServiceOfferingId(soId); + usageInstance.setStartDate(event.getCreateDate()); + usageInstance.setEndDate(null); + m_usageInstanceDao.persist(usageInstance); + } + } + + Long templateId = event.getTemplateId(); + String hypervisorType = event.getResourceType(); + + // add this VM to the usage helper table with new service offering Id + UsageVMInstanceVO usageInstanceNew = new UsageVMInstanceVO(UsageTypes.RUNNING_VM, zoneId, event.getAccountId(), vmId, vmName, + soId, templateId, hypervisorType, event.getCreateDate(), null); + m_usageInstanceDao.persist(usageInstanceNew); } }