Add storage migration

This commit is contained in:
Edison Su 2011-10-24 15:56:23 -07:00
parent fc3d93e3e7
commit 92eaf49f29
35 changed files with 735 additions and 277 deletions

View File

@ -27,6 +27,8 @@ import com.cloud.agent.api.ModifyStoragePoolCommand;
import com.cloud.agent.api.SecStorageSetupCommand;
import com.cloud.agent.api.SecStorageVMSetupCommand;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
@ -77,5 +79,7 @@ public interface MockStorageManager extends Manager {
public Answer CreatePrivateTemplateFromVolume(CreatePrivateTemplateFromVolumeCommand cmd);
StoragePoolInfo getLocalStorage(String hostGuid, Long storageSize);
StoragePoolInfo getLocalStorage(String hostGuid, Long storageSize);
CopyVolumeAnswer CopyVolume(CopyVolumeCommand cmd);
}

View File

@ -44,6 +44,8 @@ import com.cloud.agent.api.SecStorageSetupAnswer;
import com.cloud.agent.api.SecStorageSetupCommand;
import com.cloud.agent.api.SecStorageVMSetupCommand;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
@ -669,6 +671,50 @@ public class MockStorageManagerImpl implements MockStorageManager {
return new CreatePrivateTemplateAnswer(cmd, true, "", template.getName(), template.getSize(), template.getSize(), template.getName(), ImageFormat.QCOW2);
}
@Override
public CopyVolumeAnswer CopyVolume(CopyVolumeCommand cmd) {
boolean toSecondaryStorage = cmd.toSecondaryStorage();
MockSecStorageVO sec = _mockSecStorageDao.findByUrl(cmd.getSecondaryStorageURL());
if (sec == null) {
return new CopyVolumeAnswer(cmd, false, "can't find secondary storage", null, null);
}
MockStoragePoolVO primaryStorage = _mockStoragePoolDao.findByUuid(cmd.getPool().getUuid());
if (primaryStorage == null) {
return new CopyVolumeAnswer(cmd, false, "Can't find primary storage", null, null);
}
MockVolumeVO volume = _mockVolumeDao.findByStoragePathAndType(cmd.getVolumePath());
if (volume == null) {
return new CopyVolumeAnswer(cmd, false, "cant' find volume" + cmd.getVolumePath(), null, null);
}
String name = UUID.randomUUID().toString();
if (toSecondaryStorage) {
MockVolumeVO vol = new MockVolumeVO();
vol.setName(name);
vol.setPath(sec.getMountPoint() + name);
vol.setPoolId(sec.getId());
vol.setSize(volume.getSize());
vol.setStatus(Status.DOWNLOADED);
vol.setType(MockVolumeType.VOLUME);
vol = _mockVolumeDao.persist(vol);
return new CopyVolumeAnswer(cmd, true, null, sec.getMountPoint(), vol.getPath());
}
else {
MockVolumeVO vol = new MockVolumeVO();
vol.setName(name);
vol.setPath(primaryStorage.getMountPoint() + name);
vol.setPoolId(primaryStorage.getId());
vol.setSize(volume.getSize());
vol.setStatus(Status.DOWNLOADED);
vol.setType(MockVolumeType.VOLUME);
vol = _mockVolumeDao.persist(vol);
return new CopyVolumeAnswer(cmd, true, null, primaryStorage.getMountPoint(), vol.getPath());
}
}
}

View File

@ -13,6 +13,8 @@ import java.util.Set;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.CheckVirtualMachineCommand;
import com.cloud.agent.api.CleanupNetworkRulesCmd;
import com.cloud.agent.api.GetDomRVersionAnswer;
import com.cloud.agent.api.GetDomRVersionCmd;
import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.GetVncPortCommand;
import com.cloud.agent.api.MigrateAnswer;
@ -80,5 +82,6 @@ public interface MockVmManager extends Manager {
HashMap<String, Pair<Long, Long>> syncNetworkGroups(SimulatorInfo info);
SecurityIngressRuleAnswer AddSecurityIngressRules(SecurityIngressRulesCmd cmd, SimulatorInfo info);
MigrateAnswer Migrate(MigrateCommand cmd, SimulatorInfo info);
GetDomRVersionAnswer getDomRVersion(GetDomRVersionCmd cmd);
}

View File

