stop vm is now formalized

This commit is contained in:
Alex Huang 2010-11-04 10:48:48 -07:00
parent d5d1808488
commit 1fe446002b
15 changed files with 194 additions and 59 deletions

View File

@ -23,7 +23,6 @@ import com.cloud.agent.api.to.VolumeTO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.offering.ServiceOffering;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.template.VirtualMachineTemplate.BootloaderType;
import com.cloud.user.Account;
@ -66,11 +65,6 @@ public interface VirtualMachineProfile<T extends VirtualMachine> {
*/
HypervisorType getHypervisorType();
/**
* @return os to be run on the virtual machine.
*/
String getGuestOs();
/**
* @return template the virtual machine is based on.
*/
@ -109,11 +103,6 @@ public interface VirtualMachineProfile<T extends VirtualMachine> {
void addDisk(VolumeTO disk);
void setBootloader(BootloaderType type);
BootloaderType getBootloader();
String getOs();
VirtualMachine.Type getType();
void setParameter(String name, Object value);

View File

@ -134,6 +134,9 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
@Column(name="service_offering_id")
long serviceOfferingId;
@Column(name="reservation_id")
String reservationId;
public VMInstanceVO(long id,
long serviceOfferingId,
String name,
@ -412,8 +415,20 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
this.mirroredVols = mirroredVols;
}
public void setReservationId(String reservationId) {
this.reservationId = reservationId;
}
public String getReservationId() {
return this.reservationId;
}
transient String toString;
@Override
public String toString() {
return new StringBuilder("[").append(type.toString()).append("|").append(instanceName).append("]").toString();
if (toString == null) {
toString = new StringBuilder("VM[").append(type.toString()).append("|").append(instanceName).append("]").toString();
}
return toString;
}
}

View File

@ -2443,7 +2443,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach
}
@Override
public boolean processDeploymentResult(Commands cmds, VirtualMachineProfile<ConsoleProxyVO> profile, DeployDestination dest, ReservationContext context) {
public boolean finalizeStart(Commands cmds, VirtualMachineProfile<ConsoleProxyVO> profile, DeployDestination dest, ReservationContext context) {
CheckSshAnswer answer = (CheckSshAnswer)cmds.getAnswer("checkSsh");
if (!answer.getResult()) {
s_logger.warn("Unable to ssh to the VM: " + answer.getDetails());
@ -2521,4 +2521,8 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach
}
return findById(VirtualMachineName.getConsoleProxyId(name));
}
@Override
public void finalizeStop(VirtualMachineProfile<ConsoleProxyVO> profile, long hostId, String reservationId) {
}
}

View File

@ -57,7 +57,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
ServiceOffering offering = vmProfile.getServiceOffering();
VirtualMachine vm = vmProfile.getVirtualMachine();
VirtualMachineTO to = new VirtualMachineTO(vm.getId(), vm.getInstanceName(), vm.getType(), offering.getCpu(), offering.getSpeed(), offering.getRamSize() * 1024l * 1024l, offering.getRamSize() * 1024l * 1024l, null, vmProfile.getOs());
VirtualMachineTO to = new VirtualMachineTO(vm.getId(), vm.getInstanceName(), vm.getType(), offering.getCpu(), offering.getSpeed(), offering.getRamSize() * 1024l * 1024l, offering.getRamSize() * 1024l * 1024l, null, null);
to.setBootArgs(vmProfile.getBootArgs());
List<NicProfile> nicProfiles = vmProfile.getNics();

View File

@ -21,14 +21,18 @@ import javax.ejb.Local;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.Storage;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.template.VirtualMachineTemplate.BootloaderType;
import com.cloud.utils.component.Inject;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@Local(value=HypervisorGuru.class)
public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru {
@Inject GuestOSDao _guestOsDao;
protected XenServerGuru() {
super();
@ -51,6 +55,10 @@ public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru
VirtualMachineTO to = toVirtualMachineTO(vm);
to.setBootloader(bt);
// Determine the VM's OS description
GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine().getGuestOSId());
to.setOs(guestOS.getDisplayName());
return to;
}
}

View File

