mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Add storage migration
This commit is contained in:
parent
fc3d93e3e7
commit
92eaf49f29
@ -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;
|
||||
@ -78,4 +80,6 @@ public interface MockStorageManager extends Manager {
|
||||
public Answer CreatePrivateTemplateFromVolume(CreatePrivateTemplateFromVolumeCommand cmd);
|
||||
|
||||
StoragePoolInfo getLocalStorage(String hostGuid, Long storageSize);
|
||||
|
||||
CopyVolumeAnswer CopyVolume(CopyVolumeCommand cmd);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -670,5 +672,49 @@ 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -352,6 +354,11 @@ public class MockVmManagerImpl implements MockVmManager {
|
||||
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) {
|
||||
if (!info.isEnabled()) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -71,5 +71,12 @@ 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 ///////////////////////
|
||||
@ -67,6 +70,10 @@ public class MigrateVMCmd extends BaseAsyncCmd {
|
||||
return virtualMachineId;
|
||||
}
|
||||
|
||||
public Long getStoragePoolId() {
|
||||
return storageId;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
@ -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());
|
||||
|
||||
@ -105,6 +105,7 @@ public class EventTypes {
|
||||
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_MIGRATE = "VOLUME.MIGRATE";
|
||||
|
||||
// Domains
|
||||
public static final String EVENT_DOMAIN_CREATE = "DOMAIN.CREATE";
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -50,6 +50,9 @@ public class VolumeVO implements Volume {
|
||||
@Column(name = "pool_id")
|
||||
Long poolId;
|
||||
|
||||
@Column(name = "last_pool_id")
|
||||
Long lastPoolId;
|
||||
|
||||
@Column(name = "account_id")
|
||||
long accountId;
|
||||
|
||||
@ -111,6 +114,9 @@ public class VolumeVO implements Volume {
|
||||
@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;
|
||||
}
|
||||
@ -382,6 +400,14 @@ public class VolumeVO implements Volume {
|
||||
this.chainInfo = chainInfo;
|
||||
}
|
||||
|
||||
public Long getLastPoolId() {
|
||||
return this.lastPoolId;
|
||||
}
|
||||
|
||||
public void setLastPoolId(Long poolId) {
|
||||
this.lastPoolId = poolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return NumbersUtil.hash(id);
|
||||
|
||||
@ -2376,8 +2376,10 @@ 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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -87,8 +89,9 @@ public interface StorageManager extends Manager {
|
||||
* @param destPoolPodId
|
||||
* @param destPoolClusterId
|
||||
* @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
|
||||
@ -111,8 +114,9 @@ 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
|
||||
* @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;
|
||||
|
||||
}
|
||||
|
||||
@ -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,28 +570,32 @@ 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) {
|
||||
|
||||
// By default, assume failure.
|
||||
@ -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();
|
||||
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;
|
||||
}
|
||||
|
||||
_volsDao.update(volume, Volume.Event.Destroy);
|
||||
long volumeId = volume.getId();
|
||||
|
||||
// Delete the recurring snapshot policies for this volume.
|
||||
@ -1804,7 +1785,18 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
||||
_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;
|
||||
@ -2570,6 +2549,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);
|
||||
}
|
||||
|
||||
@ -2958,6 +3121,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
||||
return capacities;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
public StoragePool getStoragePool(long id) {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 ) {
|
||||
@ -460,9 +476,12 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -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();
|
||||
@ -3187,6 +3192,39 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
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)
|
||||
public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -1170,6 +1171,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,
|
||||
VirtualMachineMigrationException {
|
||||
|
||||
@ -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,7 +280,7 @@ 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());
|
||||
@ -287,6 +288,10 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Pair<Long, Long> hosts = (Pair<Long,Long>)opaque;
|
||||
Long newHostId = hosts.second();
|
||||
|
||||
VMInstanceVO vmi = (VMInstanceVO)vm;
|
||||
Long oldHostId = vmi.getHostId();
|
||||
Long oldUpdated = vmi.getUpdated();
|
||||
@ -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());
|
||||
|
||||
|
||||
@ -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` (
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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={}):
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -23,5 +23,4 @@ public interface StateObject<S> {
|
||||
* @return finite state.
|
||||
*/
|
||||
S getState();
|
||||
Long getHostId();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user