@ -21,6 +21,8 @@ import com.cloud.agent.api.Answer;
import com.cloud.agent.api.CheckVirtualMachineAnswer;
import com.cloud.agent.api.CheckVirtualMachineCommand;
import com.cloud.agent.api.CleanupNetworkRulesCmd;
import com.cloud.agent.api.GetDomRVersionAnswer;
import com.cloud.agent.api.GetDomRVersionCmd;
import com.cloud.agent.api.GetVmStatsAnswer;
import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.GetVncPortAnswer;
@ -351,6 +353,11 @@ public class MockVmManagerImpl implements MockVmManager {
public Answer WatchConsoleProxyLoad(WatchConsoleProxyLoadCommand cmd) {
return Answer.createUnsupportedCommandAnswer(cmd);
}
@Override
public GetDomRVersionAnswer getDomRVersion(GetDomRVersionCmd cmd) {
return new GetDomRVersionAnswer(cmd, null, null, null);
}
@Override
public SecurityIngressRuleAnswer AddSecurityIngressRules(SecurityIngressRulesCmd cmd, SimulatorInfo info) {

View File

@ -17,6 +17,7 @@ import com.cloud.agent.api.AttachVolumeCommand;
import com.cloud.agent.api.BackupSnapshotCommand;
import com.cloud.agent.api.CheckHealthCommand;
import com.cloud.agent.api.CleanupNetworkRulesCmd;
import com.cloud.agent.api.ClusterSyncCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.ComputeChecksumCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
@ -25,6 +26,7 @@ import com.cloud.agent.api.CreateStoragePoolCommand;
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
import com.cloud.agent.api.DeleteSnapshotBackupCommand;
import com.cloud.agent.api.DeleteStoragePoolCommand;
import com.cloud.agent.api.GetDomRVersionCmd;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.GetStorageStatsCommand;
import com.cloud.agent.api.GetVmStatsCommand;
@ -52,6 +54,7 @@ import com.cloud.agent.api.routing.SavePasswordCommand;
import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
import com.cloud.agent.api.routing.VmDataCommand;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.DeleteTemplateCommand;
import com.cloud.agent.api.storage.DestroyCommand;
@ -260,6 +263,12 @@ public class SimulatorManagerImpl implements SimulatorManager {
return _mockAgentMgr.MaintainCommand((MaintainCommand)cmd);
} else if (cmd instanceof GetVmStatsCommand) {
return _mockVmMgr.getVmStats((GetVmStatsCommand)cmd);
} else if (cmd instanceof GetDomRVersionCmd) {
return _mockVmMgr.getDomRVersion((GetDomRVersionCmd)cmd);
} else if (cmd instanceof ClusterSyncCommand) {
return new Answer(cmd);
} else if (cmd instanceof CopyVolumeCommand) {
return _mockStorageMgr.CopyVolume((CopyVolumeCommand)cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}

View File

@ -70,6 +70,13 @@ public class MockVm {
public int getVncPort() {
return vncPort;
}
public static void main(String[] args) {
long i = 10;
Long l = null;
if (i == l) {
System.out.print("fdfd");
}
}
}

View File

@ -33,6 +33,7 @@ import com.cloud.exception.ManagementServerException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.VirtualMachineMigrationException;
import com.cloud.host.Host;
import com.cloud.storage.StoragePool;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.uservm.UserVm;
@ -48,12 +49,14 @@ public class MigrateVMCmd extends BaseAsyncCmd {
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.HOST_ID, type=CommandType.LONG, required=true, description="destination Host ID to migrate VM to")
@Parameter(name=ApiConstants.HOST_ID, type=CommandType.LONG, required=false, description="destination Host ID to migrate VM to")
private Long hostId;
@Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.LONG, required=true, description="the ID of the virtual machine")
private Long virtualMachineId;
@Parameter(name=ApiConstants.STORAGE_ID, type=CommandType.LONG, required=false, description="destination storage pool ID to migrate VM to")
private Long storageId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
@ -66,6 +69,10 @@ public class MigrateVMCmd extends BaseAsyncCmd {
public Long getVirtualMachineId() {
return virtualMachineId;
}
public Long getStoragePoolId() {
return storageId;
}
/////////////////////////////////////////////////////
@ -99,18 +106,44 @@ public class MigrateVMCmd extends BaseAsyncCmd {
@Override
public void execute(){
if (getHostId() == null && getStoragePoolId() == null) {
throw new InvalidParameterValueException("either hostId or storageId must be specified");
}
if (getHostId() != null && getStoragePoolId() != null) {
throw new InvalidParameterValueException("only one of hostId and storageId can be specified");
}
UserVm userVm = _userVmService.getUserVm(getVirtualMachineId());
if (userVm == null) {
throw new InvalidParameterValueException("Unable to find the VM by id=" + getVirtualMachineId());
}
Host destinationHost = _resourceService.getHost(getHostId());
if (destinationHost == null) {
throw new InvalidParameterValueException("Unable to find the host to migrate the VM, host id=" + getHostId());
}
try{
Host destinationHost = null;
if (getHostId() != null) {
destinationHost = _resourceService.getHost(getHostId());
if (destinationHost == null) {
throw new InvalidParameterValueException("Unable to find the host to migrate the VM, host id=" + getHostId());
}
UserContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to host Id: "+ getHostId());
VirtualMachine migratedVm = _userVmService.migrateVirtualMachine(getVirtualMachineId(), destinationHost);
}
StoragePool destStoragePool = null;
if (getStoragePoolId() != null) {
destStoragePool = _storageService.getStoragePool(getStoragePoolId());
if (destStoragePool == null) {
throw new InvalidParameterValueException("Unable to find the storage pool to migrate the VM");
}
UserContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to storage pool Id: "+ getStoragePoolId());
}
try{
VirtualMachine migratedVm = null;
if (getHostId() != null) {
migratedVm = _userVmService.migrateVirtualMachine(getVirtualMachineId(), destinationHost);
} else if (getStoragePoolId() != null) {
migratedVm = _userVmService.vmStorageMigration(getVirtualMachineId(), destStoragePool);
}
if (migratedVm != null) {
UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", (UserVm)migratedVm).get(0);
response.setResponseName(getCommandName());

View File

@ -104,7 +104,8 @@ public class EventTypes {
public static final String EVENT_VOLUME_ATTACH = "VOLUME.ATTACH";
public static final String EVENT_VOLUME_DETACH = "VOLUME.DETACH";
public static final String EVENT_VOLUME_EXTRACT = "VOLUME.EXTRACT";
public static final String EVENT_VOLUME_UPLOAD = "VOLUME.UPLOAD";
public static final String EVENT_VOLUME_UPLOAD = "VOLUME.UPLOAD";
public static final String EVENT_VOLUME_MIGRATE = "VOLUME.MIGRATE";
// Domains
public static final String EVENT_DOMAIN_CREATE = "DOMAIN.CREATE";

View File

@ -18,6 +18,7 @@
package com.cloud.storage;
import java.net.UnknownHostException;
import java.util.List;
import com.cloud.api.commands.CancelPrimaryStorageMaintenanceCmd;
import com.cloud.api.commands.CreateStoragePoolCmd;
@ -105,4 +106,5 @@ public interface StorageService {
public StoragePool getStoragePool(long id);
Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException;
}

View File

@ -25,16 +25,22 @@ import com.cloud.acl.ControlledEntity;
import com.cloud.template.BasedOn;
import com.cloud.utils.fsm.FiniteState;
import com.cloud.utils.fsm.StateMachine;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.utils.fsm.StateObject;
import com.cloud.vm.VirtualMachine;
public interface Volume extends ControlledEntity, BasedOn {
public interface Volume extends ControlledEntity, BasedOn, StateObject<Volume.State> {
enum Type {
UNKNOWN, ROOT, SWAP, DATADISK, ISO
};
enum State implements FiniteState<State, Event> {
enum State {
Allocated("The volume is allocated but has not been created yet."),
Creating("The volume is being created. getPoolId() should reflect the pool where it is being created."),
Ready("The volume is ready to be used."),
Migrating("The volume is migrating to other storage pool"),
Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"),
Expunging("The volume is being expunging"),
Destroy("The volume is destroyed, and can't be recovered.");
String _description;
@ -43,46 +49,44 @@ public interface Volume extends ControlledEntity, BasedOn {
_description = description;
}
@Override
public StateMachine<State, Event> getStateMachine() {
public static StateMachine2<State, Event, Volume> getStateMachine() {
return s_fsm;
}
@Override
public State getNextState(Event event) {
return s_fsm.getNextState(this, event);
}
@Override
public List<State> getFromStates(Event event) {
return s_fsm.getFromStates(this, event);
}
@Override
public Set<Event> getPossibleEvents() {
return s_fsm.getPossibleEvents(this);
}
@Override
public String getDescription() {
return _description;
}
private final static StateMachine<State, Event> s_fsm = new StateMachine<State, Event>();
private final static StateMachine2<State, Event, Volume> s_fsm = new StateMachine2<State, Event, Volume>();
static {
s_fsm.addTransition(Allocated, Event.Create, Creating);
s_fsm.addTransition(Allocated, Event.Destroy, Destroy);
s_fsm.addTransition(Allocated, Event.CreateRequested, Creating);
s_fsm.addTransition(Allocated, Event.DestroyRequested, Destroy);
s_fsm.addTransition(Creating, Event.OperationRetry, Creating);
s_fsm.addTransition(Creating, Event.OperationFailed, Allocated);
s_fsm.addTransition(Creating, Event.OperationSucceeded, Ready);
s_fsm.addTransition(Creating, Event.Destroy, Destroy);
s_fsm.addTransition(Creating, Event.Create, Creating);
s_fsm.addTransition(Ready, Event.Destroy, Destroy);
s_fsm.addTransition(Creating, Event.DestroyRequested, Destroy);
s_fsm.addTransition(Creating, Event.CreateRequested, Creating);
s_fsm.addTransition(Ready, Event.DestroyRequested, Destroy);
s_fsm.addTransition(Destroy, Event.ExpungingRequested, Expunging);
s_fsm.addTransition(Ready, Event.SnapshotRequested, Snapshotting);
s_fsm.addTransition(Snapshotting, Event.OperationSucceeded, Ready);
s_fsm.addTransition(Snapshotting, Event.OperationFailed, Ready);
s_fsm.addTransition(Ready, Event.MigrationRequested, Migrating);
s_fsm.addTransition(Migrating, Event.OperationSucceeded, Ready);
s_fsm.addTransition(Migrating, Event.OperationFailed, Ready);
s_fsm.addTransition(Destroy, Event.OperationSucceeded, Destroy);
}
}
enum Event {
Create, OperationFailed, OperationSucceeded, OperationRetry, Destroy;
CreateRequested,
OperationFailed,
OperationSucceeded,
OperationRetry,
MigrationRequested,
SnapshotRequested,
DestroyRequested,
ExpungingRequested;
}
long getId();
@ -133,4 +137,10 @@ public interface Volume extends ControlledEntity, BasedOn {
String getChainInfo();
boolean isRecreatable();
public long getUpdatedCount();
public void incrUpdatedCount();
public Date getUpdated();
}

View File

@ -48,6 +48,7 @@ import com.cloud.exception.VirtualMachineMigrationException;
import com.cloud.host.Host;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.StoragePool;
import com.cloud.storage.Volume;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
@ -358,11 +359,12 @@ public interface UserVmService {
/**
* Migrate the given VM to the destination host provided. The API returns the migrated VM if migration succeeds. Only Root
* Admin can migrate a VM.
*
* @param destinationStorage TODO
* @param Long vmId
* vmId of The VM to migrate
* @param Host
* destinationHost to migrate the VM
*
* @return VirtualMachine migrated VM
* @throws ManagementServerException
* in case we get error finding the VM or host or access errors or other internal errors.
@ -376,4 +378,6 @@ public interface UserVmService {
VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException;
UserVm moveVMToUser(MoveUserVMCmd moveUserVMCmd) throws ResourceAllocationException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException ;
VirtualMachine vmStorageMigration(Long vmId, StoragePool destPool);
}

View File

@ -79,6 +79,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, StateObject
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.OperationFailed, State.Stopped);
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.ExpungeOperation, State.Expunging);
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.AgentReportShutdowned, State.Stopped);
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.StorageMigrationRequested, State.Migrating);
s_fsm.addTransition(State.Starting, VirtualMachine.Event.OperationRetry, State.Starting);
s_fsm.addTransition(State.Starting, VirtualMachine.Event.OperationSucceeded, State.Running);
s_fsm.addTransition(State.Starting, VirtualMachine.Event.OperationFailed, State.Stopped);
@ -160,6 +161,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, StateObject
AgentReportStopped,
AgentReportRunning,
MigrationRequested,
StorageMigrationRequested,
ExpungeOperation,
OperationSucceeded,
OperationFailed,

View File

@ -49,7 +49,10 @@ public class VolumeVO implements Volume {
@Column(name = "pool_id")
Long poolId;
@Column(name = "last_pool_id")
Long lastPoolId;
@Column(name = "account_id")
long accountId;
@ -110,6 +113,9 @@ public class VolumeVO implements Volume {
@Column(name = "updated")
@Temporal(value = TemporalType.TIMESTAMP)
Date updated;
@Column(name="update_count", updatable = true, nullable=false)
protected long updatedCount; // This field should be updated everytime the state is updated. There's no set method in the vo object because it is done with in the dao code.
@Column(name = "recreatable")
boolean recreatable;
@ -144,6 +150,7 @@ public class VolumeVO implements Volume {
this.podId = podId;
this.dataCenterId = dcId;
this.volumeType = vType;
this.state = Volume.State.Allocated;
this.recreatable = false;
}
@ -162,6 +169,20 @@ public class VolumeVO implements Volume {
this.deviceId = that.getDeviceId();
}
@Override
public long getUpdatedCount() {
return this.updatedCount;
}
@Override
public void incrUpdatedCount() {
this.updatedCount++;
}
public void decrUpdatedCount() {
this.updatedCount--;
}
@Override
public boolean isRecreatable() {
return recreatable;
@ -342,6 +363,7 @@ public class VolumeVO implements Volume {
this.poolId = poolId;
}
@Override
public Date getUpdated() {
return updated;
}
@ -351,10 +373,6 @@ public class VolumeVO implements Volume {
return state;
}
public void setState(State state) {
this.state = state;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
@ -381,6 +399,14 @@ public class VolumeVO implements Volume {
public void setChainInfo(String chainInfo) {
this.chainInfo = chainInfo;
}
public Long getLastPoolId() {
return this.lastPoolId;
}
public void setLastPoolId(Long poolId) {
this.lastPoolId = poolId;
}
@Override
public int hashCode() {

View File

@ -2376,9 +2376,11 @@ public class ApiResponseHelper implements ResponseGenerator {
sgr.setDescription(sgd.getDescription());
Account account = ApiDBUtils.findAccountByNameDomain(sgd.getAccountName(), sgd.getDomainId());
populateAccount(sgr, account.getId());
populateDomain(sgr, sgd.getDomainId());
if (account != null) {
populateAccount(sgr, account.getId());
populateDomain(sgr, sgd.getDomainId());
}
sgr.setObjectName(sgd.getObjectName());
securityGroupResponse.add(sgr);
}

View File

@ -510,12 +510,12 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet
}
@Override
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Long id) {
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) {
return true;
}
@Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Long id) {
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) {
if (newState != State.Starting && newState != State.Error && newState != State.Expunging) {
return true;
}

View File

@ -50,6 +50,7 @@ import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.utils.DateUtil;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Inject;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.DB;
@ -530,15 +531,18 @@ public class CapacityManagerImpl implements CapacityManager, StateListener<State
}
@Override
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean transitionStatus, Long id) {
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean transitionStatus, Object opaque) {
return true;
}
@Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Long oldHostId) {
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Object opaque) {
if (!status) {
return false;
}
@SuppressWarnings("unchecked")
Pair<Long, Long> hosts = (Pair<Long, Long>)opaque;
Long oldHostId = hosts.first();
s_logger.debug("VM state transitted from :" + oldState + " to " + newState + " with event: " + event + "vm's original host id: "
+ vm.getLastHostId() + " new host id: " + vm.getHostId() + " host id before state transition: " + oldHostId);

View File

@ -110,7 +110,7 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
}
@Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Long oldHostId) {
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Object opaque) {
if (!_isEnabled || !status || (vm.getType() != VirtualMachine.Type.User && vm.getType() != VirtualMachine.Type.DomainRouter)) {
return false;
}
@ -123,7 +123,7 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
}
@Override
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Long id) {
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Object opaque) {
if (!_isEnabled || !status || (vm.getType() != VirtualMachine.Type.User && vm.getType() != VirtualMachine.Type.DomainRouter)) {
return false;
}

View File

@ -1243,12 +1243,12 @@ public class SecurityGroupManagerImpl implements SecurityGroupManager, SecurityG
}
@Override
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Long id) {
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) {
return true;
}
@Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Long oldHostId) {
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Object opaque) {
if (!status) {
return false;
}

View File

@ -33,10 +33,12 @@ import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.storage.Volume.Event;
import com.cloud.storage.Volume.Type;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Manager;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
@ -86,9 +88,10 @@ public interface StorageManager extends Manager {
* @param destPoolDcId
* @param destPoolPodId
* @param destPoolClusterId
* @return VolumeVO
* @return VolumeVO
* @throws ConcurrentOperationException
*/
VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType);
VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException;
/**
* Create a volume based on the given criteria
@ -110,9 +113,10 @@ public interface StorageManager extends Manager {
/**
* Marks the specified volume as destroyed in the management server database. The expunge thread will delete the volume from its storage pool.
* @param volume
* @param volume
* @return
*/
void destroyVolume(VolumeVO volume) throws ConcurrentOperationException;
boolean destroyVolume(VolumeVO volume) throws ConcurrentOperationException;
/** Create capacity entries in the op capacity table
* @param storagePool
@ -207,4 +211,11 @@ public interface StorageManager extends Manager {
VMTemplateHostVO getTemplateHostRef(long zoneId, long tmpltId, boolean readyOnly);
boolean StorageMigration(
VirtualMachineProfile<? extends VirtualMachine> vm,
StoragePool destPool) throws ConcurrentOperationException;
boolean stateTransitTo(Volume vol, Event event)
throws NoTransitionException;
}

View File

@ -123,6 +123,7 @@ import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.Volume.Event;
import com.cloud.storage.Volume.Type;
import com.cloud.storage.allocator.StoragePoolAllocator;
import com.cloud.storage.dao.DiskOfferingDao;
@ -166,6 +167,8 @@ import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExecutionException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.vm.ConsoleProxyVO;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.DomainRouterVO;
@ -310,6 +313,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
protected float _overProvisioningFactor = 1;
private long _maxVolumeSizeInGb;
private long _serverId;
private StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine;
public boolean share(VMInstanceVO vm, List<VolumeVO> vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException {
@ -495,6 +499,12 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
String volumeFolder = null;
try {
stateTransitTo(volume, Volume.Event.CreateRequested);
} catch (NoTransitionException e) {
s_logger.debug(e.toString());
return null;
}
// Create the Volume object and save it so that we can return it to the user
Account account = _accountDao.findById(volume.getAccountId());
@ -560,27 +570,31 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
throw new CloudRuntimeException(msg);
}
// Update the volume in the database
Transaction txn = Transaction.currentTxn();
txn.start();
createdVolume = _volsDao.findById(volumeId);
if (success) {
createdVolume.setPodId(pod.first().getId());
createdVolume.setPoolId(pool.getId());
createdVolume.setPoolType(pool.getPoolType());
createdVolume.setFolder(volumeFolder);
createdVolume.setPath(volumeUUID);
createdVolume.setDomainId(account.getDomainId());
createdVolume.setState(Volume.State.Ready);
} else {
createdVolume.setState(Volume.State.Destroy);
try {
if (success) {
createdVolume.setPodId(pod.first().getId());
createdVolume.setPoolId(pool.getId());
createdVolume.setPoolType(pool.getPoolType());
createdVolume.setFolder(volumeFolder);
createdVolume.setPath(volumeUUID);
createdVolume.setDomainId(account.getDomainId());
stateTransitTo(createdVolume, Volume.Event.OperationSucceeded);
}
} catch (NoTransitionException e) {
s_logger.debug("Failed to update volume state: " + e.toString());
return null;
}
_volsDao.update(volumeId, createdVolume);
txn.commit();
return new Pair<VolumeVO, String>(createdVolume, details);
}
@Override
public boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException {
return _volStateMachine.transitTo(vol, event, null, _volsDao);
}
protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId) {
@ -589,7 +603,9 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
SnapshotVO snapshot = _snapshotDao.findById(snapshotId); // Precondition: snapshot is not null and not removed.
Pair<VolumeVO, String> volumeDetails = createVolumeFromSnapshot(volume, snapshot);
createdVolume = volumeDetails.first();
if (volumeDetails != null) {
createdVolume = volumeDetails.first();
}
return createdVolume;
}
@ -670,6 +686,13 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
StoragePoolVO pool = null;
final HashSet<StoragePool> avoidPools = new HashSet<StoragePool>(avoids);
try {
stateTransitTo(volume, Volume.Event.CreateRequested);
} catch (NoTransitionException e) {
s_logger.debug("Unable to update volume state: " + e.toString());
return null;
}
if (diskOffering != null && diskOffering.isCustomized()) {
diskOffering.setDiskSize(size);
}
@ -755,8 +778,13 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
volume.setPoolType(pool.getPoolType());
volume.setPoolId(pool.getId());
volume.setPodId(pod.getId());
volume.setState(Volume.State.Ready);
return _volsDao.persist(volume);
try {
stateTransitTo(volume, Volume.Event.OperationSucceeded);
} catch (NoTransitionException e) {
s_logger.debug("Unable to update volume state: " + e.toString());
return null;
}
return volume;
}
}
@ -1062,6 +1090,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
}
protected StorageManagerImpl() {
_volStateMachine = Volume.State.getStateMachine();
}
@Override
@ -1511,7 +1540,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
}
@Override
public VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) {
public VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException {
List<SnapshotVO> snapshots = _snapshotDao.listByVolumeId(volume.getId());
if (snapshots != null && snapshots.size() > 0) {
@ -1532,7 +1561,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
HostPodVO destPoolPod = _podDao.findById(destPoolPodId);
StoragePoolVO destPool = findStoragePool(dskCh, destPoolDataCenter, destPoolPod, destPoolClusterId, null, new HashSet<StoragePool>());
String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId());
String secondaryStorageVolumePath = null;
if (destPool == null) {
throw new CloudRuntimeException("Failed to find a storage pool with enough capacity to move the volume to.");
@ -1541,56 +1569,9 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
throw new CloudRuntimeException("Failed to find secondary storage.");
}
StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId());
// Copy the volume from the source storage pool to secondary storage
CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volume.getPath(), srcPool, secondaryStorageURL, true, _copyvolumewait);
CopyVolumeAnswer cvAnswer;
try {
cvAnswer = (CopyVolumeAnswer) sendToPool(srcPool, cvCmd);
} catch (StorageUnavailableException e1) {
throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.", e1);
}
if (cvAnswer == null || !cvAnswer.getResult()) {
throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.");
}
secondaryStorageVolumePath = cvAnswer.getVolumePath();
// Copy the volume from secondary storage to the destination storage
// pool
cvCmd = new CopyVolumeCommand(volume.getId(), secondaryStorageVolumePath, destPool, secondaryStorageURL, false, _copyvolumewait);
try {
cvAnswer = (CopyVolumeAnswer) sendToPool(destPool, cvCmd);
} catch (StorageUnavailableException e1) {
throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool.");
}
if (cvAnswer == null || !cvAnswer.getResult()) {
throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool.");
}
String destPrimaryStorageVolumePath = cvAnswer.getVolumePath();
String destPrimaryStorageVolumeFolder = cvAnswer.getVolumeFolder();
// Delete the volume on the source storage pool
final DestroyCommand cmd = new DestroyCommand(srcPool, volume, null);
volume.setPath(destPrimaryStorageVolumePath);
volume.setFolder(destPrimaryStorageVolumeFolder);
volume.setPodId(destPool.getPodId());
volume.setPoolId(destPool.getId());
_volsDao.update(volume.getId(), volume);
Answer destroyAnswer = null;
try {
destroyAnswer = sendToPool(srcPool, cmd);
} catch (StorageUnavailableException e1) {
throw new CloudRuntimeException("Failed to destroy the volume from the source primary storage pool to secondary storage.");
}
if (destroyAnswer == null || !destroyAnswer.getResult()) {
throw new CloudRuntimeException("Failed to destroy the volume from the source primary storage pool to secondary storage.");
}
List<Volume> vols = new ArrayList<Volume>();
vols.add(volume);
migrateVolumes(vols, destPool);
return _volsDao.findById(volume.getId());
}
@ -1730,11 +1711,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
volume.setInstanceId(null);
volume.setUpdated(new Date());
volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId());
if (cmd.getSnapshotId() == null) {
volume.setState(Volume.State.Allocated);
} else {
volume.setState(Volume.State.Creating);
}
volume = _volsDao.persist(volume);
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, size);
_usageEventDao.persist(usageEvent);
@ -1779,12 +1756,16 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
@Override
@DB
public void destroyVolume(VolumeVO volume) throws ConcurrentOperationException {
assert (volume.getState() != Volume.State.Destroy) : "Why destroy method is called for the volume that is already destroyed?";
Transaction txn = Transaction.currentTxn();
txn.start();
_volsDao.update(volume, Volume.Event.Destroy);
public boolean destroyVolume(VolumeVO volume) throws ConcurrentOperationException {
try {
if (!stateTransitTo(volume, Volume.Event.DestroyRequested)) {
throw new ConcurrentOperationException("Failed to transit to destroyed state");
}
} catch (NoTransitionException e) {
s_logger.debug("Unable to destoy the volume: " + e.toString());
return false;
}
long volumeId = volume.getId();
// Delete the recurring snapshot policies for this volume.
@ -1803,8 +1784,19 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName());
_usageEventDao.persist(usageEvent);
}
txn.commit();
try {
if (!stateTransitTo(volume, Volume.Event.OperationSucceeded)) {
throw new ConcurrentOperationException("Failed to transit state");
}
} catch (NoTransitionException e) {
s_logger.debug("Unable to change volume state: " + e.toString());
return false;
}
return true;
}
@Override
@ -2406,7 +2398,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
Account caller = UserContext.current().getCaller();
// Check that the volume ID is valid
VolumeVO volume = _volsDao.acquireInLockTable(volumeId, 10);
VolumeVO volume = _volsDao.findById(volumeId);
if (volume == null) {
throw new InvalidParameterValueException("Unable to aquire volume with ID: " + volumeId);
}
@ -2414,36 +2406,23 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
//permission check
_accountMgr.checkAccess(caller, null, volume);
try {
// Check that the volume is not currently attached to any VM
if (volume.getInstanceId() != null) {
throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM.");
}
// Check that the volume is stored on shared storage
// NOTE: We used to ensure the volume is on shared storage before deleting. However, this seems like an unnecessary
// check since all we allow
// is deleting a detached volume. Is there a technical reason why the volume has to be on shared storage? If so,
// uncomment this...otherwise,
// just delete the detached volume regardless of storage pool.
// if (!volumeOnSharedStoragePool(volume)) {
// throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
// }
// Check that the volume is not currently attached to any VM
if (volume.getInstanceId() != null) {
throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM.");
}
// Check that the volume is not already destroyed
if (volume.getState() != Volume.State.Destroy) {
destroyVolume(volume);
}
try {
expungeVolume(volume);
} catch (Exception e) {
s_logger.warn("Failed to expunge volume:", e);
// Check that the volume is not already destroyed
if (volume.getState() != Volume.State.Destroy) {
if (!destroyVolume(volume)) {
return false;
}
} finally {
_volumeDao.releaseFromLockTable(volumeId);
}
try {
expungeVolume(volume);
} catch (Exception e) {
s_logger.warn("Failed to expunge volume:", e);
return false;
}
return true;
@ -2569,6 +2548,189 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
}
}
}
@DB
@Override
public Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException {
VolumeVO vol = _volsDao.findById(volumeId);
if (vol == null) {
throw new InvalidParameterValueException("Failed to find the volume id: " + volumeId);
}
if (vol.getState() != Volume.State.Ready) {
throw new InvalidParameterValueException("Volume must be in ready state");
}
if (vol.getInstanceId() != null) {
throw new InvalidParameterValueException("Volume needs to be dettached from VM");
}
StoragePool destPool = _storagePoolDao.findById(storagePoolId);
if (destPool == null) {
throw new InvalidParameterValueException("Faild to find the destination storage pool: " + storagePoolId);
}
List<Volume> vols = new ArrayList<Volume>();
vols.add(vol);
migrateVolumes(vols, destPool);
return vol;
}
@DB
public boolean migrateVolumes(List<Volume> volumes, StoragePool destPool) throws ConcurrentOperationException {
Transaction txn = Transaction.currentTxn();
txn.start();
boolean transitResult = false;
try {
for (Volume volume : volumes) {
try {
if (!stateTransitTo(volume, Volume.Event.MigrationRequested)) {
throw new ConcurrentOperationException("Failed to transit volume state");
}
} catch (NoTransitionException e) {
s_logger.debug("Failed to set state into migrate: " + e.toString());
throw new CloudRuntimeException("Failed to set state into migrate: " + e.toString());
}
}
transitResult = true;
} finally {
if (!transitResult) {
txn.rollback();
} else {
txn.commit();
}
}
//At this stage, nobody can modify volumes. Send the copyvolume command
List<Pair<StoragePoolVO,DestroyCommand>> destroyCmds = new ArrayList<Pair<StoragePoolVO,DestroyCommand>>();
List<CopyVolumeAnswer> answers = new ArrayList<CopyVolumeAnswer>();
try {
for (Volume volume: volumes) {
String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId());
StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId());
CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volume.getPath(), srcPool, secondaryStorageURL, true, _copyvolumewait);
CopyVolumeAnswer cvAnswer;
try {
cvAnswer = (CopyVolumeAnswer) sendToPool(srcPool, cvCmd);
} catch (StorageUnavailableException e1) {
throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.", e1);
}
if (cvAnswer == null || !cvAnswer.getResult()) {
throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.");
}
String secondaryStorageVolumePath = cvAnswer.getVolumePath();
// Copy the volume from secondary storage to the destination storage
// pool
cvCmd = new CopyVolumeCommand(volume.getId(), secondaryStorageVolumePath, destPool, secondaryStorageURL, false, _copyvolumewait);
try {
cvAnswer = (CopyVolumeAnswer) sendToPool(destPool, cvCmd);
} catch (StorageUnavailableException e1) {
throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool.");
}
if (cvAnswer == null || !cvAnswer.getResult()) {
throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool.");
}
answers.add(cvAnswer);
destroyCmds.add(new Pair<StoragePoolVO, DestroyCommand>(srcPool, new DestroyCommand(srcPool, volume, null)));
}
} finally {
if (answers.size() != volumes.size()) {
//this means one of copying volume failed
for (Volume volume : volumes) {
try {
stateTransitTo(volume, Volume.Event.OperationFailed);
} catch (NoTransitionException e) {
s_logger.debug("Failed to change volume state: " + e.toString());
}
}
} else {
//Need a transaction, make sure all the volumes get migrated to new storage pool
txn = Transaction.currentTxn();
txn.start();
transitResult = false;
try {
for (int i = 0; i < volumes.size(); i++) {
CopyVolumeAnswer answer = answers.get(i);
VolumeVO volume = (VolumeVO)volumes.get(i);
Long oldPoolId = volume.getPoolId();
volume.setPath(answer.getVolumePath());
volume.setFolder(answer.getVolumeFolder());
volume.setPodId(destPool.getPodId());
volume.setPoolId(destPool.getId());
volume.setLastPoolId(oldPoolId);
try {
stateTransitTo(volume, Volume.Event.OperationSucceeded);
} catch (NoTransitionException e) {
s_logger.debug("Failed to change volume state: " + e.toString());
throw new CloudRuntimeException("Failed to change volume state: " + e.toString());
}
}
transitResult = true;
} finally {
if (!transitResult) {
txn.rollback();
} else {
txn.commit();
}
}
}
}
//all the volumes get migrated to new storage pool, need to delete the copy on old storage pool
for (Pair<StoragePoolVO, DestroyCommand> cmd : destroyCmds) {
try {
Answer cvAnswer = sendToPool(cmd.first(), cmd.second());
} catch (StorageUnavailableException e) {
s_logger.debug("Unable to delete the old copy on storage pool: " + e.toString());
}
}
return true;
}
@Override
public boolean StorageMigration(VirtualMachineProfile<? extends VirtualMachine> vm, StoragePool destPool) throws ConcurrentOperationException {
List<VolumeVO> vols = _volsDao.findUsableVolumesForInstance(vm.getId());
List<Volume> volumesNeedToMigrate = new ArrayList<Volume>();
for (VolumeVO volume : vols) {
if (volume.getState() != Volume.State.Ready) {
s_logger.debug("volume: " + volume.getId() + " is in " + volume.getState() + " state");
throw new CloudRuntimeException("volume: " + volume.getId() + " is in " + volume.getState() + " state");
}
if (volume.getPoolId() == destPool.getId()) {
s_logger.debug("volume: " + volume.getId() + " is on the same storage pool: " + destPool.getId());
continue;
}
//Only support migrate in the same pod at first.
if (volume.getPodId() != destPool.getPodId()) {
throw new InvalidParameterValueException("Can't migrate vm between different pods: volume: " + volume.getId() + " at pod: "
+ volume.getPodId() + ", while dest pool: " + destPool.getId() + " at pod: " + destPool.getPodId());
}
volumesNeedToMigrate.add(volume);
}
if (volumesNeedToMigrate.isEmpty()) {
s_logger.debug("No volume need to be migrated");
return true;
}
return migrateVolumes(volumesNeedToMigrate, destPool);
}
@Override
public void prepare(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException {
@ -2639,19 +2801,19 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
}
try {
_volsDao.update(newVol, Volume.Event.Create);
} catch (ConcurrentOperationException e) {
throw new StorageUnavailableException("Unable to create " + newVol, newVol.getPoolId());
}
stateTransitTo(newVol, Volume.Event.CreateRequested);
} catch (NoTransitionException e) {
throw new CloudRuntimeException("Unable to create " + e.toString());
}
Pair<VolumeTO, StoragePool> created = createVolume(newVol, _diskOfferingDao.findById(newVol.getDiskOfferingId()), vm, vols, dest);
if (created == null) {
Long poolId = newVol.getPoolId();
newVol.setPoolId(null);
try {
_volsDao.update(newVol, Volume.Event.OperationFailed);
} catch (ConcurrentOperationException e) {
throw new CloudRuntimeException("Unable to update the failure on a volume: " + newVol, e);
}
stateTransitTo(newVol, Volume.Event.OperationFailed);
} catch (NoTransitionException e) {
throw new CloudRuntimeException("Unable to update the failure on a volume: " + newVol, e);
}
throw new StorageUnavailableException("Unable to create " + newVol, poolId == null ? -1L : poolId);
}
created.first().setDeviceId(newVol.getDeviceId().intValue());
@ -2661,8 +2823,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
newVol.setPoolType(created.second().getPoolType());
newVol.setPodId(created.second().getPodId());
try {
_volsDao.update(newVol, Volume.Event.OperationSucceeded);
} catch (ConcurrentOperationException e) {
stateTransitTo(newVol, Volume.Event.OperationSucceeded);
} catch (NoTransitionException e) {
throw new CloudRuntimeException("Unable to update an CREATE operation succeeded on volume " + newVol, e);
}
if (s_logger.isDebugEnabled()) {
@ -2676,25 +2838,26 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
@DB
protected VolumeVO switchVolume(VolumeVO existingVolume, VirtualMachineProfile<? extends VirtualMachine> vm) throws StorageUnavailableException {
Transaction txn = Transaction.currentTxn();
txn.start();
try {
txn.start();
_volsDao.update(existingVolume, Volume.Event.Destroy);
Long templateIdToUse = null;
Long volTemplateId = existingVolume.getTemplateId();
long vmTemplateId = vm.getTemplateId();
if (volTemplateId != null && volTemplateId.longValue() != vmTemplateId) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("switchVolume: Old Volume's templateId: "+volTemplateId + " does not match the VM's templateId: "+vmTemplateId+", updating templateId in the new Volume");
}
templateIdToUse = vmTemplateId;
}
VolumeVO newVolume = allocateDuplicateVolume(existingVolume, templateIdToUse);
txn.commit();
return newVolume;
} catch (ConcurrentOperationException e) {
throw new StorageUnavailableException("Unable to duplicate the volume " + existingVolume, existingVolume.getPoolId(), e);
stateTransitTo(existingVolume, Volume.Event.DestroyRequested);
} catch (NoTransitionException e) {
s_logger.debug("Unable to destroy existing volume: " + e.toString());
}
Long templateIdToUse = null;
Long volTemplateId = existingVolume.getTemplateId();
long vmTemplateId = vm.getTemplateId();
if (volTemplateId != null && volTemplateId.longValue() != vmTemplateId) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("switchVolume: Old Volume's templateId: "+volTemplateId + " does not match the VM's templateId: "+vmTemplateId+", updating templateId in the new Volume");
}
templateIdToUse = vmTemplateId;
}
VolumeVO newVolume = allocateDuplicateVolume(existingVolume, templateIdToUse);
txn.commit();
return newVolume;
}
public Pair<VolumeTO, StoragePool> createVolume(VolumeVO toBeCreated, DiskOfferingVO offering, VirtualMachineProfile<? extends VirtualMachine> vm, List<? extends Volume> alreadyCreated,
@ -2716,8 +2879,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
}
toBeCreated.setPoolId(pool.getId());
try {
_volsDao.update(toBeCreated, Volume.Event.OperationRetry);
} catch (ConcurrentOperationException e) {
stateTransitTo(toBeCreated, Volume.Event.OperationRetry);
} catch (NoTransitionException e) {
throw new CloudRuntimeException("Unable to retry a create operation on volume " + toBeCreated);
}
@ -2957,6 +3120,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
}
return capacities;
}
@Override

View File

@ -26,8 +26,9 @@ import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.fsm.StateDao;
public interface VolumeDao extends GenericDao<VolumeVO, Long> {
public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.State, Volume.Event, Volume> {
List<VolumeVO> findDetachedByAccount(long accountId);
List<VolumeVO> findByAccount(long accountId);
Pair<Long, Long> getCountAndTotalByPool(long poolId);
@ -45,13 +46,7 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long> {
List<VolumeVO> findByInstanceAndDeviceId(long instanceId, long deviceId);
List<VolumeVO> findUsableVolumesForInstance(long instanceId);
Long countAllocatedVolumesForAccount(long accountId);
/**
* Updates the volume only if the state in memory matches the state in the database.
* @param vol Volume to be updated.
* @param event event that causes the database change.
* @return true if update happened, false if not.
*/
boolean update(VolumeVO vol, Volume.Event event) throws ConcurrentOperationException;
HypervisorType getHypervisorType(long volumeId);
List<VolumeVO> listVolumesToBeDestroyed();

View File

@ -31,6 +31,7 @@ import com.cloud.exception.ConcurrentOperationException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Volume;
import com.cloud.storage.Volume.Event;
import com.cloud.storage.Volume.Type;
import com.cloud.storage.VolumeVO;
import com.cloud.utils.Pair;
@ -58,7 +59,6 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
protected final SearchBuilder<VolumeVO> InstanceStatesSearch;
protected final SearchBuilder<VolumeVO> AllFieldsSearch;
protected GenericSearchBuilder<VolumeVO, Long> CountByAccount;
protected final Attribute _stateAttr;
protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?";
protected static final String SELECT_HYPERTYPE_FROM_VOLUME = "SELECT c.hypervisor_type from volumes v, storage_pool s, cluster c where v.pool_id = s.id and s.cluster_id = c.id and v.id = ?";
@ -203,28 +203,6 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
update(volumeId, volume);
}
@Override
public boolean update(VolumeVO vol, Volume.Event event) throws ConcurrentOperationException {
Volume.State oldState = vol.getState();
Volume.State newState = oldState.getNextState(event);
assert newState != null : "Event "+ event + " cannot happen from " + oldState;
UpdateBuilder builder = getUpdateBuilder(vol);
builder.set(vol, _stateAttr, newState);
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("id", vol.getId());
sc.setParameters("state", oldState);
int rows = update(builder, sc, null);
if (rows != 1) {
VolumeVO dbVol = findById(vol.getId());
throw new ConcurrentOperationException("Unable to update " + vol + ": Old State=" + oldState + "; New State = " + newState + "; DB State=" + dbVol.getState());
}
return rows == 1;
}
@Override
@DB
public HypervisorType getHypervisorType(long volumeId) {
@ -275,6 +253,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ);
AllFieldsSearch.and("destroyed", AllFieldsSearch.entity().getState(), Op.EQ);
AllFieldsSearch.and("notDestroyed", AllFieldsSearch.entity().getState(), Op.NEQ);
AllFieldsSearch.and("updatedCount", AllFieldsSearch.entity().getUpdatedCount(), Op.EQ);
AllFieldsSearch.done();
DetachedAccountIdSearch = createSearchBuilder();
@ -312,9 +291,6 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
CountByAccount.and("account", CountByAccount.entity().getAccountId(), SearchCriteria.Op.EQ);
CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN);
CountByAccount.done();
_stateAttr = _allAttributes.get("state");
assert _stateAttr != null : "Couldn't get the state attribute";
}
@Override @DB(txn=false)
@ -348,4 +324,38 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
return listBy(sc);
}
@Override
public boolean updateState(com.cloud.storage.Volume.State currentState,
Event event, com.cloud.storage.Volume.State nextState, Volume vo,
Object data) {
Long oldUpdated = vo.getUpdatedCount();
Date oldUpdatedTime = vo.getUpdated();
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("id", vo.getId());
sc.setParameters("state", currentState);
sc.setParameters("updatedCount", vo.getUpdatedCount());
vo.incrUpdatedCount();
UpdateBuilder builder = getUpdateBuilder(vo);
builder.set(vo, "state", nextState);
builder.set(vo, "updated", new Date());
int rows = update((VolumeVO)vo, sc);
if (rows == 0 && s_logger.isDebugEnabled()) {
VolumeVO dbVol = findByIdIncludingRemoved(vo.getId());
if (dbVol != null) {
StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString());
str.append(": DB Data={id=").append(dbVol.getId()).append("; state=").append(dbVol.getState()).append("; updatecount=").append(dbVol.getUpdatedCount()).append(";updatedTime=").append(dbVol.getUpdated());
str.append(": New Data={id=").append(vo.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(vo.getUpdatedCount()).append("; updatedTime=").append(vo.getUpdated());
str.append(": stale Data={id=").append(vo.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated).append("; updatedTime=").append(oldUpdatedTime);
} else {
s_logger.debug("Unable to update volume: id=" + vo.getId() + ", as there is no such volume exists in the database anymore");
}
}
return rows > 0;
}
}

View File

@ -112,6 +112,7 @@ import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
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.State;
@ -292,6 +293,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
_snapshotDao.update(snapshotId, snapshot);
} else {
long preSnapshotId = 0;
if (preSnapshotVO != null && preSnapshotVO.getBackupSnapshotId() != null) {
preSnapshotId = preId;
// default delta snap number is 16
@ -315,6 +317,12 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
preSnapshotId = 0;
}
}
//If the volume is moved around, backup a full snapshot to secondary storage
if (volume.getLastPoolId() != null && volume.getPoolId() != volume.getLastPoolId()) {
preSnapshotId = 0;
volume.setLastPoolId(volume.getPoolId());
}
snapshot = updateDBOnCreate(snapshotId, answer.getSnapshotPath(), preSnapshotId);
}
// Get the snapshot_schedule table entry for this snapshot and
@ -348,17 +356,24 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
@DB
@ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "creating snapshot", async = true)
public SnapshotVO createSnapshot(Long volumeId, Long policyId, Long snapshotId) {
VolumeVO v = _volsDao.findById(volumeId);
Account owner = _accountMgr.getAccount(v.getAccountId());
VolumeVO volume = _volsDao.findById(volumeId);
if (volume == null) {
throw new InvalidParameterValueException("No such volume exist");
}
Account owner = _accountMgr.getAccount(volume.getAccountId());
SnapshotVO snapshot = null;
VolumeVO volume = null;
boolean backedUp = false;
// does the caller have the authority to act on this volume
_accountMgr.checkAccess(UserContext.current().getCaller(), null, v);
_accountMgr.checkAccess(UserContext.current().getCaller(), null, volume);
try {
if (v != null && _volsDao.getHypervisorType(v.getId()).equals(HypervisorType.KVM)) {
if (volume != null && _volsDao.getHypervisorType(volume.getId()).equals(HypervisorType.KVM)) {
/* KVM needs to lock on the vm of volume, because it takes snapshot on behalf of vm, not volume */
UserVmVO uservm = _vmDao.findById(v.getInstanceId());
UserVmVO uservm = _vmDao.findById(volume.getInstanceId());
if (uservm != null) {
UserVmVO vm = _vmDao.acquireInLockTable(uservm.getId(), 10);
if (vm == null) {
@ -366,13 +381,13 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
}
}
}
Long poolId = v.getPoolId();
Long poolId = volume.getPoolId();
if (poolId == null) {
throw new CloudRuntimeException("You cannot take a snapshot of a volume until it has been attached to an instance");
}
if (_volsDao.getHypervisorType(v.getId()).equals(HypervisorType.KVM)) {
StoragePoolVO storagePool = _storagePoolDao.findById(v.getPoolId());
if (_volsDao.getHypervisorType(volume.getId()).equals(HypervisorType.KVM)) {
StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId());
ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId());
List<HostVO> hosts = _hostDao.listByCluster(cluster.getId());
if (hosts != null && !hosts.isEmpty()) {
@ -385,8 +400,8 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
}
// if volume is attached to a vm in destroyed or expunging state; disallow
if (v.getInstanceId() != null) {
UserVmVO userVm = _vmDao.findById(v.getInstanceId());
if (volume.getInstanceId() != null) {
UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
if (userVm != null) {
if (userVm.getState().equals(State.Destroyed) || userVm.getState().equals(State.Expunging)) {
_snapshotDao.expunge(snapshotId);
@ -395,23 +410,24 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
}
if(userVm.getHypervisorType() == HypervisorType.VMware) {
List<SnapshotVO> activeSnapshots = _snapshotDao.listByInstanceId(v.getInstanceId(), Snapshot.Status.Creating, Snapshot.Status.CreatedOnPrimary, Snapshot.Status.BackingUp);
List<SnapshotVO> activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.Status.Creating, Snapshot.Status.CreatedOnPrimary, Snapshot.Status.BackingUp);
if(activeSnapshots.size() > 1)
throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later");
}
}
}
volume = _volsDao.acquireInLockTable(volumeId, 10);
if (volume == null) {
_snapshotDao.expunge(snapshotId);
volume = _volsDao.findById(volumeId);
if (volume == null) {
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist");
} else {
volume = null;
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " is being used, try it later ");
}
//when taking snapshot, make sure nobody can delete/move the volume
boolean stateTransit = false;
try {
stateTransit = _storageMgr.stateTransitTo(volume, Volume.Event.SnapshotRequested);
} catch (NoTransitionException e) {
s_logger.debug("Failed transit volume state: " + e.toString());
} finally {
if (!stateTransit) {
_snapshotDao.expunge(snapshotId);
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " is being used, try it later ");
}
}
snapshot = createSnapshotOnPrimary(volume, policyId, snapshotId);
@ -442,7 +458,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId());
if ((freshSnapshot != null) && backedUp) {
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null,
v.getSize());
volume.getSize());
_usageEventDao.persist(usageEvent);
}
if( !backedUp ) {
@ -459,10 +475,13 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
_snapshotDao.update(snapshotId, snapshot);
}
}
if ( volume != null ) {
_volsDao.releaseFromLockTable(volumeId);
try {
_storageMgr.stateTransitTo(volume, Volume.Event.OperationSucceeded);
} catch (NoTransitionException e) {
s_logger.debug("Failed to transit volume state: " + e.toString());
}
}
return snapshot;

View File

@ -156,6 +156,7 @@ import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.Storage.TemplateType;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolStatus;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VMTemplateHostVO;
@ -650,7 +651,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
if (moveVolumeNeeded) {
// Move the volume to a storage pool in the VM's zone, pod, or cluster
volume = _storageMgr.moveVolume(volume, vmRootVolumePool.getDataCenterId(), vmRootVolumePool.getPodId(), vmRootVolumePool.getClusterId(), dataDiskHyperType);
try {
volume = _storageMgr.moveVolume(volume, vmRootVolumePool.getDataCenterId(), vmRootVolumePool.getPodId(), vmRootVolumePool.getClusterId(), dataDiskHyperType);
} catch (ConcurrentOperationException e) {
throw new CloudRuntimeException(e.toString());
}
}
AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor();
@ -3186,6 +3191,39 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
public UserVm getUserVm(long vmId) {
return _vmDao.findById(vmId);
}
@Override
public VirtualMachine vmStorageMigration(Long vmId, StoragePool destPool) {
// access check - only root admin can migrate VM
Account caller = UserContext.current().getCaller();
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Caller is not a root admin, permission denied to migrate the VM");
}
throw new PermissionDeniedException("No permission to migrate VM, Only Root Admin can migrate a VM!");
}
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
if (vm == null) {
throw new InvalidParameterValueException("Unable to find the VM by id=" + vmId);
}
if (vm.getState() != State.Stopped) {
throw new InvalidParameterValueException("VM is not Stopped, unable to migrate the vm " + vm);
}
if (vm.getType() != VirtualMachine.Type.User) {
throw new InvalidParameterValueException("can only do storage migration on user vm");
}
HypervisorType destHypervisorType = _clusterDao.findById(destPool.getClusterId()).getHypervisorType();
if (vm.getHypervisorType() != destHypervisorType) {
throw new InvalidParameterValueException("hypervisor is not compatible: dest: " + destHypervisorType.toString() + ", vm: " + vm.getHypervisorType().toString());
}
VMInstanceVO migratedVm = _itMgr.storageMigration(vm, destPool);
return migratedVm;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true)

View File

@ -42,12 +42,12 @@ public class UserVmStateListener implements StateListener<State, VirtualMachine.
}
@Override
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Long id) {
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) {
return true;
}
@Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Long id) {
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) {
if(!status){
return false;
}

View File

@ -35,6 +35,7 @@ import com.cloud.network.NetworkVO;
import com.cloud.offering.ServiceOffering;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateVO;
import com.cloud.user.Account;
import com.cloud.user.User;
@ -122,4 +123,6 @@ public interface VirtualMachineManager extends Manager {
VMInstanceVO findById(long vmId);
<T extends VMInstanceVO> T storageMigration(T vm, StoragePool storagePoolId);
}

View File

@ -109,6 +109,7 @@ import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
@ -1104,7 +1105,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
protected boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId, String reservationId) throws NoTransitionException {
vm.setReservationId(reservationId);
return _stateMachine.transitTo(vm, e, hostId, _vmDao);
return _stateMachine.transitTo(vm, e, new Pair<Long, Long>(vm.getHostId(), hostId), _vmDao);
}
@Override
@ -1119,7 +1120,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
vm.setLastHostId(vm.getHostId());
}
}
return _stateMachine.transitTo(vm, e, hostId, _vmDao);
return _stateMachine.transitTo(vm, e, new Pair<Long, Long>(vm.getHostId(), hostId), _vmDao);
}
@Override
@ -1169,6 +1170,52 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
return true;
}
@Override
public <T extends VMInstanceVO> T storageMigration(T vm, StoragePool destPool) {
VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
long vmId = vm.getId();
vm = vmGuru.findById(vmId);
try {
stateTransitTo(vm, VirtualMachine.Event.StorageMigrationRequested, null);
} catch (NoTransitionException e) {
s_logger.debug("Unable to migrate vm: " + e.toString());
throw new CloudRuntimeException("Unable to migrate vm: " + e.toString());
}
VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
boolean migrationResult = false;
try {
try {
migrationResult = _storageMgr.StorageMigration(profile, destPool);
} catch (ConcurrentOperationException e) {
}
} finally {
if (migrationResult) {
try {
//when start the vm next time, don;'t look at last_host_id, only choose the host based on volume/storage pool
vm.setLastHostId(null);
stateTransitTo(vm, VirtualMachine.Event.AgentReportStopped, null);
} catch (NoTransitionException e) {
s_logger.debug("Failed to migrate vm: " + e.toString());
throw new CloudRuntimeException("Failed to migrate vm: " + e.toString());
}
} else {
s_logger.debug("storage migration failed: ");
try {
stateTransitTo(vm, VirtualMachine.Event.AgentReportStopped, null);
} catch (NoTransitionException e) {
s_logger.debug("Failed to change vm state: " + e.toString());
throw new CloudRuntimeException("Failed to change vm state: " + e.toString());
}
}
}
return vm;
}
@Override
public <T extends VMInstanceVO> T migrate(T vm, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException,

View File

@ -28,6 +28,7 @@ import org.apache.log4j.Logger;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDaoImpl;
import com.cloud.utils.Pair;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.db.Attribute;
import com.cloud.utils.db.GenericDaoBase;
@ -279,13 +280,17 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
}
@Override
public boolean updateState(State oldState, Event event, State newState, VirtualMachine vm, Long hostId) {
public boolean updateState(State oldState, Event event, State newState, VirtualMachine vm, Object opaque) {
if (newState == null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("There's no way to transition from old state: " + oldState.toString() + " event: " + event.toString());
}
return false;
}
@SuppressWarnings("unchecked")
Pair<Long, Long> hosts = (Pair<Long,Long>)opaque;
Long newHostId = hosts.second();
VMInstanceVO vmi = (VMInstanceVO)vm;
Long oldHostId = vmi.getHostId();
@ -302,7 +307,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
UpdateBuilder ub = getUpdateBuilder(vmi);
ub.set(vmi, "state", newState);
ub.set(vmi, "hostId", hostId);
ub.set(vmi, "hostId", newHostId);
ub.set(vmi, "podIdToDeployIn", vmi.getPodIdToDeployIn());
ub.set(vmi, _updateTimeAttr, new Date());

View File

@ -382,6 +382,7 @@ CREATE TABLE `cloud`.`volumes` (
`account_id` bigint unsigned NOT NULL COMMENT 'owner. foreign key to account table',
`domain_id` bigint unsigned NOT NULL COMMENT 'the domain that the owner belongs to',
`pool_id` bigint unsigned COMMENT 'pool it belongs to. foreign key to storage_pool table',
`last_pool_id` bigint unsigned COMMENT 'last pool it belongs to.',
`instance_id` bigint unsigned NULL COMMENT 'vm instance it belongs to. foreign key to vm_instance table',
`device_id` bigint unsigned NULL COMMENT 'which device inside vm instance it is ',
`name` varchar(255) COMMENT 'A user specified name for the volume',
@ -404,6 +405,7 @@ CREATE TABLE `cloud`.`volumes` (
`removed` datetime COMMENT 'Date removed. not null if removed',
`state` varchar(32) COMMENT 'State machine',
`chain_info` text COMMENT 'save possible disk chain info in primary storage',
`update_count` bigint unsigned NOT NULL DEFAULT 0 COMMENT 'date state was updated',
PRIMARY KEY (`id`),
INDEX `i_volumes__removed`(`removed`),
INDEX `i_volumes__pod_id`(`pod_id`),
@ -412,9 +414,11 @@ CREATE TABLE `cloud`.`volumes` (
INDEX `i_volumes__account_id`(`account_id`),
CONSTRAINT `fk_volumes__pool_id` FOREIGN KEY `fk_volumes__pool_id` (`pool_id`) REFERENCES `storage_pool` (`id`),
INDEX `i_volumes__pool_id`(`pool_id`),
INDEX `i_volumes__last_pool_id`(`last_pool_id`),
CONSTRAINT `fk_volumes__instance_id` FOREIGN KEY `fk_volumes__instance_id` (`instance_id`) REFERENCES `vm_instance` (`id`) ON DELETE CASCADE,
INDEX `i_volumes__instance_id`(`instance_id`),
INDEX `i_volumes__state`(`state`)
INDEX `i_volumes__state`(`state`),
INDEX `i_volumes__update_count`(`update_count`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`snapshots` (

View File

@ -20,12 +20,14 @@ class jobStatus(object):
self.duration = None
self.jobId = None
self.responsecls = None
def __str__(self):
return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems()))
class workThread(threading.Thread):
def __init__(self, in_queue, outqueue, apiClient, db=None, lock=None):
threading.Thread.__init__(self)
self.inqueue = in_queue
self.output = outqueue
self.connection = apiClient.connection
self.connection = apiClient.connection.__copy__()
self.db = None
self.lock = lock

View File

@ -51,6 +51,7 @@ class cloudConnection(object):
requestUrl += "&signature=%s"%sig
self.connection.request("GET", "/client/api?%s"%requestUrl)
return self.connection.getresponse().read()
def make_request_without_auth(self, command, requests={}):

View File

@ -20,6 +20,6 @@ package com.cloud.utils.fsm;
public interface StateDao <S,E,V> {
boolean updateState(S currentState, E event, S nextState, V vo, Long id);
boolean updateState(S currentState, E event, S nextState, V vo, Object data);
}

View File

@ -27,11 +27,11 @@ public interface StateListener <S,E,V> {
* @param newState VM's new state
* @param vo the VM instance
* @param status the state transition is allowed or not
* @param id host id
* @param opaque host id
* @param vmDao VM dao
* @return
*/
public boolean preStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Long id);
public boolean preStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Object opaque);
/**
* Event is triggered after state machine transition finished
@ -42,5 +42,5 @@ public interface StateListener <S,E,V> {
* @param status the state transition is allowed or not
* @return
*/
public boolean postStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Long id);
public boolean postStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Object opaque);
}

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) throws NoTransitionException {
public boolean transitTo(V vo, E e, Object opaque, StateDao<S,E,V> dao) throws NoTransitionException {
S currentState = vo.getState();
S nextState = getNextState(currentState, e);
@ -109,17 +109,16 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
}
for (StateListener<S,E, V> listener : _listeners) {
listener.preStateTransitionEvent(currentState, e, nextState, vo, transitionStatus, id);
listener.preStateTransitionEvent(currentState, e, nextState, vo, transitionStatus, opaque);
}
Long oldHostId = vo.getHostId();
transitionStatus = dao.updateState(currentState, e, nextState, vo, id);
transitionStatus = dao.updateState(currentState, e, nextState, vo, opaque);
if (!transitionStatus) {
return false;
}
for (StateListener<S,E, V> listener : _listeners) {
listener.postStateTransitionEvent(currentState, e, nextState, vo, transitionStatus, oldHostId);
listener.postStateTransitionEvent(currentState, e, nextState, vo, transitionStatus, opaque);
}
return true;

View File

@ -23,5 +23,4 @@ public interface StateObject<S> {
* @return finite state.
*/
S getState();
Long getHostId();
}