/** * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. * * This software is licensed under the GNU General Public License v3 or later. * * It is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ package com.cloud.vm; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import javax.ejb.Local; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.api.Answer; import com.cloud.agent.api.StartAnswer; import com.cloud.agent.api.StartCommand; import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.manager.Commands; import com.cloud.cluster.ClusterManager; import com.cloud.cluster.ClusterManagerListener; import com.cloud.cluster.ManagementServerHostVO; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.dao.DomainDao; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventVO; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuru; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkVO; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume.VolumeType; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; import com.cloud.utils.Journal; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.Adapters; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.component.Inject; import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.StateListener; import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.ItWorkVO.Type; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.SecondaryStorageVmDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @Local(value=VirtualMachineManager.class) public class VirtualMachineManagerImpl implements VirtualMachineManager, ClusterManagerListener { private static final Logger s_logger = Logger.getLogger(VirtualMachineManagerImpl.class); String _name; @Inject private StorageManager _storageMgr; @Inject private NetworkManager _networkMgr; @Inject private AgentManager _agentMgr; @Inject private VMInstanceDao _vmDao; @Inject private ServiceOfferingDao _offeringDao; @Inject private VMTemplateDao _templateDao; @Inject private UserDao _userDao; @Inject private AccountDao _accountDao; @Inject private DomainDao _domainDao; @Inject private ClusterManager _clusterMgr; @Inject private ItWorkDao _workDao; @Inject private UserVmDao _userVmDao; @Inject private DomainRouterDao _routerDao; @Inject private ConsoleProxyDao _consoleDao; @Inject private SecondaryStorageVmDao _secondaryDao; @Inject private UsageEventDao _usageEventDao; @Inject private NicDao _nicsDao; @Inject(adapter=DeploymentPlanner.class) private Adapters _planners; @Inject(adapter=StateListener.class) private Adapters> _stateListner; Map> _vmGurus = new HashMap>(); Map _hvGurus = new HashMap(); private StateMachine2 _stateMachine; private int _retry; private long _nodeId; @Override public void registerGuru(VirtualMachine.Type type, VirtualMachineGuru guru) { synchronized(_vmGurus) { _vmGurus.put(type, guru); } } @Override @DB public T allocate(T vm, VMTemplateVO template, ServiceOfferingVO serviceOffering, Pair rootDiskOffering, List> dataDiskOfferings, List> networks, Map params, DeploymentPlan plan, HypervisorType hyperType, Account owner) throws InsufficientCapacityException { if (s_logger.isDebugEnabled()) { s_logger.debug("Allocating entries for VM: " + vm); } VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, serviceOffering, owner, params, hyperType); vm.setDataCenterId(plan.getDataCenterId()); if (plan.getPodId() != null) { vm.setPodId(plan.getPodId()); } assert (plan.getClusterId() == null && plan.getPoolId() == null) : "We currently don't support cluster and pool preset yet"; @SuppressWarnings("unchecked") VirtualMachineGuru guru = (VirtualMachineGuru)_vmGurus.get(vm.getType()); Transaction txn = Transaction.currentTxn(); txn.start(); vm = guru.persist(vm); if (s_logger.isDebugEnabled()) { s_logger.debug("Allocating nics for " + vm); } try { _networkMgr.allocate(vmProfile, networks); } catch (ConcurrentOperationException e) { throw new CloudRuntimeException("Concurrent operation while trying to allocate resources for the VM", e); } if (dataDiskOfferings == null) { dataDiskOfferings = new ArrayList>(0); } if (s_logger.isDebugEnabled()) { s_logger.debug("Allocaing disks for " + vm); } if (template.getFormat() == ImageFormat.ISO) { _storageMgr.allocateRawVolume(VolumeType.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner); } else { _storageMgr.allocateTemplatedVolume(VolumeType.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner); } for (Pair offering : dataDiskOfferings) { _storageMgr.allocateRawVolume(VolumeType.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner); } stateTransitTo(vm, Event.OperationSucceeded, null); txn.commit(); if (s_logger.isDebugEnabled()) { s_logger.debug("Allocation completed for VM: " + vm); } return vm; } protected void reserveNics(VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { // List nics = _nicsDao.listBy(vmProfile.getId()); // for (NicVO nic : nics) { // Pair implemented = _networkMgr.implementNetwork(nic.getNetworkId(), dest, context); // NetworkGuru concierge = implemented.first(); // NetworkVO network = implemented.second(); // NicProfile profile = null; // if (nic.getReservationStrategy() == ReservationStrategy.Start) { // nic.setState(Resource.State.Reserving); // nic.setReservationId(context.getReservationId()); // _nicsDao.update(nic.getId(), nic); // URI broadcastUri = nic.getBroadcastUri(); // if (broadcastUri == null) { // network.getBroadcastUri(); // } // // URI isolationUri = nic.getIsolationUri(); // // profile = new NicProfile(nic, network, broadcastUri, isolationUri); // concierge.reserve(profile, network, vmProfile, dest, context); // nic.setIp4Address(profile.getIp4Address()); // nic.setIp6Address(profile.getIp6Address()); // nic.setMacAddress(profile.getMacAddress()); // nic.setIsolationUri(profile.getIsolationUri()); // nic.setBroadcastUri(profile.getBroadCastUri()); // nic.setReserver(concierge.getName()); // nic.setState(Resource.State.Reserved); // nic.setNetmask(profile.getNetmask()); // nic.setGateway(profile.getGateway()); // nic.setAddressFormat(profile.getFormat()); // _nicsDao.update(nic.getId(), nic); // } else { // profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri()); // } // // for (NetworkElement element : _networkElements) { // if (s_logger.isDebugEnabled()) { // s_logger.debug("Asking " + element.getName() + " to prepare for " + nic); // } // element.prepare(network, profile, vmProfile, dest, context); // } // // vmProfile.addNic(profile); // _networksDao.changeActiveNicsBy(network.getId(), 1); // } } protected void prepareNics(VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context) { } @Override public T allocate(T vm, VMTemplateVO template, ServiceOfferingVO serviceOffering, Long rootSize, Pair dataDiskOffering, List> networks, DeploymentPlan plan, HypervisorType hyperType, Account owner) throws InsufficientCapacityException { List> diskOfferings = new ArrayList>(1); if (dataDiskOffering != null) { diskOfferings.add(dataDiskOffering); } return allocate(vm, template, serviceOffering, new Pair(serviceOffering, rootSize), diskOfferings, networks, null, plan, hyperType, owner); } @Override public T allocate(T vm, VMTemplateVO template, ServiceOfferingVO serviceOffering, List> networks, DeploymentPlan plan, HypervisorType hyperType, Account owner) throws InsufficientCapacityException { return allocate(vm, template, serviceOffering, new Pair(serviceOffering, null), null, networks, null, plan, hyperType, owner); } @SuppressWarnings("unchecked") private VirtualMachineGuru getVmGuru(T vm) { return (VirtualMachineGuru)_vmGurus.get(vm.getType()); } @Override public boolean expunge(T vm, User caller, Account account) throws ResourceUnavailableException { try { return advanceExpunge(vm, caller, account); } catch (OperationTimedoutException e) { throw new CloudRuntimeException("Operation timed out", e); } catch (ConcurrentOperationException e) { throw new CloudRuntimeException("Concurrent operation ", e); } } @Override public boolean advanceExpunge(T vm, User caller, Account account) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException { if (vm == null || vm.getRemoved() != null) { if (s_logger.isDebugEnabled()) { s_logger.debug("Unable to find vm or vm is destroyed: " + vm); } return true; } if (!this.advanceStop(vm, false, caller, account)) { if (s_logger.isDebugEnabled()) { s_logger.debug("Unable to stop the VM so we can't expunge it."); } } if (!stateTransitTo(vm, VirtualMachine.Event.ExpungeOperation, vm.getHostId())) { s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm.toString()); return false; } if (s_logger.isDebugEnabled()) { s_logger.debug("Destroying vm " + vm); } VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); _networkMgr.cleanupNics(profile); //Clean up volumes based on the vm's instance id _storageMgr.cleanupVolumes(vm.getId()); if (s_logger.isDebugEnabled()) { s_logger.debug("Expunged " + vm); } return true; } @Override public boolean start() { return true; } @Override public boolean stop() { return true; } @Override public boolean configure(String name, Map xmlParams) throws ConfigurationException { _name = name; ComponentLocator locator = ComponentLocator.getCurrentLocator(); ConfigurationDao configDao = locator.getDao(ConfigurationDao.class); Map params = configDao.getConfiguration(xmlParams); _retry = NumbersUtil.parseInt(params.get(Config.StartRetry.key()), 10); ReservationContextImpl.setComponents(_userDao, _domainDao, _accountDao); VirtualMachineProfileImpl.setComponents(_offeringDao, _templateDao, _accountDao); Adapters hvGurus = locator.getAdapters(HypervisorGuru.class); for (HypervisorGuru guru : hvGurus) { _hvGurus.put(guru.getHypervisorType(), guru); } _nodeId = _clusterMgr.getId(); _clusterMgr.registerListener(this); setStateMachine(); return true; } @Override public String getName() { return _name; } protected VirtualMachineManagerImpl() { } @Override public T start(T vm, Map params, User caller, Account account, HypervisorType hyperType) throws InsufficientCapacityException, ResourceUnavailableException { try { return advanceStart(vm, params, caller, account, hyperType); } catch (ConcurrentOperationException e) { throw new CloudRuntimeException("Unable to start a VM due to concurrent operation", e); } } private Answer getStartAnswer(Answer[] answers) { for (Answer ans : answers) { if (ans instanceof StartAnswer) { return ans; } } assert 1 == 0 : "Why there is no Start Answer???"; return null; } @Override public T advanceStart(T vm, Map params, User caller, Account account, HypervisorType hyperType) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { State state = vm.getState(); if (state == State.Running) { s_logger.debug("VM is already started: " + vm); return vm; } if (state == State.Starting) { } if (state != State.Stopped) { s_logger.debug("VM " + vm + " is not in a state to be started: " + state); return null; } if (s_logger.isDebugEnabled()) { s_logger.debug("Creating actual resources for VM " + vm); } Journal journal = new Journal.LogJournal("Creating " + vm, s_logger); ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, ItWorkVO.Type.Start, vm.getId()); work = _workDao.persist(work); ReservationContextImpl context = new ReservationContextImpl(work.getId(), journal, caller, account); ServiceOfferingVO offering = _offeringDao.findById(vm.getServiceOfferingId()); VMTemplateVO template = _templateDao.findById(vm.getTemplateId()); DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), vm.getPodId(), null, null); HypervisorGuru hvGuru; if (hyperType != null && !hyperType.equals(HypervisorType.None)) { hvGuru = _hvGurus.get(hyperType); } else { hvGuru = _hvGurus.get(template.getHypervisorType()); } @SuppressWarnings("unchecked") VirtualMachineGuru vmGuru = (VirtualMachineGuru)_vmGurus.get(vm.getType()); vm.setReservationId(work.getId()); ExcludeList avoids = new ExcludeList(); int retry = _retry; DeployDestination dest = null; while (retry-- != 0) { // It's != so that it can match -1. VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, null, params, hyperType); for (DeploymentPlanner planner : _planners) { dest = planner.plan(vmProfile, plan, avoids); if (dest != null) { avoids.addHost(dest.getHost().getId()); journal.record("Deployment found ", vmProfile, dest); break; } } if (dest == null) { if (retry != (_retry -1)) { stateTransitTo(vm, Event.OperationFailed, null); } throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId()); } if (retry == (_retry -1)) { if (!stateTransitTo(vm, Event.StartRequested, dest.getHost().getId())) { throw new ConcurrentOperationException("Unable to start vm " + vm + " due to concurrent operations"); } } else { stateTransitTo(vm, Event.OperationRetry, dest.getHost().getId()); } vm.setDataCenterId(dest.getDataCenter().getId()); vm.setPodId(dest.getPod().getId()); try { _storageMgr.prepare(vmProfile, dest); _networkMgr.prepare(vmProfile, dest, context); } catch (ConcurrentOperationException e) { stateTransitTo(vm, Event.OperationFailed, null); throw e; } catch (ResourceUnavailableException e) { s_logger.warn("Unable to contact storage.", e); avoids.addCluster(dest.getCluster().getId()); continue; } catch (InsufficientCapacityException e) { s_logger.warn("Insufficient capacity ", e); avoids.add(e); continue; } catch (RuntimeException e) { s_logger.warn("Failed to start instance " + vm, e); stateTransitTo(vm, Event.OperationFailed, null); return null; } vmGuru.finalizeVirtualMachineProfile(vmProfile, dest, context); VirtualMachineTO vmTO = hvGuru.implement(vmProfile); Commands cmds = new Commands(OnError.Revert); cmds.addCommand(new StartCommand(vmTO)); vmGuru.finalizeDeployment(cmds, vmProfile, dest, context); try { Answer[] answers = _agentMgr.send(dest.getHost().getId(), cmds); if (getStartAnswer(answers).getResult() && vmGuru.finalizeStart(cmds, vmProfile, dest, context)) { if (!stateTransitTo(vm, Event.OperationSucceeded, dest.getHost().getId())) { throw new CloudRuntimeException("Unable to transition to a new state."); } if(vm instanceof UserVm){ UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_START, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), vm.getServiceOfferingId(), vm.getTemplateId(), null); _usageEventDao.persist(usageEvent); } return vm; } s_logger.info("Unable to start VM on " + dest.getHost() + " due to " + answers[0].getDetails()); } catch (AgentUnavailableException e) { s_logger.debug("Unable to send the start command to host " + dest.getHost()); continue; } catch (OperationTimedoutException e) { s_logger.debug("Unable to send the start command to host " + dest.getHost()); continue; } } stateTransitTo(vm, Event.OperationFailed, null); if (s_logger.isDebugEnabled()) { s_logger.debug("Creation complete for VM " + vm); } return null; } @Override public boolean stop(T vm, User user, Account account) throws ResourceUnavailableException { try { return advanceStop(vm, false, user, account); } catch (OperationTimedoutException e) { throw new AgentUnavailableException("Unable to stop vm because the operation to stop timed out", vm.getHostId(), e); } catch (ConcurrentOperationException e) { throw new CloudRuntimeException("Unable to stop vm because of a concurrent operation", e); } } @Override public boolean advanceStop(T vm, boolean forced, User user, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException { State state = vm.getState(); if (state == State.Stopped) { if (s_logger.isDebugEnabled()) { s_logger.debug("VM is already stopped: " + vm); } return true; } if (state == State.Creating || state == State.Destroyed || state == State.Expunging || state == State.Error) { s_logger.debug("Stopped called on " + vm + " but the state is " + state); return true; } if (!stateTransitTo(vm, Event.StopRequested, vm.getHostId())) { throw new ConcurrentOperationException("VM is being operated on by someone else."); } if (vm.getHostId() == null) { s_logger.debug("Host id is null so we can't stop it. How did we get into here?"); return false; } String reservationId = vm.getReservationId(); StopCommand stop = new StopCommand(vm, vm.getInstanceName(), null); boolean stopped = false; StopAnswer answer = null; try { answer = (StopAnswer)_agentMgr.send(vm.getHostId(), stop); stopped = answer.getResult(); if (!stopped) { throw new CloudRuntimeException("Unable to stop the virtual machine due to " + answer.getDetails()); } else { UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_STOP, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), vm.getServiceOfferingId(), vm.getTemplateId(), null); _usageEventDao.persist(usageEvent); } } finally { if (!stopped) { if (!forced) { stateTransitTo(vm, Event.OperationFailed, vm.getHostId()); } else { s_logger.warn("Unable to actually stop " + vm + " but continue with release because it's a force stop"); } } } if (s_logger.isDebugEnabled()) { s_logger.debug(vm + " is stopped on the host. Proceeding to release resource held."); } boolean cleanup = false; VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); try { _networkMgr.release(profile, forced); s_logger.debug("Successfully released network resources for the vm " + vm); } catch (Exception e) { s_logger.warn("Unable to release some network resources.", e); cleanup = true; } try { _storageMgr.release(profile); s_logger.debug("Successfully released storage resources for the vm " + vm); } catch (Exception e) { s_logger.warn("Unable to release storage resources.", e); cleanup = true; } @SuppressWarnings("unchecked") VirtualMachineGuru guru = (VirtualMachineGuru)_vmGurus.get(vm.getType()); try { guru.finalizeStop(profile, vm.getHostId(), vm.getReservationId(), answer); } catch (Exception e) { s_logger.warn("Guru " + guru.getClass() + " has trouble processing stop "); cleanup = true; } vm.setReservationId(null); stateTransitTo(vm, Event.OperationSucceeded, null); if (cleanup) { ItWorkVO work = new ItWorkVO(reservationId, _nodeId, Type.Cleanup, vm.getId()); _workDao.persist(work); } return stopped; } @Override public void onManagementNodeJoined(List nodeList, long selfNodeId) { } @Override public void onManagementNodeLeft(List nodeList, long selfNodeId) { } private void setStateMachine() { _stateMachine = new StateMachine2(); _stateMachine.addTransition(null, VirtualMachine.Event.CreateRequested, State.Creating); _stateMachine.addTransition(State.Creating, VirtualMachine.Event.OperationSucceeded, State.Stopped); _stateMachine.addTransition(State.Creating, VirtualMachine.Event.OperationFailed, State.Error); _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.StartRequested, State.Starting); _stateMachine.addTransition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging); _stateMachine.addTransition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging); _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.DestroyRequested, State.Destroyed); _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.StopRequested, State.Stopped); _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.AgentReportStopped, State.Stopped); _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.OperationFailed, State.Error); _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.ExpungeOperation, State.Expunging); _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); _stateMachine.addTransition(State.Starting, VirtualMachine.Event.OperationRetry, State.Starting); _stateMachine.addTransition(State.Starting, VirtualMachine.Event.OperationSucceeded, State.Running); _stateMachine.addTransition(State.Starting, VirtualMachine.Event.OperationFailed, State.Stopped); _stateMachine.addTransition(State.Starting, VirtualMachine.Event.AgentReportRunning, State.Running); _stateMachine.addTransition(State.Starting, VirtualMachine.Event.AgentReportStopped, State.Stopped); _stateMachine.addTransition(State.Starting, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); _stateMachine.addTransition(State.Destroyed, VirtualMachine.Event.RecoveryRequested, State.Stopped); _stateMachine.addTransition(State.Destroyed, VirtualMachine.Event.ExpungeOperation, State.Expunging); _stateMachine.addTransition(State.Creating, VirtualMachine.Event.MigrationRequested, State.Destroyed); _stateMachine.addTransition(State.Running, VirtualMachine.Event.MigrationRequested, State.Migrating); _stateMachine.addTransition(State.Running, VirtualMachine.Event.AgentReportRunning, State.Running); _stateMachine.addTransition(State.Running, VirtualMachine.Event.AgentReportStopped, State.Stopped); _stateMachine.addTransition(State.Running, VirtualMachine.Event.StopRequested, State.Stopping); _stateMachine.addTransition(State.Running, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); _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); _stateMachine.addTransition(State.Migrating, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); _stateMachine.addTransition(State.Stopping, VirtualMachine.Event.OperationFailed, State.Running); _stateMachine.addTransition(State.Stopping, VirtualMachine.Event.AgentReportRunning, State.Running); _stateMachine.addTransition(State.Stopping, VirtualMachine.Event.AgentReportStopped, State.Stopped); _stateMachine.addTransition(State.Stopping, VirtualMachine.Event.StopRequested, State.Stopping); _stateMachine.addTransition(State.Stopping, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); _stateMachine.addTransition(State.Expunging, VirtualMachine.Event.OperationFailed, State.Expunging); _stateMachine.addTransition(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging); _stateMachine.registerListeners(_stateListner); } @Override public boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long 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); } else { return _stateMachine.transitTO(vm, e, id, _vmDao); } } @Override public boolean remove(T vm, User user, Account caller) { return _vmDao.remove(vm.getId()); } @Override public boolean destroy(T vm, User user, Account caller) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException { if (s_logger.isDebugEnabled()) { s_logger.debug("Destroying vm " + vm.toString()); } if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) { if (s_logger.isDebugEnabled()) { s_logger.debug("Unable to find vm or vm is destroyed: " + vm); } return true; } if (!advanceStop(vm, false, user, caller)) { s_logger.debug("Unable to stop " + vm); return false; } if (!stateTransitTo(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId())) { s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm.toString()); return false; } return true; } }