@ -2132,7 +2132,7 @@ public class DomainRouterManagerImpl implements DomainRouterManager, VirtualMach
}
@Override
public boolean processDeploymentResult(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest, ReservationContext context) {
public boolean finalizeStart(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest, ReservationContext context) {
CheckSshAnswer answer = (CheckSshAnswer)cmds.getAnswer("checkSsh");
if (!answer.getResult()) {
s_logger.warn("Unable to ssh to the VM: " + answer.getDetails());
@ -2141,6 +2141,10 @@ public class DomainRouterManagerImpl implements DomainRouterManager, VirtualMach
return true;
}
@Override
public void finalizeStop(VirtualMachineProfile<DomainRouterVO> profile, long hostId, String reservationId) {
}
@Override
public RemoteAccessVpnVO startRemoteAccessVpn(RemoteAccessVpnVO vpnVO) throws ResourceUnavailableException {
DomainRouterVO router = getRouter(vpnVO.getAccountId(), vpnVO.getZoneId());

View File

@ -22,7 +22,7 @@ import javax.ejb.Local;
import com.cloud.utils.db.GenericDaoBase;
@Local(value=ItWorkDao.class)
public class ItWorkDaoImpl extends GenericDaoBase<ItWorkVO, Long> implements ItWorkDao {
public class ItWorkDaoImpl extends GenericDaoBase<ItWorkVO, String> implements ItWorkDao {
protected ItWorkDaoImpl() {
super();
}

View File

@ -32,7 +32,8 @@ import com.cloud.utils.db.GenericDao;
@Table(name="op_it_work")
public class ItWorkVO {
enum Type {
Start;
Start,
Cleanup;
}
enum State {
@ -90,6 +91,10 @@ public class ItWorkVO {
return type;
}
public void setType(Type type) {
this.type = type;
}
public String getThreadName() {
return threadName;
}

View File

@ -32,6 +32,8 @@ import com.cloud.agent.AgentManager;
import com.cloud.agent.AgentManager.OnError;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Start2Command;
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;
@ -45,6 +47,8 @@ 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.EventVO;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
@ -59,12 +63,10 @@ import com.cloud.network.NetworkManager;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.GuestOSVO;
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.GuestOSDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.user.Account;
import com.cloud.user.User;
@ -79,6 +81,7 @@ 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.vm.ItWorkVO.Type;
import com.cloud.vm.VirtualMachine.Event;
import com.cloud.vm.dao.VMInstanceDao;
@ -92,7 +95,6 @@ public class MauriceMoss implements VmManager, ClusterManagerListener {
@Inject private AgentManager _agentMgr;
@Inject private VMInstanceDao _vmDao;
@Inject private ServiceOfferingDao _offeringDao;
@Inject private GuestOSDao _guestOsDao;
@Inject private VMTemplateDao _templateDao;
@Inject private UserDao _userDao;
@Inject private AccountDao _accountDao;
@ -130,9 +132,7 @@ public class MauriceMoss implements VmManager, ClusterManagerListener {
s_logger.debug("Allocating entries for VM: " + vm);
}
// Determine the VM's OS description
GuestOSVO guestOS = _guestOsDao.findById(vm.getGuestOSId());
VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, guestOS.getDisplayName(), template, serviceOffering, owner, params);
VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, template, serviceOffering, owner, params);
vm.setDataCenterId(plan.getDataCenterId());
if (plan.getPodId() != null) {
@ -286,8 +286,8 @@ public class MauriceMoss implements VmManager, ClusterManagerListener {
VirtualMachineGuru<T> vmGuru = (VirtualMachineGuru<T>)_vmGurus.get(vm.getType());
// Determine the VM's OS description
GuestOSVO guestOS = _guestOsDao.findById(vm.getGuestOSId());
vm.setReservationId(work.getId());
if (!_vmDao.updateIf(vm, Event.StartRequested, null)) {
throw new ConcurrentOperationException("Unable to start vm " + vm + " due to concurrent operations");
}
@ -295,7 +295,7 @@ public class MauriceMoss implements VmManager, ClusterManagerListener {
ExcludeList avoids = new ExcludeList();
int retry = _retry;
while (retry-- != 0) { // It's != so that it can match -1.
VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, guestOS.getDisplayName(), 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);
@ -334,7 +334,7 @@ public class MauriceMoss implements VmManager, ClusterManagerListener {
vmGuru.finalizeDeployment(cmds, vmProfile, dest, context);
try {
Answer[] answers = _agentMgr.send(dest.getHost().getId(), cmds);
if (answers[0].getResult() && vmGuru.processDeploymentResult(cmds, vmProfile, dest, context)) {
if (answers[0].getResult() && vmGuru.finalizeStart(cmds, vmProfile, dest, context)) {
if (!_vmDao.updateIf(vm, Event.OperationSucceeded, dest.getHost().getId())) {
throw new CloudRuntimeException("Unable to transition to a new state.");
}
@ -358,9 +358,93 @@ public class MauriceMoss implements VmManager, ClusterManagerListener {
}
@Override
public <T extends VMInstanceVO> T stop(T vm, User user, Account account) throws AgentUnavailableException {
// TODO Auto-generated method stub
return null;
public <T extends VMInstanceVO> boolean stop(T vm, 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) {
s_logger.warn("Stopped called on " + vm.toString() + " but the state is " + state.toString());
return true;
}
if (!_vmDao.updateIf(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();
EventVO event = new EventVO();
event.setUserId(user.getId());
event.setAccountId(vm.getAccountId());
event.setType(EventTypes.EVENT_VM_STOP);
event.setStartId(1); // FIXME:
event.setParameters("id="+vm.getId() + "\n" + "vmName=" + vm.getHostName() + "\nsoId=" + vm.getServiceOfferingId() + "\ntId=" + vm.getTemplateId() + "\ndcId=" + vm.getDataCenterId());
StopCommand stop = new StopCommand(vm, vm.getInstanceName(), null);
boolean stopped = false;
try {
StopAnswer 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());
}
} finally {
if (!stopped) {
_vmDao.updateIf(vm, Event.OperationFailed, vm.getHostId());
}
}
if (s_logger.isDebugEnabled()) {
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);
} catch (Exception e) {
s_logger.warn("Unable to release some network resources.", e);
cleanup = true;
}
try {
_storageMgr.release(profile);
} 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());
} catch (Exception e) {
s_logger.warn("Guru " + guru.getClass() + " has trouble processing stop ");
cleanup = true;
}
vm.setReservationId(null);
vm.setHostId(null);
_vmDao.updateIf(vm, Event.OperationSucceeded, null);
if (cleanup) {
ItWorkVO work = new ItWorkVO(reservationId, _nodeId, Type.Cleanup);
_workDao.persist(work);
}
return stopped;
}
@Override

View File

@ -77,6 +77,7 @@ import com.cloud.api.commands.RecoverVMCmd;
import com.cloud.api.commands.ResetVMPasswordCmd;
import com.cloud.api.commands.StartVMCmd;
import com.cloud.api.commands.StopVMCmd;
import com.cloud.api.commands.StopVm2Cmd;
import com.cloud.api.commands.UpdateVMCmd;
import com.cloud.api.commands.UpgradeVMCmd;
import com.cloud.async.AsyncJobExecutor;
@ -3745,7 +3746,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, VirtualM
}
@Override
public boolean processDeploymentResult(Commands cmds, VirtualMachineProfile<UserVmVO> profile, DeployDestination dest, ReservationContext context) {
public boolean finalizeStart(Commands cmds, VirtualMachineProfile<UserVmVO> profile, DeployDestination dest, ReservationContext context) {
return true;
}
@ -3766,4 +3767,41 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, VirtualM
}
return findById(VirtualMachineName.getVmId(name));
}
@Override
public UserVm stopVirtualMachine(StopVm2Cmd cmd) throws ConcurrentOperationException {
//Input validation
Account caller = UserContext.current().getAccount();
Long userId = UserContext.current().getUserId();
long id = cmd.getId();
//if account is removed, return error
if (caller != null && caller.getRemoved() != null)
throw new PermissionDeniedException("The account " + caller.getId()+" is removed");
UserVmVO vmInstance = _vmDao.findById(id);
if (vmInstance == null) {
throw new InvalidParameterValueException("unable to find a virtual machine with id " + id);
}
long eventId = EventUtils.saveScheduledEvent(userId, vmInstance.getAccountId(), EventTypes.EVENT_VM_STOP, "stopping Vm with Id: "+id);
userId = accountAndUserValidation(id, caller, userId, vmInstance);
UserVO user = _userDao.findById(userId);
try {
_itMgr.stop(vmInstance, user, caller);
} catch (AgentUnavailableException e) {
throw new CloudRuntimeException("Unable to contact the agent to stop the virtual machine " + vmInstance, e);
} catch (OperationTimedoutException e) {
throw new CloudRuntimeException("Waiting too long for agent to stop the virtual machine " + vmInstance, e);
}
return _vmDao.findById(id);
}
@Override
public void finalizeStop(VirtualMachineProfile<UserVmVO> profile, long hostId, String reservationId) {
}
}

View File

@ -29,6 +29,7 @@ import com.cloud.api.commands.RecoverVMCmd;
import com.cloud.api.commands.ResetVMPasswordCmd;
import com.cloud.api.commands.StartVMCmd;
import com.cloud.api.commands.StopVMCmd;
import com.cloud.api.commands.StopVm2Cmd;
import com.cloud.api.commands.UpdateVMCmd;
import com.cloud.api.commands.UpgradeVMCmd;
import com.cloud.async.executor.OperationResponse;
@ -145,4 +146,6 @@ public interface UserVmService extends Manager {
* @throws InvalidParameterValueException
*/
UserVm upgradeVirtualMachine(UpgradeVMCmd cmd);
UserVm stopVirtualMachine(StopVm2Cmd cmd) throws ConcurrentOperationException;
}

View File

@ -47,7 +47,6 @@ public interface VirtualMachineGuru<T extends VirtualMachine> {
*/
boolean finalizeDeployment(Commands cmds, VirtualMachineProfile<T> profile, DeployDestination dest, ReservationContext context);
/**
* Check the deployment results.
* @param cmds commands and answers that were sent.
@ -55,5 +54,7 @@ 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 processDeploymentResult(Commands cmds, VirtualMachineProfile<T> profile, DeployDestination dest, ReservationContext context);
boolean finalizeStart(Commands cmds, VirtualMachineProfile<T> profile, DeployDestination dest, ReservationContext context);
void finalizeStop(VirtualMachineProfile<T> profile, long hostId, String reservationId);
}

View File

@ -47,13 +47,12 @@ public class VirtualMachineProfileImpl<T extends VMInstanceVO> implements Virtua
List<NicProfile> _nics = new ArrayList<NicProfile>();
List<VolumeTO> _disks = new ArrayList<VolumeTO>();
StringBuilder _bootArgs = new StringBuilder();
String _guestOs;
Account _owner;
BootloaderType _bootloader;
VirtualMachine.Type _type;
public VirtualMachineProfileImpl(T vm, String guestOs, VMTemplateVO template, ServiceOfferingVO offering, Account owner, Map<String, Object> params) {
public VirtualMachineProfileImpl(T vm, VMTemplateVO template, ServiceOfferingVO offering, Account owner, Map<String, Object> params) {
_vm = vm;
_template = template;
_offering = offering;
@ -62,29 +61,17 @@ public class VirtualMachineProfileImpl<T extends VMInstanceVO> implements Virtua
if (_params == null) {
_params = new HashMap<String, Object>();
}
_guestOs = guestOs;
_type = vm.getType();
}
public VirtualMachineProfileImpl(T vm) {
this(vm, null, null, null, null);
}
public VirtualMachineProfileImpl(VirtualMachine.Type type) {
_type = type;
}
@Override
public String getOs() {
return _guestOs;
}
@Override
public void setBootloader(BootloaderType bootloader) {
_bootloader = bootloader;
}
@Override
public BootloaderType getBootloader() {
return _bootloader;
}
@Override
public String toString() {
return _vm.toString();
@ -108,11 +95,6 @@ public class VirtualMachineProfileImpl<T extends VMInstanceVO> implements Virtua
_params.put(name, value);
}
@Override
public String getGuestOs() {
return _guestOs;
}
@Override
public VirtualMachineTemplate getTemplate() {
if (_template == null) {

View File

@ -24,6 +24,7 @@ import com.cloud.deploy.DeploymentPlan;
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.network.NetworkConfigurationVO;
@ -68,7 +69,7 @@ public interface VmManager extends Manager {
<T extends VMInstanceVO> T start(T vm, Map<String, Object> params, User caller, Account account) throws InsufficientCapacityException, StorageUnavailableException, ConcurrentOperationException, ResourceUnavailableException;
<T extends VMInstanceVO> T stop(T vm, User caller, Account account) throws AgentUnavailableException, ConcurrentOperationException;
<T extends VMInstanceVO> boolean stop(T vm, User caller, Account account) throws AgentUnavailableException, ConcurrentOperationException, OperationTimedoutException;
void destroy();

View File

@ -616,6 +616,7 @@ CREATE TABLE `cloud`.`vm_instance` (
`account_id` bigint unsigned NOT NULL COMMENT 'user id of owner',
`domain_id` bigint unsigned NOT NULL,
`service_offering_id` bigint unsigned NOT NULL COMMENT 'service offering id',
`reservation_id` char(40) COMMENT 'reservation id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;