added more robust start code

This commit is contained in:
Alex Huang 2011-01-18 16:09:24 -08:00
parent 6a66fc58c2
commit e8f89004d9
13 changed files with 272 additions and 652 deletions

View File

@ -27,7 +27,6 @@ import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.AgentControlAnswer;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.ConsoleAccessAuthenticationAnswer;
import com.cloud.agent.api.ConsoleAccessAuthenticationCommand;
@ -36,6 +35,7 @@ import com.cloud.agent.api.GetVncPortAnswer;
import com.cloud.agent.api.GetVncPortCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupProxyCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.manager.Commands;
import com.cloud.configuration.dao.ConfigurationDao;
@ -282,14 +282,6 @@ public class AgentBasedConsoleProxyManager implements ConsoleProxyManager, Virtu
return new StopCommand(vm, vmName, null);
}
@Override
public void completeStartCommand(ConsoleProxyVO vm) {
}
@Override
public void completeStopCommand(ConsoleProxyVO vm) {
}
@Override
public Long convertToId(String vmName) {
if (!VirtualMachineName.isValidConsoleProxyName(vmName, _instance)) {
@ -346,13 +338,13 @@ public class AgentBasedConsoleProxyManager implements ConsoleProxyManager, Virtu
}
@Override
public boolean finalizeStart(Commands cmds, VirtualMachineProfile<ConsoleProxyVO> profile, DeployDestination dest, ReservationContext context) {
public boolean finalizeStart(VirtualMachineProfile<ConsoleProxyVO> profile, long hostId, Commands cmds, ReservationContext context) {
// TODO Auto-generated method stub
return false;
}
@Override
public void finalizeStop(VirtualMachineProfile<ConsoleProxyVO> profile, long hostId, String reservationId, Answer... answer) {
public void finalizeStop(VirtualMachineProfile<ConsoleProxyVO> profile, StopAnswer answer) {
// TODO Auto-generated method stub
}

View File

@ -48,6 +48,7 @@ import com.cloud.agent.api.ConsoleProxyLoadReportCommand;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupProxyCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.check.CheckSshAnswer;
import com.cloud.agent.api.check.CheckSshCommand;
@ -1416,16 +1417,6 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
}
}
@Override
public void completeStartCommand(ConsoleProxyVO vm) {
_itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportRunning, vm.getHostId());
}
@Override
public void completeStopCommand(ConsoleProxyVO vm) {
completeStopCommand(vm, VirtualMachine.Event.AgentReportStopped);
}
@DB
protected void completeStopCommand(ConsoleProxyVO proxy, VirtualMachine.Event ev) {
@ -1607,11 +1598,6 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
@Override
public boolean stop(ConsoleProxyVO proxy) throws ResourceUnavailableException {
if (!_itMgr.stateTransitTo(proxy, VirtualMachine.Event.StopRequested, proxy.getHostId())) {
s_logger.debug("Unable to stop console proxy: " + proxy.toString());
return false;
}
GlobalLock proxyLock = GlobalLock.getInternLock(getProxyLockName(proxy.getId()));
try {
if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) {
@ -1633,101 +1619,6 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
}
}
// @Override
// public boolean migrate(ConsoleProxyVO proxy, HostVO host) {
// HostVO fromHost = _hostDao.findById(proxy.getId());
//
// if (! _itMgr.stateTransitTo(proxy, VirtualMachine.Event.MigrationRequested, proxy.getHostId())) {
// s_logger.debug("State for " + proxy.toString() + " has changed so migration can not take place.");
// return false;
// }
//
// MigrateCommand cmd = new MigrateCommand(proxy.getInstanceName(), host.getPrivateIpAddress(), false);
// Answer answer = _agentMgr.easySend(fromHost.getId(), cmd);
// if (answer == null || !answer.getResult()) {
// return false;
// }
//
// _storageMgr.unshare(proxy, fromHost);
//
// return true;
// }
//
// @Override
// public boolean completeMigration(ConsoleProxyVO proxy, HostVO host) throws AgentUnavailableException, OperationTimedoutException {
//
// CheckVirtualMachineCommand cvm = new CheckVirtualMachineCommand(proxy.getInstanceName());
// CheckVirtualMachineAnswer answer = (CheckVirtualMachineAnswer) _agentMgr.send(host.getId(), cvm);
// if (!answer.getResult()) {
// s_logger.debug("Unable to complete migration for " + proxy.getId());
// _itMgr.stateTransitTo(proxy, VirtualMachine.Event.AgentReportStopped, null);
// return false;
// }
//
// State state = answer.getState();
// if (state == State.Stopped) {
// s_logger.warn("Unable to complete migration as we can not detect it on " + host.getId());
// _itMgr.stateTransitTo(proxy, VirtualMachine.Event.AgentReportStopped, null);
// return false;
// }
//
// _itMgr.stateTransitTo(proxy, VirtualMachine.Event.OperationSucceeded, host.getId());
// return true;
// }
//
// @Override
// public HostVO prepareForMigration(ConsoleProxyVO proxy) throws StorageUnavailableException {
//
// VMTemplateVO template = _templateDao.findById(proxy.getTemplateId());
// long routerId = proxy.getId();
// boolean mirroredVols = proxy.isMirroredVols();
// DataCenterVO dc = _dcDao.findById(proxy.getDataCenterId());
// HostPodVO pod = _podDao.findById(proxy.getPodId());
// StoragePoolVO sp = _storageMgr.getStoragePoolForVm(proxy.getId());
//
// List<VolumeVO> vols = _volsDao.findCreatedByInstance(routerId);
//
// String[] storageIps = new String[2];
// VolumeVO vol = vols.get(0);
// storageIps[0] = vol.getHostIp();
// if (mirroredVols && (vols.size() == 2)) {
// storageIps[1] = vols.get(1).getHostIp();
// }
//
// PrepareForMigrationCommand cmd = new PrepareForMigrationCommand(proxy.getName(), null, storageIps, vols, mirroredVols);
//
// HostVO routingHost = null;
// HashSet<Host> avoid = new HashSet<Host>();
//
// HostVO fromHost = _hostDao.findById(proxy.getHostId());
// if (fromHost.getClusterId() == null) {
// s_logger.debug("The host is not in a cluster");
// return null;
// }
// avoid.add(fromHost);
//
// while ((routingHost = (HostVO) _agentMgr.findHost(Host.Type.Routing, dc, pod, sp, _serviceOffering, template, proxy, fromHost, avoid)) != null) {
// avoid.add(routingHost);
//
// if (s_logger.isDebugEnabled()) {
// s_logger.debug("Trying to migrate router to host " + routingHost.getName());
// }
//
// if (!_storageMgr.share(proxy, vols, routingHost, false)) {
// s_logger.warn("Can not share " + proxy.getName());
// throw new StorageUnavailableException("Can not share " + proxy.getName(), vol.getPoolId());
// }
//
// Answer answer = _agentMgr.easySend(routingHost.getId(), cmd);
// if (answer != null && answer.getResult()) {
// return routingHost;
// }
// _storageMgr.unshare(proxy, vols, routingHost);
// }
//
// return null;
// }
private String getCapacityScanLockName() {
// to improve security, it may be better to return a unique mashed
// name(for example MD5 hashed)
@ -1985,7 +1876,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
}
@Override
public boolean finalizeStart(Commands cmds, VirtualMachineProfile<ConsoleProxyVO> profile, DeployDestination dest, ReservationContext context) {
public boolean finalizeStart(VirtualMachineProfile<ConsoleProxyVO> profile, long hostId, Commands cmds, ReservationContext context) {
CheckSshAnswer answer = (CheckSshAnswer)cmds.getAnswer("checkSsh");
if (!answer.getResult()) {
s_logger.warn("Unable to ssh to the VM: " + answer.getDetails());
@ -2053,6 +1944,6 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
}
@Override
public void finalizeStop(VirtualMachineProfile<ConsoleProxyVO> profile, long hostId, String reservationId, Answer... answer) {
public void finalizeStop(VirtualMachineProfile<ConsoleProxyVO> profile, StopAnswer answer) {
}
}

View File

@ -36,6 +36,7 @@ import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.StopAnswer;
import com.cloud.alert.AlertManager;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenterVO;
@ -72,6 +73,7 @@ import com.cloud.vm.VirtualMachine.Event;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachineGuru;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.VirtualMachineProfileImpl;
import com.cloud.vm.dao.VMInstanceDao;
/**
@ -270,6 +272,10 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
@Override
public void scheduleRestart(VMInstanceVO vm, final boolean investigate) {
Long hostId = vm.getHostId();
if (hostId == null) {
_itMgr.stateTransitTo(vm, Event.OperationFailed, null);
return;
}
VirtualMachineGuru<VMInstanceVO> mgr = findManager(vm.getType());
vm = mgr.findById(vm.getId());
if (!investigate) {
@ -297,7 +303,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
}
}
mgr.completeStopCommand(vm);
mgr.finalizeStop(new VirtualMachineProfileImpl<VMInstanceVO>(vm), null);
}
final List<HaWorkVO> items = _haDao.findPreviousHA(vm.getId());
@ -409,7 +415,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
return (System.currentTimeMillis() >> 10) + _restartRetryInterval;
}
mgr.completeStopCommand(vm);
mgr.finalizeStop(new VirtualMachineProfileImpl<VMInstanceVO>(vm), null);
work.setStep(Step.Scheduled);
_haDao.update(work.getId(), work);
@ -546,7 +552,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
if (fullSync) {
s_logger.debug("VM is in stopping state on full sync. Updating the status to stopped");
vm = info.mgr.findById(vm.getId());
info.mgr.completeStopCommand(vm);
info.mgr.finalizeStop(new VirtualMachineProfileImpl<VMInstanceVO>(vm), null);
command = info.mgr.cleanup(vm, agentName);
} else {
s_logger.debug("Ignoring VM in stopping mode: " + vm.getName());
@ -563,13 +569,13 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
if (fullSync) {
s_logger.debug("VM state is starting on full sync so updating it to running");
vm = info.mgr.findById(vm.getId());
info.mgr.completeStartCommand(vm);
info.mgr.finalizeStart(new VirtualMachineProfileImpl<VMInstanceVO>(vm), vm.getHostId(), null, null);
}
} else if (serverState == State.Stopping) {
if (fullSync) {
s_logger.debug("VM state is in stopping on fullsync so resend stop.");
vm = info.mgr.findById(vm.getId());
info.mgr.completeStopCommand(vm);
info.mgr.finalizeStop(new VirtualMachineProfileImpl<VMInstanceVO>(vm), null);
command = info.mgr.cleanup(vm, agentName);
} else {
s_logger.debug("VM is in stopping state so no action.");
@ -906,7 +912,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
Command cmd = mgr.cleanup(vm, null);
Answer ans = _agentMgr.send(work.getHostId(), cmd);
if (ans.getResult()) {
mgr.completeStopCommand(vm);
mgr.finalizeStop(new VirtualMachineProfileImpl<VMInstanceVO>(vm), (StopAnswer)ans);
s_logger.info("Successfully stopped " + vm.toString());
return null;
}

View File

@ -40,6 +40,7 @@ import com.cloud.agent.api.ModifySshKeysCommand;
import com.cloud.agent.api.NetworkUsageAnswer;
import com.cloud.agent.api.NetworkUsageCommand;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.check.CheckSshAnswer;
import com.cloud.agent.api.check.CheckSshCommand;
@ -89,7 +90,6 @@ import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.ha.HighAvailabilityManager;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.IPAddressVO;
import com.cloud.network.IpAddress;
@ -686,49 +686,6 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
}
}
@Override
public void completeStopCommand(final DomainRouterVO router) {
completeStopCommand(router, VirtualMachine.Event.AgentReportStopped);
}
@DB
public void completeStopCommand(final DomainRouterVO router, final VirtualMachine.Event ev) {
final long routerId = router.getId();
final Transaction txn = Transaction.currentTxn();
try {
txn.start();
if (_vmDao.listBy(routerId, State.Starting, State.Running).size() == 0) {
_dcDao.releaseVnet(router.getVnet(), router.getDataCenterId(), router.getAccountId(), null);
}
router.setVnet(null);
String privateIpAddress = router.getPrivateIpAddress();
if (privateIpAddress != null) {
if (_defaultHypervisorType == null || !_defaultHypervisorType.equalsIgnoreCase(Hypervisor.HypervisorType.VmWare.toString())) {
_dcDao.releaseLinkLocalIpAddress(privateIpAddress, router.getDataCenterId(), router.getId());
} else {
_dcDao.releasePrivateIpAddress(privateIpAddress, router.getDataCenterId(), router.getId());
}
}
router.setPrivateIpAddress(null);
if (!_itMgr.stateTransitTo(router, ev, null)) {
s_logger.debug("Router is not updated");
return;
}
txn.commit();
} catch (final Exception e) {
throw new CloudRuntimeException("Unable to complete stop", e);
}
if (_storageMgr.unshare(router, null) == null) {
s_logger.warn("Unable to set share to false for " + router.getId() + " on host ");
}
}
@Override
public Long convertToId(final String vmName) {
if (!VirtualMachineName.isValidRouterName(vmName, _instance)) {
@ -1293,9 +1250,9 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
}
@Override
public boolean finalizeStart(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest, ReservationContext context) {
public boolean finalizeStart(VirtualMachineProfile<DomainRouterVO> profile, long hostId, Commands cmds, ReservationContext context) {
CheckSshAnswer answer = (CheckSshAnswer) cmds.getAnswer("checkSsh");
if (!answer.getResult()) {
if (answer == null || !answer.getResult()) {
s_logger.warn("Unable to ssh to the VM: " + answer.getDetails());
return false;
}
@ -1306,9 +1263,9 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
}
@Override
public void finalizeStop(VirtualMachineProfile<DomainRouterVO> profile, long hostId, String reservationId, Answer... answer) {
if (answer != null && answer.length > 0) {
processStopOrRebootAnswer(profile.getVirtualMachine(), answer[0]);
public void finalizeStop(VirtualMachineProfile<DomainRouterVO> profile, StopAnswer answer) {
if (answer != null) {
processStopOrRebootAnswer(profile.getVirtualMachine(), answer);
}
DomainRouterVO router = profile.getVirtualMachine();
@ -1818,9 +1775,4 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
return routersToStop;
}
@Override
public void completeStartCommand(DomainRouterVO router) {
_itMgr.stateTransitTo(router, VirtualMachine.Event.AgentReportRunning, router.getHostId());
}
}

View File

@ -39,6 +39,7 @@ import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.SecStorageFirewallCfgCommand;
import com.cloud.agent.api.SecStorageSetupCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.check.CheckSshAnswer;
import com.cloud.agent.api.check.CheckSshCommand;
@ -62,10 +63,8 @@ import com.cloud.event.EventTypes;
import com.cloud.event.EventUtils;
import com.cloud.event.EventVO;
import com.cloud.event.dao.EventDao;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.ha.HighAvailabilityManager;
@ -971,16 +970,6 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V
}
}
@Override
public void completeStartCommand(SecondaryStorageVmVO vm) {
_itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportRunning, vm.getHostId());
}
@Override
public void completeStopCommand(SecondaryStorageVmVO vm) {
completeStopCommand(vm, VirtualMachine.Event.AgentReportStopped);
}
@DB
protected void completeStopCommand(SecondaryStorageVmVO secStorageVm, VirtualMachine.Event ev) {
Transaction txn = Transaction.currentTxn();
@ -1440,9 +1429,8 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V
}
@Override
public boolean finalizeStart(Commands cmds,
VirtualMachineProfile<SecondaryStorageVmVO> profile,
DeployDestination dest, ReservationContext context) {
public boolean finalizeStart(VirtualMachineProfile<SecondaryStorageVmVO> profile,
long hostId, Commands cmds,ReservationContext context) {
CheckSshAnswer answer = (CheckSshAnswer)cmds.getAnswer("checkSsh");
if (!answer.getResult()) {
s_logger.warn("Unable to ssh to the VM: " + answer.getDetails());
@ -1453,8 +1441,6 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V
}
@Override
public void finalizeStop(
VirtualMachineProfile<SecondaryStorageVmVO> profile, long hostId,
String reservationId, Answer... answer) {
public void finalizeStop(VirtualMachineProfile<SecondaryStorageVmVO> profile, StopAnswer answer) {
}
}

View File

@ -18,6 +18,7 @@
package com.cloud.vm;
import com.cloud.utils.db.GenericDao;
import com.cloud.vm.ItWorkVO.Step;
import com.cloud.vm.VirtualMachine.State;
public interface ItWorkDao extends GenericDao<ItWorkVO, String> {
@ -28,11 +29,13 @@ public interface ItWorkDao extends GenericDao<ItWorkVO, String> {
* @param state state
* @return ItWorkVO if found; null if not.
*/
ItWorkVO findByInstance(long instanceId, State state);
ItWorkVO findByOutstandingWork(long instanceId, State state);
/**
* cleanup rows that are either Done or Cancelled and been that way
* for at least wait time.
*/
void cleanup(long wait);
boolean updateStep(ItWorkVO work, Step step);
}

View File

@ -31,6 +31,7 @@ import com.cloud.vm.VirtualMachine.State;
public class ItWorkDaoImpl extends GenericDaoBase<ItWorkVO, String> implements ItWorkDao {
protected final SearchBuilder<ItWorkVO> AllFieldsSearch;
protected final SearchBuilder<ItWorkVO> CleanupSearch;
protected final SearchBuilder<ItWorkVO> OutstandingWorkSearch;
protected ItWorkDaoImpl() {
super();
@ -45,13 +46,20 @@ public class ItWorkDaoImpl extends GenericDaoBase<ItWorkVO, String> implements I
CleanupSearch.and("step", CleanupSearch.entity().getType(), Op.IN);
CleanupSearch.and("time", CleanupSearch.entity().getUpdatedAt(), Op.LT);
CleanupSearch.done();
OutstandingWorkSearch = createSearchBuilder();
OutstandingWorkSearch.and("instance", OutstandingWorkSearch.entity().getInstanceId(), Op.EQ);
OutstandingWorkSearch.and("op", OutstandingWorkSearch.entity().getType(), Op.EQ);
OutstandingWorkSearch.and("step", OutstandingWorkSearch.entity().getStep(), Op.NEQ);
OutstandingWorkSearch.done();
}
@Override
public ItWorkVO findByInstance(long instanceId, State state) {
public ItWorkVO findByOutstandingWork(long instanceId, State state) {
SearchCriteria<ItWorkVO> sc = AllFieldsSearch.create();
sc.setParameters("instance", instanceId);
sc.setParameters("op", state);
sc.setParameters("step", Step.Done);
return findOneBy(sc);
}
@ -59,7 +67,7 @@ public class ItWorkDaoImpl extends GenericDaoBase<ItWorkVO, String> implements I
@Override
public void cleanup(long wait) {
SearchCriteria<ItWorkVO> sc = CleanupSearch.create();
sc.setParameters("step", Step.Done, Step.Cancelled);
sc.setParameters("step", Step.Done);
sc.setParameters("time", InaccurateClock.getTimeInSeconds() - wait);
remove(sc);
@ -71,4 +79,10 @@ public class ItWorkDaoImpl extends GenericDaoBase<ItWorkVO, String> implements I
return super.update(id, work);
}
@Override
public boolean updateStep(ItWorkVO work, Step step) {
work.setStep(step);
return update(work.getId(), work);
}
}

View File

@ -34,11 +34,10 @@ public class ItWorkVO {
}
enum Step {
Reserve,
Prepare,
Start,
Started,
Cancelled,
Release,
Done
}

View File

@ -28,7 +28,6 @@ import com.cloud.server.Criteria;
import com.cloud.user.Account;
import com.cloud.uservm.UserVm;
import com.cloud.utils.exception.ExecutionException;
import com.cloud.vm.VirtualMachine.Event;
/**
*
@ -66,8 +65,6 @@ public interface UserVmManager extends VirtualMachineGuru<UserVmVO>{
* @return true if stopped; false if problems.
*/
boolean stopVirtualMachine(long userId, long vmId);
void completeStopCommand(long userId, UserVmVO vm, Event e);
/**
* Obtains statistics for a list of host or VMs; CPU and network utilization
@ -78,12 +75,6 @@ public interface UserVmManager extends VirtualMachineGuru<UserVmVO>{
*/
HashMap<Long, VmStatsEntry> getVirtualMachineStatistics(long hostId, String hostName, List<Long> vmIds);
/**
* Releases a guest IP address for a VM. If the VM is on a direct attached network, will also unassign the IP address.
* @param userVm
*/
void releaseGuestIpAddress(UserVmVO userVm);
boolean deleteVmGroup(long groupId);
boolean addInstanceToGroup(long userVmId, String group);

View File

@ -47,6 +47,7 @@ import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.SnapshotCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
@ -97,7 +98,6 @@ import com.cloud.event.EventVO;
import com.cloud.event.UsageEventVO;
import com.cloud.event.dao.EventDao;
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.InvalidParameterValueException;
@ -111,7 +111,6 @@ import com.cloud.host.HostVO;
import com.cloud.host.dao.DetailsDao;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.IPAddressVO;
import com.cloud.network.IpAddrAllocator;
import com.cloud.network.Network;
import com.cloud.network.NetworkManager;
@ -128,7 +127,6 @@ import com.cloud.network.ovs.OvsNetworkManager;
import com.cloud.network.router.VirtualNetworkApplianceManager;
import com.cloud.network.rules.RulesManager;
import com.cloud.network.security.SecurityGroupManager;
import com.cloud.offering.ServiceOffering;
import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.server.Criteria;
import com.cloud.service.ServiceOfferingVO;
@ -191,7 +189,6 @@ import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExecutionException;
import com.cloud.utils.net.Ip;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachine.Type;
@ -356,7 +353,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
if (s_logger.isDebugEnabled()) {
s_logger.debug("Stopping vm=" + vmId);
}
UserVmVO vm = _vmDao.findById(vmId);
UserVmVO vm = _vmDao.findById(vmId);
if (vm == null || vm.getRemoved() != null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("VM is either removed or deleted.");
@ -365,8 +362,15 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
}
long startEventId = EventUtils.saveStartedEvent(userId, vm.getAccountId(), EventTypes.EVENT_VM_STOP, "stopping Vm with Id: "+vmId);
User user = _userDao.findById(userId);
Account account = _accountDao.findById(user.getAccountId());
status = stop(userId, vm);
try {
status = _itMgr.stop(vm, user, account);
} catch (ResourceUnavailableException e) {
s_logger.debug("Unable to stop due to ", e);
status = false;
}
if(status){
EventUtils.saveEvent(userId, vm.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_VM_STOP, "Successfully stopped VM instance : " + vmId, startEventId);
@ -377,6 +381,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
return status;
}
}
@Override
public boolean stop(UserVmVO vm) {
return stopVirtualMachine(_accountMgr.getSystemUser().getId(), vm.getId());
}
@Override
@ -929,32 +938,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
return vmStatsById;
}
@Override
public void releaseGuestIpAddress(UserVmVO userVm) {
ServiceOffering offering = _offeringDao.findById(userVm.getServiceOfferingId());
if (offering.getGuestIpType() != Network.GuestIpType.Virtual) {
IPAddressVO guestIP = (userVm.getGuestIpAddress() == null) ? null : _ipAddressDao.findById(new Ip(userVm.getGuestIpAddress()));
if (guestIP != null && guestIP.getAllocatedTime() != null) {
_ipAddressDao.unassignIpAddress(new Ip(userVm.getGuestIpAddress()));
s_logger.debug("Released guest IP address=" + userVm.getGuestIpAddress() + " vmName=" + userVm.getName() + " dcId=" + userVm.getDataCenterId());
EventUtils.saveEvent(User.UID_SYSTEM, userVm.getAccountId(), EventTypes.EVENT_NET_IP_RELEASE, "released a public ip: " + userVm.getGuestIpAddress());
} else {
if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) {
String guestIp = userVm.getGuestIpAddress();
if (guestIp != null) {
_IpAllocator.releasePrivateIpAddress(guestIp, userVm.getDataCenterId(), userVm.getPodId());
}
}
}
}
userVm.setGuestIpAddress(null);
_vmDao.update(userVm.getId(), userVm);
}
@Override @DB
public UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationException, CloudRuntimeException {
@ -1127,49 +1110,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
}
}
@Override
public void completeStopCommand(UserVmVO instance) {
completeStopCommand(1L, instance, VirtualMachine.Event.AgentReportStopped);
}
@Override
@DB
public void completeStopCommand(long userId, UserVmVO vm, VirtualMachine.Event e) {
Transaction txn = Transaction.currentTxn();
try {
String vnet = vm.getVnet();
vm.setVnet(null);
vm.setProxyAssignTime(null);
vm.setProxyId(null);
txn.start();
if (!_itMgr.stateTransitTo(vm, e, null)) {
s_logger.debug("Unable to update ");
return;
}
if ((vm.getDomainRouterId() != null) && _vmDao.listBy(vm.getDomainRouterId(), State.Starting, State.Running).size() == 0) {
DomainRouterVO router = _routerDao.findById(vm.getDomainRouterId());
if (router.getState().equals(State.Stopped)) {
_dcDao.releaseVnet(vnet, router.getDataCenterId(), router.getAccountId(), null);
}
}
txn.commit();
} catch (Throwable th) {
s_logger.error("Error during stop: ", th);
throw new CloudRuntimeException("Error during stop: ", th);
}
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_STOP, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), vm.getServiceOfferingId(), vm.getTemplateId(), null);
_usageEventDao.persist(usageEvent);
if (_storageMgr.unshare(vm, null) == null) {
s_logger.warn("Unable to set share to false for " + vm.toString());
}
}
public String getRandomPrivateTemplateName() {
return UUID.randomUUID().toString();
}
@ -1192,139 +1132,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
return startVirtualMachine(vmId);
}
@Override
public boolean stop(UserVmVO vm) throws ResourceUnavailableException {
return stop(1L, vm);
}
private boolean stop(long userId, UserVmVO vm) {
State state = vm.getState();
if (state == State.Stopped) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("VM is already stopped: " + vm.toString());
}
return true;
}
if (state == State.Destroyed || state == State.Expunging || state == State.Error) {
s_logger.warn("Stopped called on " + vm.toString() + " but the state is " + state.toString());
return true;
}
if (!_itMgr.stateTransitTo(vm, VirtualMachine.Event.StopRequested, vm.getHostId())) {
s_logger.debug("VM is not in a state to stop: " + vm.getState().toString());
return false;
}
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;
}
StopCommand stop = new StopCommand(vm, vm.getInstanceName(), vm.getVnet());
boolean stopped = false;
try {
Answer answer = _agentMgr.send(vm.getHostId(), stop);
if (!answer.getResult()) {
s_logger.warn("Unable to stop vm " + vm.getName() + " due to " + answer.getDetails());
} else {
stopped = true;
}
} catch(AgentUnavailableException e) {
s_logger.warn("Agent is not available to stop vm " + vm.toString());
} catch(OperationTimedoutException e) {
s_logger.warn("operation timed out " + vm.toString());
}
if (stopped) {
completeStopCommand(userId, vm, VirtualMachine.Event.OperationSucceeded);
} else
{
_itMgr.stateTransitTo(vm, VirtualMachine.Event.OperationFailed, vm.getHostId());
s_logger.error("Unable to stop vm " + vm.getName());
}
return stopped;
}
// @Override
// public HostVO prepareForMigration(UserVmVO vm) throws StorageUnavailableException {
// long vmId = vm.getId();
// boolean mirroredVols = vm.isMirroredVols();
// DataCenterVO dc = _dcDao.findById(vm.getDataCenterId());
// HostPodVO pod = _podDao.findById(vm.getPodId());
// ServiceOfferingVO offering = _offeringDao.findById(vm.getServiceOfferingId());
// VMTemplateVO template = _templateDao.findById(vm.getTemplateId());
// StoragePoolVO sp = _storageMgr.getStoragePoolForVm(vm.getId());
//
// List<VolumeVO> vols = _volsDao.findCreatedByInstance(vmId);
//
// String [] storageIps = new String[2];
// VolumeVO vol = vols.get(0);
// storageIps[0] = vol.getHostIp();
// if (mirroredVols && (vols.size() == 2)) {
// storageIps[1] = vols.get(1).getHostIp();
// }
//
// PrepareForMigrationCommand cmd = new PrepareForMigrationCommand(vm.getInstanceName(), vm.getVnet(), storageIps, vols, mirroredVols);
//
// HostVO vmHost = null;
// HashSet<Host> avoid = new HashSet<Host>();
//
// HostVO fromHost = _hostDao.findById(vm.getHostId());
// if (fromHost.getClusterId() == null) {
// s_logger.debug("The host is not in a cluster");
// return null;
// }
// avoid.add(fromHost);
//
// while ((vmHost = (HostVO)_agentMgr.findHost(Host.Type.Routing, dc, pod, sp, offering, template, vm, null, avoid)) != null) {
// avoid.add(vmHost);
//
// if (s_logger.isDebugEnabled()) {
// s_logger.debug("Trying to migrate router to host " + vmHost.getName());
// }
//
// _storageMgr.share(vm, vols, vmHost, false);
//
// Answer answer = _agentMgr.easySend(vmHost.getId(), cmd);
// if (answer != null && answer.getResult()) {
// return vmHost;
// }
//
// _storageMgr.unshare(vm, vols, vmHost);
//
// }
//
// return null;
// }
//
// @Override
// public boolean migrate(UserVmVO vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException {
// HostVO fromHost = _hostDao.findById(vm.getHostId());
//
// if (!_itMgr.stateTransitTo(vm, VirtualMachine.Event.MigrationRequested, vm.getHostId())) {
// s_logger.debug("State for " + vm.toString() + " has changed so migration can not take place.");
// return false;
// }
// boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
// MigrateCommand cmd = new MigrateCommand(vm.getInstanceName(), host.getPrivateIpAddress(), isWindows);
// Answer answer = _agentMgr.send(fromHost.getId(), cmd);
// if (answer == null) {
// return false;
// }
//
// List<VolumeVO> vols = _volsDao.findCreatedByInstance(vm.getId());
// if (vols.size() == 0) {
// return true;
// }
//
// _storageMgr.unshare(vm, vols, fromHost);
//
// return true;
// }
@Override
public boolean expunge(UserVmVO vm, long callerUserId, Account caller) {
try {
@ -1364,77 +1171,8 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
s_logger.warn("Concurrent operations on expunging " + vm, e);
return false;
}
// long vmId = vm.getId();
// releaseGuestIpAddress(vm);
// vm.setGuestNetmask(null);
// vm.setGuestMacAddress(null);
// if (!_itMgr.stateTransitTo(vm, VirtualMachine.Event.ExpungeOperation, null)) {
// s_logger.info("vm " + vmId + " is skipped because it is no longer in Destroyed or Error state");
// continue;
// }
//
// List<VolumeVO> vols = null;
// try {
// vols = _volsDao.findByInstanceIdDestroyed(vmId);
// _storageMgr.destroy(vm, vols);
//
//
// //cleanup load balancer rules
// if (_lbMgr.removeVmFromLoadBalancers(vmId)) {
// s_logger.debug("LB rules are removed successfully as a part of vm id=" + vmId + " expunge");
// } else {
// s_logger.warn("Fail to remove lb rules as a part of vm id=" + vmId + " expunge");
// }
//
// _vmDao.remove(vm.getId());
// s_logger.debug("vm is destroyed");
// } catch (Exception e) {
// s_logger.info("VM " + vm +" expunge failed due to ", e);
// }
// }
//
// List<VolumeVO> destroyedVolumes = _volsDao.findByDetachedDestroyed();
// s_logger.info("Found " + destroyedVolumes.size() + " detached volumes to expunge.");
// _storageMgr.destroy(null, destroyedVolumes);
}
// @Override @DB
// public boolean completeMigration(UserVmVO vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException {
// CheckVirtualMachineCommand cvm = new CheckVirtualMachineCommand(vm.getInstanceName());
// CheckVirtualMachineAnswer answer = (CheckVirtualMachineAnswer)_agentMgr.send(host.getId(), cvm);
// if (!answer.getResult()) {
// s_logger.debug("Unable to complete migration for " + vm.toString());
// _itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportStopped, null);
// return false;
// }
//
// State state = answer.getState();
// if (state == State.Stopped) {
// s_logger.warn("Unable to complete migration as we can not detect it on " + host.toString());
// _itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportStopped, null);
// return false;
// }
//
// if (s_logger.isDebugEnabled()) {
// s_logger.debug("Marking port " + answer.getVncPort() + " on " + host.getId());
// }
//
// Transaction txn = Transaction.currentTxn();
// try {
// txn.start();
// _itMgr.stateTransitTo(vm, VirtualMachine.Event.OperationSucceeded, host.getId());
// txn.commit();
// _networkGroupMgr.handleVmStateTransition(vm, State.Running);
// return true;
// } catch(Exception e) {
// s_logger.warn("Exception during completion of migration process " + vm.toString());
// return false;
// }
// }
@Override
public void deletePrivateTemplateRecord(Long templateId){
if ( templateId != null) {
@ -2463,7 +2201,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
}
@Override
public boolean finalizeStart(Commands cmds, VirtualMachineProfile<UserVmVO> profile, DeployDestination dest, ReservationContext context) {
public boolean finalizeStart(VirtualMachineProfile<UserVmVO> profile, long hostId, Commands cmds, ReservationContext context) {
UserVmVO vm = profile.getVirtualMachine();
_networkGroupMgr.handleVmStateTransition(vm, State.Running);
_ovsNetworkMgr.handleVmStateTransition(vm, State.Running);
@ -2521,7 +2259,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
}
@Override
public void finalizeStop(VirtualMachineProfile<UserVmVO> profile, long hostId, String reservationId, Answer...answer) {
public void finalizeStop(VirtualMachineProfile<UserVmVO> profile, StopAnswer answer) {
UserVmVO vm = profile.getVirtualMachine();
_networkGroupMgr.handleVmStateTransition(vm, State.Stopped);
_ovsNetworkMgr.handleVmStateTransition(vm, State.Stopped);
@ -2584,12 +2322,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
}
}
@Override
public void completeStartCommand(UserVmVO vm) {
_itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportRunning, vm.getHostId());
}
@Override
public List<UserVmVO> searchForUserVMs(ListVMsCmd cmd) throws InvalidParameterValueException, PermissionDeniedException {
Account account = UserContext.current().getCaller();

View File

@ -17,11 +17,10 @@
*/
package com.cloud.vm;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.manager.Commands;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
@ -62,9 +61,10 @@ public interface VirtualMachineGuru<T extends VirtualMachine> {
* @param dest destination it was sent to.
* @return true if deployment was fine; false if it didn't go well.
*/
boolean finalizeStart(Commands cmds, VirtualMachineProfile<T> profile, DeployDestination dest, ReservationContext context);
boolean finalizeStart(VirtualMachineProfile<T> profile, long hostId, Commands cmds, ReservationContext context);
void finalizeStop(VirtualMachineProfile<T> profile, StopAnswer answer);
void finalizeStop(VirtualMachineProfile<T> profile, long hostId, String reservationId, Answer... answer);
/**
* Returns the id parsed from the name. If it cannot parse the name,
* then return null. This method is used to determine if this is
@ -75,22 +75,6 @@ public interface VirtualMachineGuru<T extends VirtualMachine> {
*/
Long convertToId(String vmName);
/**
* Complete the start command. HA calls this when it determines that
* a vm was starting but the state was not complete.
*
* @param vm vm to execute this on.
*/
void completeStartCommand(T vm);
/**
* Complete the stop command. HA calls this when it determines that
* a vm was being stopped but it didn't complete.
*
* @param vm vm to stop.
*/
void completeStopCommand(T vm);
/**
* start the vm
*
@ -122,18 +106,4 @@ public interface VirtualMachineGuru<T extends VirtualMachine> {
*/
Command cleanup(T vm, String vmName);
/**
* Prepare for migration.
*
* @param vm vm to migrate.
* @return HostVO if a host is found.
*/
// HostVO prepareForMigration(T vm) throws InsufficientCapacityException, StorageUnavailableException;
// /**
// * Migrate the vm.
// */
// boolean migrate(T vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException;
//
// boolean completeMigration(T vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException;
}

View File

@ -435,20 +435,9 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
}
}
private Answer getStartAnswer(Answer[] answers) {
for (Answer ans : answers) {
if (ans instanceof StartAnswer) {
return ans;
}
}
assert false : "Why there is no Start Answer???";
return null;
}
protected boolean checkWorkItems(VMInstanceVO vm, State state) throws ConcurrentOperationException {
while (true) {
ItWorkVO vo = _workDao.findByInstance(vm.getId(), state);
ItWorkVO vo = _workDao.findByOutstandingWork(vm.getId(), state);
if (vo == null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Unable to find work for " + vm);
@ -456,7 +445,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
return true;
}
if (vo.getStep() == Step.Done || vo.getStep() == Step.Cancelled) {
if (vo.getStep() == Step.Done) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Work for " + vm + " is " + vo.getStep());
}
@ -538,6 +527,18 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
throw new ConcurrentOperationException("Unable to change the state of " + vm);
}
@DB
protected <T extends VMInstanceVO> boolean changeState(T vm, Event event, Long hostId, ItWorkVO work, Step step) {
Transaction txn = Transaction.currentTxn();
txn.start();
if (!stateTransitTo(vm, event, hostId)) {
return false;
}
_workDao.updateStep(work, step);
txn.commit();
return true;
}
@Override
public <T extends VMInstanceVO> T advanceStart(T vm, Map<String, Object> params, User caller, Account account) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
long vmId = vm.getId();
@ -566,9 +567,8 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
ExcludeList avoids = new ExcludeList();
int retry = _retry;
while (retry-- != 0) { // It's != so that it can match -1.
//Note: need to re-intialize vmProfile in every re-try, or you will got a lot of duplicate disks and nics.
VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, template, offering, null, params);
VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, template, offering, null, params);
DeployDestination dest = null;
for (DeploymentPlanner planner : _planners) {
dest = planner.plan(vmProfile, plan, avoids);
@ -583,11 +583,55 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId());
}
stateTransitTo(vm, Event.OperationRetry, dest.getHost().getId());
long destHostId = dest.getHost().getId();
if (!changeState(vm, Event.OperationRetry, destHostId, work, Step.Prepare)) {
throw new ConcurrentOperationException("Unable to update the state of the Virtual Machine");
}
try {
_storageMgr.prepare(vmProfile, dest);
_networkMgr.prepare(vmProfile, dest, ctx);
vmGuru.finalizeVirtualMachineProfile(vmProfile, dest, ctx);
VirtualMachineTO vmTO = hvGuru.implement(vmProfile);
Commands cmds = new Commands(OnError.Revert);
cmds.addCommand(new StartCommand(vmTO));
vmGuru.finalizeDeployment(cmds, vmProfile, dest, ctx);
vm.setPodId(dest.getPod().getId());
work = _workDao.findById(work.getId());
if (work == null || work.getStep() != Step.Prepare) {
throw new ConcurrentOperationException("Work steps have been changed: " + work);
}
_workDao.updateStep(work, Step.Start);
_agentMgr.send(destHostId, cmds);
_workDao.updateStep(work, Step.Started);
Answer startAnswer = cmds.getAnswer(StartAnswer.class);
if (startAnswer != null && startAnswer.getResult()) {
if (vmGuru.finalizeStart(vmProfile, destHostId, cmds, ctx)) {
if (!changeState(vm, Event.OperationSucceeded, destHostId, work, Step.Done)) {
throw new ConcurrentOperationException("Unable to transition to a new state.");
}
startedVm = vm;
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creation complete for VM " + vm);
}
return startedVm;
}
}
s_logger.info("Unable to start VM on " + dest.getHost() + " due to " + (startAnswer == null ? " no start answer" : startAnswer.getDetails()));
} catch (OperationTimedoutException e) {
s_logger.debug("Unable to send the start command to host " + dest.getHost());
if (e.isActive()) {
//TODO: This one is different as we're not sure if the VM is actually started.
}
avoids.addHost(destHostId);
continue;
} catch (ResourceUnavailableException e) {
if (!avoids.add(e)) {
if (e.getScope() == Volume.class || e.getScope() == Nic.class) {
@ -611,45 +655,19 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
} catch (RuntimeException e) {
s_logger.warn("Failed to start instance " + vm, e);
throw new CloudRuntimeException("Failed to start " + vm, e);
}
vmGuru.finalizeVirtualMachineProfile(vmProfile, dest, ctx);
VirtualMachineTO vmTO = hvGuru.implement(vmProfile);
Commands cmds = new Commands(OnError.Revert);
cmds.addCommand(new StartCommand(vmTO));
vmGuru.finalizeDeployment(cmds, vmProfile, dest, ctx);
vm.setPodId(dest.getPod().getId());
try {
Answer[] answers = _agentMgr.send(dest.getHost().getId(), cmds);
if (getStartAnswer(answers).getResult() && vmGuru.finalizeStart(cmds, vmProfile, dest, ctx)) {
if (!stateTransitTo(vm, Event.OperationSucceeded, dest.getHost().getId())) {
throw new CloudRuntimeException("Unable to transition to a new state.");
}
startedVm = vm;
break;
} finally {
if (startedVm == null) {
_workDao.updateStep(work, Step.Release);
_networkMgr.release(vmProfile, false);
_storageMgr.release(vmProfile);
}
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;
}
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creation complete for VM " + vm);
}
}
} finally {
if (startedVm == null) {
stateTransitTo(vm, Event.OperationFailed, null);
// FIXME: Cleanup.
changeState(vm, Event.OperationFailed, null, work, Step.Done);
}
work.setStep(Step.Done);
_workDao.update(work.getId(), work);
}
return startedVm;
@ -665,9 +683,83 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
throw new CloudRuntimeException("Unable to stop vm because of a concurrent operation", e);
}
}
protected <T extends VMInstanceVO> boolean sendStop(VirtualMachineGuru<T> guru, VirtualMachineProfile<T> profile, boolean force) {
VMInstanceVO vm = profile.getVirtualMachine();
StopCommand stop = new StopCommand(vm, vm.getInstanceName(), null);
try {
StopAnswer answer = (StopAnswer)_agentMgr.send(vm.getHostId(), stop);
if (!answer.getResult()) {
s_logger.debug("Unable to stop VM due to " + answer.getDetails());
return false;
}
guru.finalizeStop(profile, answer);
} catch (AgentUnavailableException e) {
if (!force) {
return false;
}
} catch (OperationTimedoutException e) {
if (!force) {
return false;
}
}
return true;
}
protected <T extends VMInstanceVO> boolean cleanup(VirtualMachineGuru<T> guru, VirtualMachineProfile<T> profile, ItWorkVO work, boolean force, User user, Account account) {
T vm = profile.getVirtualMachine();
State state = vm.getState();
if (state == State.Starting) {
Step step = work.getStep();
if (step == Step.Start && !force) {
return false;
}
if (step == Step.Started || step == Step.Start) {
if (vm.getHostId() != null) {
if (!sendStop(guru, profile, force)) {
return false;
}
}
}
if (step != Step.Release && step != Step.Prepare && step != Step.Started && step != Step.Start) {
return true;
}
} else if (state == State.Stopping) {
if (vm.getHostId() != null) {
if (!sendStop(guru, profile, force)) {
return false;
}
}
} else if (state == State.Migrating) {
if (vm.getHostId() != null) {
if (!sendStop(guru, profile, force)) {
return false;
}
}
if (vm.getLastHostId() != null) {
if (!sendStop(guru, profile, force)) {
return false;
}
}
} else if (state == State.Running) {
if (!sendStop(guru, profile, force)) {
return false;
}
}
_networkMgr.release(profile, force);
_storageMgr.release(profile);
return true;
}
@Override
public <T extends VMInstanceVO> boolean advanceStop(T vm, boolean forced, User user, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
long vmId = vm.getId();
State state = vm.getState();
if (state == State.Stopped) {
if (s_logger.isDebugEnabled()) {
@ -677,40 +769,63 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
}
if (state == State.Destroyed || state == State.Expunging || state == State.Error) {
s_logger.debug("Stopped called on " + vm + " but the state is " + state);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Stopped called on " + vm + " but the state is " + state);
}
return true;
}
VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
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);
if (!forced) {
throw new ConcurrentOperationException("VM is being operated on by someone else.");
}
} finally {
if (!stopped) {
if (!forced) {
stateTransitTo(vm, Event.OperationFailed, vm.getHostId());
vm = vmGuru.findById(vmId);
if (vm == null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Unable to find VM " + vmId);
}
return true;
}
}
if ((vm.getState() == State.Starting || vm.getState() == State.Stopping || vm.getState() == State.Migrating) && forced) {
ItWorkVO work = _workDao.findByOutstandingWork(vm.getId(), vm.getState());
if (work != null) {
if (cleanup(vmGuru, new VirtualMachineProfileImpl<T>(vm), work, forced, user, account)) {
return stateTransitTo(vm, Event.AgentReportStopped, null);
}
}
}
VirtualMachineProfile<T> profile = new VirtualMachineProfileImpl<T>(vm);
if (vm.getHostId() != null) {
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 {
s_logger.warn("Unable to actually stop " + vm + " but continue with release because it's a force stop");
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_STOP, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), vm.getServiceOfferingId(), vm.getTemplateId(), null);
_usageEventDao.persist(usageEvent);
}
vmGuru.finalizeStop(profile, answer);
} catch (AgentUnavailableException e) {
} catch (OperationTimedoutException e) {
} 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");
}
}
}
}
@ -719,15 +834,11 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
s_logger.debug(vm + " is stopped on the host. Proceeding to release resource held.");
}
boolean cleanup = false;
VirtualMachineProfile<T> profile = new VirtualMachineProfileImpl<T>(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 {
@ -735,28 +846,11 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
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<T> guru = (VirtualMachineGuru<T>)_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, State.Stopping, vm.getId());
_workDao.persist(work);
}
return stopped;
return stateTransitTo(vm, Event.OperationSucceeded, null);
}
private void setStateMachine() {
@ -807,31 +901,21 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager {
protected boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId, String reservationId) {
vm.setReservationId(reservationId);
if (vm instanceof UserVmVO) {
return _stateMachine.transitTO(vm, e, hostId, _userVmDao);
return _stateMachine.transitTo(vm, e, hostId, _userVmDao);
} else if (vm instanceof ConsoleProxyVO) {
return _stateMachine.transitTO(vm, e, hostId, _consoleDao);
return _stateMachine.transitTo(vm, e, hostId, _consoleDao);
} else if (vm instanceof SecondaryStorageVmVO) {
return _stateMachine.transitTO(vm, e, hostId, _secondaryDao);
return _stateMachine.transitTo(vm, e, hostId, _secondaryDao);
} else if (vm instanceof DomainRouterVO) {
return _stateMachine.transitTO(vm, e, hostId, _routerDao);
return _stateMachine.transitTo(vm, e, hostId, _routerDao);
} else {
return _stateMachine.transitTO(vm, e, hostId, _vmDao);
return _stateMachine.transitTo(vm, e, hostId, _vmDao);
}
}
@Override
public boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId) {
if (vm instanceof UserVmVO) {
return _stateMachine.transitTO(vm, e, hostId, _userVmDao);
} else if (vm instanceof ConsoleProxyVO) {
return _stateMachine.transitTO(vm, e, hostId, _consoleDao);
} else if (vm instanceof SecondaryStorageVmVO) {
return _stateMachine.transitTO(vm, e, hostId, _secondaryDao);
} else if (vm instanceof DomainRouterVO) {
return _stateMachine.transitTO(vm, e, hostId, _routerDao);
} else {
return _stateMachine.transitTO(vm, e, hostId, _vmDao);
}
return _stateMachine.transitTo(vm, e, hostId, _vmDao);
}
@Override

View File

@ -99,7 +99,7 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
}
public boolean transitTO(V vo, E e, Long id, StateDao<S,E,V> dao) {
public boolean transitTo(V vo, E e, Long id, StateDao<S,E,V> dao) {
S currentState = vo.getState();
S nextState = getNextState(currentState, e);