1) remove snapshoting/reverting states from VM state machine,2) change vmsnapshotservice interface

This commit is contained in:
Mice Xia 2013-02-02 00:36:21 +08:00
parent bb7cd90b61
commit ebca6890fd
13 changed files with 173 additions and 227 deletions

View File

@ -295,7 +295,7 @@ public class EventTypes {
// vm snapshot events
public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE";
public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE";
public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERT";
public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERTTO";
// external network device events
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_ADD = "PHYSICAL.NVPCONTROLLER.ADD";

View File

@ -42,11 +42,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
Migrating(true, "VM is being migrated. host id holds to from host"),
Error(false, "VM is in error"),
Unknown(false, "VM state is unknown."),
Shutdowned(false, "VM is shutdowned from inside"),
RunningSnapshotting(true, "VM is taking a snapshot in running state"),
StoppedSnapshotting(true, "VM is taking a snapshot in stopped state"),
RevertingToRunning(true, "VM is reverting to snapshot"),
RevertingToStopped(true, "VM is reverting to snapshot");
Shutdowned(false, "VM is shutdowned from inside");
private final boolean _transitional;
String _description;
@ -114,22 +110,6 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
s_fsm.addTransition(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging);
s_fsm.addTransition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging);
s_fsm.addTransition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging);
s_fsm.addTransition(State.Running, VirtualMachine.Event.SnapshotRequested, State.RunningSnapshotting);
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.SnapshotRequested, State.StoppedSnapshotting);
s_fsm.addTransition(State.RunningSnapshotting, VirtualMachine.Event.OperationSucceeded, State.Running);
s_fsm.addTransition(State.StoppedSnapshotting, VirtualMachine.Event.OperationSucceeded, State.Stopped);
s_fsm.addTransition(State.RunningSnapshotting, VirtualMachine.Event.OperationFailed, State.Running);
s_fsm.addTransition(State.StoppedSnapshotting, VirtualMachine.Event.OperationFailed, State.Stopped);
s_fsm.addTransition(State.Running, VirtualMachine.Event.RevertRequested, State.RevertingToRunning);
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.RevertRequested, State.RevertingToStopped);
s_fsm.addTransition(State.RevertingToRunning, VirtualMachine.Event.OperationFailed, State.Running);
s_fsm.addTransition(State.RevertingToStopped, VirtualMachine.Event.OperationFailed, State.Stopped);
s_fsm.addTransition(State.RevertingToRunning, VirtualMachine.Event.OperationSucceeded, State.Running);
s_fsm.addTransition(State.RevertingToStopped, VirtualMachine.Event.OperationSucceeded, State.Stopped);
}
public static boolean isVmStarted(State oldState, Event e, State newState) {

View File

@ -61,6 +61,7 @@ public interface VMSnapshot extends ControlledEntity, Identity, InternalIdentity
s_fsm.addTransition(Reverting, Event.OperationFailed, Ready);
s_fsm.addTransition(Ready, Event.ExpungeRequested, Expunging);
s_fsm.addTransition(Error, Event.ExpungeRequested, Expunging);
s_fsm.addTransition(Expunging, Event.ExpungeRequested, Expunging);
s_fsm.addTransition(Expunging, Event.OperationSucceeded, Removed);
}
}

View File

@ -19,10 +19,7 @@ package com.cloud.vm.snapshot;
import java.util.List;
import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd;
import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd;
import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
@ -36,16 +33,16 @@ public interface VMSnapshotService {
List<? extends VMSnapshot> listVMSnapshots(ListVMSnapshotCmd cmd);
VMSnapshot getVMSnapshotById(long id);
VMSnapshot getVMSnapshotById(Long id);
VMSnapshot creatVMSnapshot(CreateVMSnapshotCmd cmd);
VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId);
VMSnapshot allocVMSnapshot(CreateVMSnapshotCmd cmd)
VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDescription, Boolean snapshotMemory)
throws ResourceAllocationException;
boolean deleteVMSnapshot(DeleteVMSnapshotCmd cmd);
boolean deleteVMSnapshot(Long vmSnapshotId);
UserVm revertToSnapshot(RevertToSnapshotCmd cmd) throws InsufficientServerCapacityException, InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException;
UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientServerCapacityException, InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException;
VirtualMachine getVMBySnapshotId(Long id);
}

View File

