diff --git a/api/src/com/cloud/deploy/DeploymentPlanner.java b/api/src/com/cloud/deploy/DeploymentPlanner.java index 915e56b97f1..668b6952f6a 100644 --- a/api/src/com/cloud/deploy/DeploymentPlanner.java +++ b/api/src/com/cloud/deploy/DeploymentPlanner.java @@ -121,5 +121,32 @@ public interface DeploymentPlanner extends Adapter { return false; } + + public boolean shouldAvoid(Cluster cluster) { + if (_dcIds != null && _dcIds.contains(cluster.getDataCenterId())) { + return true; + } + + if (_podIds != null && _podIds.contains(cluster.getPodId())) { + return true; + } + + if (_clusterIds != null && _clusterIds.contains(cluster.getId())) { + return true; + } + return false; + } + + public boolean shouldAvoid(Pod pod) { + if (_dcIds != null && _dcIds.contains(pod.getDataCenterId())) { + return true; + } + + if (_podIds != null && _podIds.contains(pod.getId())) { + return true; + } + + return false; + } } } diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index 4e1f23f985a..538a6fb5db5 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -38,6 +38,8 @@ public interface VirtualMachine extends RunningOn, ControlledEntity { ExpungeOperation, OperationSucceeded, OperationFailed, + MigrationFailedOnSource, + MigrationFailedOnDest, OperationRetry, OperationCancelled }; diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 4c00f6ef25d..ce44e1be6be 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -2159,9 +2159,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS if (capacityVOCpus != null && !capacityVOCpus.isEmpty()) { CapacityVO CapacityVOCpu = capacityVOCpus.get(0); long newTotalCpu = (long)(server.getCpus().longValue() * server.getSpeed().longValue()*_cpuOverProvisioningFactor); - if (CapacityVOCpu.getTotalCapacity() < newTotalCpu) { + if ((CapacityVOCpu.getTotalCapacity() <= newTotalCpu) || ((CapacityVOCpu.getUsedCapacity() + CapacityVOCpu.getReservedCapacity()) <= newTotalCpu)) { CapacityVOCpu.setTotalCapacity(newTotalCpu); - } else if (CapacityVOCpu.getUsedCapacity() + CapacityVOCpu.getReservedCapacity() > newTotalCpu && CapacityVOCpu.getUsedCapacity() < newTotalCpu) { + } else if ((CapacityVOCpu.getUsedCapacity() + CapacityVOCpu.getReservedCapacity() > newTotalCpu) && (CapacityVOCpu.getUsedCapacity() < newTotalCpu)) { CapacityVOCpu.setReservedCapacity(0); CapacityVOCpu.setTotalCapacity(newTotalCpu); } else { @@ -2180,12 +2180,12 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS capacityMem.addAnd("dataCenterId", SearchCriteria.Op.EQ, server.getDataCenterId()); capacityMem.addAnd("podId", SearchCriteria.Op.EQ, server.getPodId()); capacityMem.addAnd("capacityType", SearchCriteria.Op.EQ, CapacityVO.CAPACITY_TYPE_MEMORY); - List capacityVOMems = _capacityDao.search(capacitySC, null); + List capacityVOMems = _capacityDao.search(capacityMem, null); if (capacityVOMems != null && !capacityVOMems.isEmpty()) { CapacityVO CapacityVOMem = capacityVOMems.get(0); long newTotalMem = server.getTotalMemory(); - if (CapacityVOMem.getTotalCapacity() < newTotalMem) { + if (CapacityVOMem.getTotalCapacity() <= newTotalMem || (CapacityVOMem.getUsedCapacity() + CapacityVOMem.getReservedCapacity() <= newTotalMem)) { CapacityVOMem.setTotalCapacity(newTotalMem); } else if (CapacityVOMem.getUsedCapacity() + CapacityVOMem.getReservedCapacity() > newTotalMem && CapacityVOMem.getUsedCapacity() < newTotalMem) { CapacityVOMem.setReservedCapacity(0); diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index f6938435557..8990059cd71 100644 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -1,11 +1,12 @@ package com.cloud.deploy; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import javax.ejb.Local; +import org.apache.log4j.Logger; + import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; import com.cloud.dc.ClusterVO; @@ -26,7 +27,6 @@ import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.GuestOSVO; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; import com.cloud.template.VirtualMachineTemplate; @@ -35,8 +35,10 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; + @Local(value=DeploymentPlanner.class) public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { + private static final Logger s_logger = Logger.getLogger(FirstFitPlanner.class); @Inject private HostDao _hostDao; @Inject private CapacityDao _capacityDao; @Inject private DataCenterDao _dcDao; @@ -56,10 +58,12 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { int cpu_requested = offering.getCpu() * offering.getSpeed(); long ram_requested = offering.getRamSize() * 1024L * 1024L; + s_logger.debug("try to allocate a host from dc:" + plan.getDataCenterId() + ", pod:" + plan.getPodId() + ",cluster:" + plan.getClusterId() + + ", requested cpu: " + cpu_requested + ", requested ram: " + ram_requested); if (vm.getLastHostId() != null) { HostVO host = _hostDao.findById(vm.getLastHostId()); - if (host.getStatus() == Status.Up) { + if (host != null && host.getStatus() == Status.Up) { boolean canDepployToLastHost = deployToHost(host, cpu_requested, ram_requested, true, avoid); if (canDepployToLastHost) { Pod pod = _podDao.findById(vm.getPodId()); @@ -70,29 +74,52 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { } /*Go through all the pods/clusters under zone*/ - List pods; + List pods = null; if (plan.getPodId() != null) { - pods = new ArrayList(1); - pods.add(_podDao.findById(plan.getPodId())); - } else { - pods = _podDao.listByDataCenterId(plan.getDataCenterId()); - } + HostPodVO pod = _podDao.findById(plan.getPodId()); + if (pod != null && dc.getId() == pod.getDataCenterId()) { + pods = new ArrayList(1); + pods.add(pod); + } else { + s_logger.debug("Can't enforce the pod selector"); + return null; + } + } + + if (pods == null) + pods = _podDao.listByDataCenterId(plan.getDataCenterId()); + //Collections.shuffle(pods); for (HostPodVO hostPod : pods) { + if (avoid.shouldAvoid(hostPod)) { + continue; + } //Collections.shuffle(clusters); - List clusters; + List clusters = null; if (plan.getClusterId() != null) { - clusters = new ArrayList(1); - clusters.add(_clusterDao.findById(plan.getClusterId())); - } else { + ClusterVO cluster = _clusterDao.findById(plan.getClusterId()); + if (cluster != null && hostPod.getId() == cluster.getPodId()) { + clusters = new ArrayList(1); + clusters.add(cluster); + } else { + s_logger.debug("Can't enforce the cluster selector"); + return null; + } + } + + if (clusters == null) { clusters = _clusterDao.listByPodId(hostPod.getId()); } for (ClusterVO clusterVO : clusters) { + if (avoid.shouldAvoid(clusterVO)) { + continue; + } if (clusterVO.getHypervisorType() != vmProfile.getHypervisorType()) { + avoid.addCluster(clusterVO.getId()); continue; } @@ -111,8 +138,11 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { Host host = _hostDao.findById(hostVO.getId()); return new DeployDestination(dc, pod, cluster, host); } + avoid.addHost(hostVO.getId()); } + avoid.addCluster(clusterVO.getId()); } + avoid.addPod(hostPod.getId()); } return null; diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java index ea752049bd8..1037199a44b 100644 --- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -777,7 +777,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager { HostPodVO podVO = _podDao.findById(vm.getPodId()); _alertMgr.sendAlert(alertType, fromHost.getDataCenterId(), fromHost.getPodId(), "Unable to migrate vm " + vm.getHostName() + " from host " + fromHost.getName() + " in zone " + dcVO.getName() + " and pod " + podVO.getName(), "Migrate Command failed. Please check logs."); - _itMgr.stateTransitTo(vm, Event.OperationFailed, vm.getHostId()); + _itMgr.stateTransitTo(vm, Event.MigrationFailedOnSource, toHost.getId()); _agentMgr.maintenanceFailed(vm.getHostId()); Command cleanup = mgr.cleanup(vm, null); @@ -807,7 +807,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager { } catch (final OperationTimedoutException e) { s_logger.warn("Operation timed outfor " + vm.toString()); } - _itMgr.stateTransitTo(vm, Event.OperationFailed, toHost.getId()); + _itMgr.stateTransitTo(vm, Event.MigrationFailedOnDest, toHost.getId()); return (System.currentTimeMillis() >> 10) + _migrateRetryInterval; } diff --git a/server/src/com/cloud/vm/MauriceMoss.java b/server/src/com/cloud/vm/MauriceMoss.java index f83a0b41112..cc2c0f38701 100644 --- a/server/src/com/cloud/vm/MauriceMoss.java +++ b/server/src/com/cloud/vm/MauriceMoss.java @@ -94,6 +94,10 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.ItWorkVO.Type; import com.cloud.vm.VirtualMachine.Event; +import com.cloud.vm.dao.ConsoleProxyDao; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.SecondaryStorageVmDao; +import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @Local(value=VmManager.class) @@ -113,6 +117,10 @@ public class MauriceMoss implements VmManager, ClusterManagerListener { @Inject private ClusterManager _clusterMgr; @Inject private ItWorkDao _workDao; @Inject private CapacityDao _capacityDao; + @Inject private UserVmDao _userVmDao; + @Inject private DomainRouterDao _routerDao; + @Inject private ConsoleProxyDao _consoleDao; + @Inject private SecondaryStorageVmDao _secondaryDao; @Inject(adapter=DeploymentPlanner.class) private Adapters _planners; @@ -340,13 +348,15 @@ public class MauriceMoss implements VmManager, ClusterManagerListener { ExcludeList avoids = new ExcludeList(); int retry = _retry; - while (retry-- != 0) { // It's != so that it can match -1. + DeployDestination dest = null; + while (retry-- != 0) { // It's != so that it can match -1. + /*this will release resource allocated on dest host*/ if (retry < (_retry -1)) { - stateTransitTo(vm, Event.OperationRetry, null); + stateTransitTo(vm, Event.OperationRetry, dest.getHost().getId()); } VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, null, params); - DeployDestination dest = null; + for (DeploymentPlanner planner : _planners) { dest = planner.plan(vmProfile, plan, avoids); if (dest != null) { @@ -366,7 +376,7 @@ public class MauriceMoss implements VmManager, ClusterManagerListener { try { _storageMgr.prepare(vmProfile, dest); } catch (ConcurrentOperationException e) { - stateTransitTo(vm, Event.OperationFailed, null); + stateTransitTo(vm, Event.OperationFailed, dest.getHost().getId()); throw e; } catch (StorageUnavailableException e) { s_logger.warn("Unable to contact storage.", e); @@ -401,7 +411,7 @@ public class MauriceMoss implements VmManager, ClusterManagerListener { } } - stateTransitTo(vm, Event.OperationFailed, null); + stateTransitTo(vm, Event.OperationFailed, dest.getHost().getId()); if (s_logger.isDebugEnabled()) { s_logger.debug("Creation complete for VM " + vm); @@ -463,7 +473,7 @@ public class MauriceMoss implements VmManager, ClusterManagerListener { } boolean cleanup = false; - + VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); try { _networkMgr.release(profile); @@ -510,7 +520,7 @@ public class MauriceMoss implements VmManager, ClusterManagerListener { } private void setStateMachine() { - _stateMachine = new StateMachine2(_vmDao); + _stateMachine = new StateMachine2(); _stateMachine.addTransition(null, VirtualMachine.Event.CreateRequested, State.Creating); _stateMachine.addTransition(State.Creating, VirtualMachine.Event.OperationSucceeded, State.Stopped); @@ -534,6 +544,8 @@ public class MauriceMoss implements VmManager, ClusterManagerListener { _stateMachine.addTransition(State.Migrating, VirtualMachine.Event.MigrationRequested, State.Migrating); _stateMachine.addTransition(State.Migrating, VirtualMachine.Event.OperationSucceeded, State.Running); _stateMachine.addTransition(State.Migrating, VirtualMachine.Event.OperationFailed, State.Running); + _stateMachine.addTransition(State.Migrating, VirtualMachine.Event.MigrationFailedOnSource, State.Running); + _stateMachine.addTransition(State.Migrating, VirtualMachine.Event.MigrationFailedOnDest, State.Running); _stateMachine.addTransition(State.Migrating, VirtualMachine.Event.AgentReportRunning, State.Running); _stateMachine.addTransition(State.Migrating, VirtualMachine.Event.AgentReportStopped, State.Stopped); _stateMachine.addTransition(State.Stopping, VirtualMachine.Event.OperationSucceeded, State.Stopped); @@ -544,11 +556,20 @@ public class MauriceMoss implements VmManager, ClusterManagerListener { _stateMachine.addTransition(State.Expunging, VirtualMachine.Event.OperationFailed, State.Expunging); _stateMachine.addTransition(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging); - _stateMachine.registerListener(new VMStateListener(_capacityDao, _offeringDao, _vmDao)); + _stateMachine.registerListener(new VMStateListener(_capacityDao, _offeringDao)); } @Override public boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long id) { - return _stateMachine.transitTO(vm, e, id); + if (vm instanceof UserVmVO) { + return _stateMachine.transitTO(vm, e, id, _userVmDao); + } else if (vm instanceof ConsoleProxyVO) { + return _stateMachine.transitTO(vm, e, id, _consoleDao); + } else if (vm instanceof SecondaryStorageVmVO) { + return _stateMachine.transitTO(vm, e, id, _secondaryDao); + } else if (vm instanceof DomainRouterVO) { + return _stateMachine.transitTO(vm, e, id, _routerDao); + } + return false; } } diff --git a/server/src/com/cloud/vm/VMStateListener.java b/server/src/com/cloud/vm/VMStateListener.java index 6c753e3aab9..c295e5af101 100644 --- a/server/src/com/cloud/vm/VMStateListener.java +++ b/server/src/com/cloud/vm/VMStateListener.java @@ -7,6 +7,7 @@ import com.cloud.capacity.dao.CapacityDao; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.utils.db.Transaction; +import com.cloud.utils.fsm.StateDao; import com.cloud.utils.fsm.StateListener; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.dao.VMInstanceDao; @@ -15,25 +16,20 @@ public class VMStateListener implements StateListener vmDao) { + s_logger.debug("VM state transitted from :" + oldState + " to " + newState + " with event: " + event + + "vm's original host id: " + vm.getHostId() + " new host id: " + id); if (!transitionStatus) { - return true; + return false; } Transaction txn = Transaction.open(Transaction.CLOUD_DB); @@ -42,53 +38,58 @@ public class VMStateListener implements StateListener { +public interface ConsoleProxyDao extends GenericDao, StateDao { public void update(long id, int activeSession, Date updateTime, byte[] sessionDetails); diff --git a/server/src/com/cloud/vm/dao/ConsoleProxyDaoImpl.java b/server/src/com/cloud/vm/dao/ConsoleProxyDaoImpl.java index 3142e0ff471..2f112224087 100644 --- a/server/src/com/cloud/vm/dao/ConsoleProxyDaoImpl.java +++ b/server/src/com/cloud/vm/dao/ConsoleProxyDaoImpl.java @@ -39,7 +39,9 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.db.UpdateBuilder; import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.State; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.Event; @Local(value={ConsoleProxyDao.class}) public class ConsoleProxyDaoImpl extends GenericDaoBase implements ConsoleProxyDao { @@ -386,5 +388,40 @@ public class ConsoleProxyDaoImpl extends GenericDaoBase im } catch (Throwable e) { } return l; - } + } + + @Override + public boolean updateState(State oldState, Event event, + State newState, VMInstanceVO vm, Long hostId) { + if (newState == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("There's no way to transition from old state: " + oldState.toString() + " event: " + event.toString()); + } + return false; + } + + ConsoleProxyVO consoleVM = (ConsoleProxyVO)vm; + + SearchCriteria sc = StateChangeSearch.create(); + sc.setParameters("id", consoleVM.getId()); + sc.setParameters("states", oldState); + sc.setParameters("host", consoleVM.getHostId()); + sc.setParameters("update", consoleVM.getUpdated()); + + vm.incrUpdated(); + UpdateBuilder ub = getUpdateBuilder(consoleVM); + ub.set(consoleVM, "state", newState); + ub.set(consoleVM, "hostId", hostId); + ub.set(consoleVM, _updateTimeAttr, new Date()); + + int result = update(consoleVM, sc); + if (result == 0 && s_logger.isDebugEnabled()) { + ConsoleProxyVO vo = findById(consoleVM.getId()); + StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); + str.append(": DB Data={Host=").append(vo.getHostId()).append("; State=").append(vo.getState().toString()).append("; updated=").append(vo.getUpdated()); + str.append("} Stale Data: {Host=").append(consoleVM.getHostId()).append("; State=").append(consoleVM.getState().toString()).append("; updated=").append(consoleVM.getUpdated()).append("}"); + s_logger.debug(str.toString()); + } + return result > 0; + } } diff --git a/server/src/com/cloud/vm/dao/DomainRouterDao.java b/server/src/com/cloud/vm/dao/DomainRouterDao.java index 0956ed125f4..acf35488bb1 100755 --- a/server/src/com/cloud/vm/dao/DomainRouterDao.java +++ b/server/src/com/cloud/vm/dao/DomainRouterDao.java @@ -21,14 +21,17 @@ import java.util.List; import com.cloud.network.router.VirtualRouter.Role; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.State; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; /** * * DomainRouterDao implements */ -public interface DomainRouterDao extends GenericDao { +public interface DomainRouterDao extends GenericDao, StateDao { //@Deprecated //public boolean updateIf(DomainRouterVO router, State state, State... ifStates); diff --git a/server/src/com/cloud/vm/dao/DomainRouterDaoImpl.java b/server/src/com/cloud/vm/dao/DomainRouterDaoImpl.java index bf47e79396e..e6f286522c8 100755 --- a/server/src/com/cloud/vm/dao/DomainRouterDaoImpl.java +++ b/server/src/com/cloud/vm/dao/DomainRouterDaoImpl.java @@ -36,9 +36,12 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.State; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.Event; @Local(value = { DomainRouterDao.class }) public class DomainRouterDaoImpl extends GenericDaoBase implements DomainRouterDao { @@ -307,4 +310,39 @@ public class DomainRouterDaoImpl extends GenericDaoBase im sc.setParameters("network", networkConfigurationId); return findOneBy(sc); } + + @Override + public boolean updateState(State oldState, Event event, + State newState, VMInstanceVO vm, Long hostId) { + if (newState == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("There's no way to transition from old state: " + oldState.toString() + " event: " + event.toString()); + } + return false; + } + + DomainRouterVO routerVM = (DomainRouterVO)vm; + + SearchCriteria sc = StateChangeSearch.create(); + sc.setParameters("id", routerVM.getId()); + sc.setParameters("states", oldState); + sc.setParameters("host", routerVM.getHostId()); + sc.setParameters("update", routerVM.getUpdated()); + + vm.incrUpdated(); + UpdateBuilder ub = getUpdateBuilder(routerVM); + ub.set(routerVM, "state", newState); + ub.set(routerVM, "hostId", hostId); + ub.set(routerVM, _updateTimeAttr, new Date()); + + int result = update(routerVM, sc); + if (result == 0 && s_logger.isDebugEnabled()) { + DomainRouterVO vo = findById(routerVM.getId()); + StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); + str.append(": DB Data={Host=").append(vo.getHostId()).append("; State=").append(vo.getState().toString()).append("; updated=").append(vo.getUpdated()); + str.append("} Stale Data: {Host=").append(routerVM.getHostId()).append("; State=").append(routerVM.getState().toString()).append("; updated=").append(routerVM.getUpdated()).append("}"); + s_logger.debug(str.toString()); + } + return result > 0; + } } diff --git a/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java b/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java index d3e9e353a52..fcc05d0b22f 100644 --- a/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java +++ b/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java @@ -21,11 +21,13 @@ import java.util.List; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.State; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; -public interface SecondaryStorageVmDao extends GenericDao { +public interface SecondaryStorageVmDao extends GenericDao, StateDao { public List getSecStorageVmListInStates(long dataCenterId, State... states); public List getSecStorageVmListInStates(State... states); diff --git a/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java b/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java index 86f4819bde7..f55e972b938 100644 --- a/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java +++ b/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java @@ -34,9 +34,12 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.db.UpdateBuilder; +import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.State; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.Event; @Local(value={SecondaryStorageVmDao.class}) public class SecondaryStorageVmDaoImpl extends GenericDaoBase implements SecondaryStorageVmDao { @@ -209,5 +212,40 @@ public class SecondaryStorageVmDaoImpl extends GenericDaoBase sc = ZoneSearch.create(); sc.setParameters("zone", zoneId); return listBy(sc); + } + + @Override + public boolean updateState(State oldState, Event event, + State newState, VMInstanceVO vm, Long hostId) { + if (newState == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("There's no way to transition from old state: " + oldState.toString() + " event: " + event.toString()); + } + return false; + } + + SecondaryStorageVmVO secondaryVM = (SecondaryStorageVmVO)vm; + + SearchCriteria sc = StateChangeSearch.create(); + sc.setParameters("id", secondaryVM.getId()); + sc.setParameters("states", oldState); + sc.setParameters("host", secondaryVM.getHostId()); + sc.setParameters("update", secondaryVM.getUpdated()); + + vm.incrUpdated(); + UpdateBuilder ub = getUpdateBuilder(secondaryVM); + ub.set(secondaryVM, "state", newState); + ub.set(secondaryVM, "hostId", hostId); + ub.set(secondaryVM, _updateTimeAttr, new Date()); + + int result = update(secondaryVM, sc); + if (result == 0 && s_logger.isDebugEnabled()) { + SecondaryStorageVmVO vo = findById(secondaryVM.getId()); + StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); + str.append(": DB Data={Host=").append(vo.getHostId()).append("; State=").append(vo.getState().toString()).append("; updated=").append(vo.getUpdated()); + str.append("} Stale Data: {Host=").append(secondaryVM.getHostId()).append("; State=").append(secondaryVM.getState().toString()).append("; updated=").append(secondaryVM.getUpdated()).append("}"); + s_logger.debug(str.toString()); + } + return result > 0; } } diff --git a/server/src/com/cloud/vm/dao/UserVmDao.java b/server/src/com/cloud/vm/dao/UserVmDao.java index 2b73d629247..f62130db87d 100755 --- a/server/src/com/cloud/vm/dao/UserVmDao.java +++ b/server/src/com/cloud/vm/dao/UserVmDao.java @@ -22,11 +22,13 @@ import java.util.List; import com.cloud.uservm.UserVm; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; import com.cloud.vm.State; import com.cloud.vm.UserVmVO; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; -public interface UserVmDao extends GenericDao { +public interface UserVmDao extends GenericDao, StateDao { List listByAccountId(long id); List listByAccountAndPod(long accountId, long podId); diff --git a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java index 9061dcbeb11..5b3f4c55845 100755 --- a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java +++ b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java @@ -37,7 +37,9 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.UpdateBuilder; import com.cloud.vm.State; import com.cloud.vm.UserVmVO; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.Event; @Local(value={UserVmDao.class}) public class UserVmDaoImpl extends GenericDaoBase implements UserVmDao { @@ -311,4 +313,39 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use return findOneBy(sc); } + + @Override + public boolean updateState(State oldState, Event event, + State newState, VMInstanceVO vm, Long hostId) { + if (newState == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("There's no way to transition from old state: " + oldState.toString() + " event: " + event.toString()); + } + return false; + } + + UserVmVO userVM = (UserVmVO)vm; + + SearchCriteria sc = StateChangeSearch.create(); + sc.setParameters("id", userVM.getId()); + sc.setParameters("states", oldState); + sc.setParameters("host", userVM.getHostId()); + sc.setParameters("update", userVM.getUpdated()); + + vm.incrUpdated(); + UpdateBuilder ub = getUpdateBuilder(userVM); + ub.set(userVM, "state", newState); + ub.set(userVM, "hostId", hostId); + ub.set(userVM, _updateTimeAttr, new Date()); + + int result = update(userVM, sc); + if (result == 0 && s_logger.isDebugEnabled()) { + UserVmVO vo = findById(userVM.getId()); + StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); + str.append(": DB Data={Host=").append(vo.getHostId()).append("; State=").append(vo.getState().toString()).append("; updated=").append(vo.getUpdated()); + str.append("} Stale Data: {Host=").append(userVM.getHostId()).append("; State=").append(userVM.getState().toString()).append("; updated=").append(userVM.getUpdated()).append("}"); + s_logger.debug(str.toString()); + } + return result > 0; + } } diff --git a/utils/src/com/cloud/utils/fsm/StateListener.java b/utils/src/com/cloud/utils/fsm/StateListener.java index c54bff436b2..7923b302b8a 100644 --- a/utils/src/com/cloud/utils/fsm/StateListener.java +++ b/utils/src/com/cloud/utils/fsm/StateListener.java @@ -1,5 +1,5 @@ package com.cloud.utils.fsm; public interface StateListener { - public boolean processStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Long id); + public boolean processStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Long id, StateDao vmDao); } \ No newline at end of file diff --git a/utils/src/com/cloud/utils/fsm/StateMachine2.java b/utils/src/com/cloud/utils/fsm/StateMachine2.java index 0afa09e7e0a..403e6a02768 100644 --- a/utils/src/com/cloud/utils/fsm/StateMachine2.java +++ b/utils/src/com/cloud/utils/fsm/StateMachine2.java @@ -41,12 +41,12 @@ import com.cloud.utils.db.Transaction; public class StateMachine2> { private final HashMap _states = new HashMap(); private final StateEntry _initialStateEntry; - private StateDao _instanceDao; + private List> _listeners = new ArrayList>(); - public StateMachine2(StateDao dao) { + public StateMachine2() { _initialStateEntry = new StateEntry(null); - _instanceDao = dao; + } public void addTransition(S currentState, E event, S toState) { @@ -98,7 +98,7 @@ public class StateMachine2> { } - public boolean transitTO(V vo, E e, Long id) { + public boolean transitTO(V vo, E e, Long id, StateDao dao) { S currentState = vo.getState(); S nextState = getNextState(currentState, e); @@ -108,7 +108,7 @@ public class StateMachine2> { } for (StateListener listener : _listeners) { - transitionStatus = listener.processStateTransitionEvent(currentState, e, nextState, vo, transitionStatus, id); + transitionStatus = listener.processStateTransitionEvent(currentState, e, nextState, vo, transitionStatus, id, dao); } return transitionStatus;