@ -75,7 +75,7 @@ public class CreateVMSnapshotCmd extends BaseAsyncCreateCmd {
@Override
public void create() throws ResourceAllocationException {
VMSnapshot vmsnapshot = _vmSnapshotService.allocVMSnapshot(this);
VMSnapshot vmsnapshot = _vmSnapshotService.allocVMSnapshot(getVmId(),getDisplayName(),getDescription(),snapshotMemory());
if (vmsnapshot != null) {
this.setEntityId(vmsnapshot.getId());
} else {
@ -86,7 +86,7 @@ public class CreateVMSnapshotCmd extends BaseAsyncCreateCmd {
@Override
public String getEventDescription() {
return "creating snapshot for vm: " + getVmId();
return "creating snapshot for VM: " + getVmId();
}
@Override
@ -97,7 +97,7 @@ public class CreateVMSnapshotCmd extends BaseAsyncCreateCmd {
@Override
public void execute() {
UserContext.current().setEventDetails("VM Id: " + getVmId());
VMSnapshot result = _vmSnapshotService.creatVMSnapshot(this);
VMSnapshot result = _vmSnapshotService.creatVMSnapshot(getVmId(),getEntityId());
if (result != null) {
VMSnapshotResponse response = _responseGenerator
.createVMSnapshotResponse(result);

View File

@ -17,30 +17,20 @@
package org.apache.cloudstack.api.command.user.vmsnapshot;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.BaseCmd.CommandType;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.VMSnapshotResponse;
import org.apache.log4j.Logger;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Volume;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.uservm.UserVm;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.snapshot.VMSnapshot;
//import com.cloud.api.ApiDBUtils;
@APICommand(name="deleteVMSnapshot", description = "Deletes a vmsnapshot.", responseObject = SuccessResponse.class)
public class DeleteVMSnapshotCmd extends BaseAsyncCmd {
@ -61,10 +51,6 @@ public class DeleteVMSnapshotCmd extends BaseAsyncCmd {
return s_name;
}
public static String getResultObjectName() {
return "vm_snapshots";
}
@Override
public long getEntityOwnerId() {
VMSnapshot vmSnapshot = _entityMgr.findById(VMSnapshot.class, getId());
@ -77,7 +63,7 @@ public class DeleteVMSnapshotCmd extends BaseAsyncCmd {
@Override
public void execute() {
UserContext.current().setEventDetails("vmsnapshot id: " + getId());
boolean result = _vmSnapshotService.deleteVMSnapshot(this);
boolean result = _vmSnapshotService.deleteVMSnapshot(getId());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);

View File

@ -39,10 +39,6 @@ public class ListVMSnapshotCmd extends BaseListTaggedResourcesCmd {
private static final String s_name = "listvmsnapshotresponse";
// ///////////////////////////////////////////////////
// ////////////// API parameters /////////////////////
// ///////////////////////////////////////////////////
@Parameter(name=ApiConstants.VM_SNAPSHOT_ID, type=CommandType.UUID, entityType=VMSnapshotResponse.class,
description="The ID of the VM snapshot")
private Long id;
@ -56,10 +52,6 @@ public class ListVMSnapshotCmd extends BaseListTaggedResourcesCmd {
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "lists snapshot by snapshot name or display name")
private String vmSnapshotName;
// ///////////////////////////////////////////////////
// ///////////////// Accessors ///////////////////////
// ///////////////////////////////////////////////////
public String getState() {
return state;
}
@ -76,10 +68,6 @@ public class ListVMSnapshotCmd extends BaseListTaggedResourcesCmd {
return id;
}
// ///////////////////////////////////////////////////
// ///////////// API Implementation///////////////////
// ///////////////////////////////////////////////////
@Override
public void execute() {
List<? extends VMSnapshot> result = _vmSnapshotService

View File

@ -30,9 +30,9 @@ import org.apache.cloudstack.api.response.VMSnapshotResponse;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.uservm.UserVm;
import com.cloud.vm.snapshot.VMSnapshot;
@ -55,33 +55,27 @@ public class RevertToSnapshotCmd extends BaseAsyncCmd {
return s_name;
}
public static String getResultObjectName() {
return "vm_snapshots";
}
@Override
public long getEntityOwnerId() {
VMSnapshot vmSnapshot = _vmSnapshotService.getVMSnapshotById(getVmSnapShotId());
if (vmSnapshot == null) {
throw new InvalidParameterValueException(
"Unable to find the snapshot by id=" + getVmSnapShotId());
VMSnapshot vmSnapshot = _entityMgr.findById(VMSnapshot.class, getVmSnapShotId());
if (vmSnapshot != null) {
return vmSnapshot.getAccountId();
}
UserVm userVM = _userVmService.getUserVm(vmSnapshot.getVmId());
return userVM.getAccountId();
return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException, ConcurrentOperationException {
UserContext.current().setEventDetails(
"vmsnapshot id: " + getVmSnapShotId());
UserVm result = _vmSnapshotService.revertToSnapshot(this);
UserVm result = _vmSnapshotService.revertToSnapshot(getVmSnapShotId());
if (result != null) {
UserVmResponse response = _responseGenerator.createUserVmResponse(
"virtualmachine", result).get(0);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,"Failed to revert vm snapshot");
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,"Failed to revert VM snapshot");
}
}

View File

@ -154,7 +154,6 @@ import com.cloud.utils.fsm.StateMachine2;
import com.cloud.vm.ItWorkVO.Step;
import com.cloud.vm.VirtualMachine.Event;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachineProfile.Param;
import com.cloud.vm.dao.ConsoleProxyDao;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicDao;
@ -1162,6 +1161,12 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
@Override
public boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId) throws NoTransitionException {
// if there are active vm snapshots task, state change is not allowed
if(_vmSnapshotMgr.hasActiveVMSnapshotTasks(vm.getId())){
s_logger.error("State transit with event: " + e + " failed due to: " + vm.getInstanceName() + " has active VM snapshots tasks");
return false;
}
State oldState = vm.getState();
if (oldState == State.Starting) {
if (e == Event.OperationSucceeded) {
@ -1650,19 +1655,15 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
AgentVmInfo info = infos.remove(vm.getId());
// sync VM Snapshots related transient states
List<VMSnapshotVO> expungingVMSnapshot = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging);
if( vm.getState() == State.RevertingToRunning || vm.getState() == State.RevertingToStopped
|| vm.getState() == State.RunningSnapshotting || vm.getState() == State.StoppedSnapshotting
|| expungingVMSnapshot.size() == 1){
s_logger.info("Found vm " + vm.getInstanceName() + " in state. " + vm.getState() + ", needs to sync VM snapshot state");
if(!_vmSnapshotMgr.syncVMSnapshot(vm, null, hostId)){
List<VMSnapshotVO> vmSnapshotsInTrasientStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging,VMSnapshot.State.Reverting, VMSnapshot.State.Creating);
if(vmSnapshotsInTrasientStates.size() > 1){
s_logger.info("Found vm " + vm.getInstanceName() + " with VM snapshots in transient states, needs to sync VM snapshot state");
if(!_vmSnapshotMgr.syncVMSnapshot(vm, hostId)){
s_logger.warn("Failed to sync VM in a transient snapshot related state: " + vm.getInstanceName());
continue;
}else{
s_logger.info("Successfully sync VM in a transient snapshot related state: " + vm.getInstanceName() + " to " + vm.getState());
s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName());
}
if(expungingVMSnapshot.size() == 1)
_vmSnapshotMgr.syncVMSnapshot(vm, expungingVMSnapshot.get(0), hostId);
}
VMInstanceVO castedVm = null;
@ -1784,29 +1785,25 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
VMInstanceVO castedVm = null;
// sync VM Snapshots related transient states
List<VMSnapshotVO> expungingVMSnapshot = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging);
if( vm.getState() == State.RevertingToRunning || vm.getState() == State.RevertingToStopped
|| vm.getState() == State.RunningSnapshotting || vm.getState() == State.StoppedSnapshotting
|| expungingVMSnapshot.size() == 1){
List<VMSnapshotVO> vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Creating,VMSnapshot.State.Reverting);
if(vmSnapshotsInExpungingStates.size() > 0){
s_logger.info("Found vm " + vm.getInstanceName() + " in state. " + vm.getState() + ", needs to sync VM snapshot state");
Long hostId = null;
Host host = null;
if(info != null && info.getHostUuid() != null){
Host host = _hostDao.findByGuid(info.getHostUuid());
hostId = host == null ? (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId()) : host.getId();
host = _hostDao.findByGuid(info.getHostUuid());
}
if(!_vmSnapshotMgr.syncVMSnapshot(vm, null, hostId)){
s_logger.warn("Failed to sync VM in a transient snapshot related state: " + vm.getInstanceName());
hostId = host == null ? (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId()) : host.getId();
if(!_vmSnapshotMgr.syncVMSnapshot(vm, hostId)){
s_logger.warn("Failed to sync VM with transient snapshot: " + vm.getInstanceName());
continue;
}else{
s_logger.info("Successfully sync VM in a transient snapshot related state: " + vm.getInstanceName() + " to " + vm.getState());
s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName());
}
if(expungingVMSnapshot.size() == 1)
_vmSnapshotMgr.syncVMSnapshot(vm, expungingVMSnapshot.get(0), hostId);
}
if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting ))
|| (info != null && (info.state == State.Running && vm.getState() == State.Starting))
|| (info != null && (info.state == State.Running && vm.getState() == State.RevertingToRunning)))
|| (info != null && (info.state == State.Running && vm.getState() == State.Starting)))
{
s_logger.info("Found vm " + vm.getInstanceName() + " in inconsistent state. " + vm.getState() + " on CS while " + (info == null ? "Stopped" : "Running") + " on agent");
info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);

View File

@ -33,14 +33,15 @@ public interface VMSnapshotManager extends VMSnapshotService, Manager {
boolean deleteAllVMSnapshots(long id, VMSnapshot.Type type);
/**
* Sync VM's state when VM in reverting or snapshotting, or VM snapshot in expunging state
* Sync VM snapshot state when VM snapshot in reverting or snapshoting or expunging state
* Used for fullsync after agent connects
*
* @param vm, the VM in question
* @param vmSnapshot, if this is not null, sync an VM snapshot in expunging state
* @param hostId
* @return true if succeeds, false if fails
*/
boolean syncVMSnapshot(VMInstanceVO vm, VMSnapshotVO vmSnapshot, Long hostId);
boolean syncVMSnapshot(VMInstanceVO vm, Long hostId);
boolean hasActiveVMSnapshotTasks(Long vmId);
}

View File

@ -26,10 +26,7 @@ import java.util.Map;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd;
import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd;
import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd;
import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager;
@ -59,7 +56,6 @@ import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.HypervisorGuruManager;
import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
@ -78,7 +74,6 @@ import com.cloud.user.dao.UserDao;
import com.cloud.uservm.UserVm;
import com.cloud.utils.DateUtil;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.component.Inject;
@ -121,7 +116,6 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
@Inject VirtualMachineManager _itMgr;
@Inject ConfigurationDao _configDao;
int _vmSnapshotMax;
StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
StateMachine2<VMSnapshot.State, VMSnapshot.Event, VMSnapshot> _vmSnapshottateMachine ;
@Override
@ -133,11 +127,10 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
if (_configDao == null) {
throw new ConfigurationException("Unable to get the configuration dao.");
}
s_logger.info("Snapshot Manager is configured.");
s_logger.info("VM Snapshot Manager is configured.");
_vmSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("vmsnapshot.max"), VMSNAPSHOTMAX);
_stateMachine = VirtualMachine.State.getStateMachine();
_vmSnapshottateMachine = VMSnapshot.State.getStateMachine();
return true;
}
@ -236,11 +229,8 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
}
@Override
public VMSnapshot allocVMSnapshot(CreateVMSnapshotCmd cmd) throws ResourceAllocationException {
Long vmId = cmd.getVmId();
String vsDisplayName = cmd.getDisplayName();
String vsDescription = cmd.getDescription();
Boolean snapshotMemory = cmd.snapshotMemory();
public VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDescription, Boolean snapshotMemory)
throws ResourceAllocationException {
Account caller = getCaller();
@ -250,6 +240,12 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
throw new InvalidParameterValueException("Creating VM snapshot failed due to VM:" + vmId + " is a system VM or does not exist");
}
// parameter length check
if(vsDisplayName != null && vsDisplayName.length()>255)
throw new InvalidParameterValueException("Creating VM snapshot failed due to length of VM snapshot vsDisplayName should not exceed 255");
if(vsDescription != null && vsDescription.length()>255)
throw new InvalidParameterValueException("Creating VM snapshot failed due to length of VM snapshot vsDescription should not exceed 255");
// VM snapshot display name must be unique for a VM
String timeString = DateUtil.getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(), DateUtil.YYYYMMDD_FORMAT);
String vmSnapshotName = userVmVo.getInstanceName() + "_VS_" + timeString;
@ -265,6 +261,10 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
throw new InvalidParameterValueException("Creating vm snapshot failed due to VM:" + vmId + " is not in the running or Stopped state");
}
if(snapshotMemory && userVmVo.getState() == VirtualMachine.State.Stopped){
throw new InvalidParameterValueException("Can not snapshot memory when VM is in stopped state");
}
// for KVM, only allow snapshot with memory when VM is in running state
if(userVmVo.getHypervisorType() == HypervisorType.KVM && userVmVo.getState() == State.Running && !snapshotMemory){
throw new InvalidParameterValueException("KVM VM does not allow to take a disk-only snapshot when VM is in running state");
@ -291,7 +291,7 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
}
// check if there are other active VM snapshot tasks
if (checkActiveVMSnapshotTasks(vmId)) {
if (hasActiveVMSnapshotTasks(vmId)) {
throw new CloudRuntimeException("There is other active vm snapshot tasks on the instance, please try again later");
}
@ -320,13 +320,22 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_CREATE, eventDescription = "creating_vm_snapshot", async = true)
public VMSnapshot creatVMSnapshot(CreateVMSnapshotCmd cmd) {
Long vmId = cmd.getVmId();
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_CREATE, eventDescription = "creating VM snapshot", async = true)
public VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId) {
UserVmVO userVm = _userVMDao.findById(vmId);
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(cmd.getEntityId());
if (userVm == null) {
throw new InvalidParameterValueException("Create vm to snapshot failed due to vm: " + vmId + " is not found");
}
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId);
if(vmSnapshot == null){
throw new CloudRuntimeException("VM snapshot id: " + vmSnapshotId + " can not be found");
}
Long hostId = pickRunningHost(vmId);
transitState(vmSnapshot, VMSnapshot.Event.CreateRequested, userVm, VirtualMachine.Event.SnapshotRequested, hostId);
try {
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.CreateRequested);
} catch (NoTransitionException e) {
throw new CloudRuntimeException(e.getMessage());
}
return createVmSnapshotInternal(userVm, vmSnapshot, hostId);
}
@ -355,15 +364,21 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
answer = (CreateVMSnapshotAnswer) sendToPool(hostId, ccmd);
if (answer != null && answer.getResult()) {
processAnswer(vmSnapshot, userVm, answer, hostId);
transitState(vmSnapshot, VMSnapshot.Event.OperationSucceeded, userVm, VirtualMachine.Event.OperationSucceeded, hostId);
s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
}else{
String errMsg = answer.getDetails();
s_logger.error("Agent reports creating vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + errMsg);
transitState(vmSnapshot, VMSnapshot.Event.OperationFailed, userVm, VirtualMachine.Event.OperationFailed, hostId);
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
}
return vmSnapshot;
} catch (Exception e) {
if(e instanceof AgentUnavailableException){
try {
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
} catch (NoTransitionException e1) {
s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
}
}
String msg = e.getMessage();
s_logger.error("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + msg);
throw new CloudRuntimeException(msg);
@ -412,26 +427,10 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
vo.getCurrent(), null);
}
private boolean vmSnapshotStateTransitTo(VMSnapshotVO vsnp, VMSnapshot.Event event) throws NoTransitionException {
protected boolean vmSnapshotStateTransitTo(VMSnapshotVO vsnp, VMSnapshot.Event event) throws NoTransitionException {
return _vmSnapshottateMachine.transitTo(vsnp, event, null, _vmSnapshotDao);
}
@DB
protected boolean transitState(VMSnapshotVO vsnp, VMSnapshot.Event e1, VMInstanceVO vm, VirtualMachine.Event e2, Long hostId){
final Transaction txn = Transaction.currentTxn();
try {
txn.start();
vmSnapshotStateTransitTo(vsnp, e1);
vmStateTransitTo(vm, e2, hostId, null);
return txn.commit();
} catch (NoTransitionException e) {
txn.rollback();
return false;
}finally{
txn.close();
}
}
@DB
protected void processAnswer(VMSnapshotVO vmSnapshot, UserVmVO userVm, Answer as, Long hostId) {
final Transaction txn = Transaction.currentTxn();
@ -440,9 +439,11 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
if (as instanceof CreateVMSnapshotAnswer) {
CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as;
finalizeCreate(vmSnapshot, answer.getVolumeTOs());
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
} else if (as instanceof RevertToVMSnapshotAnswer) {
RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as;
finalizeRevert(vmSnapshot, answer.getVolumeTOs());
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
} else if (as instanceof DeleteVMSnapshotAnswer) {
DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as;
finalizeDelete(vmSnapshot, answer.getVolumeTOs());
@ -502,9 +503,11 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
// update current snapshot, current snapshot is the one reverted to
VMSnapshotVO previousCurrent = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
previousCurrent.setCurrent(false);
if(previousCurrent != null){
previousCurrent.setCurrent(false);
_vmSnapshotDao.persist(previousCurrent);
}
vmSnapshot.setCurrent(true);
_vmSnapshotDao.persist(previousCurrent);
_vmSnapshotDao.persist(vmSnapshot);
}
@ -528,16 +531,16 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
return answer;
}
private boolean checkActiveVMSnapshotTasks(Long vmId){
@Override
public boolean hasActiveVMSnapshotTasks(Long vmId){
List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(vmId,
VMSnapshot.State.Creating, VMSnapshot.State.Expunging,VMSnapshot.State.Reverting,VMSnapshot.State.Allocated);
return activeVMSnapshots.size() > 0;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_DELETE, eventDescription = "delete_vm_snapshot", async=true)
public boolean deleteVMSnapshot(DeleteVMSnapshotCmd cmd) {
Long vmSnapshotId = cmd.getId();
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_DELETE, eventDescription = "delete vm snapshots", async=true)
public boolean deleteVMSnapshot(Long vmSnapshotId) {
Account caller = getCaller();
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId);
@ -548,13 +551,17 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
_accountMgr.checkAccess(caller, null, true, vmSnapshot);
// check VM snapshot states, only allow to delete vm snapshots in created and error state
if (VMSnapshot.State.Ready != vmSnapshot.getState() && VMSnapshot.State.Error != vmSnapshot.getState()) {
throw new InvalidParameterValueException("Can't delete the vm snapshotshot " + vmSnapshotId + " due to it is not in Created or Error State");
if (VMSnapshot.State.Ready != vmSnapshot.getState() && VMSnapshot.State.Expunging != vmSnapshot.getState() && VMSnapshot.State.Error != vmSnapshot.getState()) {
throw new InvalidParameterValueException("Can't delete the vm snapshotshot " + vmSnapshotId + " due to it is not in Created or Error, or Expunging State");
}
// check if there are other active VM snapshot tasks
if (checkActiveVMSnapshotTasks(vmSnapshot.getVmId())) {
throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
if (hasActiveVMSnapshotTasks(vmSnapshot.getVmId())) {
List<VMSnapshotVO> expungingSnapshots = _vmSnapshotDao.listByInstanceId(vmSnapshot.getVmId(), VMSnapshot.State.Expunging);
if(expungingSnapshots.size() > 0 && expungingSnapshots.get(0).getId() == vmSnapshot.getId())
s_logger.debug("Target VM snapshot already in expunging state, go on deleting it: " + vmSnapshot.getDisplayName());
else
throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
}
if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
@ -587,6 +594,7 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
if (answer != null && answer.getResult()) {
processAnswer(vmSnapshot, userVm, answer, hostId);
s_logger.debug("Delete VM snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
return true;
} else {
s_logger.error("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + answer.getDetails());
@ -600,11 +608,9 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_REVERT, eventDescription = "revert_vm", async = true)
public UserVm revertToSnapshot(RevertToSnapshotCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException {
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_REVERT, eventDescription = "revert to VM snapshot", async = true)
public UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException {
Long vmSnapshotId = cmd.getVmSnapShotId();
// check if VM snapshot exists in DB
VMSnapshotVO vmSnapshotVo = _vmSnapshotDao.findById(vmSnapshotId);
if (vmSnapshotVo == null) {
@ -621,7 +627,7 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
}
// check if there are other active VM snapshot tasks
if (checkActiveVMSnapshotTasks(vmId)) {
if (hasActiveVMSnapshotTasks(vmId)) {
throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
}
@ -672,19 +678,21 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
throw new CloudRuntimeException("Can not find any host to revert snapshot " + vmSnapshotVo.getName());
// check if there are other active VM snapshot tasks
if (checkActiveVMSnapshotTasks(userVm.getId())) {
if (hasActiveVMSnapshotTasks(userVm.getId())) {
throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
}
userVm = _userVMDao.findById(userVm.getId());
transitState(vmSnapshotVo, VMSnapshot.Event.RevertRequested, userVm, VirtualMachine.Event.RevertRequested, hostId);
try {
vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.RevertRequested);
} catch (NoTransitionException e) {
throw new CloudRuntimeException(e.getMessage());
}
return revertInternal(userVm, vmSnapshotVo, hostId);
}
private UserVm revertInternal(UserVmVO userVm, VMSnapshotVO vmSnapshotVo, Long hostId) {
try {
VMSnapshotVO snapshot = _vmSnapshotDao.findById(vmSnapshotVo.getId());
// prepare RevertToSnapshotCommand
List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
@ -697,20 +705,27 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
RevertToVMSnapshotCommand revertToSnapshotCommand = new RevertToVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs, guestOS.getDisplayName());
RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) sendToPool(hostId, revertToSnapshotCommand);
if (answer.getResult()) {
if (answer != null && answer.getResult()) {
processAnswer(vmSnapshotVo, userVm, answer, hostId);
transitState(vmSnapshotVo, VMSnapshot.Event.OperationSucceeded, userVm, VirtualMachine.Event.OperationSucceeded, hostId);
s_logger.debug("RevertTo " + vmSnapshotVo.getName() + " succeeded for vm: " + userVm.getInstanceName());
} else {
String errMsg = "Revert VM: " + userVm.getInstanceName() + " to snapshot: "+ vmSnapshotVo.getName() + " failed";
if(answer != null && answer.getDetails() != null)
errMsg = errMsg + " due to " + answer.getDetails();
s_logger.error(errMsg);
// agent report revert operation fails
transitState(vmSnapshotVo, VMSnapshot.Event.OperationFailed, userVm, VirtualMachine.Event.OperationFailed, hostId);
vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
throw new CloudRuntimeException(errMsg);
}
} catch (Exception e) {
// for other exceptions, do not change VM state, leave it for snapshotSync
if(e instanceof AgentUnavailableException){
try {
vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
} catch (NoTransitionException e1) {
s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
}
}
// for other exceptions, do not change VM snapshot state, leave it for snapshotSync
String errMsg = "revert vm: " + userVm.getInstanceName() + " to snapshot " + vmSnapshotVo.getName() + " failed due to " + e.getMessage();
s_logger.error(errMsg);
throw new CloudRuntimeException(e.getMessage());
@ -718,18 +733,14 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
return userVm;
}
private boolean vmStateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId, String reservationId) throws NoTransitionException {
vm.setReservationId(reservationId);
return _stateMachine.transitTo(vm, e, new Pair<Long, Long>(vm.getHostId(), hostId), _vmInstanceDao);
}
@Override
public VMSnapshot getVMSnapshotById(long id) {
public VMSnapshot getVMSnapshotById(Long id) {
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
return vmSnapshot;
}
private Long pickRunningHost(Long vmId) {
protected Long pickRunningHost(Long vmId) {
UserVmVO vm = _userVMDao.findById(vmId);
// use VM's host if VM is running
if(vm.getState() == State.Running)
@ -766,6 +777,9 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
@Override
public VirtualMachine getVMBySnapshotId(Long id) {
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
if(vmSnapshot == null){
throw new InvalidParameterValueException("unable to find the vm snapshot with id " + id);
}
Long vmId = vmSnapshot.getVmId();
UserVmVO vm = _userVMDao.findById(vmId);
return vm;
@ -790,37 +804,29 @@ public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotServi
}
@Override
public boolean syncVMSnapshot(VMInstanceVO vm, VMSnapshotVO vmSnapshot, Long hostId) {
public boolean syncVMSnapshot(VMInstanceVO vm, Long hostId) {
try{
UserVmVO userVm = _userVMDao.findById(vm.getId());
if(userVm == null)
return false;
if(userVm.getState() == State.RevertingToRunning || userVm.getState() == State.RevertingToStopped){
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(), VMSnapshot.State.Reverting);
if(vmSnapshots.size() != 1){
s_logger.error("VM:" + userVm.getInstanceName()+ " expected to have one VM snapshot in reverting state but actually has " + vmSnapshots.size());
return false;
List<VMSnapshotVO> vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Reverting, VMSnapshot.State.Creating);
for (VMSnapshotVO vmSnapshotVO : vmSnapshotsInExpungingStates) {
if(vmSnapshotVO.getState() == VMSnapshot.State.Expunging){
return deleteSnapshotInternal(vmSnapshotVO);
}else if(vmSnapshotVO.getState() == VMSnapshot.State.Creating){
return createVmSnapshotInternal(userVm, vmSnapshotVO, hostId) != null;
}else if(vmSnapshotVO.getState() == VMSnapshot.State.Reverting){
return revertInternal(userVm, vmSnapshotVO, hostId) != null;
}
// send revert command again
revertInternal(userVm, vmSnapshots.get(0), hostId);
return true;
}else if (userVm.getState() == State.RunningSnapshotting || userVm.getState() == State.StoppedSnapshotting){
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(), VMSnapshot.State.Creating);
if(vmSnapshots.size() != 1){
s_logger.error("VM:" + userVm.getInstanceName()+ " expected to have one VM snapshot in creating state but actually has " + vmSnapshots.size());
return false;
}
// send create vm snapshot command again
createVmSnapshotInternal(userVm, vmSnapshots.get(0), hostId);
return true;
}else if (vmSnapshot != null && vmSnapshot.getState() == VMSnapshot.State.Expunging){
return deleteSnapshotInternal(vmSnapshot);
}
}catch (Exception e) {
s_logger.error(e.getMessage(),e);
return false;
if(_vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging).size() == 0)
return true;
else
return false;
}
return false;
}

View File

@ -16,17 +16,27 @@
// under the License.
package com.cloud.vm.snapshot;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.CreateVMSnapshotAnswer;
import com.cloud.agent.api.CreateVMSnapshotCommand;
import com.cloud.agent.api.to.VolumeTO;
@ -49,25 +59,15 @@ import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.uservm.UserVm;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.Event;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.Before;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
public class VMSnapshotManagerTest {
@ -90,8 +90,6 @@ public class VMSnapshotManagerTest {
@Mock ConfigurationDao _configDao;
int _vmSnapshotMax = 10;
@Mock CreateVMSnapshotCmd createCmd;
private static long TEST_VM_ID = 3L;
@Mock UserVmVO vmMock;
@Mock VolumeVO volumeMock;
@ -113,9 +111,6 @@ public class VMSnapshotManagerTest {
_vmSnapshotMgr._vmSnapshotMax = _vmSnapshotMax;
when(createCmd.getVmId()).thenReturn(TEST_VM_ID);
when(createCmd.getDisplayName()).thenReturn("testName");
when(_userVMDao.findById(anyLong())).thenReturn(vmMock);
when(_vmSnapshotDao.findByName(anyLong(), anyString())).thenReturn(null);
when(_vmSnapshotDao.findByVm(anyLong())).thenReturn(new ArrayList<VMSnapshotVO>());
@ -135,48 +130,57 @@ public class VMSnapshotManagerTest {
@Test(expected=InvalidParameterValueException.class)
public void testAllocVMSnapshotF1() throws ResourceAllocationException{
when(_userVMDao.findById(TEST_VM_ID)).thenReturn(null);
_vmSnapshotMgr.allocVMSnapshot(createCmd);
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
}
// vm state not in [running, stopped] case
@Test(expected=InvalidParameterValueException.class)
public void testAllocVMSnapshotF2() throws ResourceAllocationException{
when(vmMock.getState()).thenReturn(State.Starting);
_vmSnapshotMgr.allocVMSnapshot(createCmd);
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
}
// VM in stopped state & snapshotmemory case
@Test(expected=InvalidParameterValueException.class)
public void testCreateVMSnapshotF3() throws AgentUnavailableException, OperationTimedoutException, ResourceAllocationException{
when(vmMock.getState()).thenReturn(State.Stopped);
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
}
// max snapshot limit case
@SuppressWarnings("unchecked")
@Test(expected=CloudRuntimeException.class)
public void testAllocVMSnapshotF3() throws ResourceAllocationException{
public void testAllocVMSnapshotF4() throws ResourceAllocationException{
List<VMSnapshotVO> mockList = mock(List.class);
when(mockList.size()).thenReturn(10);
when(_vmSnapshotDao.findByVm(TEST_VM_ID)).thenReturn(mockList);
_vmSnapshotMgr.allocVMSnapshot(createCmd);
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
}
// active volume snapshots case
@SuppressWarnings("unchecked")
@Test(expected=CloudRuntimeException.class)
public void testAllocVMSnapshotF4() throws ResourceAllocationException{
public void testAllocVMSnapshotF5() throws ResourceAllocationException{
List<SnapshotVO> mockList = mock(List.class);
when(mockList.size()).thenReturn(1);
when(_snapshotDao.listByInstanceId(TEST_VM_ID,Snapshot.Status.Creating,
Snapshot.Status.CreatedOnPrimary, Snapshot.Status.BackingUp)).thenReturn(mockList);
_vmSnapshotMgr.allocVMSnapshot(createCmd);
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
}
// successful creation case
@Test
public void testCreateVMSnapshot() throws AgentUnavailableException, OperationTimedoutException{
public void testCreateVMSnapshot() throws AgentUnavailableException, OperationTimedoutException, ResourceAllocationException, NoTransitionException{
when(vmMock.getState()).thenReturn(State.Running);
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
when(_vmSnapshotDao.findCurrentSnapshotByVmId(anyLong())).thenReturn(null);
doReturn(new ArrayList<VolumeTO>()).when(_vmSnapshotMgr).getVolumeTOList(anyLong());
doReturn(new CreateVMSnapshotAnswer(null,true,"")).when(_vmSnapshotMgr).sendToPool(anyLong(), any(CreateVMSnapshotCommand.class));
doReturn(true).when(_vmSnapshotMgr).transitState(any(VMSnapshotVO.class),
any(VMSnapshot.Event.class), any(VMInstanceVO.class), any(VirtualMachine.Event.class), anyLong());
doNothing().when(_vmSnapshotMgr).processAnswer(any(VMSnapshotVO.class),
any(UserVmVO.class), any(Answer.class), anyLong());
doReturn(true).when(_vmSnapshotMgr).vmSnapshotStateTransitTo(any(VMSnapshotVO.class),any(VMSnapshot.Event.class));
_vmSnapshotMgr.createVmSnapshotInternal(vmMock, mock(VMSnapshotVO.class), 5L);
}
}

View File

@ -49,14 +49,6 @@
zonename: { label: 'label.zone.name' },
state: {
label: 'label.state',
converter: function(data) {
if(data == 'StoppedSnapshotting' || data == 'RunningSnapshotting')
return 'Snapshotting';
if(data == 'RevertingToRunning' || data == 'RevertingToStopped'){
return 'Reverting';
}
return data;
},
indicator: {
'Running': 'on',
'Stopped': 'off',